/// An AST check that diagnose when the class requires a -dealloc method and /// is missing one. void ObjCDeallocChecker::checkASTDecl(const ObjCImplementationDecl *D, AnalysisManager &Mgr, BugReporter &BR) const { assert(Mgr.getLangOpts().getGC() != LangOptions::GCOnly); assert(!Mgr.getLangOpts().ObjCAutoRefCount); initIdentifierInfoAndSelectors(Mgr.getASTContext()); const ObjCInterfaceDecl *ID = D->getClassInterface(); // If the class is known to have a lifecycle with a separate teardown method // then it may not require a -dealloc method. if (classHasSeparateTeardown(ID)) return; // Does the class contain any synthesized properties that are retainable? // If not, skip the check entirely. const ObjCPropertyImplDecl *PropImplRequiringRelease = nullptr; bool HasOthers = false; for (const auto *I : D->property_impls()) { if (getDeallocReleaseRequirement(I) == ReleaseRequirement::MustRelease) { if (!PropImplRequiringRelease) PropImplRequiringRelease = I; else { HasOthers = true; break; } } } if (!PropImplRequiringRelease) return; const ObjCMethodDecl *MD = nullptr; // Scan the instance methods for "dealloc". for (const auto *I : D->instance_methods()) { if (I->getSelector() == DeallocSel) { MD = I; break; } } if (!MD) { // No dealloc found. const char* Name = "Missing -dealloc"; std::string Buf; llvm::raw_string_ostream OS(Buf); OS << "'" << *D << "' lacks a 'dealloc' instance method but " << "must release '" << *PropImplRequiringRelease->getPropertyIvarDecl() << "'"; if (HasOthers) OS << " and others"; PathDiagnosticLocation DLoc = PathDiagnosticLocation::createBegin(D, BR.getSourceManager()); BR.EmitBasicReport(D, this, Name, categories::CoreFoundationObjectiveC, OS.str(), DLoc); return; } }
void DanglingDelegateChecker::checkASTDecl(const ObjCImplDecl *implDecl, AnalysisManager& manager, BugReporter &bugReporter) const { const NamedDecl *namedDecl = dyn_cast<NamedDecl>(implDecl); if (!namedDecl) { assert(false); return; } std::string name = namedDecl->getNameAsString(); // obtain the map of facts for the current class implementation, possibly a new one ObjCImplFacts &facts = _implFacts[name]; for (ObjCImplDecl::method_iterator it = implDecl->meth_begin(), end = implDecl->meth_end(); it != end; ++it) { FactFinder factFinder(*it, facts); factFinder.VisitMethodDecl(); Stmt *body = (*it)->getBody(); if (body) { factFinder.Visit(body); } } PathDiagnosticLocation pLoc(implDecl->getLocation(), bugReporter.getSourceManager()); const std::function<void(StringRef)> emitBug([implDecl, &pLoc, &bugReporter, this](StringRef str) { bugReporter.EmitBasicReport(implDecl, this, "Leaking unsafe reference to self", "Memory error (Facebook)", str, pLoc); }); // The default dealloc in ARC mode does not clear delegates. if (!facts._hasDealloc && manager.getLangOpts().ObjCAutoRefCount) { const StringSet emptySet; for (auto it = facts._ivarFactsMap.begin(), end = facts._ivarFactsMap.end(); it != end; it++) { verifyAndReportDangerousProperties(it->second._mayStoreSelfInUnsafeProperty, emptySet, it->first->getNameAsString(), it->first->getType(), "ARC-generated dealloc", emitBug); } } }