From: Ted Kremenek Date: Wed, 4 Apr 2012 18:11:35 +0000 (+0000) Subject: Include the "issue context" (e.g. function or method) where a static analyzer issue... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=07189521a15d9c088216b943649cb9fe231cbb57;p=clang Include the "issue context" (e.g. function or method) where a static analyzer issue occurred in the plist output. Fixes git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@154030 91177308-0d34-0410-b5e6-96231b3b80d8 --- 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 OtherDesc; PathPieces pathImpl; llvm::SmallVector 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::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 { 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 - 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/lib/StaticAnalyzer/Core/PathDiagnostic.cpp b/lib/StaticAnalyzer/Core/PathDiagnostic.cpp index 989553e375..01dd965ac5 100644 --- a/lib/StaticAnalyzer/Core/PathDiagnostic.cpp +++ b/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/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp b/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp index e94b54c825..323cede778 100644 --- a/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp +++ b/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp @@ -145,10 +145,9 @@ static void EmitRange(raw_ostream &o, const SourceManager &SM, Indent(o, indent) << "\n"; } -static raw_ostream &EmitString(raw_ostream &o, - const std::string& s) { +static raw_ostream &EmitString(raw_ostream &o, StringRef s) { o << ""; - 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) << "message\n"; EmitString(o, P.getString()) << '\n'; - + // Finish up. --indent; Indent(o, indent); o << "\n"; @@ -447,6 +446,38 @@ void PlistDiagnostics::FlushDiagnosticsImpl( EmitString(o, D->getCategory()) << '\n'; o << " type"; 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(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 << " issue_context_kind"; + EmitString(o, declKind) << '\n'; + o << " issue_context"; + EmitString(o, declName) << '\n'; + } + } + } // Output the location of the bug. o << " location\n"; diff --git a/test/Analysis/inline-plist.c b/test/Analysis/inline-plist.c index 8b0e40541d..0001972996 100644 --- a/test/Analysis/inline-plist.c +++ b/test/Analysis/inline-plist.c @@ -232,6 +232,8 @@ void test_has_bug() { // CHECK: descriptionDivision by zero // CHECK: categoryLogic error // CHECK: typeDivision by zero +// CHECK: issue_context_kindfunction +// CHECK: issue_contextfoo // CHECK: location // CHECK: // CHECK: line14 @@ -352,6 +354,8 @@ void test_has_bug() { // CHECK: descriptionDereference of null pointer (loaded from variable 'p') // CHECK: categoryLogic error // CHECK: typeDereference of null pointer +// CHECK: issue_context_kindfunction +// CHECK: issue_contexthas_bug // CHECK: location // CHECK: // CHECK: line19 @@ -362,3 +366,4 @@ void test_has_bug() { // CHECK: // CHECK: // CHECK: + diff --git a/test/Analysis/malloc-plist.c b/test/Analysis/malloc-plist.c index 1e8193021d..db2e0f01e7 100644 --- a/test/Analysis/malloc-plist.c +++ b/test/Analysis/malloc-plist.c @@ -306,6 +306,8 @@ void LeakedSymbol(int in) { // CHECK: descriptionMemory is never released; potential leak of memory pointed to by 'p' // CHECK: categoryMemory Error // CHECK: typeMemory leak +// CHECK: issue_context_kindfunction +// CHECK: issue_contextdiagnosticTest // CHECK: location // CHECK: // CHECK: line14 @@ -465,6 +467,8 @@ void LeakedSymbol(int in) { // CHECK: descriptionMemory is never released; potential leak of memory pointed to by 'A' // CHECK: categoryMemory Error // CHECK: typeMemory leak +// CHECK: issue_context_kindfunction +// CHECK: issue_contextmyArrayAllocation // CHECK: location // CHECK: // CHECK: line21 @@ -862,6 +866,8 @@ void LeakedSymbol(int in) { // CHECK: descriptionMemory is never released; potential leak of memory pointed to by 'buf' // CHECK: categoryMemory Error // CHECK: typeMemory leak +// CHECK: issue_context_kindfunction +// CHECK: issue_contextreallocDiagnostics // CHECK: location // CHECK: // CHECK: line28 @@ -1258,6 +1264,8 @@ void LeakedSymbol(int in) { // CHECK: descriptionMemory is never released; potential leak of memory pointed to by 'buf' // CHECK: categoryMemory Error // CHECK: typeMemory leak +// CHECK: issue_context_kindfunction +// CHECK: issue_contexttest_wrapper // CHECK: location // CHECK: // CHECK: line45 @@ -1775,6 +1783,8 @@ void LeakedSymbol(int in) { // CHECK: descriptionUse of memory after it is freed // CHECK: categoryMemory Error // CHECK: typeUse-after-free +// CHECK: issue_context_kindfunction +// CHECK: issue_contexttest_double_action_call // CHECK: location // CHECK: // CHECK: line61 @@ -2346,6 +2356,8 @@ void LeakedSymbol(int in) { // CHECK: descriptionMemory is never released; potential leak of memory pointed to by 'buf' // CHECK: categoryMemory Error // CHECK: typeMemory leak +// CHECK: issue_context_kindfunction +// CHECK: issue_contextreallocIntra // CHECK: location // CHECK: // CHECK: line76 @@ -2611,6 +2623,8 @@ void LeakedSymbol(int in) { // CHECK: descriptionMemory is never released; potential leak of memory pointed to by 'v' // CHECK: categoryMemory Error // CHECK: typeMemory leak +// CHECK: issue_context_kindfunction +// CHECK: issue_contextuse_ret // CHECK: location // CHECK: // CHECK: line86 @@ -2785,6 +2799,8 @@ void LeakedSymbol(int in) { // CHECK: descriptionMemory is never released; potential leak of memory pointed to by 'm' // CHECK: categoryMemory Error // CHECK: typeMemory leak +// CHECK: issue_context_kindfunction +// CHECK: issue_contextLeakedSymbol // CHECK: location // CHECK: // CHECK: line97 @@ -2795,3 +2811,4 @@ void LeakedSymbol(int in) { // CHECK: // CHECK: // CHECK: + diff --git a/test/Analysis/plist-output-alternate.m b/test/Analysis/plist-output-alternate.m index 750c309e06..b53efcf015 100644 --- a/test/Analysis/plist-output-alternate.m +++ b/test/Analysis/plist-output-alternate.m @@ -125,6 +125,7 @@ void rdar8331641(int x) { // CHECK: // CHECK: // CHECK: +// CHECK: depth0 // CHECK: extended_message // CHECK: Dereference of null pointer (loaded from variable 'p') // CHECK: message @@ -134,6 +135,8 @@ void rdar8331641(int x) { // CHECK: descriptionDereference of null pointer (loaded from variable 'p') // CHECK: categoryLogic error // CHECK: typeDereference of null pointer +// CHECK: issue_context_kindfunction +// CHECK: issue_contexttest_null_init // CHECK: location // CHECK: // CHECK: line6 @@ -201,6 +204,7 @@ void rdar8331641(int x) { // CHECK: // CHECK: // CHECK: +// CHECK: depth0 // CHECK: extended_message // CHECK: Dereference of null pointer (loaded from variable 'p') // CHECK: message @@ -210,6 +214,8 @@ void rdar8331641(int x) { // CHECK: descriptionDereference of null pointer (loaded from variable 'p') // CHECK: categoryLogic error // CHECK: typeDereference of null pointer +// CHECK: issue_context_kindfunction +// CHECK: issue_contexttest_null_assign // CHECK: location // CHECK: // CHECK: line12 @@ -277,6 +283,7 @@ void rdar8331641(int x) { // CHECK: // CHECK: // CHECK: +// CHECK: depth0 // CHECK: extended_message // CHECK: Dereference of null pointer (loaded from variable 'q') // CHECK: message @@ -286,6 +293,8 @@ void rdar8331641(int x) { // CHECK: descriptionDereference of null pointer (loaded from variable 'q') // CHECK: categoryLogic error // CHECK: typeDereference of null pointer +// CHECK: issue_context_kindfunction +// CHECK: issue_contexttest_null_assign_transitive // CHECK: location // CHECK: // CHECK: line19 @@ -353,6 +362,7 @@ void rdar8331641(int x) { // CHECK: // CHECK: // CHECK: +// CHECK: depth0 // CHECK: extended_message // CHECK: Assuming 'p' is null // CHECK: message @@ -415,6 +425,7 @@ void rdar8331641(int x) { // CHECK: // CHECK: // CHECK: +// CHECK: depth0 // CHECK: extended_message // CHECK: Dereference of null pointer (loaded from variable 'p') // CHECK: message @@ -424,6 +435,8 @@ void rdar8331641(int x) { // CHECK: descriptionDereference of null pointer (loaded from variable 'p') // CHECK: categoryLogic error // CHECK: typeDereference of null pointer +// CHECK: issue_context_kindfunction +// CHECK: issue_contexttest_null_cond // CHECK: location // CHECK: // CHECK: line24 @@ -559,6 +572,7 @@ void rdar8331641(int x) { // CHECK: // CHECK: // CHECK: +// CHECK: depth0 // CHECK: extended_message // CHECK: Dereference of null pointer (loaded from variable 'p') // CHECK: message @@ -568,6 +582,8 @@ void rdar8331641(int x) { // CHECK: descriptionDereference of null pointer (loaded from variable 'p') // CHECK: categoryLogic error // CHECK: typeDereference of null pointer +// CHECK: issue_context_kindfunction +// CHECK: issue_contexttest_null_cond_transitive // CHECK: location // CHECK: // CHECK: line31 @@ -669,6 +685,7 @@ void rdar8331641(int x) { // CHECK: // CHECK: // CHECK: +// CHECK: depth0 // CHECK: extended_message // CHECK: Dereference of null pointer (loaded from field 'p') // CHECK: message @@ -678,6 +695,8 @@ void rdar8331641(int x) { // CHECK: descriptionDereference of null pointer (loaded from field 'p') // CHECK: categoryLogic error // CHECK: typeDereference of null pointer +// CHECK: issue_context_kindfunction +// CHECK: issue_contexttest_null_field // CHECK: location // CHECK: // CHECK: line38 @@ -779,6 +798,7 @@ void rdar8331641(int x) { // CHECK: // CHECK: // CHECK: +// CHECK: depth0 // CHECK: extended_message // CHECK: Call to function 'CFNumberCreate' returns a Core Foundation object with a +1 retain count // CHECK: message @@ -928,6 +948,7 @@ void rdar8331641(int x) { // CHECK: col1 // CHECK: file0 // CHECK: +// CHECK: depth0 // CHECK: extended_message // CHECK: Object leaked: object allocated and stored into 'value' is not referenced later in this execution path and has a retain count of +1 // CHECK: message @@ -937,6 +958,8 @@ void rdar8331641(int x) { // CHECK: descriptionPotential leak of an object stored into 'value' // CHECK: categoryMemory (Core Foundation/Objective-C) // CHECK: typeLeak +// CHECK: issue_context_kindfunction +// CHECK: issue_contextrdar8331641 // CHECK: location // CHECK: // CHECK: line58 diff --git a/test/Analysis/plist-output.m b/test/Analysis/plist-output.m index 375d234207..3b83e9c11b 100644 --- a/test/Analysis/plist-output.m +++ b/test/Analysis/plist-output.m @@ -148,6 +148,7 @@ int test_cond_assign() { // CHECK: // CHECK: // CHECK: +// CHECK: depth0 // CHECK: extended_message // CHECK: Dereference of null pointer (loaded from variable 'p') // CHECK: message @@ -157,6 +158,8 @@ int test_cond_assign() { // CHECK: descriptionDereference of null pointer (loaded from variable 'p') // CHECK: categoryLogic error // CHECK: typeDereference of null pointer +// CHECK: issue_context_kindfunction +// CHECK: issue_contexttest_null_init // CHECK: location // CHECK: // CHECK: line6 @@ -224,6 +227,7 @@ int test_cond_assign() { // CHECK: // CHECK: // CHECK: +// CHECK: depth0 // CHECK: extended_message // CHECK: Dereference of null pointer (loaded from variable 'p') // CHECK: message @@ -233,6 +237,8 @@ int test_cond_assign() { // CHECK: descriptionDereference of null pointer (loaded from variable 'p') // CHECK: categoryLogic error // CHECK: typeDereference of null pointer +// CHECK: issue_context_kindfunction +// CHECK: issue_contexttest_null_assign // CHECK: location // CHECK: // CHECK: line12 @@ -300,6 +306,7 @@ int test_cond_assign() { // CHECK: // CHECK: // CHECK: +// CHECK: depth0 // CHECK: extended_message // CHECK: Dereference of null pointer (loaded from variable 'q') // CHECK: message @@ -309,6 +316,8 @@ int test_cond_assign() { // CHECK: descriptionDereference of null pointer (loaded from variable 'q') // CHECK: categoryLogic error // CHECK: typeDereference of null pointer +// CHECK: issue_context_kindfunction +// CHECK: issue_contexttest_null_assign_transitive // CHECK: location // CHECK: // CHECK: line19 @@ -376,6 +385,7 @@ int test_cond_assign() { // CHECK: // CHECK: // CHECK: +// CHECK: depth0 // CHECK: extended_message // CHECK: Assuming 'p' is null // CHECK: message @@ -438,6 +448,7 @@ int test_cond_assign() { // CHECK: // CHECK: // CHECK: +// CHECK: depth0 // CHECK: extended_message // CHECK: Dereference of null pointer (loaded from variable 'p') // CHECK: message @@ -447,6 +458,8 @@ int test_cond_assign() { // CHECK: descriptionDereference of null pointer (loaded from variable 'p') // CHECK: categoryLogic error // CHECK: typeDereference of null pointer +// CHECK: issue_context_kindfunction +// CHECK: issue_contexttest_null_cond // CHECK: location // CHECK: // CHECK: line24 @@ -582,6 +595,7 @@ int test_cond_assign() { // CHECK: // CHECK: // CHECK: +// CHECK: depth0 // CHECK: extended_message // CHECK: Dereference of null pointer (loaded from variable 'p') // CHECK: message @@ -591,6 +605,8 @@ int test_cond_assign() { // CHECK: descriptionDereference of null pointer (loaded from variable 'p') // CHECK: categoryLogic error // CHECK: typeDereference of null pointer +// CHECK: issue_context_kindfunction +// CHECK: issue_contexttest_null_cond_transitive // CHECK: location // CHECK: // CHECK: line32 @@ -692,6 +708,7 @@ int test_cond_assign() { // CHECK: // CHECK: // CHECK: +// CHECK: depth0 // CHECK: extended_message // CHECK: Dereference of null pointer (loaded from field 'p') // CHECK: message @@ -701,6 +718,8 @@ int test_cond_assign() { // CHECK: descriptionDereference of null pointer (loaded from field 'p') // CHECK: categoryLogic error // CHECK: typeDereference of null pointer +// CHECK: issue_context_kindfunction +// CHECK: issue_contexttest_null_field // CHECK: location // CHECK: // CHECK: line39 @@ -904,6 +923,7 @@ int test_cond_assign() { // CHECK: // CHECK: // CHECK: +// CHECK: depth0 // CHECK: extended_message // CHECK: Dereference of null pointer (loaded from variable 'p') // CHECK: message @@ -913,6 +933,8 @@ int test_cond_assign() { // CHECK: descriptionDereference of null pointer (loaded from variable 'p') // CHECK: categoryLogic error // CHECK: typeDereference of null pointer +// CHECK: issue_context_kindfunction +// CHECK: issue_contexttest_assumptions // CHECK: location // CHECK: // CHECK: line51 @@ -1014,6 +1036,7 @@ int test_cond_assign() { // CHECK: // CHECK: // CHECK: +// CHECK: depth0 // CHECK: extended_message // CHECK: Assuming 'p' is null // CHECK: message @@ -1110,6 +1133,7 @@ int test_cond_assign() { // CHECK: // CHECK: // CHECK: +// CHECK: depth0 // CHECK: extended_message // CHECK: Dereference of null pointer (loaded from variable 'p') // CHECK: message @@ -1119,6 +1143,8 @@ int test_cond_assign() { // CHECK: descriptionDereference of null pointer (loaded from variable 'p') // CHECK: categoryLogic error // CHECK: typeDereference of null pointer +// CHECK: issue_context_kindfunction +// CHECK: issue_contexttest_cond_assign // CHECK: location // CHECK: // CHECK: line59 @@ -1288,6 +1314,7 @@ int test_cond_assign() { // CHECK: // CHECK: // CHECK: +// CHECK: depth0 // CHECK: extended_message // CHECK: Dereference of null pointer (loaded from variable 'p') // CHECK: message @@ -1297,6 +1324,8 @@ int test_cond_assign() { // CHECK: descriptionDereference of null pointer (loaded from variable 'p') // CHECK: categoryLogic error // CHECK: typeDereference of null pointer +// CHECK: issue_context_kindObjective-C method +// CHECK: issue_contexttest // CHECK: location // CHECK: // CHECK: line78 @@ -1308,4 +1337,3 @@ int test_cond_assign() { // CHECK: // CHECK: -