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 | 5a10f08b52eb8f6a9bedccd712026c9baae529df (patch) | |
tree | 94edf3f958f0872da7f3895744a83c82361d3f8b | |
parent | b61e809b42156161b17ff1bf805da01499d73b9f (diff) | |
download | bcm5719-llvm-5a10f08b52eb8f6a9bedccd712026c9baae529df.tar.gz bcm5719-llvm-5a10f08b52eb8f6a9bedccd712026c9baae529df.zip |
Include the "issue context" (e.g. function or method) where a static analyzer issue occurred in the plist output.
Fixes <rdar://problem/11004527>
llvm-svn: 154030
24 files changed, 251 insertions, 80 deletions
diff --git a/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h b/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h index bca28c00e14..9890a808ad8 100644 --- a/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h +++ b/clang/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/clang/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h b/clang/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h index 521b8999c42..5a8a1c78ca7 100644 --- a/clang/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h +++ b/clang/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/clang/lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp index 9dd8da57ec9..aa6f97b2fa8 100644 --- a/clang/lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp +++ b/clang/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/clang/lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp index 6005ecdf51c..befc935d4f3 100644 --- a/clang/lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp +++ b/clang/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/clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp b/clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp index 257dcca413c..690e2ce346f 100644 --- a/clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp +++ b/clang/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/clang/lib/StaticAnalyzer/Checkers/CheckObjCInstMethSignature.cpp b/clang/lib/StaticAnalyzer/Checkers/CheckObjCInstMethSignature.cpp index c076c1e39b0..d7321fa3cff 100644 --- a/clang/lib/StaticAnalyzer/Checkers/CheckObjCInstMethSignature.cpp +++ b/clang/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/clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp b/clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp index 10f86a13ffa..dde90713ce1 100644 --- a/clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp +++ b/clang/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/clang/lib/StaticAnalyzer/Checkers/CheckSizeofPointer.cpp b/clang/lib/StaticAnalyzer/Checkers/CheckSizeofPointer.cpp index 55945e6c07c..cc7fd37ff60 100644 --- a/clang/lib/StaticAnalyzer/Checkers/CheckSizeofPointer.cpp +++ b/clang/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/clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp index 7202a1ff3af..7457e44e18b 100644 --- a/clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp +++ b/clang/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/clang/lib/StaticAnalyzer/Checkers/LLVMConventionsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/LLVMConventionsChecker.cpp index 3e0ef21c963..757a4ce2881 100644 --- a/clang/lib/StaticAnalyzer/Checkers/LLVMConventionsChecker.cpp +++ b/clang/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/clang/lib/StaticAnalyzer/Checkers/MallocOverflowSecurityChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MallocOverflowSecurityChecker.cpp index c9d315a32e6..b11c94793f5 100644 --- a/clang/lib/StaticAnalyzer/Checkers/MallocOverflowSecurityChecker.cpp +++ b/clang/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/clang/lib/StaticAnalyzer/Checkers/MallocSizeofChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MallocSizeofChecker.cpp index 28f89931809..4e10633da7b 100644 --- a/clang/lib/StaticAnalyzer/Checkers/MallocSizeofChecker.cpp +++ b/clang/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/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp index 7d4520d75d6..f826573c9ec 100644 --- a/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp +++ b/clang/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/clang/lib/StaticAnalyzer/Checkers/ObjCContainersASTChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ObjCContainersASTChecker.cpp index 5508a497844..aeb90a6e510 100644 --- a/clang/lib/StaticAnalyzer/Checkers/ObjCContainersASTChecker.cpp +++ b/clang/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/clang/lib/StaticAnalyzer/Checkers/ObjCUnusedIVarsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ObjCUnusedIVarsChecker.cpp index bbc262fe8ef..4718dc7c7aa 100644 --- a/clang/lib/StaticAnalyzer/Checkers/ObjCUnusedIVarsChecker.cpp +++ b/clang/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/clang/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp index c40912ce2f3..5a13ed0a2e1 100644 --- a/clang/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp +++ b/clang/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/clang/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp index 1d1803ce4c5..f7c7c0ce346 100644 --- a/clang/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp +++ b/clang/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/clang/lib/StaticAnalyzer/Core/BugReporter.cpp b/clang/lib/StaticAnalyzer/Core/BugReporter.cpp index e1be6e910b5..2752e32e508 100644 --- a/clang/lib/StaticAnalyzer/Core/BugReporter.cpp +++ b/clang/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 NumRanges) { - EmitBasicReport(name, "", str, Loc, RBeg, NumRanges); + EmitBasicReport(DeclWithIssue, name, "", str, Loc, RBeg, NumRanges); } -void BugReporter::EmitBasicReport(StringRef name, +void BugReporter::EmitBasicReport(const Decl *DeclWithIssue, + StringRef name, StringRef category, StringRef str, PathDiagnosticLocation Loc, SourceRange* RBeg, unsigned NumRanges) { @@ -2027,6 +2043,7 @@ void BugReporter::EmitBasicReport(StringRef name, // 'BT' is owned by BugReporter. BugType *BT = getBugTypeForName(name, category); BugReport *R = new BugReport(*BT, str, Loc); + R->setDeclWithIssue(DeclWithIssue); for ( ; NumRanges > 0 ; --NumRanges, ++RBeg) R->addRange(*RBeg); EmitReport(R); } diff --git a/clang/lib/StaticAnalyzer/Core/PathDiagnostic.cpp b/clang/lib/StaticAnalyzer/Core/PathDiagnostic.cpp index 989553e3759..01dd965ac55 100644 --- a/clang/lib/StaticAnalyzer/Core/PathDiagnostic.cpp +++ b/clang/lib/StaticAnalyzer/Core/PathDiagnostic.cpp @@ -55,13 +55,16 @@ PathDiagnosticEventPiece::~PathDiagnosticEventPiece() {} PathDiagnosticCallPiece::~PathDiagnosticCallPiece() {} PathDiagnosticControlFlowPiece::~PathDiagnosticControlFlowPiece() {} PathDiagnosticMacroPiece::~PathDiagnosticMacroPiece() {} -PathDiagnostic::PathDiagnostic() : path(pathImpl) {} + + PathPieces::~PathPieces() {} PathDiagnostic::~PathDiagnostic() {} -PathDiagnostic::PathDiagnostic(StringRef bugtype, StringRef desc, +PathDiagnostic::PathDiagnostic(const Decl *declWithIssue, + StringRef bugtype, StringRef desc, StringRef category) - : BugType(StripTrailingDots(bugtype)), + : DeclWithIssue(declWithIssue), + BugType(StripTrailingDots(bugtype)), Desc(StripTrailingDots(desc)), Category(StripTrailingDots(category)), path(pathImpl) {} diff --git a/clang/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp b/clang/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp index e94b54c825b..323cede7786 100644 --- a/clang/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp +++ b/clang/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp @@ -145,10 +145,9 @@ static void EmitRange(raw_ostream &o, const SourceManager &SM, Indent(o, indent) << "</array>\n"; } -static raw_ostream &EmitString(raw_ostream &o, - const std::string& s) { +static raw_ostream &EmitString(raw_ostream &o, StringRef s) { o << "<string>"; - for (std::string::const_iterator I=s.begin(), E=s.end(); I!=E; ++I) { + for (StringRef::const_iterator I = s.begin(), E = s.end(); I != E; ++I) { char c = *I; switch (c) { default: o << c; break; @@ -252,7 +251,7 @@ static void ReportEvent(raw_ostream &o, const PathDiagnosticPiece& P, // FIXME: Really use a short string. Indent(o, indent) << "<key>message</key>\n"; EmitString(o, P.getString()) << '\n'; - + // Finish up. --indent; Indent(o, indent); o << "</dict>\n"; @@ -447,6 +446,38 @@ void PlistDiagnostics::FlushDiagnosticsImpl( EmitString(o, D->getCategory()) << '\n'; o << " <key>type</key>"; EmitString(o, D->getBugType()) << '\n'; + + // Output information about the semantic context where + // the issue occurred. + if (const Decl *DeclWithIssue = D->getDeclWithIssue()) { + // FIXME: handle blocks, which have no name. + if (const NamedDecl *ND = dyn_cast<NamedDecl>(DeclWithIssue)) { + StringRef declKind; + switch (ND->getKind()) { + case Decl::CXXRecord: + declKind = "C++ class"; + break; + case Decl::CXXMethod: + declKind = "C++ method"; + break; + case Decl::ObjCMethod: + declKind = "Objective-C method"; + break; + case Decl::Function: + declKind = "function"; + break; + default: + break; + } + if (!declKind.empty()) { + const std::string &declName = ND->getDeclName().getAsString(); + o << " <key>issue_context_kind</key>"; + EmitString(o, declKind) << '\n'; + o << " <key>issue_context</key>"; + EmitString(o, declName) << '\n'; + } + } + } // Output the location of the bug. o << " <key>location</key>\n"; diff --git a/clang/test/Analysis/inline-plist.c b/clang/test/Analysis/inline-plist.c index 8b0e40541d5..00019729963 100644 --- a/clang/test/Analysis/inline-plist.c +++ b/clang/test/Analysis/inline-plist.c @@ -232,6 +232,8 @@ void test_has_bug() { // CHECK: <key>description</key><string>Division by zero</string> // CHECK: <key>category</key><string>Logic error</string> // CHECK: <key>type</key><string>Division by zero</string> +// CHECK: <key>issue_context_kind</key><string>function</string> +// CHECK: <key>issue_context</key><string>foo</string> // CHECK: <key>location</key> // CHECK: <dict> // CHECK: <key>line</key><integer>14</integer> @@ -352,6 +354,8 @@ void test_has_bug() { // CHECK: <key>description</key><string>Dereference of null pointer (loaded from variable 'p')</string> // CHECK: <key>category</key><string>Logic error</string> // CHECK: <key>type</key><string>Dereference of null pointer</string> +// CHECK: <key>issue_context_kind</key><string>function</string> +// CHECK: <key>issue_context</key><string>has_bug</string> // CHECK: <key>location</key> // CHECK: <dict> // CHECK: <key>line</key><integer>19</integer> @@ -362,3 +366,4 @@ void test_has_bug() { // CHECK: </array> // CHECK: </dict> // CHECK: </plist> + diff --git a/clang/test/Analysis/malloc-plist.c b/clang/test/Analysis/malloc-plist.c index 1e8193021db..db2e0f01e73 100644 --- a/clang/test/Analysis/malloc-plist.c +++ b/clang/test/Analysis/malloc-plist.c @@ -306,6 +306,8 @@ void LeakedSymbol(int in) { // CHECK: <key>description</key><string>Memory is never released; potential leak of memory pointed to by 'p'</string> // CHECK: <key>category</key><string>Memory Error</string> // CHECK: <key>type</key><string>Memory leak</string> +// CHECK: <key>issue_context_kind</key><string>function</string> +// CHECK: <key>issue_context</key><string>diagnosticTest</string> // CHECK: <key>location</key> // CHECK: <dict> // CHECK: <key>line</key><integer>14</integer> @@ -465,6 +467,8 @@ void LeakedSymbol(int in) { // CHECK: <key>description</key><string>Memory is never released; potential leak of memory pointed to by 'A'</string> // CHECK: <key>category</key><string>Memory Error</string> // CHECK: <key>type</key><string>Memory leak</string> +// CHECK: <key>issue_context_kind</key><string>function</string> +// CHECK: <key>issue_context</key><string>myArrayAllocation</string> // CHECK: <key>location</key> // CHECK: <dict> // CHECK: <key>line</key><integer>21</integer> @@ -862,6 +866,8 @@ void LeakedSymbol(int in) { // CHECK: <key>description</key><string>Memory is never released; potential leak of memory pointed to by 'buf'</string> // CHECK: <key>category</key><string>Memory Error</string> // CHECK: <key>type</key><string>Memory leak</string> +// CHECK: <key>issue_context_kind</key><string>function</string> +// CHECK: <key>issue_context</key><string>reallocDiagnostics</string> // CHECK: <key>location</key> // CHECK: <dict> // CHECK: <key>line</key><integer>28</integer> @@ -1258,6 +1264,8 @@ void LeakedSymbol(int in) { // CHECK: <key>description</key><string>Memory is never released; potential leak of memory pointed to by 'buf'</string> // CHECK: <key>category</key><string>Memory Error</string> // CHECK: <key>type</key><string>Memory leak</string> +// CHECK: <key>issue_context_kind</key><string>function</string> +// CHECK: <key>issue_context</key><string>test_wrapper</string> // CHECK: <key>location</key> // CHECK: <dict> // CHECK: <key>line</key><integer>45</integer> @@ -1775,6 +1783,8 @@ void LeakedSymbol(int in) { // CHECK: <key>description</key><string>Use of memory after it is freed</string> // CHECK: <key>category</key><string>Memory Error</string> // CHECK: <key>type</key><string>Use-after-free</string> +// CHECK: <key>issue_context_kind</key><string>function</string> +// CHECK: <key>issue_context</key><string>test_double_action_call</string> // CHECK: <key>location</key> // CHECK: <dict> // CHECK: <key>line</key><integer>61</integer> @@ -2346,6 +2356,8 @@ void LeakedSymbol(int in) { // CHECK: <key>description</key><string>Memory is never released; potential leak of memory pointed to by 'buf'</string> // CHECK: <key>category</key><string>Memory Error</string> // CHECK: <key>type</key><string>Memory leak</string> +// CHECK: <key>issue_context_kind</key><string>function</string> +// CHECK: <key>issue_context</key><string>reallocIntra</string> // CHECK: <key>location</key> // CHECK: <dict> // CHECK: <key>line</key><integer>76</integer> @@ -2611,6 +2623,8 @@ void LeakedSymbol(int in) { // CHECK: <key>description</key><string>Memory is never released; potential leak of memory pointed to by 'v'</string> // CHECK: <key>category</key><string>Memory Error</string> // CHECK: <key>type</key><string>Memory leak</string> +// CHECK: <key>issue_context_kind</key><string>function</string> +// CHECK: <key>issue_context</key><string>use_ret</string> // CHECK: <key>location</key> // CHECK: <dict> // CHECK: <key>line</key><integer>86</integer> @@ -2785,6 +2799,8 @@ void LeakedSymbol(int in) { // CHECK: <key>description</key><string>Memory is never released; potential leak of memory pointed to by 'm'</string> // CHECK: <key>category</key><string>Memory Error</string> // CHECK: <key>type</key><string>Memory leak</string> +// CHECK: <key>issue_context_kind</key><string>function</string> +// CHECK: <key>issue_context</key><string>LeakedSymbol</string> // CHECK: <key>location</key> // CHECK: <dict> // CHECK: <key>line</key><integer>97</integer> @@ -2795,3 +2811,4 @@ void LeakedSymbol(int in) { // CHECK: </array> // CHECK: </dict> // CHECK: </plist> + diff --git a/clang/test/Analysis/plist-output-alternate.m b/clang/test/Analysis/plist-output-alternate.m index 750c309e06e..b53efcf0156 100644 --- a/clang/test/Analysis/plist-output-alternate.m +++ b/clang/test/Analysis/plist-output-alternate.m @@ -125,6 +125,7 @@ void rdar8331641(int x) { // CHECK: </dict> // CHECK: </array> // CHECK: </array> +// CHECK: <key>depth</key><integer>0</integer> // CHECK: <key>extended_message</key> // CHECK: <string>Dereference of null pointer (loaded from variable 'p')</string> // CHECK: <key>message</key> @@ -134,6 +135,8 @@ void rdar8331641(int x) { // CHECK: <key>description</key><string>Dereference of null pointer (loaded from variable 'p')</string> // CHECK: <key>category</key><string>Logic error</string> // CHECK: <key>type</key><string>Dereference of null pointer</string> +// CHECK: <key>issue_context_kind</key><string>function</string> +// CHECK: <key>issue_context</key><string>test_null_init</string> // CHECK: <key>location</key> // CHECK: <dict> // CHECK: <key>line</key><integer>6</integer> @@ -201,6 +204,7 @@ void rdar8331641(int x) { // CHECK: </dict> // CHECK: </array> // CHECK: </array> +// CHECK: <key>depth</key><integer>0</integer> // CHECK: <key>extended_message</key> // CHECK: <string>Dereference of null pointer (loaded from variable 'p')</string> // CHECK: <key>message</key> @@ -210,6 +214,8 @@ void rdar8331641(int x) { // CHECK: <key>description</key><string>Dereference of null pointer (loaded from variable 'p')</string> // CHECK: <key>category</key><string>Logic error</string> // CHECK: <key>type</key><string>Dereference of null pointer</string> +// CHECK: <key>issue_context_kind</key><string>function</string> +// CHECK: <key>issue_context</key><string>test_null_assign</string> // CHECK: <key>location</key> // CHECK: <dict> // CHECK: <key>line</key><integer>12</integer> @@ -277,6 +283,7 @@ void rdar8331641(int x) { // CHECK: </dict> // CHECK: </array> // CHECK: </array> +// CHECK: <key>depth</key><integer>0</integer> // CHECK: <key>extended_message</key> // CHECK: <string>Dereference of null pointer (loaded from variable 'q')</string> // CHECK: <key>message</key> @@ -286,6 +293,8 @@ void rdar8331641(int x) { // CHECK: <key>description</key><string>Dereference of null pointer (loaded from variable 'q')</string> // CHECK: <key>category</key><string>Logic error</string> // CHECK: <key>type</key><string>Dereference of null pointer</string> +// CHECK: <key>issue_context_kind</key><string>function</string> +// CHECK: <key>issue_context</key><string>test_null_assign_transitive</string> // CHECK: <key>location</key> // CHECK: <dict> // CHECK: <key>line</key><integer>19</integer> @@ -353,6 +362,7 @@ void rdar8331641(int x) { // CHECK: </dict> // CHECK: </array> // CHECK: </array> +// CHECK: <key>depth</key><integer>0</integer> // CHECK: <key>extended_message</key> // CHECK: <string>Assuming 'p' is null</string> // CHECK: <key>message</key> @@ -415,6 +425,7 @@ void rdar8331641(int x) { // CHECK: </dict> // CHECK: </array> // CHECK: </array> +// CHECK: <key>depth</key><integer>0</integer> // CHECK: <key>extended_message</key> // CHECK: <string>Dereference of null pointer (loaded from variable 'p')</string> // CHECK: <key>message</key> @@ -424,6 +435,8 @@ void rdar8331641(int x) { // CHECK: <key>description</key><string>Dereference of null pointer (loaded from variable 'p')</string> // CHECK: <key>category</key><string>Logic error</string> // CHECK: <key>type</key><string>Dereference of null pointer</string> +// CHECK: <key>issue_context_kind</key><string>function</string> +// CHECK: <key>issue_context</key><string>test_null_cond</string> // CHECK: <key>location</key> // CHECK: <dict> // CHECK: <key>line</key><integer>24</integer> @@ -559,6 +572,7 @@ void rdar8331641(int x) { // CHECK: </dict> // CHECK: </array> // CHECK: </array> +// CHECK: <key>depth</key><integer>0</integer> // CHECK: <key>extended_message</key> // CHECK: <string>Dereference of null pointer (loaded from variable 'p')</string> // CHECK: <key>message</key> @@ -568,6 +582,8 @@ void rdar8331641(int x) { // CHECK: <key>description</key><string>Dereference of null pointer (loaded from variable 'p')</string> // CHECK: <key>category</key><string>Logic error</string> // CHECK: <key>type</key><string>Dereference of null pointer</string> +// CHECK: <key>issue_context_kind</key><string>function</string> +// CHECK: <key>issue_context</key><string>test_null_cond_transitive</string> // CHECK: <key>location</key> // CHECK: <dict> // CHECK: <key>line</key><integer>31</integer> @@ -669,6 +685,7 @@ void rdar8331641(int x) { // CHECK: </dict> // CHECK: </array> // CHECK: </array> +// CHECK: <key>depth</key><integer>0</integer> // CHECK: <key>extended_message</key> // CHECK: <string>Dereference of null pointer (loaded from field 'p')</string> // CHECK: <key>message</key> @@ -678,6 +695,8 @@ void rdar8331641(int x) { // CHECK: <key>description</key><string>Dereference of null pointer (loaded from field 'p')</string> // CHECK: <key>category</key><string>Logic error</string> // CHECK: <key>type</key><string>Dereference of null pointer</string> +// CHECK: <key>issue_context_kind</key><string>function</string> +// CHECK: <key>issue_context</key><string>test_null_field</string> // CHECK: <key>location</key> // CHECK: <dict> // CHECK: <key>line</key><integer>38</integer> @@ -779,6 +798,7 @@ void rdar8331641(int x) { // CHECK: </dict> // CHECK: </array> // CHECK: </array> +// CHECK: <key>depth</key><integer>0</integer> // CHECK: <key>extended_message</key> // CHECK: <string>Call to function 'CFNumberCreate' returns a Core Foundation object with a +1 retain count</string> // CHECK: <key>message</key> @@ -928,6 +948,7 @@ void rdar8331641(int x) { // CHECK: <key>col</key><integer>1</integer> // CHECK: <key>file</key><integer>0</integer> // CHECK: </dict> +// CHECK: <key>depth</key><integer>0</integer> // CHECK: <key>extended_message</key> // CHECK: <string>Object leaked: object allocated and stored into 'value' is not referenced later in this execution path and has a retain count of +1</string> // CHECK: <key>message</key> @@ -937,6 +958,8 @@ void rdar8331641(int x) { // CHECK: <key>description</key><string>Potential leak of an object stored into 'value'</string> // CHECK: <key>category</key><string>Memory (Core Foundation/Objective-C)</string> // CHECK: <key>type</key><string>Leak</string> +// CHECK: <key>issue_context_kind</key><string>function</string> +// CHECK: <key>issue_context</key><string>rdar8331641</string> // CHECK: <key>location</key> // CHECK: <dict> // CHECK: <key>line</key><integer>58</integer> diff --git a/clang/test/Analysis/plist-output.m b/clang/test/Analysis/plist-output.m index 375d2342075..3b83e9c11b6 100644 --- a/clang/test/Analysis/plist-output.m +++ b/clang/test/Analysis/plist-output.m @@ -148,6 +148,7 @@ int test_cond_assign() { // CHECK: </dict> // CHECK: </array> // CHECK: </array> +// CHECK: <key>depth</key><integer>0</integer> // CHECK: <key>extended_message</key> // CHECK: <string>Dereference of null pointer (loaded from variable 'p')</string> // CHECK: <key>message</key> @@ -157,6 +158,8 @@ int test_cond_assign() { // CHECK: <key>description</key><string>Dereference of null pointer (loaded from variable 'p')</string> // CHECK: <key>category</key><string>Logic error</string> // CHECK: <key>type</key><string>Dereference of null pointer</string> +// CHECK: <key>issue_context_kind</key><string>function</string> +// CHECK: <key>issue_context</key><string>test_null_init</string> // CHECK: <key>location</key> // CHECK: <dict> // CHECK: <key>line</key><integer>6</integer> @@ -224,6 +227,7 @@ int test_cond_assign() { // CHECK: </dict> // CHECK: </array> // CHECK: </array> +// CHECK: <key>depth</key><integer>0</integer> // CHECK: <key>extended_message</key> // CHECK: <string>Dereference of null pointer (loaded from variable 'p')</string> // CHECK: <key>message</key> @@ -233,6 +237,8 @@ int test_cond_assign() { // CHECK: <key>description</key><string>Dereference of null pointer (loaded from variable 'p')</string> // CHECK: <key>category</key><string>Logic error</string> // CHECK: <key>type</key><string>Dereference of null pointer</string> +// CHECK: <key>issue_context_kind</key><string>function</string> +// CHECK: <key>issue_context</key><string>test_null_assign</string> // CHECK: <key>location</key> // CHECK: <dict> // CHECK: <key>line</key><integer>12</integer> @@ -300,6 +306,7 @@ int test_cond_assign() { // CHECK: </dict> // CHECK: </array> // CHECK: </array> +// CHECK: <key>depth</key><integer>0</integer> // CHECK: <key>extended_message</key> // CHECK: <string>Dereference of null pointer (loaded from variable 'q')</string> // CHECK: <key>message</key> @@ -309,6 +316,8 @@ int test_cond_assign() { // CHECK: <key>description</key><string>Dereference of null pointer (loaded from variable 'q')</string> // CHECK: <key>category</key><string>Logic error</string> // CHECK: <key>type</key><string>Dereference of null pointer</string> +// CHECK: <key>issue_context_kind</key><string>function</string> +// CHECK: <key>issue_context</key><string>test_null_assign_transitive</string> // CHECK: <key>location</key> // CHECK: <dict> // CHECK: <key>line</key><integer>19</integer> @@ -376,6 +385,7 @@ int test_cond_assign() { // CHECK: </dict> // CHECK: </array> // CHECK: </array> +// CHECK: <key>depth</key><integer>0</integer> // CHECK: <key>extended_message</key> // CHECK: <string>Assuming 'p' is null</string> // CHECK: <key>message</key> @@ -438,6 +448,7 @@ int test_cond_assign() { // CHECK: </dict> // CHECK: </array> // CHECK: </array> +// CHECK: <key>depth</key><integer>0</integer> // CHECK: <key>extended_message</key> // CHECK: <string>Dereference of null pointer (loaded from variable 'p')</string> // CHECK: <key>message</key> @@ -447,6 +458,8 @@ int test_cond_assign() { // CHECK: <key>description</key><string>Dereference of null pointer (loaded from variable 'p')</string> // CHECK: <key>category</key><string>Logic error</string> // CHECK: <key>type</key><string>Dereference of null pointer</string> +// CHECK: <key>issue_context_kind</key><string>function</string> +// CHECK: <key>issue_context</key><string>test_null_cond</string> // CHECK: <key>location</key> // CHECK: <dict> // CHECK: <key>line</key><integer>24</integer> @@ -582,6 +595,7 @@ int test_cond_assign() { // CHECK: </dict> // CHECK: </array> // CHECK: </array> +// CHECK: <key>depth</key><integer>0</integer> // CHECK: <key>extended_message</key> // CHECK: <string>Dereference of null pointer (loaded from variable 'p')</string> // CHECK: <key>message</key> @@ -591,6 +605,8 @@ int test_cond_assign() { // CHECK: <key>description</key><string>Dereference of null pointer (loaded from variable 'p')</string> // CHECK: <key>category</key><string>Logic error</string> // CHECK: <key>type</key><string>Dereference of null pointer</string> +// CHECK: <key>issue_context_kind</key><string>function</string> +// CHECK: <key>issue_context</key><string>test_null_cond_transitive</string> // CHECK: <key>location</key> // CHECK: <dict> // CHECK: <key>line</key><integer>32</integer> @@ -692,6 +708,7 @@ int test_cond_assign() { // CHECK: </dict> // CHECK: </array> // CHECK: </array> +// CHECK: <key>depth</key><integer>0</integer> // CHECK: <key>extended_message</key> // CHECK: <string>Dereference of null pointer (loaded from field 'p')</string> // CHECK: <key>message</key> @@ -701,6 +718,8 @@ int test_cond_assign() { // CHECK: <key>description</key><string>Dereference of null pointer (loaded from field 'p')</string> // CHECK: <key>category</key><string>Logic error</string> // CHECK: <key>type</key><string>Dereference of null pointer</string> +// CHECK: <key>issue_context_kind</key><string>function</string> +// CHECK: <key>issue_context</key><string>test_null_field</string> // CHECK: <key>location</key> // CHECK: <dict> // CHECK: <key>line</key><integer>39</integer> @@ -904,6 +923,7 @@ int test_cond_assign() { // CHECK: </dict> // CHECK: </array> // CHECK: </array> +// CHECK: <key>depth</key><integer>0</integer> // CHECK: <key>extended_message</key> // CHECK: <string>Dereference of null pointer (loaded from variable 'p')</string> // CHECK: <key>message</key> @@ -913,6 +933,8 @@ int test_cond_assign() { // CHECK: <key>description</key><string>Dereference of null pointer (loaded from variable 'p')</string> // CHECK: <key>category</key><string>Logic error</string> // CHECK: <key>type</key><string>Dereference of null pointer</string> +// CHECK: <key>issue_context_kind</key><string>function</string> +// CHECK: <key>issue_context</key><string>test_assumptions</string> // CHECK: <key>location</key> // CHECK: <dict> // CHECK: <key>line</key><integer>51</integer> @@ -1014,6 +1036,7 @@ int test_cond_assign() { // CHECK: </dict> // CHECK: </array> // CHECK: </array> +// CHECK: <key>depth</key><integer>0</integer> // CHECK: <key>extended_message</key> // CHECK: <string>Assuming 'p' is null</string> // CHECK: <key>message</key> @@ -1110,6 +1133,7 @@ int test_cond_assign() { // CHECK: </dict> // CHECK: </array> // CHECK: </array> +// CHECK: <key>depth</key><integer>0</integer> // CHECK: <key>extended_message</key> // CHECK: <string>Dereference of null pointer (loaded from variable 'p')</string> // CHECK: <key>message</key> @@ -1119,6 +1143,8 @@ int test_cond_assign() { // CHECK: <key>description</key><string>Dereference of null pointer (loaded from variable 'p')</string> // CHECK: <key>category</key><string>Logic error</string> // CHECK: <key>type</key><string>Dereference of null pointer</string> +// CHECK: <key>issue_context_kind</key><string>function</string> +// CHECK: <key>issue_context</key><string>test_cond_assign</string> // CHECK: <key>location</key> // CHECK: <dict> // CHECK: <key>line</key><integer>59</integer> @@ -1288,6 +1314,7 @@ int test_cond_assign() { // CHECK: </dict> // CHECK: </array> // CHECK: </array> +// CHECK: <key>depth</key><integer>0</integer> // CHECK: <key>extended_message</key> // CHECK: <string>Dereference of null pointer (loaded from variable 'p')</string> // CHECK: <key>message</key> @@ -1297,6 +1324,8 @@ int test_cond_assign() { // CHECK: <key>description</key><string>Dereference of null pointer (loaded from variable 'p')</string> // CHECK: <key>category</key><string>Logic error</string> // CHECK: <key>type</key><string>Dereference of null pointer</string> +// CHECK: <key>issue_context_kind</key><string>Objective-C method</string> +// CHECK: <key>issue_context</key><string>test</string> // CHECK: <key>location</key> // CHECK: <dict> // CHECK: <key>line</key><integer>78</integer> @@ -1308,4 +1337,3 @@ int test_cond_assign() { // CHECK: </dict> // CHECK: </plist> - |