Index: clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.h =================================================================== --- clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.h +++ clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.h @@ -103,43 +103,6 @@ typedef ::llvm::DenseMap SummaryLogTy; -/// Visitors. - -class CFRefReportVisitor : public BugReporterVisitor { -protected: - SymbolRef Sym; - const SummaryLogTy &SummaryLog; - -public: - CFRefReportVisitor(SymbolRef sym, const SummaryLogTy &log) - : Sym(sym), SummaryLog(log) {} - - void Profile(llvm::FoldingSetNodeID &ID) const override { - static int x = 0; - ID.AddPointer(&x); - ID.AddPointer(Sym); - } - - std::shared_ptr VisitNode(const ExplodedNode *N, - BugReporterContext &BRC, - BugReport &BR) override; - - std::shared_ptr getEndPath(BugReporterContext &BRC, - const ExplodedNode *N, - BugReport &BR) override; -}; - -class CFRefLeakReportVisitor : public CFRefReportVisitor { -public: - CFRefLeakReportVisitor(SymbolRef sym, - const SummaryLogTy &log) - : CFRefReportVisitor(sym, log) {} - - std::shared_ptr getEndPath(BugReporterContext &BRC, - const ExplodedNode *N, - BugReport &BR) override; -}; - class CFRefReport : public BugReport { protected: SymbolRef Sym; @@ -147,18 +110,11 @@ public: CFRefReport(CFRefBug &D, const LangOptions &LOpts, const SummaryLogTy &Log, ExplodedNode *n, SymbolRef sym, - bool registerVisitor = true) - : BugReport(D, D.getDescription(), n), Sym(sym) { - if (registerVisitor) - addVisitor(llvm::make_unique(sym, Log)); - } + bool registerVisitor = true); CFRefReport(CFRefBug &D, const LangOptions &LOpts, const SummaryLogTy &Log, ExplodedNode *n, SymbolRef sym, - StringRef endText) - : BugReport(D, D.getDescription(), endText, n) { - addVisitor(llvm::make_unique(sym, Log)); - } + StringRef endText); llvm::iterator_range getRanges() override { const CFRefBug& BugTy = static_cast(getBugType()); Index: clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp =================================================================== --- clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp +++ clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp @@ -102,6 +102,119 @@ return true; } +static void generateDiagnosticsForCallLike( + ProgramStateRef CurrSt, + const LocationContext *LCtx, + const RefVal &CurrV, + SymbolRef &Sym, + const Stmt *S, + llvm::raw_string_ostream &os) { + if (const CallExpr *CE = dyn_cast(S)) { + // Get the name of the callee (if it is available) + // from the tracked SVal. + SVal X = CurrSt->getSValAsScalarOrLoc(CE->getCallee(), LCtx); + const FunctionDecl *FD = X.getAsFunctionDecl(); + + // If failed, try to get it from AST. + if (!FD) + FD = dyn_cast(CE->getCalleeDecl()); + + if (FD) { + os << "Call to function '" << FD->getQualifiedNameAsString() << '\''; + } else { + os << "function call"; + } + } else { + assert(isa(S)); + CallEventManager &Mgr = CurrSt->getStateManager().getCallEventManager(); + CallEventRef Call = + Mgr.getObjCMethodCall(cast(S), CurrSt, LCtx); + + switch (Call->getMessageKind()) { + case OCM_Message: + os << "Method"; + break; + case OCM_PropertyAccess: + os << "Property"; + break; + case OCM_Subscript: + os << "Subscript"; + break; + } + } + + if (CurrV.getObjKind() == RetEffect::CF) { + os << " returns a Core Foundation object of type " + << Sym->getType().getAsString() << " with a "; + } else if (CurrV.getObjKind() == RetEffect::OS) { + os << " returns an OSObject of type " << Sym->getType().getAsString() + << " with a "; + } else if (CurrV.getObjKind() == RetEffect::Generalized) { + os << " returns an object of type " << Sym->getType().getAsString() + << " with a "; + } else { + assert(CurrV.getObjKind() == RetEffect::ObjC); + QualType T = Sym->getType(); + if (!isa(T)) { + os << " returns an Objective-C object with a "; + } else { + const ObjCObjectPointerType *PT = cast(T); + os << " returns an instance of " << PT->getPointeeType().getAsString() + << " with a "; + } + } + + if (CurrV.isOwned()) { + os << "+1 retain count"; + } else { + assert(CurrV.isNotOwned()); + os << "+0 retain count"; + } +} + +namespace clang { +namespace ento { +namespace retaincountchecker { + +class CFRefReportVisitor : public BugReporterVisitor { +protected: + SymbolRef Sym; + const SummaryLogTy &SummaryLog; + +public: + CFRefReportVisitor(SymbolRef sym, const SummaryLogTy &log) + : Sym(sym), SummaryLog(log) {} + + void Profile(llvm::FoldingSetNodeID &ID) const override { + static int x = 0; + ID.AddPointer(&x); + ID.AddPointer(Sym); + } + + std::shared_ptr VisitNode(const ExplodedNode *N, + BugReporterContext &BRC, + BugReport &BR) override; + + std::shared_ptr getEndPath(BugReporterContext &BRC, + const ExplodedNode *N, + BugReport &BR) override; +}; + +class CFRefLeakReportVisitor : public CFRefReportVisitor { +public: + CFRefLeakReportVisitor(SymbolRef sym, + const SummaryLogTy &log) + : CFRefReportVisitor(sym, log) {} + + std::shared_ptr getEndPath(BugReporterContext &BRC, + const ExplodedNode *N, + BugReport &BR) override; +}; + +} // end namespace retaincountchecker +} // end namespace ento +} // end namespace clang + std::shared_ptr CFRefReportVisitor::VisitNode(const ExplodedNode *N, BugReporterContext &BRC, BugReport &BR) { @@ -111,7 +224,8 @@ return nullptr; // Check if the type state has changed. - ProgramStateRef PrevSt = N->getFirstPred()->getState(); + const ExplodedNode *PrevNode = N->getFirstPred(); + ProgramStateRef PrevSt = PrevNode->getState(); ProgramStateRef CurrSt = N->getState(); const LocationContext *LCtx = N->getLocationContext(); @@ -161,67 +275,7 @@ } else if (isa(S)) { os << "Object loaded from instance variable"; } else { - if (const CallExpr *CE = dyn_cast(S)) { - // Get the name of the callee (if it is available) - // from the tracked SVal. - SVal X = CurrSt->getSValAsScalarOrLoc(CE->getCallee(), LCtx); - const FunctionDecl *FD = X.getAsFunctionDecl(); - - // If failed, try to get it from AST. - if (!FD) - FD = dyn_cast(CE->getCalleeDecl()); - - if (FD) { - os << "Call to function '" << FD->getQualifiedNameAsString() << '\''; - } else { - os << "function call"; - } - } else { - assert(isa(S)); - CallEventManager &Mgr = CurrSt->getStateManager().getCallEventManager(); - CallEventRef Call - = Mgr.getObjCMethodCall(cast(S), CurrSt, LCtx); - - switch (Call->getMessageKind()) { - case OCM_Message: - os << "Method"; - break; - case OCM_PropertyAccess: - os << "Property"; - break; - case OCM_Subscript: - os << "Subscript"; - break; - } - } - - if (CurrV.getObjKind() == RetEffect::CF) { - os << " returns a Core Foundation object of type " - << Sym->getType().getAsString() << " with a "; - } else if (CurrV.getObjKind() == RetEffect::OS) { - os << " returns an OSObject of type " - << Sym->getType().getAsString() << " with a "; - } else if (CurrV.getObjKind() == RetEffect::Generalized) { - os << " returns an object of type " << Sym->getType().getAsString() - << " with a "; - } else { - assert (CurrV.getObjKind() == RetEffect::ObjC); - QualType T = Sym->getType(); - if (!isa(T)) { - os << " returns an Objective-C object with a "; - } else { - const ObjCObjectPointerType *PT = cast(T); - os << " returns an instance of " - << PT->getPointeeType().getAsString() << " with a "; - } - } - - if (CurrV.isOwned()) { - os << "+1 retain count"; - } else { - assert (CurrV.isNotOwned()); - os << "+0 retain count"; - } + generateDiagnosticsForCallLike(CurrSt, LCtx, CurrV, Sym, S, os); } PathDiagnosticLocation Pos(S, BRC.getSourceManager(), @@ -487,6 +541,22 @@ return std::make_shared(L, os.str()); } +CFRefReport::CFRefReport(CFRefBug &D, const LangOptions &LOpts, + const SummaryLogTy &Log, ExplodedNode *n, + SymbolRef sym, bool registerVisitor) + : BugReport(D, D.getDescription(), n), Sym(sym) { + if (registerVisitor) + addVisitor(llvm::make_unique(sym, Log)); +} + +CFRefReport::CFRefReport(CFRefBug &D, const LangOptions &LOpts, + const SummaryLogTy &Log, ExplodedNode *n, + SymbolRef sym, StringRef endText) + : BugReport(D, D.getDescription(), endText, n) { + + addVisitor(llvm::make_unique(sym, Log)); +} + void CFRefLeakReport::deriveParamLocation(CheckerContext &Ctx, SymbolRef sym) { const SourceManager& SMgr = Ctx.getSourceManager(); Index: clang/test/Analysis/osobject-retain-release.cpp =================================================================== --- clang/test/Analysis/osobject-retain-release.cpp +++ clang/test/Analysis/osobject-retain-release.cpp @@ -34,6 +34,10 @@ struct OSArray : public OSObject { unsigned int getCount(); + static OSArray *generateArrayHasCode() { + return new OSArray; + } + static OSArray *withCapacity(unsigned int capacity); static void consumeArray(OS_CONSUME OSArray * array);