r361976 - [analyzer] print() JSONify: Environment implementation

Csaba Dabis via cfe-commits cfe-commits at lists.llvm.org
Wed May 29 08:36:58 PDT 2019


Author: charusso
Date: Wed May 29 08:36:58 2019
New Revision: 361976

URL: http://llvm.org/viewvc/llvm-project?rev=361976&view=rev
Log:
[analyzer] print() JSONify: Environment implementation

Summary: -

Reviewers: NoQ, xazax.hun, ravikandhadai, baloghadamsoftware, Szelethus

Reviewed By: NoQ

Subscribers: szepet, rnkovacs, a.sidorin, mikhail.ramalho, donat.nagy,
             dkrupp

Tags: #clang

Differential Revision: https://reviews.llvm.org/D62081

Modified:
    cfe/trunk/include/clang/Analysis/AnalysisDeclContext.h
    cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h
    cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
    cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h
    cfe/trunk/lib/Analysis/AnalysisDeclContext.cpp
    cfe/trunk/lib/StaticAnalyzer/Core/Environment.cpp
    cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp
    cfe/trunk/lib/StaticAnalyzer/Core/PrettyStackTraceLocationContext.h
    cfe/trunk/lib/StaticAnalyzer/Core/ProgramState.cpp
    cfe/trunk/test/Analysis/expr-inspection.c

Modified: cfe/trunk/include/clang/Analysis/AnalysisDeclContext.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/AnalysisDeclContext.h?rev=361976&r1=361975&r2=361976&view=diff
==============================================================================
--- cfe/trunk/include/clang/Analysis/AnalysisDeclContext.h (original)
+++ cfe/trunk/include/clang/Analysis/AnalysisDeclContext.h Wed May 29 08:36:58 2019
@@ -274,11 +274,17 @@ public:
   virtual void Profile(llvm::FoldingSetNodeID &ID) = 0;
 
   void dumpStack(
-      raw_ostream &OS, StringRef Indent = {}, const char *NL = "\n",
-      const char *Sep = "",
+      raw_ostream &Out, const char *NL = "\n",
       std::function<void(const LocationContext *)> printMoreInfoPerContext =
           [](const LocationContext *) {}) const;
-  void dumpStack() const;
+
+  void printJson(
+      raw_ostream &Out, const char *NL = "\n", unsigned int Space = 0,
+      bool IsDot = false,
+      std::function<void(const LocationContext *)> printMoreInfoPerContext =
+          [](const LocationContext *) {}) const;
+
+  void dump() const;
 
 public:
   static void ProfileCommon(llvm::FoldingSetNodeID &ID,

Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h?rev=361976&r1=361975&r2=361976&view=diff
==============================================================================
--- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h (original)
+++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h Wed May 29 08:36:58 2019
@@ -91,9 +91,9 @@ public:
     return ExprBindings == RHS.ExprBindings;
   }
 
-  void print(raw_ostream &Out, const char *NL, const char *Sep,
-             const ASTContext &Context,
-             const LocationContext *WithLC = nullptr) const;
+  void printJson(raw_ostream &Out, const ASTContext &Ctx,
+                 const LocationContext *LCtx = nullptr, const char *NL = "\n",
+                 unsigned int Space = 0, bool IsDot = false) const;
 };
 
 class EnvironmentManager {

Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h?rev=361976&r1=361975&r2=361976&view=diff
==============================================================================
--- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h (original)
+++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h Wed May 29 08:36:58 2019
@@ -377,9 +377,9 @@ public:
                        const CallEvent *Call) override;
 
   /// printState - Called by ProgramStateManager to print checker-specific data.
-  void printState(raw_ostream &Out, ProgramStateRef State, const char *NL,
-                  const char *Sep,
-                  const LocationContext *LCtx = nullptr) override;
+  void printState(raw_ostream &Out, ProgramStateRef State,
+                  const LocationContext *LCtx, const char *NL,
+                  unsigned int Space, bool IsDot) const override;
 
   ProgramStateManager &getStateManager() override { return StateMgr; }
 

Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h?rev=361976&r1=361975&r2=361976&view=diff
==============================================================================
--- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h (original)
+++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h Wed May 29 08:36:58 2019
@@ -160,8 +160,8 @@ public:
 
   /// printState - Called by ProgramStateManager to print checker-specific data.
   virtual void printState(raw_ostream &Out, ProgramStateRef State,
-                          const char *NL, const char *Sep,
-                          const LocationContext *LCtx = nullptr) = 0;
+                          const LocationContext *LCtx, const char *NL,
+                          unsigned int Space, bool IsDot) const = 0;
 
   /// Called by CoreEngine when the analysis worklist is either empty or the
   //  maximum number of analysis steps have been reached.

