NoQ created this revision.
NoQ added reviewers: dcoughlin, xazax.hun, a_sidorin, rnkovacs, Szelethus, 
baloghadamsoftware, Charusso.
Herald added subscribers: cfe-commits, dkrupp, donat.nagy, mikhail.ramalho, 
a.sidorin, szepet.
Herald added a project: clang.

I need this for the demo at the dev meeting ^.^"

Instead of using an allocator-based stable identifier as in D51667 
<https://reviews.llvm.org/D51667>, let's make truly stable identifiers. The 
nodes now identify themselves as 1.,2.,3.,..., etc., which is not only nice to 
read, but also allows reliably setting conditional breakpoints. Eg., in lldb:

  (lldb) br s -n inlineCall -c 'Pred->Id == 12345'

lets you reliably debug the construction of the `CallEnter` node whose 
predecessor is node 12345.

You could do a similar trick with the current stable IDs but that worked in 
~30% of the cases because of slight indeterminism in how immutable sets and 
maps are allocated in the bump pointer allocator. Now it's fully reliable.

The `exploded-graph-rewriter` is updated accordingly. Additionally, because in 
exploded graph dumps we collapse multiple real exploded nodes into a single 
dumped graph node when they have the same state and the respective sub-graph is 
linear, i changed it to dump *each* node's identifier near the program point. 
Additionally, the "sink node" and "bug report attached" messages are also 
passed one per point rather than once per visible node.

Notice the 1., 2., 3. things on the left:

F10279509: Screen Shot 2019-10-15 at 7.26.37 PM.png 
<https://reviews.llvm.org/F10279509>

That's how bug/sink notices now look:

F10279512: Screen Shot 2019-10-15 at 7.27.18 PM.png 
<https://reviews.llvm.org/F10279512>

In the worst case this patch may increase memory usage of the static analyzer 
by around 1MB per process (if all 225000 nodes are constructed, times 4 bytes 
per unsigned integer on most architectures; note that only one analysis is kept 
in memory at a time, so the overhead doesn't add up for multiple exploded 
graphs). So even though i could have hidden the new feature under `#ifndef 
NDEBUG`, like the whole graph dumping facility, i don't think it's really worth 
it; i'd much rather enable graph dumping in noassert builds.


Repository:
  rC Clang

https://reviews.llvm.org/D69015

Files:
  clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h
  clang/lib/StaticAnalyzer/Core/BugReporter.cpp
  clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp
  clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
  clang/test/Analysis/dump_egraph.c
  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/edge.dot
  clang/test/Analysis/exploded-graph-rewriter/environment.dot
  clang/test/Analysis/exploded-graph-rewriter/environment_diff.dot
  clang/test/Analysis/exploded-graph-rewriter/node_labels.dot
  clang/test/Analysis/exploded-graph-rewriter/program_points.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/exploded-graph-rewriter/trimmers.dot
  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
@@ -67,6 +67,9 @@
         super(ProgramPoint, self).__init__()
         self.kind = json_pp['kind']
         self.tag = json_pp['tag']
+        self.node_id = json_pp['node_id']
+        self.is_sink = bool(json_pp['is_sink'])
+        self.has_report = bool(json_pp['has_report'])
         if self.kind == 'Edge':
             self.src_id = json_pp['src_id']
             self.dst_id = json_pp['dst_id']
@@ -309,11 +312,9 @@
 
     def construct(self, node_id, json_node):
         logging.debug('Adding ' + node_id)
-        self.node_id = json_node['node_id']
-        self.ptr = json_node['pointer']
-        self.has_report = json_node['has_report']
-        self.is_sink = json_node['is_sink']
+        self.ptr = node_id[4:]
         self.points = [ProgramPoint(p) for p in json_node['program_points']]
+        self.node_id = self.points[-1].node_id
         self.state = ProgramState(json_node['state_id'],
                                   json_node['program_state']) \
             if json_node['program_state'] is not None else None
@@ -488,12 +489,14 @@
         else:
             color = 'forestgreen'
 
+        self._dump('<tr><td align="left">%s.</td>' % p.node_id)
+
         if p.kind == 'Statement':
             # This avoids pretty-printing huge statements such as CompoundStmt.
             # Such statements show up only at [Pre|Post]StmtPurgeDeadSymbols
             skip_pretty = 'PurgeDeadSymbols' in p.stmt_point_kind
             stmt_color = 'cyan3'
