friend class BugReportEquivClass;
BugType& BT;
+ const Decl *DeclWithIssue;
std::string ShortDescription;
std::string Description;
PathDiagnosticLocation Location;
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.
/// 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();
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.
/// 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; }
/// 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;
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();
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(); }
<< " | 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;
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));
}
}
}
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);
}
}
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;
}
<< "' 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;
}
PathDiagnosticLocation SDLoc =
PathDiagnosticLocation::createBegin((*I), BR.getSourceManager());
- BR.EmitBasicReport(name, category, os.str(), SDLoc);
+ BR.EmitBasicReport(MD, name, category, os.str(), SDLoc);
}
}
}
PathDiagnosticLocation::createBegin(MethDerived,
BR.getSourceManager());
- BR.EmitBasicReport("Incompatible instance method return type",
+ BR.EmitBasicReport(MethDerived,
+ "Incompatible instance method return type",
os.str(), MethDLoc);
}
}
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());
}
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",
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().",
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);
}
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);
}
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);
}
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);
}
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);
}
//===----------------------------------------------------------------------===//
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' "
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 "
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);
}
//===----------------------------------------------------------------------===//
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.",
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,
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)
} // end anonymous namespace
static void CheckStringRefAssignedTemporary(const Decl *D, BugReporter &BR) {
- StringRefCheckerVisitor walker(BR);
+ StringRefCheckerVisitor walker(D, BR);
walker.Visit(D->getBody());
}
"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());
}
// 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);
}
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);
}
}
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());
}
}
}
"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);
}
}
"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);
}
}
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);
}
PathDiagnosticLocation L =
PathDiagnosticLocation::create(I->first, BR.getSourceManager());
- BR.EmitBasicReport("Unused instance variable", "Optimization",
+ BR.EmitBasicReport(D, "Unused instance variable", "Optimization",
os.str(), L);
}
}
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);
}
}
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);
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);
}
}
+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);
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(),
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) {
// '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);
}
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) {}
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;
// 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";
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";
// 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>
// 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>
// CHECK: </array>
// CHECK: </dict>
// CHECK: </plist>
+
// 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>
// 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>
// 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>
// 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>
// 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>
// 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>
// 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>
// 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>
// CHECK: </array>
// CHECK: </dict>
// CHECK: </plist>
+
// 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>
// 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>
// 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>
// 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>
// 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>
// 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>
// 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>
// 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>
// 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>
// 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>
// 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>
// 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>
// 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>
// 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>
// 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>
// 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>
// 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>
// 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>
// 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>
// 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>
// 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>
// 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>
// 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>
// 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>
// 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>
// 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>
// 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>
// 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>
// 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>
// 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>
// 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>
// 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>
// 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>
// 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>
// 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>
// 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>
// CHECK: </dict>
// CHECK: </plist>
-