Index: cfe/trunk/include/clang/Analysis/AnalysisDeclContext.h =================================================================== --- cfe/trunk/include/clang/Analysis/AnalysisDeclContext.h +++ cfe/trunk/include/clang/Analysis/AnalysisDeclContext.h @@ -265,7 +265,11 @@ virtual void Profile(llvm::FoldingSetNodeID &ID) = 0; - void dumpStack(raw_ostream &OS, StringRef Indent = "") const; + void dumpStack( + raw_ostream &OS, StringRef Indent = "", const char *NL = "\n", + const char *Sep = "", + std::function printMoreInfoPerContext = + [](const LocationContext *) {}) const; void dumpStack() const; public: Index: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h =================================================================== --- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h +++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h @@ -92,12 +92,9 @@ bool operator==(const Environment& RHS) const { return ExprBindings == RHS.ExprBindings; } - - void print(raw_ostream &Out, const char *NL, const char *Sep) const; - -private: - void printAux(raw_ostream &Out, bool printLocations, - const char *NL, const char *Sep) const; + + void print(raw_ostream &Out, const char *NL, const char *Sep, + const LocationContext *WithLC = nullptr) const; }; class EnvironmentManager { Index: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h =================================================================== --- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h +++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h @@ -435,9 +435,10 @@ } // Pretty-printing. - void print(raw_ostream &Out, const char *nl = "\n", - const char *sep = "") const; - void printDOT(raw_ostream &Out) const; + void print(raw_ostream &Out, const char *nl = "\n", const char *sep = "", + const LocationContext *CurrentLC = nullptr) const; + void printDOT(raw_ostream &Out, + const LocationContext *CurrentLC = nullptr) const; void printTaint(raw_ostream &Out, const char *nl = "\n", const char *sep = "") const; Index: cfe/trunk/lib/Analysis/AnalysisDeclContext.cpp =================================================================== --- cfe/trunk/lib/Analysis/AnalysisDeclContext.cpp +++ cfe/trunk/lib/Analysis/AnalysisDeclContext.cpp @@ -463,28 +463,54 @@ return false; } -void LocationContext::dumpStack(raw_ostream &OS, StringRef Indent) const { +static void printLocation(raw_ostream &OS, const SourceManager &SM, + SourceLocation SLoc) { + if (SLoc.isFileID() && SM.isInMainFile(SLoc)) + OS << "line " << SM.getExpansionLineNumber(SLoc); + else + SLoc.print(OS, SM); +} + +void LocationContext::dumpStack( + raw_ostream &OS, StringRef Indent, const char *NL, const char *Sep, + std::function printMoreInfoPerContext) const { ASTContext &Ctx = getAnalysisDeclContext()->getASTContext(); PrintingPolicy PP(Ctx.getLangOpts()); PP.TerseOutput = 1; + const SourceManager &SM = + getAnalysisDeclContext()->getASTContext().getSourceManager(); + unsigned Frame = 0; for (const LocationContext *LCtx = this; LCtx; LCtx = LCtx->getParent()) { + switch (LCtx->getKind()) { case StackFrame: - OS << Indent << '#' << Frame++ << ' '; - cast(LCtx)->getDecl()->print(OS, PP); - OS << '\n'; + OS << Indent << '#' << Frame << ' '; + ++Frame; + if (const NamedDecl *D = dyn_cast(LCtx->getDecl())) + OS << "Calling " << D->getQualifiedNameAsString(); + else + OS << "Calling anonymous code"; + if (const Stmt *S = cast(LCtx)->getCallSite()) { + OS << " at "; + printLocation(OS, SM, S->getLocStart()); + } break; case Scope: - OS << Indent << " (scope)\n"; + OS << "Entering scope"; break; case Block: - OS << Indent << " (block context: " - << cast(LCtx)->getContextData() - << ")\n"; + OS << "Invoking block"; + if (const Decl *D = cast(LCtx)->getDecl()) { + OS << " defined at "; + printLocation(OS, SM, D->getLocStart()); + } break; } + OS << NL; + + printMoreInfoPerContext(LCtx); } } Index: cfe/trunk/lib/StaticAnalyzer/Core/Environment.cpp =================================================================== --- cfe/trunk/lib/StaticAnalyzer/Core/Environment.cpp +++ cfe/trunk/lib/StaticAnalyzer/Core/Environment.cpp @@ -186,28 +186,41 @@ } void Environment::print(raw_ostream &Out, const char *NL, - const char *Sep) const { - bool isFirst = true; - - for (Environment::iterator I = begin(), E = end(); I != E; ++I) { - const EnvironmentEntry &En = I.getKey(); - - if (isFirst) { - Out << NL << NL - << "Expressions:" - << NL; - isFirst = false; - } else { - Out << NL; + const char *Sep, const LocationContext *WithLC) const { + if (ExprBindings.isEmpty()) + return; + + if (!WithLC) { + // Find the freshest location context. + llvm::SmallPtrSet FoundContexts; + for (auto I : *this) { + const LocationContext *LC = I.first.getLocationContext(); + if (FoundContexts.count(LC) == 0) { + // This context is fresher than all other contexts so far. + WithLC = LC; + for (const LocationContext *LCI = LC; LCI; LCI = LCI->getParent()) + FoundContexts.insert(LCI); + } } + } - const Stmt *S = En.getStmt(); - assert(S != nullptr && "Expected non-null Stmt"); + assert(WithLC); - Out << " (" << (const void*) En.getLocationContext() << ',' - << (const void*) S << ") "; - LangOptions LO; // FIXME. - S->printPretty(Out, nullptr, PrintingPolicy(LO)); - Out << " : " << I.getData(); - } + LangOptions LO; // FIXME. + PrintingPolicy PP(LO); + + Out << NL << NL << "Expressions by stack frame:" << NL; + WithLC->dumpStack(Out, "", NL, Sep, [&](const LocationContext *LC) { + for (auto I : ExprBindings) { + if (I.first.getLocationContext() != LC) + continue; + + const Stmt *S = I.first.getStmt(); + assert(S != nullptr && "Expected non-null Stmt"); + + Out << "(" << (const void *)LC << ',' << (const void *)S << ") "; + S->printPretty(Out, nullptr, PP); + Out << " : " << I.second << NL; + } + }); } Index: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp =================================================================== --- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -2768,12 +2768,6 @@ << "\\l"; } } - static void printLocation2(raw_ostream &Out, SourceLocation SLoc) { - if (SLoc.isFileID() && GraphPrintSourceManager->isInMainFile(SLoc)) - Out << "line " << GraphPrintSourceManager->getExpansionLineNumber(SLoc); - else - SLoc.print(Out, *GraphPrintSourceManager); - } static std::string getNodeLabel(const ExplodedNode *N, void*){ @@ -2948,40 +2942,7 @@ Out << "\\|StateID: " << (const void*) state.get() << " NodeID: " << (const void*) N << "\\|"; - // Analysis stack backtrace. - Out << "Location context stack (from current to outer):\\l"; - const LocationContext *LC = Loc.getLocationContext(); - unsigned Idx = 0; - for (; LC; LC = LC->getParent(), ++Idx) { - Out << Idx << ". (" << (const void *)LC << ") "; - switch (LC->getKind()) { - case LocationContext::StackFrame: - if (const NamedDecl *D = dyn_cast(LC->getDecl())) - Out << "Calling " << D->getQualifiedNameAsString(); - else - Out << "Calling anonymous code"; - if (const Stmt *S = cast(LC)->getCallSite()) { - Out << " at "; - printLocation2(Out, S->getLocStart()); - } - break; - case LocationContext::Block: - Out << "Invoking block"; - if (const Decl *D = cast(LC)->getBlockDecl()) { - Out << " defined at "; - printLocation2(Out, D->getLocStart()); - } - break; - case LocationContext::Scope: - Out << "Entering scope"; - // FIXME: Add more info once ScopeContext is activated. - break; - } - Out << "\\l"; - } - Out << "\\l"; - - state->printDOT(Out); + state->printDOT(Out, N->getLocationContext()); Out << "\\l"; Index: cfe/trunk/lib/StaticAnalyzer/Core/ProgramState.cpp =================================================================== --- cfe/trunk/lib/StaticAnalyzer/Core/ProgramState.cpp +++ cfe/trunk/lib/StaticAnalyzer/Core/ProgramState.cpp @@ -437,14 +437,14 @@ // State pretty-printing. //===----------------------------------------------------------------------===// -void ProgramState::print(raw_ostream &Out, - const char *NL, const char *Sep) const { +void ProgramState::print(raw_ostream &Out, const char *NL, const char *Sep, + const LocationContext *LC) const { // Print the store. ProgramStateManager &Mgr = getStateManager(); Mgr.getStoreManager().print(getStore(), Out, NL, Sep); // Print out the environment. - Env.print(Out, NL, Sep); + Env.print(Out, NL, Sep, LC); // Print out the constraints. Mgr.getConstraintManager().print(this, Out, NL, Sep); @@ -453,8 +453,8 @@ Mgr.getOwningEngine()->printState(Out, this, NL, Sep); } -void ProgramState::printDOT(raw_ostream &Out) const { - print(Out, "\\l", "\\|"); +void ProgramState::printDOT(raw_ostream &Out, const LocationContext *LC) const { + print(Out, "\\l", "\\|", LC); } LLVM_DUMP_METHOD void ProgramState::dump() const { Index: cfe/trunk/test/Analysis/crash-trace.c =================================================================== --- cfe/trunk/test/Analysis/crash-trace.c +++ cfe/trunk/test/Analysis/crash-trace.c @@ -18,6 +18,6 @@ // CHECK: 0. Program arguments: {{.*}}clang // CHECK-NEXT: 1. parser at end of file // CHECK-NEXT: 2. While analyzing stack: -// CHECK-NEXT: #0 void inlined() -// CHECK-NEXT: #1 void test() +// CHECK-NEXT: #0 Calling inlined at line 15 +// CHECK-NEXT: #1 Calling test // CHECK-NEXT: 3. {{.*}}crash-trace.c:{{[0-9]+}}:3: Error evaluating statement Index: cfe/trunk/test/Analysis/expr-inspection.c =================================================================== --- cfe/trunk/test/Analysis/expr-inspection.c +++ cfe/trunk/test/Analysis/expr-inspection.c @@ -18,6 +18,8 @@ // CHECK: Store (direct and default bindings) // CHECK-NEXT: (y,0,direct) : 1 S32b -// CHECK: Expressions: +// CHECK: Expressions by stack frame: +// CHECK-NEXT: #0 Calling foo // CHECK-NEXT: clang_analyzer_printState : &code{clang_analyzer_printState} -// CHECK-NEXT: {{(Ranges are empty.)|(Constraints:[[:space:]]*$)}} + +// CHECK: {{(Ranges are empty.)|(Constraints:[[:space:]]*$)}}