-            self._dump('<tr><td align="left" width="0">%s:</td>'
+            self._dump('<td align="left" width="0">%s:</td>'
                        '<td align="left" width="0"><font color="%s">'
                        '%s</font> </td>'
                        '<td align="left"><i>S%s</i></td>'
@@ -506,30 +509,41 @@
                           self._short_pretty(p.pretty)
                           if not skip_pretty else ''))
         elif p.kind == 'Edge':
-            self._dump('<tr><td width="0"></td>'
+            self._dump('<td width="0"></td>'
                        '<td align="left" width="0">'
                        '<font color="%s">%s</font></td><td align="left">'
                        '[B%d] -\\> [B%d]</td></tr>'
                        % (color, 'BlockEdge', p.src_id, p.dst_id))
         elif p.kind == 'BlockEntrance':
-            self._dump('<tr><td width="0"></td>'
+            self._dump('<td width="0"></td>'
                        '<td align="left" width="0">'
                        '<font color="%s">%s</font></td>'
                        '<td align="left">[B%d]</td></tr>'
                        % (color, p.kind, p.block_id))
         else:
             # TODO: Print more stuff for other kinds of points.
-            self._dump('<tr><td width="0"></td>'
+            self._dump('<td width="0"></td>'
                        '<td align="left" width="0" colspan="2">'
                        '<font color="%s">%s</font></td></tr>'
                        % (color, p.kind))
 
         if p.tag is not None:
-            self._dump('<tr><td width="0"></td>'
+            self._dump('<tr><td width="0"></td><td width="0"></td>'
                        '<td colspan="3" align="left">'
                        '<b>Tag: </b> <font color="crimson">'
                        '%s</font></td></tr>' % p.tag)
 
+        if p.has_report:
+            self._dump('<tr><td width="0"></td><td width="0"></td>'
+                       '<td colspan="3" align="left">'
+                       '<font color="red"><b>Bug Report Attached'
+                       '</b></font></td></tr>')
+        if p.is_sink:
+            self._dump('<tr><td width="0"></td><td width="0"></td>'
+                       '<td colspan="3" align="left">'
+                       '<font color="cornflowerblue"><b>Sink Node'
+                       '</b></font></td></tr>')
+
     def visit_environment(self, e, prev_e=None):
         self._dump('<table border="0">')
 
@@ -786,17 +800,10 @@
             self._dump('color="white",fontcolor="gray80",')
         self._dump('label=<<table border="0">')
 
-        self._dump('<tr><td bgcolor="%s"><b>Node %d (%s) - '
-                   'State %s</b></td></tr>'
+        self._dump('<tr><td bgcolor="%s"><b>State %s</b></td></tr>'
                    % ("gray20" if self._dark_mode else "gray70",
-                      node.node_id, node.ptr, node.state.state_id
+                      node.state.state_id
                       if node.state is not None else 'Unspecified'))
-        if node.has_report:
-            self._dump('<tr><td><font color="red"><b>Bug Report Attached'
-                       '</b></font></td></tr>')
-        if node.is_sink:
-            self._dump('<tr><td><font color="cornflowerblue"><b>Sink Node'
-                       '</b></font></td></tr>')
         if not self._topo_mode:
             self._dump('<tr><td align="left" width="0">')
             if len(node.points) > 1:
Index: clang/test/Analysis/exploded-graph-rewriter/trimmers.dot
===================================================================
--- clang/test/Analysis/exploded-graph-rewriter/trimmers.dot
+++ clang/test/Analysis/exploded-graph-rewriter/trimmers.dot
@@ -17,20 +17,44 @@
 // UNSUPPORTED: system-windows
 
 Node0x1 [shape=record,label=
- "{{ "node_id": 1, "pointer": "0x1", "has_report": false, "is_sink": false,
-      "program_state": null, "program_points": []}\l}"];
+ "{{ "program_state": null, "program_points": [
+       {
+         "kind": "BlockEntrance", "block_id": 1,
+         "terminator": null, "term_kind": null,
+         "tag": null, "node_id": 1,
+         "has_report": 0, "is_sink": 0
+       }
+     ]}\l}"];
 
 Node0x2 [shape=record,label=
- "{{ "node_id": 2, "pointer": "0x2", "has_report": false, "is_sink": false,
-      "program_state": null, "program_points": []}\l}"];
+ "{{ "program_state": null, "program_points": [
+       {
+         "kind": "BlockEntrance", "block_id": 1,
+         "terminator": null, "term_kind": null,
+         "tag": null, "node_id": 2,
+         "has_report": 0, "is_sink": 0
+       }
+     ]}\l}"];
 
 Node0x3 [shape=record,label=
- "{{ "node_id": 3, "pointer": "0x3", "has_report": false, "is_sink": false,
-      "program_state": null, "program_points": []}\l}"];
+ "{{ "program_state": null, "program_points": [
+       {
+         "kind": "BlockEntrance", "block_id": 1,
+         "terminator": null, "term_kind": null,
+         "tag": null, "node_id": 3,
+         "has_report": 0, "is_sink": 0
+       }
+     ]}\l}"];
 
 Node0x4 [shape=record,label=
- "{{ "node_id": 4, "pointer": "0x4", "has_report": false, "is_sink": false,
-      "program_state": null, "program_points": []}\l}"];
+ "{{ "program_state": null, "program_points": [
+       {
+         "kind": "BlockEntrance", "block_id": 1,
+         "terminator": null, "term_kind": null,
+         "tag": null, "node_id": 4,
+         "has_report": 0, "is_sink": 0
+       }
+     ]}\l}"];
 
 Node0x1 -> Node0x2;
 Node0x1 -> Node0x3;
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
@@ -12,12 +12,16 @@
 // TOPOLOGY-NOT: Checker State
 Node0x1 [shape=record,label=
  "{
-    { "node_id": 1,
-      "pointer": "0x1",
-      "has_report": false,
-      "is_sink": false,
+    {
       "state_id": 2,
-      "program_points": [],
+      "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": {
         "environment": null,
         "constraints": null,
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
@@ -10,7 +10,14 @@
       "has_report": false,
       "is_sink": false,
       "state_id": 2,
-      "program_points": [],
+      "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": {
         "environment": null,
         "constraints": null,
@@ -55,12 +62,16 @@
 // CHECK-SAME: </tr>
 Node0x4 [shape=record,label=
  "{
-    { "node_id": 4,
-      "pointer": "0x4",
-      "has_report": false,
-      "is_sink": false,
+    {
       "state_id": 5,
-      "program_points": [],
+      "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": {
         "environment": null,
         "constraints": null,
@@ -91,12 +102,16 @@
 
 Node0x6 [shape=record,label=
  "{
-    { "node_id": 6,
-      "pointer": "0x6",
-      "has_report": false,
-      "is_sink": false,
+    {
       "state_id": 7,
-      "program_points": [],
+      "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": null
     }
 \l}"];
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
@@ -23,12 +23,15 @@
 // CHECK-SAME: </table>
 Node0x1 [shape=record,label=
  "{
-    { "node_id": 1,
-      "pointer": "0x1",
-      "has_report": false,
-      "is_sink": false,
-      "state_id": 2,
-      "program_points": [],
+    { "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": {
         "environment": null,
         "constraints": null,
Index: clang/test/Analysis/exploded-graph-rewriter/program_points.dot
===================================================================
--- clang/test/Analysis/exploded-graph-rewriter/program_points.dot
+++ clang/test/Analysis/exploded-graph-rewriter/program_points.dot
@@ -28,7 +28,7 @@
 // CHECK-SAME: </table>
 Node0x1 [shape=record,label=
  "{
-    { "node_id": 1, "pointer": "0x1", "has_report": false, "is_sink": false,
+    {
       "program_state": null, "program_points": [
       {
         "kind": "Edge",
@@ -36,14 +36,20 @@
         "dst_id": 1,
         "terminator": null,
         "term_kind": null,
-        "tag": null
+        "tag": null,
+        "node_id": 1,
+        "has_report": 0,
+        "is_sink": 0
       },
       {
         "kind": "BlockEntrance",
         "block_id": 1,
         "terminator": null,
         "term_kind": null,
-        "tag": null
+        "tag": null,
+        "node_id": 2,
+        "has_report": 0,
+        "is_sink": 0
       }
     ]}
 \l}"];
@@ -72,10 +78,9 @@
 // CHECK-SAME:     </td>
 // CHECK-SAME:   </tr>
 // CHECK-SAME: </table>
-Node0x2 [shape=record,label=
+Node0x3 [shape=record,label=
  "{
-    { "node_id": 2, "pointer": "0x2", "has_report": false, "is_sink": false,
-      "program_state": null, "program_points": [
+    { "program_state": null, "program_points": [
       {
         "kind": "Statement",
         "stmt_kind": "DeclRefExpr",
@@ -88,7 +93,11 @@
           "line": 4,
           "column": 5
         },
-        "tag": "ExprEngine : Clean Node"
+        "tag": "ExprEngine : Clean Node",
+        "node_id": 3,
+        "pointer": "0x3",
+        "has_report": 0,
+        "is_sink": 0
       }
     ]}
 \l}"];
@@ -97,9 +106,9 @@
 
 // CHECK-NEXT: <b>Program point:</b>
 // CHECK-SAME: <td align="left">\{ ... \}</td>
-Node0x3 [shape=record,label=
+Node0x4 [shape=record,label=
  "{
-    { "node_id": 3, "pointer": "0x3", "has_report": false, "is_sink": false,
+    {
       "program_state": null, "program_points": [
       {
         "kind": "Statement",
@@ -112,7 +121,10 @@
           "line": 7,
           "column": 8
         },
-        "tag": "ExprEngine : Clean Node"
+        "tag": "ExprEngine : Clean Node",
+        "node_id": 4,
+        "has_report": 0,
+        "is_sink": 0
       }
     ]}
 \l}"];
@@ -143,10 +155,9 @@
 // CHECK-SAME:     </td>
 // CHECK-SAME:   </tr>
 // CHECK-SAME: </table>
-Node0x4 [shape=record,label=
+Node0x5 [shape=record,label=
  "{
-    { "node_id": 4, "pointer": "0x4", "has_report": false, "is_sink": false,
-      "program_state": null, "program_points": [
+    { "program_state": null, "program_points": [
       {
         "kind": "Statement",
         "stmt_kind": "ImplicitCastExpr",
@@ -160,7 +171,10 @@
           "line": 8,
           "column": 9
         },
-        "tag": "ExprEngine : Clean Node"
+        "tag": "ExprEngine : Clean Node",
+        "node_id": 5,
+        "has_report": 0,
+        "is_sink": 0
       }
     ]}
 \l}"];
Index: clang/test/Analysis/exploded-graph-rewriter/node_labels.dot
===================================================================
--- clang/test/Analysis/exploded-graph-rewriter/node_labels.dot
+++ clang/test/Analysis/exploded-graph-rewriter/node_labels.dot
@@ -15,30 +15,47 @@
 // CHECK-SAME:   <tr>
 // LIGHT-SAME:     <td bgcolor="gray70">
 // DARK-SAME:      <td bgcolor="gray20">
-// CHECK-SAME:       <b>Node 1 (0x1) - State Unspecified</b>
+// CHECK-SAME:       <b>State Unspecified</b>
 // CHECK-SAME:     </td>
 // CHECK-SAME:   </tr>
 Node0x1 [shape=record,label=
  "{
     { "node_id": 1, "pointer": "0x1", "has_report": false, "is_sink": false,
       "program_state": null,
-      "program_points": []
+      "program_points": [
+        {
+          "kind": "BlockEntrance", "block_id": 1,
+          "terminator": null, "term_kind": null,
+          "tag": null, "node_id": 1,
+          "has_report": 0, "is_sink": 0
+        }
+      ]
     }
 \l}"];
 
 // CHECK: Node0x2 [
-// CHECK-SAME: <tr><td>
-// COLOR-SAME:   <font color="red"><b>Bug Report Attached</b></font>
-// GRAY-SAME:    <b>Bug Report Attached</b>
-// CHECK-SAME: </td></tr>
-// CHECK-SAME: <tr><td>
-// COLOR-SAME:   <font color="cornflowerblue"><b>Sink Node</b></font>
-// GRAY-SAME:    <b>Sink Node</b>
-// CHECK-SAME: </td></tr>
+// CHECK-SAME: <tr>
+// CHECK-SAME:   <td colspan="3" align="left">
+// COLOR-SAME:     <font color="red"><b>Bug Report Attached</b></font>
+// GRAY-SAME:      <b>Bug Report Attached</b>
+// CHECK-SAME:   </td>
+// CHECK-SAME: </tr>
+// CHECK-SAME: <tr>
+// CHECK-SAME:   <td colspan="3" align="left">
+// COLOR-SAME:     <font color="cornflowerblue"><b>Sink Node</b></font>
+// GREY-SAME:      <b>Sink Node</b>
+// CHECK-SAME:   </td>
+// CHECK-SAME: </tr>
 Node0x2 [shape=record,label=
  "{
-    { "node_id": 2, "pointer": "0x2", "has_report": true, "is_sink": true,
-      "program_state": null,
-      "program_points": []
+    { "program_state": null,
+      "program_points": [
+        {
+          "kind": "BlockEntrance", "block_id": 1,
+          "terminator": null, "term_kind": null,
+          "tag": null, "node_id": 2,
+          "has_report": 1, "is_sink": 1
+        }
+      ]
     }
 \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
@@ -6,12 +6,16 @@
 // No diffs on the first node, nothing to check.
 Node0x1 [shape=record,label=
  "{
-    { "node_id": 1,
-      "pointer": "0x1",
-      "has_report": false,
-      "is_sink": false,
+    {
       "state_id": 2,
-      "program_points": [],
+      "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,
         "constraints": null,
@@ -57,12 +61,16 @@
 // CHECK-SAME: </tr>
 Node0x6 [shape=record,label=
  "{
-    { "node_id": 6,
-      "pointer": "0x6",
-      "has_report": false,
-      "is_sink": false,
+    {
       "state_id": 7,
-      "program_points": [],
+      "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,
         "constraints": null,
@@ -102,12 +110,16 @@
 // CHECK-SAME: </tr>
 Node0x9 [shape=record,label=
  "{
-    { "node_id": 9,
-      "pointer": "0x9",
-      "has_report": false,
-      "is_sink": false,
+    {
       "state_id": 7,
-      "program_points": [],
+      "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,
         "constraints": null,
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
@@ -11,7 +11,7 @@
 // CHECK-SAME:     </td>
 // CHECK-SAME:     <td align="left" colspan="2">
 // CHECK-SAME:       <font color="gray60">foo </font>
-// CHECK-SAME:       (environment.cpp:<b>4</b>:<b>6</b> 
+// CHECK-SAME:       (environment.cpp:<b>4</b>:<b>6</b>
 // CHECK-SAME:       <font color="royalblue1">
 // CHECK-SAME:         (<i>spelling at </i> environment.h:<b>7</b>:<b>8</b>)
 // CHECK-SAME:       </font>)
@@ -36,7 +36,14 @@
       "has_report": false,
       "is_sink": false,
       "state_id": 2,
-      "program_points": [],
+      "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,
         "constraints": null,
Index: clang/test/Analysis/exploded-graph-rewriter/edge.dot
===================================================================
--- clang/test/Analysis/exploded-graph-rewriter/edge.dot
+++ clang/test/Analysis/exploded-graph-rewriter/edge.dot
@@ -5,13 +5,25 @@
 // UNSUPPORTED: system-windows
 
 Node0x1 [shape=record,label=
- "{{ "node_id": 1, "pointer": "0x1", "has_report": false, "is_sink": false,
-     "program_state": null, "program_points": []}\l}"];
+ "{{ "program_state": null, "program_points": [
+    {
+      "kind": "BlockEntrance", "block_id": 1,
+      "terminator": null, "term_kind": null,
+      "tag": null, "node_id": 1,
+      "has_report": 0, "is_sink": 0
+    }
+  ]}\l}"];
 
 // LIGHT: Node0x1 -> Node0x2;
 // DARK:  Node0x1 -> Node0x2 [color="white"];
 Node0x1 -> Node0x2;
 
 Node0x2 [shape=record,label=
- "{{ "node_id": 2, "pointer": "0x2", "has_report": false, "is_sink": false,
-     "program_state": null, "program_points": []}\l}"];
+ "{{ "program_state": null, "program_points": [
+    {
+      "kind": "BlockEntrance", "block_id": 1,
+      "terminator": null, "term_kind": null,
+      "tag": null, "node_id": 1,
+      "has_report": 0, "is_sink": 0
+    }
+ ]}\l}"];
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
@@ -5,12 +5,16 @@
 
 Node0x1 [shape=record,label=
  "{
-    { "node_id": 1,
-      "pointer": "0x1",
-      "has_report": false,
-      "is_sink": false,
+    {
       "state_id": 2,
-      "program_points": [],
+      "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,
@@ -39,12 +43,16 @@
 // CHECK-SAME: </tr>
 Node0x3 [shape=record,label=
  "{
-    { "node_id": 3,
-      "pointer": "0x3",
-      "has_report": false,
-      "is_sink": false,
+    {
       "state_id": 4,
-      "program_points": [],
+      "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,
@@ -62,12 +70,16 @@
 
 Node0x5 [shape=record,label=
  "{
-    { "node_id": 5,
-      "pointer": "0x5",
-      "has_report": false,
-      "is_sink": false,
+    {
       "state_id": 6,
-      "program_points": [],
+      "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,
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
@@ -12,12 +12,16 @@
 // CHECK-SAME: </table></td></tr>
 Node0x1 [shape=record,label=
  "{
-    { "node_id": 1,
-      "pointer": "0x1",
-      "has_report": false,
-      "is_sink": false,
+    {
       "state_id": 2,
-      "program_points": [],
+      "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,
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
@@ -5,12 +5,15 @@
 
 Node0x1 [shape=record,label=
  "{
-    { "node_id": 1,
-      "pointer": "0x1",
-      "has_report": false,
-      "is_sink": false,
-      "state_id": 2,
-      "program_points": [],
+    { "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": {
         "environment": null,
         "store": null,
@@ -59,12 +62,16 @@
 // CHECK-SAME: </tr>
 Node0x4 [shape=record,label=
  "{
-    { "node_id": 4,
-      "pointer": "0x4",
-      "has_report": false,
-      "is_sink": false,
+    {
       "state_id": 5,
-      "program_points": [],
+      "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": {
         "environment": null,
         "store": null,
@@ -88,12 +95,15 @@
 
 Node0x6 [shape=record,label=
  "{
-    { "node_id": 6,
-      "pointer": "0x6",
-      "has_report": false,
-      "is_sink": false,
-      "state_id": 7,
-      "program_points": [],
+    { "state_id": 7,
+      "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": null
     }
 \l}"];
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
@@ -14,7 +14,14 @@
       "has_report": false,
       "is_sink": false,
       "state_id": 2,
-      "program_points": [],
+      "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,
         "constraints": null,
Index: clang/test/Analysis/dump_egraph.c
===================================================================
--- clang/test/Analysis/dump_egraph.c
+++ clang/test/Analysis/dump_egraph.c
@@ -18,7 +18,7 @@
   return *x + *y;
 }
 
-// CHECK: \"program_points\": [\l&nbsp;&nbsp;&nbsp;&nbsp;\{ \"kind\": \"Edge\", \"src_id\": 2, \"dst_id\": 1, \"terminator\": null, \"term_kind\": null, \"tag\": null \}\l&nbsp;&nbsp;],\l&nbsp;&nbsp;\"program_state\": null
+// CHECK: \"program_points\": [\l&nbsp;&nbsp;&nbsp;&nbsp;\{ \"kind\": \"Edge\", \"src_id\": 2, \"dst_id\": 1, \"terminator\": null, \"term_kind\": null, \"tag\": null, \"node_id\": 1, \"is_sink\":0, \"has_report\": 0 \}\l&nbsp;&nbsp;],\l&nbsp;&nbsp;\"program_state\": null
 
 // CHECK: \"program_points\": [\l&nbsp;&nbsp;&nbsp;&nbsp;\{ \"kind\": \"BlockEntrance\", \"block_id\": 1
 
@@ -27,4 +27,4 @@
 
 // CHECK: \"pretty\": \"'\\\\x13'\"
 
-// CHECK: \"has_report\": true
+// CHECK: \"has_report\": 1
Index: clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -3058,16 +3058,7 @@
     const unsigned int Space = 1;
     ProgramStateRef State = N->getState();
 
-    auto Noop = [](const ExplodedNode*){};
-    bool HasReport = traverseHiddenNodes(
-        N, Noop, Noop, &nodeHasBugReport);
-    bool IsSink = traverseHiddenNodes(
-        N, Noop, Noop, [](const ExplodedNode *N) { return N->isSink(); });
-
-    Out << "{ \"node_id\": " << N->getID(G) << ", \"pointer\": \""
-        << (const void *)N << "\", \"state_id\": " << State->getID()
-        << ", \"has_report\": " << (HasReport ? "true" : "false")
-        << ", \"is_sink\": " << (IsSink ? "true" : "false")
+    Out << "{ \"state_id\": " << State->getID()
         << ",\\l";
 
     Indent(Out, Space, IsDot) << "\"program_points\": [\\l";
@@ -3080,9 +3071,12 @@
           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 << "null";
+          Out << ", \"node_id\": " << OtherNode->getID() <<
+                 ", \"is_sink\":" << OtherNode->isSink() <<
+                 ", \"has_report\": " << nodeHasBugReport(OtherNode) << " }";
         },
         // Adds a comma and a new-line between each program point.
         [&](const ExplodedNode *) { Out << ",\\l"; },
Index: clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp
+++ clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp
@@ -283,10 +283,6 @@
   return Storage.getAddrOfPtr1() + 1;
 }
 
-int64_t ExplodedNode::getID(ExplodedGraph *G) const {
-  return G->getAllocator().identifyKnownAlignedObject<ExplodedNode>(this);
-}
-
 bool ExplodedNode::isTrivial() const {
   return pred_size() == 1 && succ_size() == 1 &&
          getFirstPred()->getState()->getID() == getState()->getID() &&
@@ -417,14 +413,14 @@
       V = (NodeTy*) getAllocator().Allocate<NodeTy>();
     }
 
-    new (V) NodeTy(L, State, IsSink);
+    ++NumNodes;
+    new (V) NodeTy(L, State, NumNodes, IsSink);
 
     if (ReclaimNodeInterval)
       ChangedNodes.push_back(V);
 
     // Insert the node into the node set and return it.
     Nodes.InsertNode(V, InsertPos);
-    ++NumNodes;
 
     if (IsNew) *IsNew = true;
   }
@@ -436,9 +432,10 @@
 
 ExplodedNode *ExplodedGraph::createUncachedNode(const ProgramPoint &L,
                                                 ProgramStateRef State,
+                                                int64_t Id,
                                                 bool IsSink) {
   NodeTy *V = (NodeTy *) getAllocator().Allocate<NodeTy>();
-  new (V) NodeTy(L, State, IsSink);
+  new (V) NodeTy(L, State, Id, IsSink);
   return V;
 }
 
@@ -498,7 +495,8 @@
 
     // Create the corresponding node in the new graph and record the mapping
     // from the old node to the new node.
-    ExplodedNode *NewN = G->createUncachedNode(N->getLocation(), N->State, N->isSink());
+    ExplodedNode *NewN = G->createUncachedNode(N->getLocation(), N->State,
+                                               N->getID(), N->isSink());
     Pass2[N] = NewN;
 
     // Also record the reverse mapping from the new node to the old node.
Index: clang/lib/StaticAnalyzer/Core/BugReporter.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Core/BugReporter.cpp
+++ clang/lib/StaticAnalyzer/Core/BugReporter.cpp
@@ -2566,7 +2566,8 @@
     // Create the equivalent node in the new graph with the same state
     // and location.
     ExplodedNode *NewN = GNew->createUncachedNode(
-        OrigN->getLocation(), OrigN->getState(), OrigN->isSink());
+        OrigN->getLocation(), OrigN->getState(),
+        OrigN->getID(), OrigN->isSink());
 
     // Link up the new node with the previous node.
     if (Succ)
Index: clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h
===================================================================
--- clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h
+++ clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h
@@ -131,10 +131,12 @@
   /// Succs - The successors of this node.
   NodeGroup Succs;
 
+  int64_t Id;
+
 public:
   explicit ExplodedNode(const ProgramPoint &loc, ProgramStateRef state,
-                        bool IsSink)
-      : Location(loc), State(std::move(state)), Succs(IsSink) {
+                        int64_t Id, bool IsSink)
+      : Location(loc), State(std::move(state)), Succs(IsSink), Id(Id) {
     assert(isSink() == IsSink);
   }
 
@@ -258,7 +260,7 @@
   }
   const_succ_range succs() const { return {Succs.begin(), Succs.end()}; }
 
-  int64_t getID(ExplodedGraph *G) const;
+  int64_t getID() const { return Id; }
 
   /// The node is trivial if it has only one successor, only one predecessor,
   /// it's predecessor has only one successor,
@@ -324,7 +326,7 @@
   BumpVectorContext BVC;
 
   /// NumNodes - The number of nodes in the graph.
-  unsigned NumNodes = 0;
+  int64_t NumNodes = 0;
 
   /// A list of recently allocated nodes that can potentially be recycled.
   NodeVector ChangedNodes;
@@ -358,6 +360,7 @@
   ///  ExplodedGraph for further processing.
   ExplodedNode *createUncachedNode(const ProgramPoint &L,
     ProgramStateRef State,
+    int64_t Id,
     bool IsSink = false);
 
   std::unique_ptr<ExplodedGraph> MakeEmptyGraph() const {
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to