Index: clang/lib/StaticAnalyzer/Core/RetainSummaryManager.cpp =================================================================== --- clang/lib/StaticAnalyzer/Core/RetainSummaryManager.cpp +++ clang/lib/StaticAnalyzer/Core/RetainSummaryManager.cpp @@ -19,6 +19,7 @@ #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/ParentMap.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" using namespace clang; using namespace ento; @@ -53,29 +54,21 @@ return Summ; } -static bool isOSObjectSubclass(QualType T); - -static bool isOSObjectSubclass(const CXXRecordDecl *RD) { - if (RD->getDeclName().getAsString() == "OSObject") - return true; - - const CXXRecordDecl *RDD = RD->getDefinition(); - if (!RDD) - return false; +static bool isSubclass(const Decl *D, + StringRef ClassName) { + using namespace ast_matchers; + DeclarationMatcher SubclassM = cxxRecordDecl( + anyOf(isDerivedFrom(ClassName), hasName(ClassName)) + ); + return !(match(SubclassM, *D, D->getASTContext()).empty()); +} - for (const CXXBaseSpecifier Spec : RDD->bases()) { - if (isOSObjectSubclass(Spec.getType())) - return true; - } - return false; +static bool isOSObjectSubclass(const Decl *D) { + return isSubclass(D, "OSObject"); } -/// \return Whether type represents an OSObject successor. -static bool isOSObjectSubclass(QualType T) { - if (const auto *RD = T->getAsCXXRecordDecl()) { - return isOSObjectSubclass(RD); - } - return false; +static bool isOSIteratorSubclass(const Decl *D) { + return isSubclass(D, "OSIterator"); } static bool hasRCAnnotation(const Decl *D, StringRef rcAnnotation) { @@ -221,15 +214,22 @@ } if (RetTy->isPointerType()) { - if (TrackOSObjects && isOSObjectSubclass(RetTy->getPointeeType())) { + + const CXXRecordDecl *PD = RetTy->getPointeeType()->getAsCXXRecordDecl(); + if (TrackOSObjects && PD && isOSObjectSubclass(PD)) { if (const IdentifierInfo *II = FD->getIdentifier()) { - StringRef FuncName = II->getName(); - if (FuncName.contains_lower("with") - || FuncName.contains_lower("create") - || FuncName.contains_lower("copy")) + + // All objects returned with functions starting with "get" are getters. + if (II->getName().startswith("get")) { + + // ...except for iterators. + if (isOSIteratorSubclass(PD)) + return getOSSummaryCreateRule(FD); + return getOSSummaryGetRule(FD); + } else { return getOSSummaryCreateRule(FD); + } } - return getOSSummaryGetRule(FD); } // For CoreFoundation ('CF') types. @@ -279,11 +279,11 @@ if (const auto *MD = dyn_cast(FD)) { const CXXRecordDecl *Parent = MD->getParent(); - if (TrackOSObjects && isOSObjectSubclass(Parent)) { - if (isRelease(FD, FName)) + if (TrackOSObjects && Parent && isOSObjectSubclass(Parent)) { + if (FName == "release") return getOSSummaryReleaseRule(FD); - if (isRetain(FD, FName)) + if (FName == "retain") return getOSSummaryRetainRule(FD); } }