[analyzer] Include inlining call stack depth in plist output.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@152584 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp b/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp
index cce75ad..ee2b3f3 100644
--- a/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp
+++ b/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp
@@ -197,7 +197,8 @@
                         const FIDMap& FM,
                         const SourceManager &SM,
                         const LangOptions &LangOpts,
-                        unsigned indent) {
+                        unsigned indent,
+                        unsigned depth) {
 
   Indent(o, indent) << "<dict>\n";
   ++indent;
@@ -223,6 +224,10 @@
     --indent;
     Indent(o, indent) << "</array>\n";
   }
+  
+  // Output the call depth.
+  Indent(o, indent) << "<key>depth</key>"
+                    << "<integer>" << depth << "</integer>\n";
 
   // Output the text.
   assert(!P.getString().empty());
@@ -245,52 +250,58 @@
                         const FIDMap& FM, const SourceManager &SM,
                         const LangOptions &LangOpts,
                         unsigned indent,
+                        unsigned depth,
                         bool includeControlFlow);
 
 static void ReportCall(raw_ostream &o,
                        const PathDiagnosticCallPiece &P,
                        const FIDMap& FM, const SourceManager &SM,
                        const LangOptions &LangOpts,
-                       unsigned indent) {
+                       unsigned indent,
+                       unsigned depth) {
   
   IntrusiveRefCntPtr<PathDiagnosticEventPiece> callEnter =
     P.getCallEnterEvent();  
 
   if (callEnter)
-    ReportPiece(o, *callEnter, FM, SM, LangOpts, indent, true);
+    ReportPiece(o, *callEnter, FM, SM, LangOpts, indent, depth, true);
 
   IntrusiveRefCntPtr<PathDiagnosticEventPiece> callEnterWithinCaller =
     P.getCallEnterWithinCallerEvent();
   
+  ++depth;
+  
   if (callEnterWithinCaller)
-    ReportPiece(o, *callEnterWithinCaller, FM, SM, LangOpts, indent, true);
+    ReportPiece(o, *callEnterWithinCaller, FM, SM, LangOpts,
+                indent, depth, true);
   
   for (PathPieces::const_iterator I = P.path.begin(), E = P.path.end();I!=E;++I)
-    ReportPiece(o, **I, FM, SM, LangOpts, indent, true);
+    ReportPiece(o, **I, FM, SM, LangOpts, indent, depth, true);
   
   IntrusiveRefCntPtr<PathDiagnosticEventPiece> callExit =
     P.getCallExitEvent();
 
   if (callExit)
-    ReportPiece(o, *callExit, FM, SM, LangOpts, indent, true);
+    ReportPiece(o, *callExit, FM, SM, LangOpts, indent, depth, true);
 }
 
 static void ReportMacro(raw_ostream &o,
                         const PathDiagnosticMacroPiece& P,
                         const FIDMap& FM, const SourceManager &SM,
                         const LangOptions &LangOpts,
-                        unsigned indent) {
+                        unsigned indent,
+                        unsigned depth) {
 
   for (PathPieces::const_iterator I = P.subPieces.begin(), E=P.subPieces.end();
        I!=E; ++I) {
-    ReportPiece(o, **I, FM, SM, LangOpts, indent, false);
+    ReportPiece(o, **I, FM, SM, LangOpts, indent, depth, false);
   }
 }
 
 static void ReportDiag(raw_ostream &o, const PathDiagnosticPiece& P,
                        const FIDMap& FM, const SourceManager &SM,
                        const LangOptions &LangOpts) {
-  ReportPiece(o, P, FM, SM, LangOpts, 4, true);
+  ReportPiece(o, P, FM, SM, LangOpts, 4, 0, true);
 }
 
 static void ReportPiece(raw_ostream &o,
@@ -298,6 +309,7 @@
                         const FIDMap& FM, const SourceManager &SM,
                         const LangOptions &LangOpts,
                         unsigned indent,
+                        unsigned depth,
                         bool includeControlFlow) {
   switch (P.getKind()) {
     case PathDiagnosticPiece::ControlFlow:
@@ -307,15 +319,15 @@
       break;
     case PathDiagnosticPiece::Call:
       ReportCall(o, cast<PathDiagnosticCallPiece>(P), FM, SM, LangOpts,
-                 indent);
+                 indent, depth);
       break;
     case PathDiagnosticPiece::Event:
       ReportEvent(o, cast<PathDiagnosticSpotPiece>(P), FM, SM, LangOpts,
-                  indent);
+                  indent, depth);
       break;
     case PathDiagnosticPiece::Macro:
       ReportMacro(o, cast<PathDiagnosticMacroPiece>(P), FM, SM, LangOpts,
-                  indent);
+                  indent, depth);
       break;
   }
 }
