This revision was automatically updated to reflect the committed changes.
Closed by commit rGb5147937b2a9: [analyzer] Add more information to the 
Exploded Graph (authored by isuckatcs).
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D131187/new/

https://reviews.llvm.org/D131187

Files:
  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
  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: clang/utils/analyzer/exploded-graph-rewriter.py
===================================================================
--- clang/utils/analyzer/exploded-graph-rewriter.py
+++ clang/utils/analyzer/exploded-graph-rewriter.py
@@ -261,48 +261,74 @@
 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 @@
         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):
Index: clang/test/Analysis/expr-inspection.c
===================================================================
--- clang/test/Analysis/expr-inspection.c
+++ clang/test/Analysis/expr-inspection.c
@@ -46,8 +46,6 @@
 // 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: clang/test/Analysis/exploded-graph-rewriter/topology.dot
===================================================================
--- clang/test/Analysis/exploded-graph-rewriter/topology.dot
+++ clang/test/Analysis/exploded-graph-rewriter/topology.dot
@@ -22,9 +22,7 @@
       "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: clang/test/Analysis/exploded-graph-rewriter/store_diff.dot
===================================================================
--- clang/test/Analysis/exploded-graph-rewriter/store_diff.dot
+++ clang/test/Analysis/exploded-graph-rewriter/store_diff.dot
@@ -18,9 +18,7 @@
       "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 @@
       "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: clang/test/Analysis/exploded-graph-rewriter/store.dot
===================================================================
--- clang/test/Analysis/exploded-graph-rewriter/store.dot
+++ clang/test/Analysis/exploded-graph-rewriter/store.dot
@@ -32,9 +32,7 @@
       "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: clang/test/Analysis/exploded-graph-rewriter/program_state_traits.dot
===================================================================
--- /dev/null
+++ 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">&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: clang/test/Analysis/exploded-graph-rewriter/environment_diff.dot
===================================================================
--- clang/test/Analysis/exploded-graph-rewriter/environment_diff.dot
+++ clang/test/Analysis/exploded-graph-rewriter/environment_diff.dot
@@ -16,9 +16,7 @@
       "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 @@
       "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 @@
       "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: clang/test/Analysis/exploded-graph-rewriter/environment.dot
===================================================================
--- clang/test/Analysis/exploded-graph-rewriter/environment.dot
+++ clang/test/Analysis/exploded-graph-rewriter/environment.dot
@@ -44,9 +44,7 @@
       "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: clang/test/Analysis/exploded-graph-rewriter/constraints_diff.dot
===================================================================
--- clang/test/Analysis/exploded-graph-rewriter/constraints_diff.dot
+++ clang/test/Analysis/exploded-graph-rewriter/constraints_diff.dot
@@ -15,9 +15,7 @@
       "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 @@
       "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 @@
         "store": null,
         "environment": null,
         "constraints": null,
-        "dynamic_types": null,
-        "constructing_objects": null,
-        "index_of_element": null,
+        "dynamic_types": null,        
         "checker_messages": null
       }
     }
Index: clang/test/Analysis/exploded-graph-rewriter/constraints.dot
===================================================================
--- clang/test/Analysis/exploded-graph-rewriter/constraints.dot
+++ clang/test/Analysis/exploded-graph-rewriter/constraints.dot
@@ -22,9 +22,7 @@
       "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: clang/test/Analysis/exploded-graph-rewriter/checker_messages_diff.dot
===================================================================
--- clang/test/Analysis/exploded-graph-rewriter/checker_messages_diff.dot
+++ clang/test/Analysis/exploded-graph-rewriter/checker_messages_diff.dot
@@ -15,9 +15,7 @@
         "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 @@
         "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: clang/test/Analysis/exploded-graph-rewriter/checker_messages.dot
===================================================================
--- clang/test/Analysis/exploded-graph-rewriter/checker_messages.dot
+++ clang/test/Analysis/exploded-graph-rewriter/checker_messages.dot
@@ -22,9 +22,7 @@
       "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: clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -693,7 +693,7 @@
       continue;
 
     if (!HasItem) {
-      Out << "[" << NL;
+      Out << '[' << NL;
       HasItem = true;
     }
 
@@ -724,12 +724,11 @@
 
 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 @@
       continue;
 
     if (!HasItem) {
-      Out << "[" << NL;
+      Out << '[' << NL;
       HasItem = true;
     }
 
@@ -761,17 +760,17 @@
     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 @@
   }
 }
 
-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 @@
           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() <<
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to