Include the "issue context" (e.g. function or method) where a static analyzer issue occurred in the plist output.

Fixes <rdar://problem/11004527>

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@154030 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/StaticAnalyzer/Core/BugReporter.cpp b/lib/StaticAnalyzer/Core/BugReporter.cpp
index e1be6e9..2752e32 100644
--- a/lib/StaticAnalyzer/Core/BugReporter.cpp
+++ b/lib/StaticAnalyzer/Core/BugReporter.cpp
@@ -1241,6 +1241,18 @@
   }
 }
 
+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 @@
   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 @@
     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 @@
   // '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 989553e..01dd965 100644
--- a/lib/StaticAnalyzer/Core/PathDiagnostic.cpp
+++ b/lib/StaticAnalyzer/Core/PathDiagnostic.cpp
@@ -55,13 +55,16 @@
 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 e94b54c..323cede 100644
--- a/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp
+++ b/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp
@@ -145,10 +145,9 @@
   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 @@
   // 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 @@
     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";