[clang] b514793 - [analyzer] Add more information to the Exploded Graph

via cfe-commits cfe-commits at lists.llvm.org
Fri Sep 2 15:21:25 PDT 2022


Author: isuckatcs
Date: 2022-09-03T00:21:05+02:00
New Revision: b5147937b2a9ffdc12110a5df5ba4d482f83d2a8

URL: https://github.com/llvm/llvm-project/commit/b5147937b2a9ffdc12110a5df5ba4d482f83d2a8
DIFF: https://github.com/llvm/llvm-project/commit/b5147937b2a9ffdc12110a5df5ba4d482f83d2a8.diff

LOG: [analyzer] Add more information to the Exploded Graph

This patch dumps every state trait in the egraph. Also
the empty state traits are no longer dumped, instead
they are treated as null by the egraph rewriter script,
which solves reverse compatibility issues.

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

Added: 
    clang/test/Analysis/exploded-graph-rewriter/program_state_traits.dot

Modified: 
    clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
    clang/test/Analysis/exploded-graph-rewriter/checker_messages.dot
    clang/test/Analysis/exploded-graph-rewriter/checker_messages_diff.dot
    clang/test/Analysis/exploded-graph-rewriter/constraints.dot
    clang/test/Analysis/exploded-graph-rewriter/constraints_diff.dot
    clang/test/Analysis/exploded-graph-rewriter/environment.dot
    clang/test/Analysis/exploded-graph-rewriter/environment_diff.dot
    clang/test/Analysis/exploded-graph-rewriter/store.dot
    clang/test/Analysis/exploded-graph-rewriter/store_diff.dot
    clang/test/Analysis/exploded-graph-rewriter/topology.dot
    clang/test/Analysis/expr-inspection.c
    clang/utils/analyzer/exploded-graph-rewriter.py

Removed: 
    