diff --git a/test/Analysis/inline-plist.c b/test/Analysis/inline-plist.c
index f2ef606..08b2aed 100644
--- a/test/Analysis/inline-plist.c
+++ b/test/Analysis/inline-plist.c
@@ -14,6 +14,15 @@
     return 5/x;
 }
 
+// Test a bug triggering only when inlined.
+void has_bug(int *p) {
+  *p = 0xDEADBEEF;
+}
+
+void test_has_bug() {
+  has_bug(0);
+}
+
 // CHECK: <?xml version="1.0" encoding="UTF-8"?>
 // CHECK: <plist version="1.0">
 // CHECK: <dict>
@@ -116,6 +125,7 @@
 // CHECK:         </dict>
 // CHECK:        </array>
 // CHECK:      </array>
+// CHECK:      <key>depth</key><integer>0</integer>
 // CHECK:      <key>extended_message</key>
 // CHECK:      <string>Assuming &apos;x&apos; is equal to 0</string>
 // CHECK:      <key>message</key>
@@ -212,6 +222,7 @@
 // CHECK:         </dict>
 // CHECK:        </array>
 // CHECK:      </array>
+// CHECK:      <key>depth</key><integer>0</integer>
 // CHECK:      <key>extended_message</key>
 // CHECK:      <string>Division by zero</string>
 // CHECK:      <key>message</key>
@@ -228,7 +239,126 @@
 // CHECK:    <key>file</key><integer>0</integer>
 // CHECK:   </dict>
 // CHECK:   </dict>
