[analyzer] add a diagnostic event when entering a call via inlining, within the callee, and add an edge.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@152086 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h b/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h
index 965ac30..245d5be 100644
--- a/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h
+++ b/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h
@@ -387,6 +387,7 @@
   const Decl *Callee;
 public:
   PathDiagnosticLocation callEnter;
+  PathDiagnosticLocation callEnterWithin;
   PathDiagnosticLocation callReturn;  
   PathPieces path;
   
@@ -402,6 +403,8 @@
   }
   
   IntrusiveRefCntPtr<PathDiagnosticEventPiece> getCallEnterEvent() const;
+  IntrusiveRefCntPtr<PathDiagnosticEventPiece>
+    getCallEnterWithinCallerEvent() const;
   IntrusiveRefCntPtr<PathDiagnosticEventPiece> getCallExitEvent() const;
 
   virtual void flattenLocations() {
diff --git a/lib/StaticAnalyzer/Core/BugReporter.cpp b/lib/StaticAnalyzer/Core/BugReporter.cpp
index 73e00e4..53fedaf 100644
--- a/lib/StaticAnalyzer/Core/BugReporter.cpp
+++ b/lib/StaticAnalyzer/Core/BugReporter.cpp
@@ -1233,10 +1233,18 @@
       // Pop the call hierarchy if we are done walking the contents
       // of a function call.
       if (const CallEnter *CE = dyn_cast<CallEnter>(&P)) {
+        // Add an edge to the start of the function.
+        const Decl *D = CE->getCalleeContext()->getDecl();
+        PathDiagnosticLocation pos =
+          PathDiagnosticLocation::createBegin(D, SM);
+        EB.addEdge(pos);
+        
+        // Flush all locations, and pop the active path.
         EB.flushLocations();
         PD.popActivePath();
         assert(!PD.getActivePath().empty());
         PDB.LC = N->getLocationContext();
+
         // The current active path should never be empty.  Either we
         // just added a bunch of stuff to the top-level path, or
         // we have a previous CallExit.  If the front of the active
diff --git a/lib/StaticAnalyzer/Core/PathDiagnostic.cpp b/lib/StaticAnalyzer/Core/PathDiagnostic.cpp
index a082bba..01b40b4 100644
--- a/lib/StaticAnalyzer/Core/PathDiagnostic.cpp
+++ b/lib/StaticAnalyzer/Core/PathDiagnostic.cpp
@@ -527,7 +527,8 @@
   const Decl *D = CE.getCalleeContext()->getDecl();
   Callee = D;
   callEnter = PathDiagnosticLocation(CE.getCallExpr(), SM,
-                                     CE.getLocationContext());  
+                                     CE.getLocationContext());
+  callEnterWithin = PathDiagnosticLocation::createBegin(D, SM);
 }
 
 IntrusiveRefCntPtr<PathDiagnosticEventPiece>
@@ -537,16 +538,32 @@
   SmallString<256> buf;
   llvm::raw_svector_ostream Out(buf);
   if (isa<BlockDecl>(Callee))
-    Out << "Entering call to block";
+    Out << "Calling anonymous block";
   else if (const NamedDecl *ND = dyn_cast<NamedDecl>(Callee))
-    Out << "Entering call to '" << *ND << "'";
+    Out << "Calling '" << *ND << "'";
   StringRef msg = Out.str();
   if (msg.empty())
     return 0;
   return new PathDiagnosticEventPiece(callEnter, msg);
 }
 
-IntrusiveRefCntPtr<PathDiagnosticEventPiece> 
+IntrusiveRefCntPtr<PathDiagnosticEventPiece>
+PathDiagnosticCallPiece::getCallEnterWithinCallerEvent() const {
+  if (!Callee)
+    return 0;
+  SmallString<256> buf;
+  llvm::raw_svector_ostream Out(buf);
+  if (isa<BlockDecl>(Callee))
+    Out << "Entered call to block";
+  else if (const NamedDecl *ND = dyn_cast<NamedDecl>(Callee))
+    Out << "Entered call to '" << *ND << "'";
+  StringRef msg = Out.str();
+  if (msg.empty())
+    return 0;
+  return new PathDiagnosticEventPiece(callEnterWithin, msg);
+}
+
+IntrusiveRefCntPtr<PathDiagnosticEventPiece>
 PathDiagnosticCallPiece::getCallExitEvent() const {
   if (!Caller)
     return 0;
diff --git a/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp b/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp
index 6f2a5ca..2c8270a 100644
--- a/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp
+++ b/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp
@@ -255,15 +255,23 @@
   
   IntrusiveRefCntPtr<PathDiagnosticEventPiece> callEnter =
     P.getCallEnterEvent();  
+
   if (callEnter)
     ReportPiece(o, *callEnter, FM, SM, LangOpts, indent, true);
 
+  IntrusiveRefCntPtr<PathDiagnosticEventPiece> callEnterWithinCaller =
+    P.getCallEnterWithinCallerEvent();
+  
+  if (callEnterWithinCaller)
+    ReportPiece(o, *callEnterWithinCaller, FM, SM, LangOpts, indent, true);
+  
   for (PathPieces::const_iterator I = P.path.begin(), E = P.path.end();I!=E;++I)
     ReportPiece(o, **I, FM, SM, LangOpts, indent, true);
   
   IntrusiveRefCntPtr<PathDiagnosticEventPiece> callExit =
     P.getCallExitEvent();
-  if (callExit)  
+
+  if (callExit)
     ReportPiece(o, *callExit, FM, SM, LangOpts, indent, true);
 }
 
diff --git a/test/Analysis/inline-unique-reports.c b/test/Analysis/inline-unique-reports.c
index f5e5b36..c99a303 100644
--- a/test/Analysis/inline-unique-reports.c
+++ b/test/Analysis/inline-unique-reports.c
@@ -84,9 +84,56 @@
 // CHECK:        </array>
 // CHECK:      </array>
 // CHECK:      <key>extended_message</key>
-// CHECK:      <string>Entering call to &apos;bug&apos;</string>
+// CHECK:      <string>Calling &apos;bug&apos;</string>
 // CHECK:      <key>message</key>
-// CHECK: <string>Entering call to &apos;bug&apos;</string>
+// CHECK: <string>Calling &apos;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>4</integer>
+// CHECK:       <key>col</key><integer>1</integer>
+// CHECK:       <key>file</key><integer>0</integer>
+// CHECK:      </dict>
+// CHECK:      <key>extended_message</key>
+// CHECK:      <string>Entered call to &apos;bug&apos;</string>
+// CHECK:      <key>message</key>
+// CHECK: <string>Entered call to &apos;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>4</integer>
+// CHECK:            <key>col</key><integer>1</integer>
+// CHECK:            <key>file</key><integer>0</integer>
+// CHECK:           </dict>
+// CHECK:           <dict>
+// CHECK:            <key>line</key><integer>4</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>5</integer>
+// CHECK:            <key>col</key><integer>3</integer>
+// CHECK:            <key>file</key><integer>0</integer>
+// CHECK:           </dict>
+// CHECK:           <dict>
+// CHECK:            <key>line</key><integer>5</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>