################################################################################
diff  --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
index 656a7c1fe590a..99aa4c506f4ee 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -693,7 +693,7 @@ printObjectsUnderConstructionJson(raw_ostream &Out, ProgramStateRef State,
       continue;
 
     if (!HasItem) {
-      Out << "[" << NL;
+      Out << '[' << NL;
       HasItem = true;
     }
 
@@ -724,12 +724,11 @@ printObjectsUnderConstructionJson(raw_ostream &Out, ProgramStateRef State,
 
 static void printIndicesOfElementsToConstructJson(
     raw_ostream &Out, ProgramStateRef State, const char *NL,
-    const LocationContext *LCtx, const ASTContext &Context,
-    unsigned int Space = 0, bool IsDot = false) {
+    const LocationContext *LCtx, unsigned int Space = 0, bool IsDot = false) {
   using KeyT = std::pair<const Expr *, const LocationContext *>;
 
-  PrintingPolicy PP =
-      LCtx->getAnalysisDeclContext()->getASTContext().getPrintingPolicy();
+  const auto &Context = LCtx->getAnalysisDeclContext()->getASTContext();
+  PrintingPolicy PP = Context.getPrintingPolicy();
 
   ++Space;
   bool HasItem = false;
@@ -742,7 +741,7 @@ static void printIndicesOfElementsToConstructJson(
       continue;
 
     if (!HasItem) {
-      Out << "[" << NL;
+      Out << '[' << NL;
       HasItem = true;
     }
 
@@ -761,17 +760,17 @@ static void printIndicesOfElementsToConstructJson(
     const Expr *E = Key.first;
     Out << "\"stmt_id\": " << E->getID(Context);
 
-    // Kind - hack to display the current index
-    Out << ", \"kind\": \"Cur: " << Value - 1 << "\"";
+    // Kind
+    Out << ", \"kind\": null";
 
     // Pretty-print
     Out << ", \"pretty\": ";
-    Out << "\"" << E->getStmtClassName() << " "
+    Out << "\"" << E->getStmtClassName() << ' '
         << E->getSourceRange().printToString(Context.getSourceManager()) << " '"
         << QualType::getAsString(E->getType().split(), PP);
     Out << "'\"";
 
-    Out << ", \"value\": \"Next: " << Value << "\" }";
+    Out << ", \"value\": \"Current index: " << Value - 1 << "\" }";
 
     if (Key != LastKey)
       Out << ',';
@@ -785,40 +784,168 @@ static void printIndicesOfElementsToConstructJson(
   }
 }
 
-void ExprEngine::printJson(raw_ostream &Out, ProgramStateRef State,
-                           const LocationContext *LCtx, const char *NL,
-                           unsigned int Space, bool IsDot) const {
-  Indent(Out, Space, IsDot) << "\"constructing_objects\": ";
+static void printPendingInitLoopJson(raw_ostream &Out, ProgramStateRef State,
+                                     const char *NL,
+                                     const LocationContext *LCtx,
+                                     unsigned int Space = 0,
+                                     bool IsDot = false) {
+  using KeyT = std::pair<const CXXConstructExpr *, const LocationContext *>;
 
-  if (LCtx && !State->get<ObjectsUnderConstruction>().isEmpty()) {
-    ++Space;
-    Out << '[' << NL;
-    LCtx->printJson(Out, NL, Space, IsDot, [&](const LocationContext *LC) {
-      printObjectsUnderConstructionJson(Out, State, NL, LC, Space, IsDot);
-    });
+  const auto &Context = LCtx->getAnalysisDeclContext()->getASTContext();
+  PrintingPolicy PP = Context.getPrintingPolicy();
 
-    --Space;
-    Indent(Out, Space, IsDot) << "]," << NL; // End of "constructing_objects".
-  } else {
-    Out << "null," << NL;
+  ++Space;
+  bool HasItem = false;
+
+  // Store the last key.
+  KeyT LastKey;
+  for (const auto &I : State->get<PendingInitLoop>()) {
+    const KeyT &Key = I.first;
+    if (Key.second != LCtx)
+      continue;
+
+    if (!HasItem) {
+      Out << '[' << NL;
+      HasItem = true;
+    }
+
+    LastKey = Key;
   }
 
-  Indent(Out, Space, IsDot) << "\"index_of_element\": ";
-  if (LCtx && !State->get<IndexOfElementToConstruct>().isEmpty()) {
-    ++Space;
+  for (const auto &I : State->get<PendingInitLoop>()) {
+    const KeyT &Key = I.first;
+    unsigned Value = I.second;
+    if (Key.second != LCtx)
+      continue;
+
+    Indent(Out, Space, IsDot) << "{ ";
+
+    const CXXConstructExpr *E = Key.first;
+    Out << "\"stmt_id\": " << E->getID(Context);
+
+    Out << ", \"kind\": null";
+    Out << ", \"pretty\": ";
+    Out << '\"' << E->getStmtClassName() << ' '
+        << E->getSourceRange().printToString(Context.getSourceManager()) << " '"
+        << QualType::getAsString(E->getType().split(), PP);
+    Out << "'\"";
+
+    Out << ", \"value\": \"Flattened size: " << Value << "\"}";
+
+    if (Key != LastKey)
+      Out << ',';
+    Out << NL;
+  }
 
-    auto &Context = getContext();
+  if (HasItem)
+    Indent(Out, --Space, IsDot) << ']'; // End of "location_context".
+  else {
+    Out << "null ";
+  }
+}
+
+static void
+printPendingArrayDestructionsJson(raw_ostream &Out, ProgramStateRef State,
+                                  const char *NL, const LocationContext *LCtx,
+                                  unsigned int Space = 0, bool IsDot = false) {
+  using KeyT = const LocationContext *;
+
+  ++Space;
+  bool HasItem = false;
+
+  // Store the last key.
+  KeyT LastKey = nullptr;
+  for (const auto &I : State->get<PendingArrayDestruction>()) {
+    const KeyT &Key = I.first;
+    if (Key != LCtx)
+      continue;
+
+    if (!HasItem) {
+      Out << '[' << NL;
+      HasItem = true;
+    }
+
+    LastKey = Key;
+  }
+
+  for (const auto &I : State->get<PendingArrayDestruction>()) {
+    const KeyT &Key = I.first;
+    if (Key != LCtx)
+      continue;
+
+    Indent(Out, Space, IsDot) << "{ ";
+
+    Out << "\"stmt_id\": null";
+    Out << ", \"kind\": null";
+    Out << ", \"pretty\": \"Current index: \"";
+    Out << ", \"value\": \"" << I.second << "\" }";
+
+    if (Key != LastKey)
+      Out << ',';
+    Out << NL;
+  }
+
+  if (HasItem)
+    Indent(Out, --Space, IsDot) << ']'; // End of "location_context".
+  else {
+    Out << "null ";
+  }
+}
+
+/// A helper function to generalize program state trait printing.
+/// The function invokes Printer as 'Printer(Out, State, NL, LC, Space, IsDot,
+/// std::forward<Args>(args)...)'. \n One possible type for Printer is
+/// 'void()(raw_ostream &, ProgramStateRef, const char *, const LocationContext
+/// *, unsigned int, bool, ...)' \n \param Trait The state trait to be printed.
+/// \param Printer A void function that prints Trait.
+/// \param Args An additional parameter pack that is passed to Print upon
+/// invocation.
+template <typename Trait, typename Printer, typename... Args>
+static void printStateTraitWithLocationContextJson(
+    raw_ostream &Out, ProgramStateRef State, const LocationContext *LCtx,
+    const char *NL, unsigned int Space, bool IsDot,
+    const char *jsonPropertyName, Printer printer, Args &&...args) {
+
+  using RequiredType =
+      void (*)(raw_ostream &, ProgramStateRef, const char *,
+               const LocationContext *, unsigned int, bool, Args &&...);
+
+  // Try to do as much compile time checking as possible.
+  // FIXME: check for invocable instead of function?
+  static_assert(std::is_function<std::remove_pointer_t<Printer>>::value,
+                "Printer is not a function!");
+  static_assert(std::is_convertible<Printer, RequiredType>::value,
+                "Printer doesn't have the required type!");
+
+  if (LCtx && !State->get<Trait>().isEmpty()) {
+    Indent(Out, Space, IsDot) << '\"' << jsonPropertyName << "\": ";
+    ++Space;
     Out << '[' << NL;
     LCtx->printJson(Out, NL, Space, IsDot, [&](const LocationContext *LC) {
-      printIndicesOfElementsToConstructJson(Out, State, NL, LC, Context, Space,
-                                            IsDot);
+      printer(Out, State, NL, LC, Space, IsDot, std::forward<Args>(args)...);
     });
 
     --Space;
-    Indent(Out, Space, IsDot) << "]," << NL; // End of "index_of_element".
-  } else {
-    Out << "null," << NL;
+    Indent(Out, Space, IsDot) << "]," << NL; // End of "jsonPropertyName".
   }
+}
+
+void ExprEngine::printJson(raw_ostream &Out, ProgramStateRef State,
+                           const LocationContext *LCtx, const char *NL,
+                           unsigned int Space, bool IsDot) const {
+
+  printStateTraitWithLocationContextJson<ObjectsUnderConstruction>(
+      Out, State, LCtx, NL, Space, IsDot, "constructing_objects",
+      printObjectsUnderConstructionJson);
+  printStateTraitWithLocationContextJson<IndexOfElementToConstruct>(
+      Out, State, LCtx, NL, Space, IsDot, "index_of_element",
+      printIndicesOfElementsToConstructJson);
+  printStateTraitWithLocationContextJson<PendingInitLoop>(
+      Out, State, LCtx, NL, Space, IsDot, "pending_init_loops",
+      printPendingInitLoopJson);
+  printStateTraitWithLocationContextJson<PendingArrayDestruction>(
+      Out, State, LCtx, NL, Space, IsDot, "pending_destructors",
+      printPendingArrayDestructionsJson);
 
   getCheckerManager().runCheckersForPrintStateJson(Out, State, NL, Space,
                                                    IsDot);
@@ -3714,7 +3841,7 @@ struct DOTGraphTraits<ExplodedGraph*> : public DefaultDOTGraphTraits {
           OtherNode->getLocation().printJson(Out, /*NL=*/"\\l");
           Out << ", \"tag\": ";
           if (const ProgramPointTag *Tag = OtherNode->getLocation().getTag())
-            Out << '\"' << Tag->getTagDescription() << "\"";
+            Out << '\"' << Tag->getTagDescription() << '\"';
           else
             Out << "null";
           Out << ", \"node_id\": " << OtherNode->getID() <<

diff  --git a/clang/test/Analysis/exploded-graph-rewriter/checker_messages.dot b/clang/test/Analysis/exploded-graph-rewriter/checker_messages.dot
index e22309d11c7b7..42d45b00daa04 100644
--- a/clang/test/Analysis/exploded-graph-rewriter/checker_messages.dot
+++ b/clang/test/Analysis/exploded-graph-rewriter/checker_messages.dot
@@ -22,9 +22,7 @@ Node0x1 [shape=record,label=
       "program_state": {
         "store": null,
         "constraints": null,
-        "dynamic_types": null,
-        "constructing_objects": null,
-        "index_of_element": null,
+        "dynamic_types": null,        
         "environment": null,
         "checker_messages": [
           { "checker": "alpha.core.FooChecker", "messages": [

diff  --git a/clang/test/Analysis/exploded-graph-rewriter/checker_messages_
diff .dot b/clang/test/Analysis/exploded-graph-rewriter/checker_messages_
diff .dot
index 48638257ff3e1..d42326ce794af 100644
--- a/clang/test/Analysis/exploded-graph-rewriter/checker_messages_
diff .dot
+++ b/clang/test/Analysis/exploded-graph-rewriter/checker_messages_
diff .dot
@@ -15,9 +15,7 @@ Node0x1 [shape=record,label=
         "environment": null,
         "store": null,
         "constraints": null,
-        "dynamic_types": null,
-        "constructing_objects": null,
-        "index_of_element": null,
+        "dynamic_types": null,        
         "checker_messages": [
           { "checker": "FooChecker", "messages": [
             "Foo: Bar"
@@ -74,9 +72,7 @@ Node0x4 [shape=record,label=
         "environment": null,
         "store": null,
         "constraints": null,
-        "dynamic_types": null,
-        "constructing_objects": null,
-        "index_of_element": null,
+        "dynamic_types": null,        
         "checker_messages": [
           { "checker": "FooChecker", "messages": [
             "Foo: Bar",

diff  --git a/clang/test/Analysis/exploded-graph-rewriter/constraints.dot b/clang/test/Analysis/exploded-graph-rewriter/constraints.dot
index fa4ab08fe3d88..d38564c2be5fc 100644
--- a/clang/test/Analysis/exploded-graph-rewriter/constraints.dot
+++ b/clang/test/Analysis/exploded-graph-rewriter/constraints.dot
@@ -22,9 +22,7 @@ Node0x1 [shape=record,label=
       "program_state": {
         "store": null,
         "environment": null,
-        "dynamic_types": null,
-        "constructing_objects": null,
-        "index_of_element": null,
+        "dynamic_types": null,        
         "checker_messages": null,
         "constraints": [
           { "symbol": "reg_$0<x>", "range": "{ [0, 0] }" }

diff  --git a/clang/test/Analysis/exploded-graph-rewriter/constraints_
diff .dot b/clang/test/Analysis/exploded-graph-rewriter/constraints_
diff .dot
index e7dfc89d9785d..214c9a35f59bf 100644
--- a/clang/test/Analysis/exploded-graph-rewriter/constraints_
diff .dot
+++ b/clang/test/Analysis/exploded-graph-rewriter/constraints_
diff .dot
@@ -15,9 +15,7 @@ Node0x1 [shape=record,label=
       "program_state": {
         "store": null,
         "environment": null,
-        "dynamic_types": null,
-        "constructing_objects": null,
-        "index_of_element": null,
+        "dynamic_types": null,        
         "checker_messages": null,
         "constraints": [
           { "symbol": "reg_$0<x>", "range": "{ [0, 10] }" }
@@ -54,9 +52,7 @@ Node0x3 [shape=record,label=
       "program_state": {
         "store": null,
         "environment": null,
-        "dynamic_types": null,
-        "constructing_objects": null,
-        "index_of_element": null,
+        "dynamic_types": null,        
         "checker_messages": null,
         "constraints": [
           { "symbol": "reg_$0<x>", "range": "{ [0, 5] }" }
@@ -83,9 +79,7 @@ Node0x5 [shape=record,label=
         "store": null,
         "environment": null,
         "constraints": null,
-        "dynamic_types": null,
-        "constructing_objects": null,
-        "index_of_element": null,
+        "dynamic_types": null,        
         "checker_messages": null
       }
     }

diff  --git a/clang/test/Analysis/exploded-graph-rewriter/environment.dot b/clang/test/Analysis/exploded-graph-rewriter/environment.dot
index d5c1fda74ec88..67f2a2acaf87c 100644
--- a/clang/test/Analysis/exploded-graph-rewriter/environment.dot
+++ b/clang/test/Analysis/exploded-graph-rewriter/environment.dot
@@ -44,9 +44,7 @@ Node0x1 [shape=record,label=
       "program_state": {
         "store": null,
         "constraints": null,
-        "dynamic_types": null,
-        "constructing_objects": null,
-        "index_of_element": null,
+        "dynamic_types": null,        
         "checker_messages": null,
         "environment": {
           "pointer": "0x2",

diff  --git a/clang/test/Analysis/exploded-graph-rewriter/environment_
diff .dot b/clang/test/Analysis/exploded-graph-rewriter/environment_
diff .dot
index 1df005c18d2dd..e237bc5b8c3b7 100644
--- a/clang/test/Analysis/exploded-graph-rewriter/environment_
diff .dot
+++ b/clang/test/Analysis/exploded-graph-rewriter/environment_
diff .dot
@@ -16,9 +16,7 @@ Node0x1 [shape=record,label=
       "program_state": {
         "store": null,
         "constraints": null,
-        "dynamic_types": null,
-        "constructing_objects": null,
-        "index_of_element": null,
+        "dynamic_types": null,        
         "checker_messages": null,
         "environment": {
           "pointer": "0x2",
@@ -72,9 +70,7 @@ Node0x6 [shape=record,label=
       "program_state": {
         "store": null,
         "constraints": null,
-        "dynamic_types": null,
-        "constructing_objects": null,
-        "index_of_element": null,
+        "dynamic_types": null,        
         "checker_messages": null,
         "environment": {
           "pointer": "0x2",
@@ -122,9 +118,7 @@ Node0x9 [shape=record,label=
       "program_state": {
         "store": null,
         "constraints": null,
-        "dynamic_types": null,
-        "constructing_objects": null,
-        "index_of_element": null,
+        "dynamic_types": null,        
         "checker_messages": null,
         "environment": {
           "pointer": "0x2",

diff  --git a/clang/test/Analysis/exploded-graph-rewriter/program_state_traits.dot b/clang/test/Analysis/exploded-graph-rewriter/program_state_traits.dot
new file mode 100644
index 0000000000000..8b51beea9e0b6
--- /dev/null
+++ b/clang/test/Analysis/exploded-graph-rewriter/program_state_traits.dot
@@ -0,0 +1,237 @@
+// RUN: %exploded_graph_rewriter %s | FileCheck %s
+
+// CHECK: <b>Objects Under Construction: </b>
+// CHECK-SAME:<table border="0">
+// CHECK-SAME:  <tr>
+// CHECK-SAME:    <td></td>
+// CHECK-SAME:    <td align="left"><b>#0 Call</b></td>
+// CHECK-SAME:    <td align="left" colspan="2">
+// CHECK-SAME:      <font color="gray60">main </font>
+// CHECK-SAME:    </td>
+// CHECK-SAME:  </tr>
+// CHECK-SAME:  <tr>
+// CHECK-SAME:    <td></td>
+// CHECK-SAME:    <td align="left"><i>S870</i></td>
+// CHECK-SAME:    <td align="left">
+// CHECK-SAME:      <font color="darkgreen">
+// CHECK-SAME:          <i>(construct into local variable)</i>
+// CHECK-SAME:      </font>
+// CHECK-SAME:    </td>
+// CHECK-SAME:    <td align="left">S s;</td>
+// CHECK-SAME:    <td align="left">&s</td>
+// CHECK-SAME:  </tr>
+// CHECK-SAME:</table>
+Node0x1 [shape=record,label=
+"{
+    {
+        "state_id": 2,
+        "program_points": [
+            {
+                "kind": "BlockEntrance", "block_id": 1,
+                "terminator": null, "term_kind": null,
+                "tag": null, "node_id": 1,
+                "has_report": 0, "is_sink": 0
+            }
+        ],
+        "program_state": {
+            "store": null,
+            "environment": null,
+            "constraints": null,
+            "equivalence_classes": null,
+            "disequality_info": null,
+            "dynamic_types": null,
+            "dynamic_casts": null,
+            "constructing_objects": [
+                { 
+                    "lctx_id": 1, "location_context": "#0 Call", "calling": "main", "location": null, "items": [
+                        { "stmt_id": 870, "kind": "construct into local variable", "argument_index": null, "pretty": "S s;", "value": "&s" }
+                    ]
+                }
+            ],
+            "checker_messages": null
+        }
+    }
+\l}"];
+
+// CHECK: <b>Indices Of Elements Under Construction: </b>
+// CHECK-SAME:<table border="0">
+// CHECK-SAME:  <tr>
+// CHECK-SAME:    <td></td>
+// CHECK-SAME:    <td align="left"><b>#0 Call</b></td>
+// CHECK-SAME:    <td align="left" colspan="2">
+// CHECK-SAME:      <font color="gray60">main </font>
+// CHECK-SAME:    </td>
+// CHECK-SAME:  </tr>
+// CHECK-SAME:  <tr>
+// CHECK-SAME:    <td></td>
+// CHECK-SAME:    <td align="left"><i>S895</i></td>
+// CHECK-SAME:    <td align="left">
+// CHECK-SAME:      <font color="darkgreen"><i> </i></font>
+// CHECK-SAME:    </td>
+// CHECK-SAME:    <td align="left">
+// CHECK-SAME:      CXXConstructExpr <test.cpp:8:7> 'S[2]'
+// CHECK-SAME:    </td>
+// CHECK-SAME:    <td align="left">Current index: 0</td>
+// CHECK-SAME:  </tr>
+// CHECK-SAME:</table>
+Node0x2 [shape=record,label=
+"{
+    {
+        "state_id": 2,
+        "program_points": [
+            {
+                "kind": "BlockEntrance", "block_id": 1,
+                "terminator": null, "term_kind": null,
+                "tag": null, "node_id": 1,
+                "has_report": 0, "is_sink": 0
+            }
+        ],
+        "program_state": {
+            "store": null,
+            "environment": null,
+            "constraints": null,
+            "equivalence_classes": null,
+            "disequality_info": null,
+            "dynamic_types": null,
+            "dynamic_casts": null,
+            "index_of_element": [
+                { 
+                    "lctx_id": 1, 
+                    "location_context": "#0 Call", 
+                    "calling": "main", 
+                    "location": null, 
+                    "items": [
+                        { 
+                            "stmt_id": 895, 
+                            "kind": null, 
+                            "pretty": "CXXConstructExpr <test.cpp:8:7> 'S[2]'", 
+                            "value": "Current index: 0" 
+                        }
+                    ]
+                }
+            ],
+            "checker_messages": null
+        }
+    }
+\l}"];
+
+// CHECK: <b>Pending Array Init Loop Expressions: </b>
+// CHECK-SAME:<table border="0">
+// CHECK-SAME:  <tr>
+// CHECK-SAME:    <td></td>
+// CHECK-SAME:    <td align="left"><b>#0 Call</b></td>
+// CHECK-SAME:    <td align="left" colspan="2">
+// CHECK-SAME:        <font color="gray60">main </font>
+// CHECK-SAME:    </td>
+// CHECK-SAME:  </tr>
+// CHECK-SAME:  <tr>
+// CHECK-SAME:    <td></td>
+// CHECK-SAME:    <td align="left"><i>S1112</i></td>
+// CHECK-SAME:    <td align="left">
+// CHECK-SAME:        <font color="darkgreen"><i> </i></font>
+// CHECK-SAME:    </td>
+// CHECK-SAME:    <td align="left">
+// CHECK-SAME:        CXXConstructExpr <test.cpp:10:6> 'S'
+// CHECK-SAME:    </td>
+// CHECK-SAME:    <td align="left">Flattened size: 2</td>
+// CHECK-SAME:  </tr>
+// CHECK-SAME:</table>
+Node0x3 [shape=record,label=
+"{
+    {
+        "state_id": 2,
+        "program_points": [
+            {
+                "kind": "BlockEntrance", "block_id": 1,
+                "terminator": null, "term_kind": null,
+                "tag": null, "node_id": 1,
+                "has_report": 0, "is_sink": 0
+            }
+        ],
+        "program_state": {
+            "store": null,
+            "environment": null,
+            "constraints": null,
+            "equivalence_classes": null,
+            "disequality_info": null,
+            "dynamic_types": null,
+            "dynamic_casts": null,
+            "pending_init_loops": [
+                { 
+                    "lctx_id": 1, 
+                    "location_context": "#0 Call",
+                    "calling": "main", 
+                    "location": null, 
+                    "items": [
+                        { 
+                            "stmt_id": 1112, 
+                            "kind": null, 
+                            "pretty": "CXXConstructExpr <test.cpp:10:6> 'S'", "value": "Flattened size: 2"
+                        }
+                    ]
+                }
+            ],
+            "checker_messages": null
+        }
+    }
+\l}"];
+
+// CHECK: <b>Indices of Elements Under Destruction: </b>
+// CHECK-SAME:<table border="0">
+// CHECK-SAME:  <tr>
+// CHECK-SAME:    <td></td>
+// CHECK-SAME:    <td align="left"><b>#0 Call</b></td>
+// CHECK-SAME:    <td align="left" colspan="2">
+// CHECK-SAME:        <font color="gray60">main </font>
+// CHECK-SAME:    </td>
+// CHECK-SAME:  </tr>
+// CHECK-SAME:  <tr>
+// CHECK-SAME:    <td></td>
+// CHECK-SAME:    <td align="left"><i>SNone</i></td>
+// CHECK-SAME:    <td align="left">
+// CHECK-SAME:        <font color="darkgreen"><i> </i></font>
+// CHECK-SAME:    </td>
+// CHECK-SAME:    <td align="left">Current index: </td>
+// CHECK-SAME:    <td align="left">1</td>
+// CHECK-SAME:  </tr>
+// CHECK-SAME:</table>
+Node0x4 [shape=record,label=
+"{
+    {
+        "state_id": 2,
+        "program_points": [
+            {
+                "kind": "BlockEntrance", "block_id": 1,
+                "terminator": null, "term_kind": null,
+                "tag": null, "node_id": 1,
+                "has_report": 0, "is_sink": 0
+            }
+        ],
+        "program_state": {
+            "store": null,
+            "environment": null,
+            "constraints": null,
+            "equivalence_classes": null,
+            "disequality_info": null,
+            "dynamic_types": null,
+            "dynamic_casts": null,
+            "pending_destructors": [
+                { 
+                    "lctx_id": 1, 
+                    "location_context": "#0 Call", 
+                    "calling": "main", 
+                    "location": null, 
+                    "items": [
+                        { 
+                            "stmt_id": null, 
+                            "kind": null, 
+                            "pretty": "Current index: ", 
+                            "value": "1" 
+                        }
+                    ]
+                }
+            ],
+            "checker_messages": null
+        }
+    }
+\l}"];

diff  --git a/clang/test/Analysis/exploded-graph-rewriter/store.dot b/clang/test/Analysis/exploded-graph-rewriter/store.dot
index 01e97b649ea8b..1d95423cfee30 100644
--- a/clang/test/Analysis/exploded-graph-rewriter/store.dot
+++ b/clang/test/Analysis/exploded-graph-rewriter/store.dot
@@ -32,9 +32,7 @@ Node0x1 [shape=record,label=
       "program_state": {
         "environment": null,
         "constraints": null,
-        "dynamic_types": null,
-        "constructing_objects": null,
-        "index_of_element": null,
+        "dynamic_types": null,        
         "checker_messages": null,
         "store": {
           "pointer": "0x2",

diff  --git a/clang/test/Analysis/exploded-graph-rewriter/store_
diff .dot b/clang/test/Analysis/exploded-graph-rewriter/store_
diff .dot
index 5c2fc9c9d088c..b7aeac7117374 100644
--- a/clang/test/Analysis/exploded-graph-rewriter/store_
diff .dot
+++ b/clang/test/Analysis/exploded-graph-rewriter/store_
diff .dot
@@ -18,9 +18,7 @@ Node0x1 [shape=record,label=
       "program_state": {
         "environment": null,
         "constraints": null,
-        "dynamic_types": null,
-        "constructing_objects": null,
-        "index_of_element": null,
+        "dynamic_types": null,        
         "checker_messages": null,
         "store": {
           "pointer": "0x2",
@@ -73,9 +71,7 @@ Node0x4 [shape=record,label=
       "program_state": {
         "environment": null,
         "constraints": null,
-        "dynamic_types": null,
-        "constructing_objects": null,
-        "index_of_element": null,
+        "dynamic_types": null,        
         "checker_messages": null,
         "store": {
           "pointer": "0x5",

diff  --git a/clang/test/Analysis/exploded-graph-rewriter/topology.dot b/clang/test/Analysis/exploded-graph-rewriter/topology.dot
index 56b4089136be3..88ac53d56c484 100644
--- a/clang/test/Analysis/exploded-graph-rewriter/topology.dot
+++ b/clang/test/Analysis/exploded-graph-rewriter/topology.dot
@@ -22,9 +22,7 @@ Node0x1 [shape=record,label=
       "program_state": {
         "environment": null,
         "constraints": null,
-        "dynamic_types": null,
-        "constructing_objects": null,
-        "index_of_element": null,
+        "dynamic_types": null,        
         "checker_messages": [
           { "checker": "foo", "messages": ["bar"] }
         ],

diff  --git a/clang/test/Analysis/expr-inspection.c b/clang/test/Analysis/expr-inspection.c
index 92bd190f7f2a3..57cd2fc165b35 100644
--- a/clang/test/Analysis/expr-inspection.c
+++ b/clang/test/Analysis/expr-inspection.c
@@ -46,8 +46,6 @@ void foo(int x) {
 // CHECK-NEXT:   "disequality_info": null,
 // CHECK-NEXT:   "dynamic_types": null,
 // CHECK-NEXT:   "dynamic_casts": null,
-// CHECK-NEXT:   "constructing_objects": null,
-// CHECK-NEXT:   "index_of_element": null,
 // CHECK-NEXT:   "checker_messages": null
 // CHECK-NEXT: }
 

diff  --git a/clang/utils/analyzer/exploded-graph-rewriter.py b/clang/utils/analyzer/exploded-graph-rewriter.py
index 603bae9d69ac7..bc447fe6cff35 100755
--- a/clang/utils/analyzer/exploded-graph-rewriter.py
+++ b/clang/utils/analyzer/exploded-graph-rewriter.py
@@ -261,48 +261,74 @@ def is_
diff erent(self, prev):
 class ProgramState:
     def __init__(self, state_id, json_ps):
         logging.debug('Adding ProgramState ' + str(state_id))
+        
+        store_key = 'store'
+        env_key = 'environment'
+        constraints_key = 'constraints'
+        dyn_ty_key = 'dynamic_types'
+        ctor_key = 'constructing_objects'
+        ind_key = 'index_of_element'
+        init_loop_key = 'pending_init_loops'
+        dtor_key = 'pending_destructors'
+        msg_key = 'checker_messages'
 
         if json_ps is None:
             json_ps = {
-                'store': None,
-                'environment': None,
-                'constraints': None,
-                'dynamic_types': None,
-                'constructing_objects': None,
-                'index_of_element': None,
-                'checker_messages': None
+                store_key: None,
+                env_key: None,
+                constraints_key: None,
+                dyn_ty_key: None,
+                ctor_key: None,
+                ind_key: None,
+                init_loop_key: None,
+                dtor_key: None,
+                msg_key: None
             }
 
         self.state_id = state_id
 
-        self.store = Store(json_ps['store']) \
-            if json_ps['store'] is not None else None
+        self.store = Store(json_ps[store_key]) \
+            if json_ps[store_key] is not None else None
 
         self.environment = \
-            GenericEnvironment(json_ps['environment']['items']) \
-            if json_ps['environment'] is not None else None
+            GenericEnvironment(json_ps[env_key]['items']) \
+            if json_ps[env_key] is not None else None
 
         self.constraints = GenericMap([
-            (c['symbol'], c['range']) for c in json_ps['constraints']
-        ]) if json_ps['constraints'] is not None else None
+            (c['symbol'], c['range']) for c in json_ps[constraints_key]
+        ]) if json_ps[constraints_key] is not None else None
 
         self.dynamic_types = GenericMap([
                 (t['region'], '%s%s' % (t['dyn_type'],
                                         ' (or a sub-class)'
                                         if t['sub_classable'] else ''))
-                for t in json_ps['dynamic_types']]) \
-            if json_ps['dynamic_types'] is not None else None
+                for t in json_ps[dyn_ty_key]]) \
+            if json_ps[dyn_ty_key] is not None else None
+
+        self.checker_messages = CheckerMessages(json_ps[msg_key]) \
+            if json_ps[msg_key] is not None else None
+
+        # State traits
+        # 
+        # For traits we always check if a key exists because if a trait
+        # has no imformation, nothing will be printed in the .dot file 
+        # we parse. 
 
         self.constructing_objects = \
-            GenericEnvironment(json_ps['constructing_objects']) \
-            if json_ps['constructing_objects'] is not None else None
+            GenericEnvironment(json_ps[ctor_key]) \
+            if ctor_key in json_ps and json_ps[ctor_key] is not None else None
 
         self.index_of_element = \
-            GenericEnvironment(json_ps['index_of_element']) \
-            if json_ps['index_of_element'] is not None else None
+            GenericEnvironment(json_ps[ind_key]) \
+            if ind_key in json_ps and json_ps[ind_key] is not None else None
+        
+        self.pending_init_loops = \
+            GenericEnvironment(json_ps[init_loop_key]) \
+            if init_loop_key in json_ps and json_ps[init_loop_key] is not None else None
 
-        self.checker_messages = CheckerMessages(json_ps['checker_messages']) \
-            if json_ps['checker_messages'] is not None else None
+        self.pending_destructors = \
+            GenericEnvironment(json_ps[dtor_key]) \
+            if dtor_key in json_ps and json_ps[dtor_key] is not None else None
 
 
 # A deserialized exploded graph node. Has a default constructor because it
@@ -801,6 +827,12 @@ def visit_state(self, s, prev_s):
         self.visit_environment_in_state('index_of_element',
                                         'Indices Of Elements Under Construction',
                                         s, prev_s)
+        self.visit_environment_in_state('pending_init_loops',
+                                        'Pending Array Init Loop Expressions',
+                                        s, prev_s)
+        self.visit_environment_in_state('pending_destructors',
+                                        'Indices of Elements Under Destruction',
+                                        s, prev_s)
         self.visit_checker_messages_in_state(s, prev_s)
 
     def visit_node(self, node):


        


More information about the cfe-commits mailing list