Skip to content

Commit 0a77d91

Browse files
committed
[analyzer] exploded-graph-rewriter: Add support for objects under construction.
This trait is Environment-like, so there was a chance to re-use a lot of code. Differential Revision: https://reviews.llvm.org/D64047 llvm-svn: 364880
1 parent 745379a commit 0a77d91

9 files changed

+137
-23
lines changed

clang/test/Analysis/exploded-graph-rewriter/constraints.dot

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ Node0x1 [shape=record,label=
2020
"store": null,
2121
"environment": null,
2222
"dynamic_types": null,
23+
"constructing_objects": null,
2324
"constraints": [
2425
{ "symbol": "reg_$0<x>", "range": "{ [0, 0] }" }
2526
]

clang/test/Analysis/exploded-graph-rewriter/constraints_diff.dot

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ Node0x1 [shape=record,label=
1313
"store": null,
1414
"environment": null,
1515
"dynamic_types": null,
16+
"constructing_objects": null,
1617
"constraints": [
1718
{ "symbol": "reg_$0<x>", "range": "{ [0, 10] }" }
1819
]
@@ -43,6 +44,7 @@ Node0x3 [shape=record,label=
4344
"store": null,
4445
"environment": null,
4546
"dynamic_types": null,
47+
"constructing_objects": null,
4648
"constraints": [
4749
{ "symbol": "reg_$0<x>", "range": "{ [0, 5] }" }
4850
]
@@ -62,7 +64,8 @@ Node0x5 [shape=record,label=
6264
"store": null,
6365
"environment": null,
6466
"constraints": null,
65-
"dynamic_types": null
67+
"dynamic_types": null,
68+
"constructing_objects": null
6669
}
6770
}
6871
\l}"];

clang/test/Analysis/exploded-graph-rewriter/environment.dot

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ Node0x1 [shape=record,label=
3535
"store": null,
3636
"constraints": null,
3737
"dynamic_types": null,
38+
"constructing_objects": null,
3839
"environment": {
3940
"pointer": "0x2",
4041
"items": [

clang/test/Analysis/exploded-graph-rewriter/environment_diff.dot

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ Node0x1 [shape=record,label=
1414
"store": null,
1515
"constraints": null,
1616
"dynamic_types": null,
17+
"constructing_objects": null,
1718
"environment": {
1819
"pointer": "0x2",
1920
"items": [
@@ -61,6 +62,7 @@ Node0x6 [shape=record,label=
6162
"store": null,
6263
"constraints": null,
6364
"dynamic_types": null,
65+
"constructing_objects": null,
6466
"environment": {
6567
"pointer": "0x2",
6668
"items": [
@@ -102,6 +104,7 @@ Node0x9 [shape=record,label=
102104
"store": null,
103105
"constraints": null,
104106
"dynamic_types": null,
107+
"constructing_objects": null,
105108
"environment": {
106109
"pointer": "0x2",
107110
"items": [
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// FIXME: Figure out how to use %clang_analyze_cc1 with our lit.local.cfg.
2+
// RUN: %clang_cc1 -analyze -triple x86_64-unknown-linux-gnu \
3+
// RUN: -analyzer-checker=core \
4+
// RUN: -analyzer-dump-egraph=%t.dot %s
5+
// RUN: %exploded_graph_rewriter %t.dot | FileCheck %s
6+
// REQUIRES: asserts
7+
8+
// FIXME: Substitution doesn't seem to work on Windows.
9+
// UNSUPPORTED: system-windows
10+
11+
struct A {
12+
A() {}
13+
};
14+
15+
struct B {
16+
A a;
17+
B() : a() {}
18+
};
19+
20+
void test() {
21+
// CHECK: (construct into member variable)
22+
// CHECK-SAME: <td align="left">a</td>
23+
// CHECK-SAME: <td align="left">&amp;b-&gt;a</td>
24+
B b;
25+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// FIXME: Figure out how to use %clang_analyze_cc1 with our lit.local.cfg.
2+
// RUN: %clang_cc1 -analyze -triple x86_64-unknown-linux-gnu \
3+
// RUN: -analyzer-checker=core \
4+
// RUN: -analyzer-dump-egraph=%t.dot %s
5+
// RUN: %exploded_graph_rewriter %t.dot | FileCheck %s
6+
// REQUIRES: asserts
7+
8+
// FIXME: Substitution doesn't seem to work on Windows.
9+
// UNSUPPORTED: system-windows
10+
11+
struct S {
12+
S() {}
13+
};
14+
15+
void test() {
16+
// CHECK: Objects Under Construction:
17+
// CHECK-SAME: <tr>
18+
// CHECK-SAME: <td align="left"><b>#0 Call</b></td>
19+
// CHECK-SAME: <td align="left" colspan="2">
20+
// CHECK-SAME: <font color="grey60">test </font>
21+
// CHECK-SAME: </td>
22+
// CHECK-SAME: </tr>
23+
// CHECK-SAME: <tr>
24+
// CHECK-SAME: <td align="left"><i>S{{[0-9]*}}</i></td>
25+
// CHECK-SAME: <td align="left"><font color="darkgreen"><i>
26+
// CHECK-SAME: (materialize temporary)
27+
// CHECK-SAME: </i></font></td>
28+
// CHECK-SAME: <td align="left">S()</td>
29+
// CHECK-SAME: <td align="left">&amp;s</td>
30+
// CHECK-SAME: </tr>
31+
// CHECK-SAME: <tr>
32+
// CHECK-SAME: <td align="left"><i>S{{[0-9]*}}</i></td>
33+
// CHECK-SAME: <td align="left"><font color="darkgreen"><i>
34+
// CHECK-SAME: (elide constructor)
35+
// CHECK-SAME: </i></font></td>
36+
// CHECK-SAME: <td align="left">S()</td>
37+
// CHECK-SAME: <td align="left">&amp;s</td>
38+
// CHECK-SAME: </tr>
39+
// CHECK-SAME: <tr>
40+
// CHECK-SAME: <td align="left"><i>S{{[0-9]*}}</i></td>
41+
// CHECK-SAME: <td align="left"><font color="darkgreen"><i>
42+
// CHECK-SAME: (construct into local variable)
43+
// CHECK-SAME: </i></font></td>
44+
// CHECK-SAME: <td align="left">S s = S();</td>
45+
// CHECK-SAME: <td align="left">&amp;s</td>
46+
// CHECK-SAME: </tr>
47+
S s = S();
48+
}

clang/test/Analysis/exploded-graph-rewriter/store.dot

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ Node0x1 [shape=record,label=
3030
"environment": null,
3131
"constraints": null,
3232
"dynamic_types": null,
33+
"constructing_objects": null,
3334
"store": {
3435
"pointer": "0x2",
3536
"items": [

clang/test/Analysis/exploded-graph-rewriter/store_diff.dot

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ Node0x1 [shape=record,label=
1313
"environment": null,
1414
"constraints": null,
1515
"dynamic_types": null,
16+
"constructing_objects": null,
1617
"store": {
1718
"pointer": "0x2",
1819
"items": [
@@ -59,6 +60,7 @@ Node0x4 [shape=record,label=
5960
"environment": null,
6061
"constraints": null,
6162
"dynamic_types": null,
63+
"constructing_objects": null,
6264
"store": {
6365
"pointer": "0x5",
6466
"items": [

clang/utils/analyzer/exploded-graph-rewriter.py

Lines changed: 52 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,11 @@ def __init__(self, json_pp):
7171
class EnvironmentBindingKey(object):
7272
def __init__(self, json_ek):
7373
super(EnvironmentBindingKey, self).__init__()
74-
self.stmt_id = json_ek['stmt_id']
74+
# CXXCtorInitializer is not a Stmt!
75+
self.stmt_id = json_ek['stmt_id'] if 'stmt_id' in json_ek \
76+
else json_ek['init_id']
7577
self.pretty = json_ek['pretty']
78+
self.kind = json_ek['kind'] if 'kind' in json_ek else None
7679

7780
def _key(self):
7881
return self.stmt_id
@@ -122,12 +125,12 @@ def is_different(self, prev):
122125
return len(removed) != 0 or len(added) != 0
123126

124127

125-
# A deserialized Environment.
126-
class Environment(object):
128+
# A deserialized Environment. This class can also hold other entities that
129+
# are similar to Environment, such as Objects Under Construction.
130+
class GenericEnvironment(object):
127131
def __init__(self, json_e):
128-
super(Environment, self).__init__()
129-
self.ptr = json_e['pointer']
130-
self.frames = [EnvironmentFrame(f) for f in json_e['items']]
132+
super(GenericEnvironment, self).__init__()
133+
self.frames = [EnvironmentFrame(f) for f in json_e]
131134

132135
def diff_frames(self, prev):
133136
# TODO: It's difficult to display a good diff when frame numbers shift.
@@ -214,21 +217,29 @@ def __init__(self, state_id, json_ps):
214217
logging.debug('Adding ProgramState ' + str(state_id))
215218

216219
self.state_id = state_id
220+
217221
self.store = Store(json_ps['store']) \
218222
if json_ps['store'] is not None else None
219-
self.environment = Environment(json_ps['environment']) \
223+
224+
self.environment = \
225+
GenericEnvironment(json_ps['environment']['items']) \
220226
if json_ps['environment'] is not None else None
227+
221228
self.constraints = GenericMap([
222229
(c['symbol'], c['range']) for c in json_ps['constraints']
223230
]) if json_ps['constraints'] is not None else None
231+
224232
self.dynamic_types = GenericMap([
225233
(t['region'], '%s%s' % (t['dyn_type'],
226234
' (or a sub-class)'
227235
if t['sub_classable'] else ''))
228236
for t in json_ps['dynamic_types']]) \
229237
if json_ps['dynamic_types'] is not None else None
230238

231-
# TODO: Objects under construction.
239+
self.constructing_objects = \
240+
GenericEnvironment(json_ps['constructing_objects']) \
241+
if json_ps['constructing_objects'] is not None else None
242+
232243
# TODO: Checker messages.
233244

234245

@@ -416,10 +427,15 @@ def dump_location_context(lc, is_added=None):
416427
def dump_binding(f, b, is_added=None):
417428
self._dump('<tr><td>%s</td>'
418429
'<td align="left"><i>S%s</i></td>'
430+
'%s'
419431
'<td align="left">%s</td>'
420432
'<td align="left">%s</td></tr>'
421433
% (self._diff_plus_minus(is_added),
422-
b.stmt_id, b.pretty, f.bindings[b]))
434+
b.stmt_id,
435+
'<td align="left"><font color="darkgreen"><i>'
436+
'(%s)</i></font></td>' % b.kind
437+
if b.kind is not None else '',
438+
b.pretty, f.bindings[b]))
423439

424440
frames_updated = e.diff_frames(prev_e) if prev_e is not None else None
425441
if frames_updated:
@@ -440,20 +456,25 @@ def dump_binding(f, b, is_added=None):
440456

441457
self._dump('</table>')
442458

443-
def visit_environment_in_state(self, s, prev_s=None):
444-
self._dump('<hr /><tr><td align="left"><b>Environment: </b>')
445-
if s.environment is None:
459+
def visit_environment_in_state(self, selector, title, s, prev_s=None):
460+
e = getattr(s, selector)
461+
prev_e = getattr(prev_s, selector) if prev_s is not None else None
462+
if e is None and prev_e is None:
463+
return
464+
465+
self._dump('<hr /><tr><td align="left"><b>%s: </b>' % title)
466+
if e is None:
446467
self._dump('<i> Nothing!</i>')
447468
else:
448-
if prev_s is not None and prev_s.environment is not None:
449-
if s.environment.is_different(prev_s.environment):
469+
if prev_e is not None:
470+
if e.is_different(prev_e):
450471
self._dump('</td></tr><tr><td align="left">')
451-
self.visit_environment(s.environment, prev_s.environment)
472+
self.visit_environment(e, prev_e)
452473
else:
453474
self._dump('<i> No changes!</i>')
454475
else:
455476
self._dump('</td></tr><tr><td align="left">')
456-
self.visit_environment(s.environment)
477+
self.visit_environment(e)
457478

458479
self._dump('</td></tr>')
459480

@@ -496,19 +517,24 @@ def dump_binding(s, c, b, is_added=None):
496517
self._dump('</table>')
497518

498519
def visit_store_in_state(self, s, prev_s=None):
520+
st = s.store
521+
prev_st = prev_s.store if prev_s is not None else None
522+
if st is None and prev_st is None:
523+
return
524+
499525
self._dump('<hr /><tr><td align="left"><b>Store: </b>')
500-
if s.store is None:
526+
if st is None:
501527
self._dump('<i> Nothing!</i>')
502528
else:
503-
if prev_s is not None and prev_s.store is not None:
504-
if s.store.is_different(prev_s.store):
529+
if prev_st is not None:
530+
if s.store.is_different(prev_st):
505531
self._dump('</td></tr><tr><td align="left">')
506-
self.visit_store(s.store, prev_s.store)
532+
self.visit_store(st, prev_st)
507533
else:
508534
self._dump('<i> No changes!</i>')
509535
else:
510536
self._dump('</td></tr><tr><td align="left">')
511-
self.visit_store(s.store)
537+
self.visit_store(st)
512538
self._dump('</td></tr>')
513539

514540
def visit_generic_map(self, m, prev_m=None):
@@ -559,11 +585,15 @@ def visit_generic_map_in_state(self, selector, title, s, prev_s=None):
559585

560586
def visit_state(self, s, prev_s):
561587
self.visit_store_in_state(s, prev_s)
562-
self.visit_environment_in_state(s, prev_s)
588+
self.visit_environment_in_state('environment', 'Environment',
589+
s, prev_s)
563590
self.visit_generic_map_in_state('constraints', 'Ranges',
564591
s, prev_s)
565592
self.visit_generic_map_in_state('dynamic_types', 'Dynamic Types',
566593
s, prev_s)
594+
self.visit_environment_in_state('constructing_objects',
595+
'Objects Under Construction',
596+
s, prev_s)
567597

568598
def visit_node(self, node):
569599
self._dump('%s [shape=record,label=<<table border="0">'

0 commit comments

Comments
 (0)