diff options
5 files changed, 90 insertions, 7 deletions
diff --git a/clang/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h b/clang/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h index 965ac3085e6..245d5be93e6 100644 --- a/clang/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h +++ b/clang/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h @@ -387,6 +387,7 @@ class PathDiagnosticCallPiece : public PathDiagnosticPiece { const Decl *Callee; public: PathDiagnosticLocation callEnter; + PathDiagnosticLocation callEnterWithin; PathDiagnosticLocation callReturn; PathPieces path; @@ -402,6 +403,8 @@ public: } IntrusiveRefCntPtr<PathDiagnosticEventPiece> getCallEnterEvent() const; + IntrusiveRefCntPtr<PathDiagnosticEventPiece> + getCallEnterWithinCallerEvent() const; IntrusiveRefCntPtr<PathDiagnosticEventPiece> getCallExitEvent() const; virtual void flattenLocations() { diff --git a/clang/lib/StaticAnalyzer/Core/BugReporter.cpp b/clang/lib/StaticAnalyzer/Core/BugReporter.cpp index 73e00e44167..53fedaf2a12 100644 --- a/clang/lib/StaticAnalyzer/Core/BugReporter.cpp +++ b/clang/lib/StaticAnalyzer/Core/BugReporter.cpp @@ -1233,10 +1233,18 @@ static void GenerateExtensivePathDiagnostic(PathDiagnostic& PD, // 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/clang/lib/StaticAnalyzer/Core/PathDiagnostic.cpp b/clang/lib/StaticAnalyzer/Core/PathDiagnostic.cpp index a082bba70dd..01b40b43baf 100644 --- a/clang/lib/StaticAnalyzer/Core/PathDiagnostic.cpp +++ b/clang/lib/StaticAnalyzer/Core/PathDiagnostic.cpp @@ -527,7 +527,8 @@ void PathDiagnosticCallPiece::setCallee(const CallEnter &CE, 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 @@ PathDiagnosticCallPiece::getCallEnterEvent() const { 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/clang/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp b/clang/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp index 6f2a5ca9313..2c8270a2dd1 100644 --- a/clang/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp +++ b/clang/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp @@ -255,15 +255,23 @@ static void ReportCall(raw_ostream &o, 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/clang/test/Analysis/inline-unique-reports.c b/clang/test/Analysis/inline-unique-reports.c index f5e5b36be71..c99a3033353 100644 --- a/clang/test/Analysis/inline-unique-reports.c +++ b/clang/test/Analysis/inline-unique-reports.c @@ -84,9 +84,56 @@ void test_bug_2() { // CHECK: </array> // CHECK: </array> // CHECK: <key>extended_message</key> -// CHECK: <string>Entering call to 'bug'</string> +// CHECK: <string>Calling 'bug'</string> // CHECK: <key>message</key> -// CHECK: <string>Entering call to 'bug'</string> +// CHECK: <string>Calling 'bug'</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 'bug'</string> +// CHECK: <key>message</key> +// CHECK: <string>Entered call to 'bug'</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> |