Modified: cfe/trunk/lib/Analysis/AnalysisDeclContext.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/AnalysisDeclContext.cpp?rev=361976&r1=361975&r2=361976&view=diff
==============================================================================
--- cfe/trunk/lib/Analysis/AnalysisDeclContext.cpp (original)
+++ cfe/trunk/lib/Analysis/AnalysisDeclContext.cpp Wed May 29 08:36:58 2019
@@ -30,6 +30,7 @@
 #include "clang/Analysis/CFG.h"
 #include "clang/Analysis/CFGStmtMap.h"
 #include "clang/Analysis/Support/BumpVector.h"
+#include "clang/Basic/JsonSupport.h"
 #include "clang/Basic/LLVM.h"
 #include "clang/Basic/SourceLocation.h"
 #include "clang/Basic/SourceManager.h"
@@ -463,17 +464,17 @@ bool LocationContext::isParentOf(const L
   return false;
 }
 
-static void printLocation(raw_ostream &OS, const SourceManager &SM,
-                          SourceLocation SLoc) {
-  if (SLoc.isFileID() && SM.isInMainFile(SLoc))
-    OS << "line " << SM.getExpansionLineNumber(SLoc);
+static void printLocation(raw_ostream &Out, const SourceManager &SM,
+                          SourceLocation Loc) {
+  if (Loc.isFileID() && SM.isInMainFile(Loc))
+    Out << SM.getExpansionLineNumber(Loc);
   else
-    SLoc.print(OS, SM);
+    Loc.print(Out, SM);
 }
 
-void LocationContext::dumpStack(
-    raw_ostream &OS, StringRef Indent, const char *NL, const char *Sep,
-    std::function<void(const LocationContext *)> printMoreInfoPerContext) const {
+void LocationContext::dumpStack(raw_ostream &Out, const char *NL,
+                                std::function<void(const LocationContext *)>
+                                    printMoreInfoPerContext) const {
   ASTContext &Ctx = getAnalysisDeclContext()->getASTContext();
   PrintingPolicy PP(Ctx.getLangOpts());
   PP.TerseOutput = 1;
@@ -485,38 +486,92 @@ void LocationContext::dumpStack(
   for (const LocationContext *LCtx = this; LCtx; LCtx = LCtx->getParent()) {
     switch (LCtx->getKind()) {
     case StackFrame:
-      OS << Indent << '#' << Frame << ' ';
+      Out << "\t#" << Frame << ' ';
       ++Frame;
       if (const auto *D = dyn_cast<NamedDecl>(LCtx->getDecl()))
-        OS << "Calling " << D->getQualifiedNameAsString();
+        Out << "Calling " << D->getQualifiedNameAsString();
       else
-        OS << "Calling anonymous code";
+        Out << "Calling anonymous code";
       if (const Stmt *S = cast<StackFrameContext>(LCtx)->getCallSite()) {
-        OS << " at ";
-        printLocation(OS, SM, S->getBeginLoc());
+        Out << " at line ";
+        printLocation(Out, SM, S->getBeginLoc());
       }
       break;
     case Scope:
-      OS << "Entering scope";
+      Out << "Entering scope";
       break;
     case Block:
-      OS << "Invoking block";
+      Out << "Invoking block";
       if (const Decl *D = cast<BlockInvocationContext>(LCtx)->getDecl()) {
-        OS << " defined at ";
-        printLocation(OS, SM, D->getBeginLoc());
+        Out << " defined at line ";
+        printLocation(Out, SM, D->getBeginLoc());
       }
       break;
     }
-    OS << NL;
+    Out << NL;
 
     printMoreInfoPerContext(LCtx);
   }
 }
 
-LLVM_DUMP_METHOD void LocationContext::dumpStack() const {
-  dumpStack(llvm::errs());
+void LocationContext::printJson(raw_ostream &Out, const char *NL,
+                                unsigned int Space, bool IsDot,
+                                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()) {
+    Indent(Out, Space, IsDot) << "{ \"location_context\": \"";
+    switch (LCtx->getKind()) {
+    case StackFrame:
+      Out << '#' << Frame << " Call\", \"calling\": \"";
+      ++Frame;
+      if (const auto *D = dyn_cast<NamedDecl>(LCtx->getDecl()))
+        Out << D->getQualifiedNameAsString();
+      else
+        Out << "anonymous code";
+
+      Out << "\", \"call_line\": ";
+      if (const Stmt *S = cast<StackFrameContext>(LCtx)->getCallSite()) {
+        Out << '\"';
+        printLocation(Out, SM, S->getBeginLoc());
+	Out << '\"';
+      } else {
+        Out << "null";
+      }
+
+      Out << ", \"items\": ";
+      break;
+    case Scope:
+      Out << "Entering scope\" ";
+      break;
+    case Block:
+      Out << "Invoking block\" ";
+      if (const Decl *D = cast<BlockInvocationContext>(LCtx)->getDecl()) {
+        Out << ", \"decl_line\": ";
+        printLocation(Out, SM, D->getBeginLoc());
+        Out << ' ';
+      }
+      break;
+    }
+
+    printMoreInfoPerContext(LCtx);
+
+    Out << '}';
+    if (LCtx->getParent())
+      Out << ',';
+    Out << NL;
+  }
 }
 
+LLVM_DUMP_METHOD void LocationContext::dump() const { printJson(llvm::errs()); }
+
 //===----------------------------------------------------------------------===//
 // Lazily generated map to query the external variables referenced by a Block.
 //===----------------------------------------------------------------------===//

Modified: cfe/trunk/lib/StaticAnalyzer/Core/Environment.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/Environment.cpp?rev=361976&r1=361975&r2=361976&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/Environment.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/Environment.cpp Wed May 29 08:36:58 2019
@@ -18,6 +18,7 @@
 #include "clang/Analysis/AnalysisDeclContext.h"
 #include "clang/Basic/LLVM.h"
 #include "clang/Basic/LangOptions.h"
+#include "clang/Basic/JsonSupport.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
@@ -199,43 +200,93 @@ EnvironmentManager::removeDeadBindings(E
   return NewEnv;
 }
 
-void Environment::print(raw_ostream &Out, const char *NL,
-                        const char *Sep,
-                        const ASTContext &Context,
-                        const LocationContext *WithLC) const {
-  if (ExprBindings.isEmpty())
+void Environment::printJson(raw_ostream &Out, const ASTContext &Ctx,
+                            const LocationContext *LCtx, const char *NL,
+                            unsigned int Space, bool IsDot) const {
+  Indent(Out, Space, IsDot) << "\"environment\": ";
+  ++Space;
+
+  if (ExprBindings.isEmpty()) {
+    Out << "null," << NL;
     return;
+  }
 
-  if (!WithLC) {
+  if (!LCtx) {
     // Find the freshest location context.
     llvm::SmallPtrSet<const LocationContext *, 16> FoundContexts;
-    for (auto I : *this) {
+    for (const 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;
+        LCtx = LC;
         for (const LocationContext *LCI = LC; LCI; LCI = LCI->getParent())
           FoundContexts.insert(LCI);
       }
     }
   }
 
-  assert(WithLC);
+  assert(LCtx);
 
-  PrintingPolicy PP = Context.getPrintingPolicy();
+  Out << '[' << NL; // Start of Environment.
+  PrintingPolicy PP = Ctx.getPrintingPolicy();
 
-  Out << NL << "Expressions by stack frame:" << NL;
-  WithLC->dumpStack(Out, "", NL, Sep, [&](const LocationContext *LC) {
-    for (auto I : ExprBindings) {
-      if (I.first.getLocationContext() != LC)
+  LCtx->printJson(Out, NL, Space, IsDot, [&](const LocationContext *LC) {
+    // LCtx items begin
+    bool HasItem = false;
+    unsigned int InnerSpace = Space + 1;
+
+    llvm::SmallString<256> TempBuf;
+    llvm::raw_svector_ostream TempOut(TempBuf);
+
+    // Store the last ExprBinding which we will print.
+    BindingsTy::iterator LastI = ExprBindings.end();
+    for (BindingsTy::iterator I = ExprBindings.begin(); I != ExprBindings.end();
+         ++I) {
+      if (I->first.getLocationContext() != LC)
         continue;
 
-      const Stmt *S = I.first.getStmt();
+      if (!HasItem) {
+        HasItem = true;
+        Out << '[' << NL;
+      }
+
+      const Stmt *S = I->first.getStmt();
       assert(S != nullptr && "Expected non-null Stmt");
 
-      Out << "(LC" << LC->getID() << ", S" << S->getID(Context) << ") ";
-      S->printPretty(Out, /*Helper=*/nullptr, PP);
-      Out << " : " << I.second << NL;
+      LastI = I;
+    }
+
+    for (BindingsTy::iterator I = ExprBindings.begin(); I != ExprBindings.end();
+         ++I) {
+      if (I->first.getLocationContext() != LC)
+        continue;
+
+      const Stmt *S = I->first.getStmt();
+      Indent(Out, InnerSpace, IsDot)
+          << "{ \"lctx_id\": " << LC->getID()
+          << ", \"stmt_id\": " << S->getID(Ctx) << ", \"pretty\": ";
+
+      // See whether the current statement is pretty-printable.
+      S->printPretty(TempOut, /*Helper=*/nullptr, PP);
+      if (!TempBuf.empty()) {
+        Out << '\"' << TempBuf.str().trim() << '\"';
+        TempBuf.clear();
+      } else {
+        Out << "null";
+      }
+
+      Out << ", \"value\": \"" << I->second << "\" }";
+
+      if (I != LastI)
+        Out << ',';
+      Out << NL;
     }
+
+    if (HasItem)
+      Indent(Out, --InnerSpace, IsDot) << ']';
+    else
+      Out << "null ";
   });
+
+  Indent(Out, --Space, IsDot) << "]," << NL; // End of Environment.
 }

Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp?rev=361976&r1=361975&r2=361976&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp Wed May 29 08:36:58 2019
@@ -558,19 +558,19 @@ static void printObjectsUnderConstructio
 }
 
 void ExprEngine::printState(raw_ostream &Out, ProgramStateRef State,
-                            const char *NL, const char *Sep,
-                            const LocationContext *LCtx) {
+                            const LocationContext *LCtx, const char *NL,
+                            unsigned int Space, bool IsDot) const {
   if (LCtx) {
     if (!State->get<ObjectsUnderConstruction>().isEmpty()) {
-      Out << Sep << "Objects under construction:" << NL;
+      Out << "Objects under construction:" << NL;
 
-      LCtx->dumpStack(Out, "", NL, Sep, [&](const LocationContext *LC) {
+      LCtx->printJson(Out, NL, Space, IsDot, [&](const LocationContext *LC) {
         printObjectsUnderConstructionForContext(Out, State, NL, LC);
       });
     }
   }
 
-  getCheckerManager().runCheckersForPrintState(Out, State, NL, Sep);
+  getCheckerManager().runCheckersForPrintState(Out, State, NL, "");
 }
 
 void ExprEngine::processEndWorklist() {

Modified: cfe/trunk/lib/StaticAnalyzer/Core/PrettyStackTraceLocationContext.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/PrettyStackTraceLocationContext.h?rev=361976&r1=361975&r2=361976&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/PrettyStackTraceLocationContext.h (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/PrettyStackTraceLocationContext.h Wed May 29 08:36:58 2019
@@ -32,9 +32,9 @@ public:
     assert(LCtx);
   }
 
-  void print(raw_ostream &OS) const override {
-    OS << "While analyzing stack: \n";
-    LCtx->dumpStack(OS, "\t");
+  void print(raw_ostream &Out) const override {
+    Out << "While analyzing stack: \n";
+    LCtx->dumpStack(Out);
   }
 };
 

Modified: cfe/trunk/lib/StaticAnalyzer/Core/ProgramState.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ProgramState.cpp?rev=361976&r1=361975&r2=361976&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/ProgramState.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/ProgramState.cpp Wed May 29 08:36:58 2019
@@ -449,7 +449,7 @@ void ProgramState::printJson(raw_ostream
   Mgr.getStoreManager().printJson(Out, getStore(), NL, Space, IsDot);
 
   // Print out the environment.
-  Env.print(Out, NL, Sep, Context, LCtx);
+  Env.printJson(Out, Context, LCtx, NL, Space, IsDot);
 
   // Print out the constraints.
   Mgr.getConstraintManager().print(this, Out, NL, Sep);
@@ -458,7 +458,7 @@ void ProgramState::printJson(raw_ostream
   printDynamicTypeInfo(this, Out, NL, Sep);
 
   // Print checker-specific data.
-  Mgr.getOwningEngine().printState(Out, this, NL, Sep, LCtx);
+  Mgr.getOwningEngine().printState(Out, this, LCtx, NL, Space, IsDot);
 }
 
 void ProgramState::printDOT(raw_ostream &Out, const LocationContext *LCtx,

Modified: cfe/trunk/test/Analysis/expr-inspection.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/expr-inspection.c?rev=361976&r1=361975&r2=361976&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/expr-inspection.c (original)
+++ cfe/trunk/test/Analysis/expr-inspection.c Wed May 29 08:36:58 2019
@@ -27,11 +27,12 @@ void foo(int x) {
 // CHECK-NEXT:   { "cluster": "y", "items": [
 // CHECK-NEXT:     { "kind": "Direct", "offset": 0, "value": "2 S32b" }
 // CHECK-NEXT:   ]}
-// CHECK-NEXT: ]
-
-// CHECK:      Expressions by stack frame:
-// CHECK-NEXT: #0 Calling foo
-// CHECK-NEXT: (LC1, S847) clang_analyzer_printState : &code{clang_analyzer_printState}
+// CHECK-NEXT: ],
+// CHECK-NEXT: "environment": [
+// CHECK-NEXT:   { "location_context": "#0 Call", "calling": "foo", "call_line": null, "items": [
+// CHECK-NEXT:     { "lctx_id": 1, "stmt_id": 847, "pretty": "clang_analyzer_printState", "value": "&code{clang_analyzer_printState}" }
+// CHECK-NEXT:   ]}
+// CHECK-NEXT: ],
 
 // CHECK:      Ranges of symbol values:
 // CHECK-NEXT:  reg_$0<int x> : { [-2147483648, 13] }




More information about the cfe-commits mailing list