+// CHECK:   <dict>
+// CHECK:    <key>path</key>
+// CHECK:    <array>
+// CHECK:     <dict>
+// CHECK:      <key>kind</key><string>event</string>
+// CHECK:      <key>location</key>
+// CHECK:      <dict>
+// CHECK:       <key>line</key><integer>23</integer>
+// CHECK:       <key>col</key><integer>3</integer>
+// CHECK:       <key>file</key><integer>0</integer>
+// CHECK:      </dict>
+// CHECK:      <key>ranges</key>
+// CHECK:      <array>
+// CHECK:        <array>
+// CHECK:         <dict>
+// CHECK:          <key>line</key><integer>23</integer>
+// CHECK:          <key>col</key><integer>3</integer>
+// CHECK:          <key>file</key><integer>0</integer>
+// CHECK:         </dict>
+// CHECK:         <dict>
+// CHECK:          <key>line</key><integer>23</integer>
+// CHECK:          <key>col</key><integer>12</integer>
+// CHECK:          <key>file</key><integer>0</integer>
+// CHECK:         </dict>
+// CHECK:        </array>
+// CHECK:      </array>
+// CHECK:      <key>depth</key><integer>0</integer>
+// CHECK:      <key>extended_message</key>
+// CHECK:      <string>Calling &apos;has_bug&apos;</string>
+// CHECK:      <key>message</key>
+// CHECK: <string>Calling &apos;has_bug&apos;</string>
+// CHECK:     </dict>
+// CHECK:     <dict>
+// CHECK:      <key>kind</key><string>event</string>
+// CHECK:      <key>location</key>
+// CHECK:      <dict>
+// CHECK:       <key>line</key><integer>18</integer>
+// CHECK:       <key>col</key><integer>1</integer>
+// CHECK:       <key>file</key><integer>0</integer>
+// CHECK:      </dict>
+// CHECK:      <key>depth</key><integer>1</integer>
+// CHECK:      <key>extended_message</key>
+// CHECK:      <string>Entered call to &apos;has_bug&apos;</string>
+// CHECK:      <key>message</key>
+// CHECK: <string>Entered call to &apos;has_bug&apos;</string>
+// CHECK:     </dict>
+// CHECK:     <dict>
+// CHECK:      <key>kind</key><string>control</string>
+// CHECK:      <key>edges</key>
+// CHECK:       <array>
+// CHECK:        <dict>
+// CHECK:         <key>start</key>
+// CHECK:          <array>
+// CHECK:           <dict>
+// CHECK:            <key>line</key><integer>18</integer>
+// CHECK:            <key>col</key><integer>1</integer>
+// CHECK:            <key>file</key><integer>0</integer>
+// CHECK:           </dict>
+// CHECK:           <dict>
+// CHECK:            <key>line</key><integer>18</integer>
+// CHECK:            <key>col</key><integer>1</integer>
+// CHECK:            <key>file</key><integer>0</integer>
+// CHECK:           </dict>
+// CHECK:          </array>
+// CHECK:         <key>end</key>
+// CHECK:          <array>
+// CHECK:           <dict>
+// CHECK:            <key>line</key><integer>19</integer>
+// CHECK:            <key>col</key><integer>3</integer>
+// CHECK:            <key>file</key><integer>0</integer>
+// CHECK:           </dict>
+// CHECK:           <dict>
+// CHECK:            <key>line</key><integer>19</integer>
+// CHECK:            <key>col</key><integer>4</integer>
+// CHECK:            <key>file</key><integer>0</integer>
+// CHECK:           </dict>
+// CHECK:          </array>
+// CHECK:        </dict>
+// CHECK:       </array>
+// CHECK:     </dict>
+// CHECK:     <dict>
+// CHECK:      <key>kind</key><string>event</string>
+// CHECK:      <key>location</key>
+// CHECK:      <dict>
+// CHECK:       <key>line</key><integer>19</integer>
+// CHECK:       <key>col</key><integer>3</integer>
+// CHECK:       <key>file</key><integer>0</integer>
+// CHECK:      </dict>
+// CHECK:      <key>ranges</key>
+// CHECK:      <array>
+// CHECK:        <array>
+// CHECK:         <dict>
+// CHECK:          <key>line</key><integer>19</integer>
+// CHECK:          <key>col</key><integer>4</integer>
+// CHECK:          <key>file</key><integer>0</integer>
+// CHECK:         </dict>
+// CHECK:         <dict>
+// CHECK:          <key>line</key><integer>19</integer>
+// CHECK:          <key>col</key><integer>4</integer>
+// CHECK:          <key>file</key><integer>0</integer>
+// CHECK:         </dict>
+// CHECK:        </array>
+// CHECK:      </array>
+// CHECK:      <key>depth</key><integer>1</integer>
+// CHECK:      <key>extended_message</key>
+// CHECK:      <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK:      <key>message</key>
+// CHECK: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK:     </dict>
+// CHECK:    </array>
+// CHECK:    <key>description</key><string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK:    <key>category</key><string>Logic error</string>
+// CHECK:    <key>type</key><string>Dereference of null pointer</string>
+// CHECK:   <key>location</key>
+// CHECK:   <dict>
+// CHECK:    <key>line</key><integer>19</integer>
+// CHECK:    <key>col</key><integer>3</integer>
+// CHECK:    <key>file</key><integer>0</integer>
+// CHECK:   </dict>
+// CHECK:   </dict>
 // CHECK:  </array>
 // CHECK: </dict>
 // CHECK: </plist>
-