[analyzer] Add more information to the Exploded Graph
authorisuckatcs <65320245+isuckatcs@users.noreply.github.com>
Thu, 4 Aug 2022 17:49:05 +0000 (19:49 +0200)
committerisuckatcs <65320245+isuckatcs@users.noreply.github.com>
Fri, 2 Sep 2022 22:21:05 +0000 (00:21 +0200)
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

13 files changed:
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/program_state_traits.dot [new file with mode: 0644]
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

index 656a7c1..99aa4c5 100644 (file)
@@ -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() <<
index e22309d..42d45b0 100644 (file)
@@ -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": [
index 4863825..d42326c 100644 (file)
@@ -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",
index fa4ab08..d38564c 100644 (file)
@@ -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] }" }
index e7dfc89..214c9a3 100644 (file)
@@ -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
       }
     }
index d5c1fda..67f2a2a 100644 (file)
@@ -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",
index 1df005c..e237bc5 100644 (file)
@@ -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 (file)
index 0000000..8b51bee
--- /dev/null
@@ -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">&amp;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}"];
index 01e97b6..1d95423 100644 (file)
@@ -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",
index 5c2fc9c..b7aeac7 100644 (file)
@@ -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",
index 56b4089..88ac53d 100644 (file)
@@ -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"] }
         ],
index 92bd190..57cd2fc 100644 (file)
@@ -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: }
 
index 603bae9..bc447fe 100755 (executable)
@@ -261,48 +261,74 @@ class CheckerMessages:
 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 @@ class DotDumpVisitor:
         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):