NoQ created this revision.
NoQ added reviewers: dcoughlin, xazax.hun, a.sidorin, george.karpenkov, szepet.
Herald added subscribers: cfe-commits, rnkovacs.

Like this:

  Expressions by stack frame:
  #0 Calling bar at line 9
  (0x7fbe2a60ea10,0x7fbe2b86ca30) x : 1 S32b
  #1 Calling foo
  (0x7fbe2a60e2e0,0x7fbe2b86cc98) bar : &code{bar}
  (0x7fbe2a60e2e0,0x7fbe2b86cce0) x : 0 S32b

Or in exploded graph:

F5784469: Frames.png <https://reviews.llvm.org/F5784469>

This way it's instantly obvious which `x` is equal to `1` and which `x` is 
equal to `0`.

Additionally, the separate section for the backtrace is removed from the 
graphviz dumps, and the respective code is deduplicated with 
`LocationContext::dumpStack()` which is also used for crash dumps.

It might be not clear where is the current location context in some cases (or 
annoying to supply location context every time you want to dump the program 
state - it is not even necessarily available), so i made a simple 
auto-detection of the freshest location context in which the environment has at 
least one entry, which would be run unless the context is specified explicitly.

The dump is a bit weird for blocks, but nevertheless it represents how the 
analyzer currently works:

F5784474: Blocks.png <https://reviews.llvm.org/F5784474>


Repository:
  rC Clang

https://reviews.llvm.org/D42552

Files:
  include/clang/Analysis/AnalysisDeclContext.h
  include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h
  include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
  lib/Analysis/AnalysisDeclContext.cpp
  lib/StaticAnalyzer/Core/Environment.cpp
  lib/StaticAnalyzer/Core/ExprEngine.cpp
  lib/StaticAnalyzer/Core/ProgramState.cpp
  test/Analysis/crash-trace.c
  test/Analysis/expr-inspection.c

Index: test/Analysis/expr-inspection.c
===================================================================
--- test/Analysis/expr-inspection.c
+++ 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:]]*$)}}
Index: test/Analysis/crash-trace.c
===================================================================
--- test/Analysis/crash-trace.c
+++ test/Analysis/crash-trace.c
@@ -18,6 +18,6 @@
 // CHECK: 0.	Program arguments: {{.*}}clang
 // CHECK-NEXT: 1.	<eof> 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: lib/StaticAnalyzer/Core/ProgramState.cpp
===================================================================
--- lib/StaticAnalyzer/Core/ProgramState.cpp
+++ lib/StaticAnalyzer/Core/ProgramState.cpp
@@ -437,24 +437,24 @@
 //  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);
 
   // Print checker-specific data.
   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: lib/StaticAnalyzer/Core/ExprEngine.cpp
===================================================================
--- lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -2769,12 +2769,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*){
 
@@ -2949,40 +2943,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<NamedDecl>(LC->getDecl()))
-          Out << "Calling " << D->getQualifiedNameAsString();
-        else
-          Out << "Calling anonymous code";
-        if (const Stmt *S = cast<StackFrameContext>(LC)->getCallSite()) {
-          Out << " at ";
-          printLocation2(Out, S->getLocStart());
-        }
-        break;
-      case LocationContext::Block:
-        Out << "Invoking block";
-        if (const Decl *D = cast<BlockInvocationContext>(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: lib/StaticAnalyzer/Core/Environment.cpp
===================================================================
--- lib/StaticAnalyzer/Core/Environment.cpp
+++ 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;
+                        const char *Sep, const LocationContext *WithLC) const {
+  if (ExprBindings.isEmpty())
+    return;
+
+  if (!WithLC) {
+    // Find the freshest location context.
+    llvm::SmallPtrSet<const LocationContext *, 16> 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);
+      }
+    }
+  }
 
-  for (Environment::iterator I = begin(), E = end(); I != E; ++I) {
-    const EnvironmentEntry &En = I.getKey();
+  assert(WithLC);
 
-    if (isFirst) {
-      Out << NL << NL
-          << "Expressions:"
-          << NL;
-      isFirst = false;
-    } else {
-      Out << NL;
-    }
+  LangOptions LO; // FIXME.
+  PrintingPolicy PP(LO);
 
-    const Stmt *S = En.getStmt();
-    assert(S != nullptr && "Expected non-null Stmt");
+  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;
 
-    Out << " (" << (const void*) En.getLocationContext() << ','
-      << (const void*) S << ") ";
-    LangOptions LO; // FIXME.
-    S->printPretty(Out, nullptr, PrintingPolicy(LO));
-    Out << " : " << I.getData();
-  }
+      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: lib/Analysis/AnalysisDeclContext.cpp
===================================================================
--- lib/Analysis/AnalysisDeclContext.cpp
+++ 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<void(const LocationContext *)> 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<StackFrameContext>(LCtx)->getDecl()->print(OS, PP);
-      OS << '\n';
+      OS << Indent << '#' << Frame << ' ';
+      ++Frame;
+      if (const NamedDecl *D = dyn_cast<NamedDecl>(LCtx->getDecl()))
+        OS << "Calling " << D->getQualifiedNameAsString();
+      else
+        OS << "Calling anonymous code";
+      if (const Stmt *S = cast<StackFrameContext>(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<BlockInvocationContext>(LCtx)->getContextData()
-                   << ")\n";
+      OS << "Invoking block";
+      if (const Decl *D = cast<BlockInvocationContext>(LCtx)->getDecl()) {
+        OS << " defined at ";
+        printLocation(OS, SM, D->getLocStart());
+      }
       break;
     }
+    OS << NL;
+
+    printMoreInfoPerContext(LCtx);
   }
 }
 
Index: include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
===================================================================
--- include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
+++ 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: include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h
===================================================================
--- include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h
+++ 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: include/clang/Analysis/AnalysisDeclContext.h
===================================================================
--- include/clang/Analysis/AnalysisDeclContext.h
+++ 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<void(const LocationContext *)> printMoreInfoPerContext =
+          [](const LocationContext *) {}) const;
   void dumpStack() const;
 
 public:
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to