diff options
author | Ted Kremenek <kremenek@apple.com> | 2012-04-04 18:11:35 +0000 |
---|---|---|
committer | Ted Kremenek <kremenek@apple.com> | 2012-04-04 18:11:35 +0000 |
commit | 07189521a15d9c088216b943649cb9fe231cbb57 (patch) | |
tree | 649cd12e68237a26ec96485b1ed9ccdde7bf4c83 | |
parent | f54486acc1cadf2791c3916ece66fded1e57ba0b (diff) |
Include the "issue context" (e.g. function or method) where a static analyzer issue occurred in the plist output.
Fixes <rdar://problem/11004527>
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@154030 91177308-0d34-0410-b5e6-96231b3b80d8
24 files changed, 251 insertions, 80 deletions
diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h index bca28c00e1..9890a808ad 100644 --- a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h +++ b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h @@ -69,6 +69,7 @@ protected: friend class BugReportEquivClass; BugType& BT; + const Decl *DeclWithIssue; std::string ShortDescription; std::string Description; PathDiagnosticLocation Location; @@ -103,16 +104,16 @@ protected: public: BugReport(BugType& bt, StringRef desc, const ExplodedNode *errornode) - : BT(bt), Description(desc), ErrorNode(errornode), + : BT(bt), DeclWithIssue(0), Description(desc), ErrorNode(errornode), ConfigurationChangeToken(0) {} BugReport(BugType& bt, StringRef shortDesc, StringRef desc, const ExplodedNode *errornode) - : BT(bt), ShortDescription(shortDesc), Description(desc), + : BT(bt), DeclWithIssue(0), ShortDescription(shortDesc), Description(desc), ErrorNode(errornode), ConfigurationChangeToken(0) {} BugReport(BugType& bt, StringRef desc, PathDiagnosticLocation l) - : BT(bt), Description(desc), Location(l), ErrorNode(0), + : BT(bt), DeclWithIssue(0), Description(desc), Location(l), ErrorNode(0), ConfigurationChangeToken(0) {} /// \brief Create a BugReport with a custom uniqueing location. @@ -124,7 +125,8 @@ public: /// the allocation site, rather then the location where the bug is reported. BugReport(BugType& bt, StringRef desc, const ExplodedNode *errornode, PathDiagnosticLocation LocationToUnique) - : BT(bt), Description(desc), UniqueingLocation(LocationToUnique), + : BT(bt), DeclWithIssue(0), Description(desc), + UniqueingLocation(LocationToUnique), ErrorNode(errornode), ConfigurationChangeToken(0) {} virtual ~BugReport(); @@ -152,6 +154,16 @@ public: return ConfigurationChangeToken; } + /// Return the canonical declaration, be it a method or class, where + /// this issue semantically occurred. + const Decl *getDeclWithIssue() const; + + /// Specifically set the Decl where an issue occurred. This isn't necessary + /// for BugReports that cover a path as it will be automatically inferred. + void setDeclWithIssue(const Decl *declWithIssue) { + DeclWithIssue = declWithIssue; + } + /// \brief This allows for addition of meta data to the diagnostic. /// /// Currently, only the HTMLDiagnosticClient knows how to display it. @@ -345,34 +357,41 @@ public: /// reports. void EmitReport(BugReport *R); - void EmitBasicReport(StringRef BugName, StringRef BugStr, + void EmitBasicReport(const Decl *DeclWithIssue, + StringRef BugName, StringRef BugStr, PathDiagnosticLocation Loc, SourceRange* RangeBeg, unsigned NumRanges); - void EmitBasicReport(StringRef BugName, StringRef BugCategory, + void EmitBasicReport(const Decl *DeclWithIssue, + StringRef BugName, StringRef BugCategory, StringRef BugStr, PathDiagnosticLocation Loc, SourceRange* RangeBeg, unsigned NumRanges); - void EmitBasicReport(StringRef BugName, StringRef BugStr, + void EmitBasicReport(const Decl *DeclWithIssue, + StringRef BugName, StringRef BugStr, PathDiagnosticLocation Loc) { - EmitBasicReport(BugName, BugStr, Loc, 0, 0); + EmitBasicReport(DeclWithIssue, BugName, BugStr, Loc, 0, 0); } - void EmitBasicReport(StringRef BugName, StringRef BugCategory, + void EmitBasicReport(const Decl *DeclWithIssue, + StringRef BugName, StringRef BugCategory, StringRef BugStr, PathDiagnosticLocation Loc) { - EmitBasicReport(BugName, BugCategory, BugStr, Loc, 0, 0); + EmitBasicReport(DeclWithIssue, BugName, BugCategory, BugStr, Loc, 0, 0); } - void EmitBasicReport(StringRef BugName, StringRef BugStr, - PathDiagnosticLocation Loc, SourceRange R) { - EmitBasicReport(BugName, BugStr, Loc, &R, 1); + void EmitBasicReport(const Decl *DeclWithIssue, + StringRef BugName, StringRef BugStr, + PathDiagnosticLocation Loc, + SourceRange R) { + EmitBasicReport(DeclWithIssue, BugName, BugStr, Loc, &R, 1); } - void EmitBasicReport(StringRef BugName, StringRef Category, + void EmitBasicReport(const Decl *DeclWithIssue, + StringRef BugName, StringRef Category, StringRef BugStr, PathDiagnosticLocation Loc, SourceRange R) { - EmitBasicReport(BugName, Category, BugStr, Loc, &R, 1); + EmitBasicReport(DeclWithIssue, BugName, Category, BugStr, Loc, &R, 1); } static bool classof(const BugReporter* R) { return true; } diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h b/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h index 521b8999c4..5a8a1c78ca 100644 --- a/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h +++ b/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h @@ -607,12 +607,15 @@ public: /// diagnostic. It represents an ordered-collection of PathDiagnosticPieces, /// each which represent the pieces of the path. class PathDiagnostic : public llvm::FoldingSetNode { + const Decl *DeclWithIssue; std::string BugType; std::string Desc; std::string Category; std::deque<std::string> OtherDesc; PathPieces pathImpl; llvm::SmallVector<PathPieces *, 3> pathStack; + + PathDiagnostic(); // Do not implement. public: const PathPieces &path; @@ -635,8 +638,10 @@ public: void pushActivePath(PathPieces *p) { pathStack.push_back(p); } void popActivePath() { if (!pathStack.empty()) pathStack.pop_back(); } - PathDiagnostic(); - PathDiagnostic(StringRef bugtype, StringRef desc, + // PathDiagnostic(); + PathDiagnostic(const Decl *DeclWithIssue, + StringRef bugtype, + StringRef desc, StringRef category); ~PathDiagnostic(); @@ -644,7 +649,11 @@ public: StringRef getDescription() const { return Desc; } StringRef getBugType() const { return BugType; } StringRef getCategory() const { return Category; } - + + /// Return the semantic context where an issue occurred. If the + /// issue occurs along a path, this represents the "central" area + /// where the bug manifests. + const Decl *getDeclWithIssue() const { return DeclWithIssue; } typedef std::deque<std::string>::const_iterator meta_iterator; meta_iterator meta_begin() const { return OtherDesc.begin(); } diff --git a/lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp b/lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp index 9dd8da57ec..aa6f97b2fa 100644 --- a/lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp @@ -112,8 +112,8 @@ void AnalyzerStatsChecker::checkEndAnalysis(ExplodedGraph &G, << " | Empty WorkList: " << (Eng.hasEmptyWorkList() ? "yes" : "no"); - B.EmitBasicReport("Analyzer Statistics", "Internal Statistics", output.str(), - PathDiagnosticLocation(D, SM)); + B.EmitBasicReport(D, "Analyzer Statistics", "Internal Statistics", + output.str(), PathDiagnosticLocation(D, SM)); // Emit warning for each block we bailed out on. typedef CoreEngine::BlocksExhausted::const_iterator ExhaustedIterator; @@ -128,8 +128,9 @@ void AnalyzerStatsChecker::checkEndAnalysis(ExplodedGraph &G, llvm::raw_svector_ostream outputI(bufI); outputI << "(" << NameOfRootFunction << ")" << ": The analyzer generated a sink at this point"; - B.EmitBasicReport("Sink Point", "Internal Statistics", outputI.str(), - PathDiagnosticLocation::createBegin(CS->getStmt(), SM, LC)); + B.EmitBasicReport(D, "Sink Point", "Internal Statistics", outputI.str(), + PathDiagnosticLocation::createBegin(CS->getStmt(), + SM, LC)); } } } diff --git a/lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp b/lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp index 6005ecdf51..befc935d4f 100644 --- a/lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp @@ -157,7 +157,7 @@ void WalkAST::VisitCallExpr(CallExpr *CE) { os << "U"; os << "se a safer 'strlcat' API"; - BR.EmitBasicReport("Anti-pattern in the argument", "C String API", + BR.EmitBasicReport(FD, "Anti-pattern in the argument", "C String API", os.str(), Loc, &R, 1); } } diff --git a/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp b/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp index 257dcca413..690e2ce346 100644 --- a/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp +++ b/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp @@ -179,7 +179,7 @@ static void checkObjCDealloc(const ObjCImplementationDecl *D, llvm::raw_string_ostream os(buf); os << "Objective-C class '" << *D << "' lacks a 'dealloc' instance method"; - BR.EmitBasicReport(name, os.str(), DLoc); + BR.EmitBasicReport(D, name, os.str(), DLoc); return; } @@ -196,7 +196,7 @@ static void checkObjCDealloc(const ObjCImplementationDecl *D, << "' does not send a 'dealloc' message to its super class" " (missing [super dealloc])"; - BR.EmitBasicReport(name, os.str(), DLoc); + BR.EmitBasicReport(MD, name, os.str(), DLoc); return; } @@ -263,7 +263,7 @@ static void checkObjCDealloc(const ObjCImplementationDecl *D, PathDiagnosticLocation SDLoc = PathDiagnosticLocation::createBegin((*I), BR.getSourceManager()); - BR.EmitBasicReport(name, category, os.str(), SDLoc); + BR.EmitBasicReport(MD, name, category, os.str(), SDLoc); } } } diff --git a/lib/StaticAnalyzer/Checkers/CheckObjCInstMethSignature.cpp b/lib/StaticAnalyzer/Checkers/CheckObjCInstMethSignature.cpp index c076c1e39b..d7321fa3cf 100644 --- a/lib/StaticAnalyzer/Checkers/CheckObjCInstMethSignature.cpp +++ b/lib/StaticAnalyzer/Checkers/CheckObjCInstMethSignature.cpp @@ -70,7 +70,8 @@ static void CompareReturnTypes(const ObjCMethodDecl *MethDerived, PathDiagnosticLocation::createBegin(MethDerived, BR.getSourceManager()); - BR.EmitBasicReport("Incompatible instance method return type", + BR.EmitBasicReport(MethDerived, + "Incompatible instance method return type", os.str(), MethDLoc); } } diff --git a/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp b/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp index 10f86a13ff..dde90713ce 100644 --- a/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp +++ b/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp @@ -286,7 +286,8 @@ void WalkAST::checkLoopConditionForFloat(const ForStmt *FS) { PathDiagnosticLocation FSLoc = PathDiagnosticLocation::createBegin(FS, BR.getSourceManager(), AC); - BR.EmitBasicReport(bugType, "Security", os.str(), + BR.EmitBasicReport(AC->getDecl(), + bugType, "Security", os.str(), FSLoc, ranges.data(), ranges.size()); } @@ -322,7 +323,8 @@ void WalkAST::checkCall_gets(const CallExpr *CE, const FunctionDecl *FD) { SourceRange R = CE->getCallee()->getSourceRange(); PathDiagnosticLocation CELoc = PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC); - BR.EmitBasicReport("Potential buffer overflow in call to 'gets'", + BR.EmitBasicReport(AC->getDecl(), + "Potential buffer overflow in call to 'gets'", "Security", "Call to function 'gets' is extremely insecure as it can " "always result in a buffer overflow", @@ -363,7 +365,8 @@ void WalkAST::checkCall_getpw(const CallExpr *CE, const FunctionDecl *FD) { SourceRange R = CE->getCallee()->getSourceRange(); PathDiagnosticLocation CELoc = PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC); - BR.EmitBasicReport("Potential buffer overflow in call to 'getpw'", + BR.EmitBasicReport(AC->getDecl(), + "Potential buffer overflow in call to 'getpw'", "Security", "The getpw() function is dangerous as it may overflow the " "provided buffer. It is obsoleted by getpwuid().", @@ -405,10 +408,12 @@ void WalkAST::checkCall_mktemp(const CallExpr *CE, const FunctionDecl *FD) { SourceRange R = CE->getCallee()->getSourceRange(); PathDiagnosticLocation CELoc = PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC); - BR.EmitBasicReport("Potential insecure temporary file in call 'mktemp'", + BR.EmitBasicReport(AC->getDecl(), + "Potential insecure temporary file in call 'mktemp'", "Security", "Call to function 'mktemp' is insecure as it always " - "creates or uses insecure temporary file. Use 'mkstemp' instead", + "creates or uses insecure temporary file. Use 'mkstemp' " + "instead", CELoc, &R, 1); } @@ -490,7 +495,8 @@ void WalkAST::checkCall_mkstemp(const CallExpr *CE, const FunctionDecl *FD) { out << " used as a suffix"; } out << ')'; - BR.EmitBasicReport("Insecure temporary file creation", "Security", + BR.EmitBasicReport(AC->getDecl(), + "Insecure temporary file creation", "Security", out.str(), CELoc, &R, 1); } @@ -511,13 +517,14 @@ void WalkAST::checkCall_strcpy(const CallExpr *CE, const FunctionDecl *FD) { SourceRange R = CE->getCallee()->getSourceRange(); PathDiagnosticLocation CELoc = PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC); - BR.EmitBasicReport("Potential insecure memory buffer bounds restriction in " + BR.EmitBasicReport(AC->getDecl(), + "Potential insecure memory buffer bounds restriction in " "call 'strcpy'", "Security", "Call to function 'strcpy' is insecure as it does not " - "provide bounding of the memory buffer. Replace " - "unbounded copy functions with analogous functions that " - "support length arguments such as 'strlcpy'. CWE-119.", + "provide bounding of the memory buffer. Replace " + "unbounded copy functions with analogous functions that " + "support length arguments such as 'strlcpy'. CWE-119.", CELoc, &R, 1); } @@ -538,13 +545,14 @@ void WalkAST::checkCall_strcat(const CallExpr *CE, const FunctionDecl *FD) { SourceRange R = CE->getCallee()->getSourceRange(); PathDiagnosticLocation CELoc = PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC); - BR.EmitBasicReport("Potential insecure memory buffer bounds restriction in " - "call 'strcat'", - "Security", - "Call to function 'strcat' is insecure as it does not " - "provide bounding of the memory buffer. Replace " - "unbounded copy functions with analogous functions that " - "support length arguments such as 'strlcat'. CWE-119.", + BR.EmitBasicReport(AC->getDecl(), + "Potential insecure memory buffer bounds restriction in " + "call 'strcat'", + "Security", + "Call to function 'strcat' is insecure as it does not " + "provide bounding of the memory buffer. Replace " + "unbounded copy functions with analogous functions that " + "support length arguments such as 'strlcat'. CWE-119.", CELoc, &R, 1); } @@ -619,7 +627,8 @@ void WalkAST::checkCall_rand(const CallExpr *CE, const FunctionDecl *FD) { SourceRange R = CE->getCallee()->getSourceRange(); PathDiagnosticLocation CELoc = PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC); - BR.EmitBasicReport(os1.str(), "Security", os2.str(), CELoc, &R, 1); + BR.EmitBasicReport(AC->getDecl(), os1.str(), "Security", os2.str(), + CELoc, &R, 1); } //===----------------------------------------------------------------------===// @@ -644,7 +653,8 @@ void WalkAST::checkCall_random(const CallExpr *CE, const FunctionDecl *FD) { SourceRange R = CE->getCallee()->getSourceRange(); PathDiagnosticLocation CELoc = PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC); - BR.EmitBasicReport("'random' is not a secure random number generator", + BR.EmitBasicReport(AC->getDecl(), + "'random' is not a secure random number generator", "Security", "The 'random' function produces a sequence of values that " "an adversary may be able to predict. Use 'arc4random' " @@ -664,7 +674,8 @@ void WalkAST::checkCall_vfork(const CallExpr *CE, const FunctionDecl *FD) { SourceRange R = CE->getCallee()->getSourceRange(); PathDiagnosticLocation CELoc = PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC); - BR.EmitBasicReport("Potential insecure implementation-specific behavior in " + BR.EmitBasicReport(AC->getDecl(), + "Potential insecure implementation-specific behavior in " "call 'vfork'", "Security", "Call to function 'vfork' is insecure as it can lead to " @@ -736,7 +747,8 @@ void WalkAST::checkUncheckedReturnValue(CallExpr *CE) { SourceRange R = CE->getCallee()->getSourceRange(); PathDiagnosticLocation CELoc = PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC); - BR.EmitBasicReport(os1.str(), "Security", os2.str(), CELoc, &R, 1); + BR.EmitBasicReport(AC->getDecl(), os1.str(), "Security", os2.str(), + CELoc, &R, 1); } //===----------------------------------------------------------------------===// diff --git a/lib/StaticAnalyzer/Checkers/CheckSizeofPointer.cpp b/lib/StaticAnalyzer/Checkers/CheckSizeofPointer.cpp index 55945e6c07..cc7fd37ff6 100644 --- a/lib/StaticAnalyzer/Checkers/CheckSizeofPointer.cpp +++ b/lib/StaticAnalyzer/Checkers/CheckSizeofPointer.cpp @@ -63,7 +63,8 @@ void WalkAST::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E) { SourceRange R = ArgEx->getSourceRange(); PathDiagnosticLocation ELoc = PathDiagnosticLocation::createBegin(E, BR.getSourceManager(), AC); - BR.EmitBasicReport("Potential unintended use of sizeof() on pointer type", + BR.EmitBasicReport(AC->getDecl(), + "Potential unintended use of sizeof() on pointer type", "Logic", "The code calls sizeof() on a pointer type. " "This can produce an unexpected result.", diff --git a/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp b/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp index 7202a1ff3a..7457e44e18 100644 --- a/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp @@ -130,7 +130,7 @@ public: return; } - BR.EmitBasicReport(BugType, "Dead store", os.str(), L, R); + BR.EmitBasicReport(AC->getDecl(), BugType, "Dead store", os.str(), L, R); } void CheckVarDecl(const VarDecl *VD, const Expr *Ex, const Expr *Val, diff --git a/lib/StaticAnalyzer/Checkers/LLVMConventionsChecker.cpp b/lib/StaticAnalyzer/Checkers/LLVMConventionsChecker.cpp index 3e0ef21c96..757a4ce288 100644 --- a/lib/StaticAnalyzer/Checkers/LLVMConventionsChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/LLVMConventionsChecker.cpp @@ -115,8 +115,10 @@ static bool IsSmallVector(QualType T) { namespace { class StringRefCheckerVisitor : public StmtVisitor<StringRefCheckerVisitor> { BugReporter &BR; + const Decl *DeclWithIssue; public: - StringRefCheckerVisitor(BugReporter &br) : BR(br) {} + StringRefCheckerVisitor(const Decl *declWithIssue, BugReporter &br) + : BR(br), DeclWithIssue(declWithIssue) {} void VisitChildren(Stmt *S) { for (Stmt::child_iterator I = S->child_begin(), E = S->child_end() ; I != E; ++I) @@ -131,7 +133,7 @@ private: } // end anonymous namespace static void CheckStringRefAssignedTemporary(const Decl *D, BugReporter &BR) { - StringRefCheckerVisitor walker(BR); + StringRefCheckerVisitor walker(D, BR); walker.Visit(D->getBody()); } @@ -176,7 +178,7 @@ void StringRefCheckerVisitor::VisitVarDecl(VarDecl *VD) { "std::string that it outlives"; PathDiagnosticLocation VDLoc = PathDiagnosticLocation::createBegin(VD, BR.getSourceManager()); - BR.EmitBasicReport(desc, "LLVM Conventions", desc, + BR.EmitBasicReport(DeclWithIssue, desc, "LLVM Conventions", desc, VDLoc, Init->getSourceRange()); } @@ -281,7 +283,7 @@ void ASTFieldVisitor::ReportError(QualType T) { // the class may be in the header file, for example). PathDiagnosticLocation L = PathDiagnosticLocation::createBegin( FieldChain.front(), BR.getSourceManager()); - BR.EmitBasicReport("AST node allocates heap memory", "LLVM Conventions", + BR.EmitBasicReport(Root, "AST node allocates heap memory", "LLVM Conventions", os.str(), L); } diff --git a/lib/StaticAnalyzer/Checkers/MallocOverflowSecurityChecker.cpp b/lib/StaticAnalyzer/Checkers/MallocOverflowSecurityChecker.cpp index c9d315a32e..b11c94793f 100644 --- a/lib/StaticAnalyzer/Checkers/MallocOverflowSecurityChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/MallocOverflowSecurityChecker.cpp @@ -214,11 +214,10 @@ void MallocOverflowSecurityChecker::OutputPossibleOverflows( i != e; ++i) { SourceRange R = i->mulop->getSourceRange(); - BR.EmitBasicReport("MallocOverflowSecurityChecker", + BR.EmitBasicReport(D, "malloc() size overflow", "the computation of the size of the memory allocation may overflow", PathDiagnosticLocation::createOperatorLoc(i->mulop, - BR.getSourceManager()), - &R, 1); + BR.getSourceManager()), &R, 1); } } diff --git a/lib/StaticAnalyzer/Checkers/MallocSizeofChecker.cpp b/lib/StaticAnalyzer/Checkers/MallocSizeofChecker.cpp index 28f8993180..4e10633da7 100644 --- a/lib/StaticAnalyzer/Checkers/MallocSizeofChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/MallocSizeofChecker.cpp @@ -194,8 +194,8 @@ public: PathDiagnosticLocation::createBegin(i->AllocCall->getCallee(), BR.getSourceManager(), ADC); - BR.EmitBasicReport("allocator sizeof operand mismatch", OS.str(), L, - Ranges.data(), Ranges.size()); + BR.EmitBasicReport(D, "allocator sizeof operand mismatch", OS.str(), + L, Ranges.data(), Ranges.size()); } } } diff --git a/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp b/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp index 7d4520d75d..f826573c9e 100644 --- a/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp @@ -74,7 +74,7 @@ void NSErrorMethodChecker::checkASTDecl(const ObjCMethodDecl *D, "error occurred"; PathDiagnosticLocation L = PathDiagnosticLocation::create(D, BR.getSourceManager()); - BR.EmitBasicReport("Bad return type when passing NSError**", + BR.EmitBasicReport(D, "Bad return type when passing NSError**", "Coding conventions (Apple)", err, L); } } @@ -122,7 +122,7 @@ void CFErrorFunctionChecker::checkASTDecl(const FunctionDecl *D, "error occurred"; PathDiagnosticLocation L = PathDiagnosticLocation::create(D, BR.getSourceManager()); - BR.EmitBasicReport("Bad return type when passing CFErrorRef*", + BR.EmitBasicReport(D, "Bad return type when passing CFErrorRef*", "Coding conventions (Apple)", err, L); } } diff --git a/lib/StaticAnalyzer/Checkers/ObjCContainersASTChecker.cpp b/lib/StaticAnalyzer/Checkers/ObjCContainersASTChecker.cpp index 5508a49784..aeb90a6e51 100644 --- a/lib/StaticAnalyzer/Checkers/ObjCContainersASTChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/ObjCContainersASTChecker.cpp @@ -142,7 +142,8 @@ void WalkAST::VisitCallExpr(CallExpr *CE) { SourceRange R = Arg->getSourceRange(); PathDiagnosticLocation CELoc = PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC); - BR.EmitBasicReport(OsName.str(), "Core Foundation/Objective-C", + BR.EmitBasicReport(AC->getDecl(), + OsName.str(), "Core Foundation/Objective-C", Os.str(), CELoc, &R, 1); } diff --git a/lib/StaticAnalyzer/Checkers/ObjCUnusedIVarsChecker.cpp b/lib/StaticAnalyzer/Checkers/ObjCUnusedIVarsChecker.cpp index bbc262fe8e..4718dc7c7a 100644 --- a/lib/StaticAnalyzer/Checkers/ObjCUnusedIVarsChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/ObjCUnusedIVarsChecker.cpp @@ -161,7 +161,7 @@ static void checkObjCUnusedIvar(const ObjCImplementationDecl *D, PathDiagnosticLocation L = PathDiagnosticLocation::create(I->first, BR.getSourceManager()); - BR.EmitBasicReport("Unused instance variable", "Optimization", + BR.EmitBasicReport(D, "Unused instance variable", "Optimization", os.str(), L); } } diff --git a/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp b/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp index c40912ce2f..5a13ed0a2e 100644 --- a/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp @@ -162,8 +162,8 @@ void UnreachableCodeChecker::checkEndAnalysis(ExplodedGraph &G, if (SM.isInSystemHeader(SL) || SM.isInExternCSystemHeader(SL)) continue; - B.EmitBasicReport("Unreachable code", "Dead code", "This statement is never" - " executed", DL, SR); + B.EmitBasicReport(D, "Unreachable code", "Dead code", + "This statement is never executed", DL, SR); } } diff --git a/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp b/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp index 1d1803ce4c..f7c7c0ce34 100644 --- a/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp @@ -186,7 +186,8 @@ void WalkAST::ReportVirtualCall(const CallExpr *CE, bool isPure) { if (isPure) { os << "\n" << "Call pure virtual functions during construction or " << "destruction may leads undefined behaviour"; - BR.EmitBasicReport("Call pure virtual function during construction or " + BR.EmitBasicReport(AC->getDecl(), + "Call pure virtual function during construction or " "Destruction", "Cplusplus", os.str(), CELoc, &R, 1); @@ -195,7 +196,8 @@ void WalkAST::ReportVirtualCall(const CallExpr *CE, bool isPure) { else { os << "\n" << "Call virtual functions during construction or " << "destruction will never go to a more derived class"; - BR.EmitBasicReport("Call virtual function during construction or " + BR.EmitBasicReport(AC->getDecl(), + "Call virtual function during construction or " "Destruction", "Cplusplus", os.str(), CELoc, &R, 1); diff --git a/lib/StaticAnalyzer/Core/BugReporter.cpp b/lib/StaticAnalyzer/Core/BugReporter.cpp index e1be6e910b..2752e32e50 100644 --- a/lib/StaticAnalyzer/Core/BugReporter.cpp +++ b/lib/StaticAnalyzer/Core/BugReporter.cpp @@ -1241,6 +1241,18 @@ BugReport::~BugReport() { } } +const Decl *BugReport::getDeclWithIssue() const { + if (DeclWithIssue) + return DeclWithIssue; + + const ExplodedNode *N = getErrorNode(); + if (!N) + return 0; + + const LocationContext *LC = N->getLocationContext(); + return LC->getCurrentStackFrame()->getDecl(); +} + void BugReport::Profile(llvm::FoldingSetNodeID& hash) const { hash.AddPointer(&BT); hash.AddString(Description); @@ -1952,7 +1964,8 @@ void BugReporter::FlushReport(BugReportEquivClass& EQ) { BugType& BT = exampleReport->getBugType(); OwningPtr<PathDiagnostic> - D(new PathDiagnostic(exampleReport->getBugType().getName(), + D(new PathDiagnostic(exampleReport->getDeclWithIssue(), + exampleReport->getBugType().getName(), !PD || PD->useVerboseDescription() ? exampleReport->getDescription() : exampleReport->getShortDescription(), @@ -2005,21 +2018,24 @@ void BugReporter::FlushReport(BugReportEquivClass& EQ) { PathDiagnosticPiece *piece = new PathDiagnosticEventPiece( exampleReport->getLocation(getSourceManager()), exampleReport->getDescription()); + for ( ; Beg != End; ++Beg) + piece->addRange(*Beg); - for ( ; Beg != End; ++Beg) piece->addRange(*Beg); D->getActivePath().push_back(piece); } PD->HandlePathDiagnostic(D.take()); } -void BugReporter::EmitBasicReport(StringRef name, StringRef str, +void BugReporter::EmitBasicReport(const Decl *DeclWithIssue, + StringRef name, StringRef str, PathDiagnosticLocation Loc, SourceRange* RBeg, unsigned Num |