Skip to content

Commit bdc68ce

Browse files
committed
Python: refactor Node class
1 parent 5f18fb4 commit bdc68ce

File tree

5 files changed

+92
-106
lines changed

5 files changed

+92
-106
lines changed

python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll

Lines changed: 27 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -40,15 +40,15 @@ module EssaFlow {
4040
// `x = f(42)`
4141
// nodeFrom is `f(42)`, cfg node
4242
// nodeTo is `x`, essa var
43-
nodeFrom.asCfgNode() = nodeTo.asEssaNode().getDefinition().(AssignmentDefinition).getValue()
43+
nodeFrom.(CfgNode).getNode() = nodeTo.(EssaNode).getVar().getDefinition().(AssignmentDefinition).getValue()
4444
or
4545
// With definition
4646
// `with f(42) as x:`
4747
// nodeFrom is `f(42)`, cfg node
4848
// nodeTo is `x`, essa var
4949
exists(With with, ControlFlowNode contextManager, ControlFlowNode var |
50-
nodeFrom.asCfgNode() = contextManager and
51-
nodeTo.asEssaNode().getDefinition().(WithDefinition).getDefiningNode() = var and
50+
nodeFrom.(CfgNode).getNode() = contextManager and
51+
nodeTo.(EssaNode).getVar().getDefinition().(WithDefinition).getDefiningNode() = var and
5252
// see `with_flow`
5353
with.getContextExpr() = contextManager.getNode() and
5454
with.getOptionalVars() = var.getNode() and
@@ -60,22 +60,22 @@ module EssaFlow {
6060
// `x = f(y)`
6161
// nodeFrom is `y` on first line, essa var
6262
// nodeTo is `y` on second line, cfg node
63-
nodeFrom.asEssaNode().getAUse() = nodeTo.asCfgNode()
63+
nodeFrom.(EssaNode).getVar().getAUse() = nodeTo.(CfgNode).getNode()
6464
or
6565
// Refinements
6666
exists(EssaEdgeRefinement r |
67-
nodeTo.asEssaNode() = r.getVariable() and
68-
nodeFrom.asEssaNode() = r.getInput()
67+
nodeTo.(EssaNode).getVar() = r.getVariable() and
68+
nodeFrom.(EssaNode).getVar() = r.getInput()
6969
)
7070
or
7171
exists(EssaNodeRefinement r |
72-
nodeTo.asEssaNode() = r.getVariable() and
73-
nodeFrom.asEssaNode() = r.getInput()
72+
nodeTo.(EssaNode).getVar() = r.getVariable() and
73+
nodeFrom.(EssaNode).getVar() = r.getInput()
7474
)
7575
or
7676
exists(PhiFunction p |
77-
nodeTo.asEssaNode() = p.getVariable() and
78-
nodeFrom.asEssaNode() = p.getAnInput()
77+
nodeTo.(EssaNode).getVar() = p.getVariable() and
78+
nodeFrom.(EssaNode).getVar() = p.getAnInput()
7979
)
8080
}
8181
}
@@ -119,19 +119,19 @@ class DataFlowCall extends CallNode {
119119
}
120120

121121
/** A data flow node that represents a call argument. */
122-
class ArgumentNode extends Node {
122+
class ArgumentNode extends CfgNode {
123123
ArgumentNode() {
124124
exists(DataFlowCall call, int pos |
125-
this.asCfgNode() = call.getArg(pos)
125+
node = call.getArg(pos)
126126
)
127127
}
128128

129-
/** Holds if this argument occurs at the given position in the given call. */
129+
/** Holds if this argument occurs at the given position in the given call. */
130130
predicate argumentOf(DataFlowCall call, int pos) {
131-
this.asCfgNode() = call.getArg(pos)
131+
node = call.getArg(pos)
132132
}
133133

134-
/** Gets the call in which this node is an argument. */
134+
/** Gets the call in which this node is an argument. */
135135
final DataFlowCall getCall() { this.argumentOf(result, _) }
136136
}
137137

@@ -152,31 +152,31 @@ class ReturnKind extends TReturnKind {
152152
}
153153

154154
/** A data flow node that represents a value returned by a callable. */
155-
class ReturnNode extends Node {
155+
class ReturnNode extends CfgNode {
156156
Return ret;
157157

158-
// See `TaintTrackingImplementation::returnFlowStep`
158+
// See `TaintTrackingImplementation::returnFlowStep`
159159
ReturnNode() {
160-
this.asCfgNode() = ret.getValue().getAFlowNode()
160+
node = ret.getValue().getAFlowNode()
161161
}
162162

163-
/** Gets the kind of this return node. */
163+
/** Gets the kind of this return node. */
164164
ReturnKind getKind() { result = TNormalReturnKind() }
165165

166-
override DataFlowCallable getEnclosingCallable() {
166+
override DataFlowCallable getEnclosingCallable() {
167167
result.getScope().getAStmt() = ret // TODO: check nested function definitions
168168
}
169169
}
170170

171171
/** A data flow node that represents the output of a call. */
172-
class OutNode extends Node {
173-
OutNode() { this.asCfgNode() instanceof CallNode }
172+
class OutNode extends CfgNode {
173+
OutNode() { node instanceof CallNode }
174174

175-
/** Gets the underlying call, where this node is a corresponding output of kind `kind`. */
175+
/** Gets the underlying call, where this node is a corresponding output of kind `kind`. */
176176
cached
177177
DataFlowCall getCall(ReturnKind kind) {
178178
kind = TNormalReturnKind() and
179-
result = this.asCfgNode()
179+
result = node
180180
}
181181
}
182182

@@ -231,13 +231,13 @@ string ppReprType(DataFlowType t) { result = t.toString() }
231231
* another. Additional steps specified by the configuration are *not*
232232
* taken into account.
233233
*/
234-
predicate jumpStep(ExprNode pred, ExprNode succ) {
234+
predicate jumpStep(Node pred, Node succ) {
235235
// As we have ESSA variables for global variables,
236236
// we include ESSA flow steps involving global variables.
237237
(
238-
pred.asEssaNode() instanceof GlobalSsaVariable
238+
pred.(EssaNode).getVar() instanceof GlobalSsaVariable
239239
or
240-
succ.asEssaNode() instanceof GlobalSsaVariable
240+
succ.(EssaNode).getVar() instanceof GlobalSsaVariable
241241
) and
242242
EssaFlow::essaFlowStep(pred, succ)
243243
}

python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll

Lines changed: 53 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -27,34 +27,23 @@ newtype TNode =
2727
* (`ExprNode`) or a parameter (`ParameterNode`).
2828
*/
2929
class Node extends TNode {
30-
31-
/**
32-
* Get the underlying SSA variable if this is such a node.
33-
*/
34-
EssaVariable asEssaNode() { this = TEssaNode(result) }
35-
36-
/**
37-
* Get the underlying ControlFlowNode if this is such a node.
38-
*/
39-
ControlFlowNode asCfgNode() { this = TCfgNode(result) }
40-
4130
/**
4231
* Get a string representation of this data flow node.
4332
*/
44-
string toString() {
45-
result = this.asEssaNode().toString()
46-
or
47-
result = this.asCfgNode().toString()
48-
}
33+
string toString() { result = "Data flow node" }
4934

50-
/** Gets the enclosing callable of this node. */
35+
/** Gets the scope of this node. */
36+
Scope getScope() { none() }
37+
38+
/** Gets the enclosing callable of this node. */
5139
DataFlowCallable getEnclosingCallable() {
52-
result.getScope() = this.asCfgNode().getNode().getScope() // this allows Cfg -> ESSA def
53-
or
54-
result.getScope() = this.asEssaNode().getScope() // this allows ESSA var -> Cfg use
40+
result.getScope() = this.getScope()
5541
}
5642

57-
/**
43+
/** Gets the location of this node */
44+
Location getLocation() { none() }
45+
46+
/**
5847
* Holds if this element is at the specified location.
5948
* The location spans column `startcolumn` of line `startline` to
6049
* column `endcolumn` of line `endline` in file `filepath`.
@@ -64,12 +53,47 @@ class Node extends TNode {
6453
predicate hasLocationInfo(
6554
string filepath, int startline, int startcolumn, int endline, int endcolumn
6655
) {
67-
this.asEssaNode().getDefinition().getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
68-
or
69-
this.asCfgNode().getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
56+
this.getLocation()
57+
.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
58+
}
59+
}
60+
61+
class EssaNode extends Node, TEssaNode {
62+
EssaVariable var;
63+
64+
EssaNode() { this = TEssaNode(var) }
65+
66+
EssaVariable getVar() { result = var }
67+
68+
/**
69+
* Get a string representation of this data flow node.
70+
*/
71+
override string toString() {
72+
result = var.toString()
73+
}
74+
75+
override Scope getScope() { result = var.getScope() }
76+
77+
override Location getLocation() { result = var.getDefinition().getLocation() }
78+
}
79+
80+
class CfgNode extends Node, TCfgNode {
81+
ControlFlowNode node;
82+
83+
CfgNode() { this = TCfgNode(node) }
84+
85+
ControlFlowNode getNode() { result = node }
86+
87+
/**
88+
* Get a string representation of this data flow node.
89+
*/
90+
override string toString() {
91+
result = node.toString()
7092
}
7193

94+
override Scope getScope() { result = node.getScope() }
7295

96+
override Location getLocation() { result = node.getLocation() }
7397
}
7498

7599
/**
@@ -89,22 +113,18 @@ ExprNode exprNode(DataFlowExpr e) { none() }
89113
* The value of a parameter at function entry, viewed as a node in a data
90114
* flow graph.
91115
*/
92-
class ParameterNode extends Node {
93-
ParameterNode() {
94-
this.asEssaNode() instanceof ParameterDefinition
95-
}
116+
class ParameterNode extends EssaNode {
117+
ParameterNode() { var instanceof ParameterDefinition }
96118

97-
/**
119+
/**
98120
* Holds if this node is the parameter of callable `c` at the specified
99121
* (zero-based) position.
100122
*/
101123
predicate isParameterOf(DataFlowCallable c, int i) {
102-
this.asEssaNode().(ParameterDefinition).getDefiningNode() = c.getParameter(i)
124+
var.(ParameterDefinition).getDefiningNode() = c.getParameter(i)
103125
}
104126

105-
override DataFlowCallable getEnclosingCallable() {
106-
this.isParameterOf(result, _)
107-
}
127+
override DataFlowCallable getEnclosingCallable() { this.isParameterOf(result, _) }
108128
}
109129

110130
/**

python/ql/test/experimental/dataflow/basic/maximalFlowsConfig.qll

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,16 @@ class MaximalFlowsConfig extends DataFlow::Configuration {
1010
override predicate isSource(DataFlow::Node node) {
1111
node instanceof DataFlow::ParameterNode
1212
or
13-
node = DataFlow::TEssaNode(_) and
14-
not exists(DataFlow::Node pred |
15-
pred = DataFlow::TEssaNode(_) and
13+
node instanceof DataFlow::EssaNode and
14+
not exists(DataFlow::EssaNode pred |
1615
DataFlow::localFlowStep(pred, node)
1716
)
1817
}
1918

2019
override predicate isSink(DataFlow::Node node) {
2120
node instanceof DataFlow::ReturnNode
2221
or
23-
node = DataFlow::TEssaNode(_) and
24-
not exists(node.asEssaNode().getASourceUse())
22+
node instanceof DataFlow::EssaNode and
23+
not exists(node.(DataFlow::EssaNode).getVar().getASourceUse())
2524
}
2625
}

python/ql/test/experimental/dataflow/consistency/dataflow-consistency.expected

Lines changed: 0 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -10,100 +10,67 @@ uniqueEnclosingCallable
1010
| test.py:6:1:6:12 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. |
1111
| test.py:6:5:6:9 | GSSA Variable test1 | Node should have one enclosing callable but has 0. |
1212
| test.py:9:1:9:12 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. |
13-
| test.py:9:1:9:12 | Exit node for Function test2 | Node should have one enclosing callable but has 0. |
1413
| test.py:9:5:9:9 | GSSA Variable test2 | Node should have one enclosing callable but has 0. |
1514
| test.py:13:1:13:13 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. |
1615
| test.py:13:5:13:10 | GSSA Variable source | Node should have one enclosing callable but has 0. |
1716
| test.py:16:1:16:14 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. |
18-
| test.py:16:1:16:14 | Exit node for Function sink | Node should have one enclosing callable but has 0. |
1917
| test.py:16:5:16:8 | GSSA Variable sink | Node should have one enclosing callable but has 0. |
2018
| test.py:19:1:19:12 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. |
21-
| test.py:19:1:19:12 | Exit node for Function test3 | Node should have one enclosing callable but has 0. |
2219
| test.py:19:5:19:9 | GSSA Variable test3 | Node should have one enclosing callable but has 0. |
2320
| test.py:23:1:23:12 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. |
24-
| test.py:23:1:23:12 | Exit node for Function test4 | Node should have one enclosing callable but has 0. |
2521
| test.py:23:5:23:9 | GSSA Variable test4 | Node should have one enclosing callable but has 0. |
2622
| test.py:27:1:27:12 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. |
27-
| test.py:27:1:27:12 | Exit node for Function test5 | Node should have one enclosing callable but has 0. |
2823
| test.py:27:5:27:9 | GSSA Variable test5 | Node should have one enclosing callable but has 0. |
2924
| test.py:31:1:31:16 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. |
30-
| test.py:31:1:31:16 | Exit node for Function test6 | Node should have one enclosing callable but has 0. |
31-
| test.py:31:1:31:16 | Exit node for Function test6 | Node should have one enclosing callable but has 0. |
3225
| test.py:31:5:31:9 | GSSA Variable test6 | Node should have one enclosing callable but has 0. |
3326
| test.py:39:1:39:16 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. |
34-
| test.py:39:1:39:16 | Exit node for Function test7 | Node should have one enclosing callable but has 0. |
35-
| test.py:39:1:39:16 | Exit node for Function test7 | Node should have one enclosing callable but has 0. |
3627
| test.py:39:5:39:9 | GSSA Variable test7 | Node should have one enclosing callable but has 0. |
3728
| test.py:47:1:47:17 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. |
38-
| test.py:47:1:47:17 | Exit node for Function source2 | Node should have one enclosing callable but has 0. |
3929
| test.py:47:5:47:11 | GSSA Variable source2 | Node should have one enclosing callable but has 0. |
4030
| test.py:50:1:50:15 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. |
41-
| test.py:50:1:50:15 | Exit node for Function sink2 | Node should have one enclosing callable but has 0. |
4231
| test.py:50:5:50:9 | GSSA Variable sink2 | Node should have one enclosing callable but has 0. |
4332
| test.py:53:1:53:21 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. |
44-
| test.py:53:1:53:21 | Exit node for Function sink3 | Node should have one enclosing callable but has 0. |
4533
| test.py:53:5:53:9 | GSSA Variable sink3 | Node should have one enclosing callable but has 0. |
4634
| test.py:57:1:57:16 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. |
47-
| test.py:57:1:57:16 | Exit node for Function test8 | Node should have one enclosing callable but has 0. |
4835
| test.py:57:5:57:9 | GSSA Variable test8 | Node should have one enclosing callable but has 0. |
4936
| test.py:62:1:62:16 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. |
50-
| test.py:62:1:62:16 | Exit node for Function test9 | Node should have one enclosing callable but has 0. |
5137
| test.py:62:5:62:9 | GSSA Variable test9 | Node should have one enclosing callable but has 0. |
5238
| test.py:69:1:69:17 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. |
53-
| test.py:69:1:69:17 | Exit node for Function test10 | Node should have one enclosing callable but has 0. |
5439
| test.py:69:5:69:10 | GSSA Variable test10 | Node should have one enclosing callable but has 0. |
5540
| test.py:76:1:76:13 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. |
56-
| test.py:76:1:76:13 | Exit node for Function hub | Node should have one enclosing callable but has 0. |
5741
| test.py:76:5:76:7 | GSSA Variable hub | Node should have one enclosing callable but has 0. |
5842
| test.py:79:1:79:13 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. |
59-
| test.py:79:1:79:13 | Exit node for Function test11 | Node should have one enclosing callable but has 0. |
6043
| test.py:79:5:79:10 | GSSA Variable test11 | Node should have one enclosing callable but has 0. |
6144
| test.py:84:1:84:13 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. |
62-
| test.py:84:1:84:13 | Exit node for Function test12 | Node should have one enclosing callable but has 0. |
6345
| test.py:84:5:84:10 | GSSA Variable test12 | Node should have one enclosing callable but has 0. |
6446
| test.py:89:8:89:13 | ControlFlowNode for ImportExpr | Node should have one enclosing callable but has 0. |
6547
| test.py:89:8:89:13 | GSSA Variable module | Node should have one enclosing callable but has 0. |
6648
| test.py:91:1:91:13 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. |
67-
| test.py:91:1:91:13 | Exit node for Function test13 | Node should have one enclosing callable but has 0. |
6849
| test.py:91:5:91:10 | GSSA Variable test13 | Node should have one enclosing callable but has 0. |
6950
| test.py:95:1:95:13 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. |
70-
| test.py:95:1:95:13 | Exit node for Function test14 | Node should have one enclosing callable but has 0. |
7151
| test.py:95:5:95:10 | GSSA Variable test14 | Node should have one enclosing callable but has 0. |
7252
| test.py:99:1:99:13 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. |
73-
| test.py:99:1:99:13 | Exit node for Function test15 | Node should have one enclosing callable but has 0. |
7453
| test.py:99:5:99:10 | GSSA Variable test15 | Node should have one enclosing callable but has 0. |
7554
| test.py:103:1:103:13 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. |
76-
| test.py:103:1:103:13 | Exit node for Function test16 | Node should have one enclosing callable but has 0. |
7755
| test.py:103:5:103:10 | GSSA Variable test16 | Node should have one enclosing callable but has 0. |
7856
| test.py:108:1:108:17 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. |
79-
| test.py:108:1:108:17 | Exit node for Function test20 | Node should have one enclosing callable but has 0. |
80-
| test.py:108:1:108:17 | Exit node for Function test20 | Node should have one enclosing callable but has 0. |
8157
| test.py:108:5:108:10 | GSSA Variable test20 | Node should have one enclosing callable but has 0. |
8258
| test.py:118:1:118:17 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. |
83-
| test.py:118:1:118:17 | Exit node for Function test21 | Node should have one enclosing callable but has 0. |
84-
| test.py:118:1:118:17 | Exit node for Function test21 | Node should have one enclosing callable but has 0. |
8559
| test.py:118:5:118:10 | GSSA Variable test21 | Node should have one enclosing callable but has 0. |
8660
| test.py:128:1:128:17 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. |
87-
| test.py:128:1:128:17 | Exit node for Function test22 | Node should have one enclosing callable but has 0. |
88-
| test.py:128:1:128:17 | Exit node for Function test22 | Node should have one enclosing callable but has 0. |
8961
| test.py:128:5:128:10 | GSSA Variable test22 | Node should have one enclosing callable but has 0. |
9062
| test.py:139:20:139:38 | ControlFlowNode for ImportMember | Node should have one enclosing callable but has 0. |
9163
| test.py:139:33:139:38 | GSSA Variable unsafe | Node should have one enclosing callable but has 0. |
9264
| test.py:140:1:140:12 | ControlFlowNode for SINK() | Node should have one enclosing callable but has 0. |
9365
| test.py:140:1:140:12 | GSSA Variable unsafe | Node should have one enclosing callable but has 0. |
9466
| test.py:140:6:140:11 | ControlFlowNode for unsafe | Node should have one enclosing callable but has 0. |
9567
| test.py:142:1:142:13 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. |
96-
| test.py:142:1:142:13 | Exit node for Function test23 | Node should have one enclosing callable but has 0. |
9768
| test.py:142:5:142:10 | GSSA Variable test23 | Node should have one enclosing callable but has 0. |
9869
| test.py:146:1:146:13 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. |
99-
| test.py:146:1:146:13 | Exit node for Function test24 | Node should have one enclosing callable but has 0. |
10070
| test.py:146:5:146:10 | GSSA Variable test24 | Node should have one enclosing callable but has 0. |
10171
| test.py:151:1:151:29 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. |
102-
| test.py:151:1:151:29 | Exit node for Function test_update_extend | Node should have one enclosing callable but has 0. |
10372
| test.py:151:5:151:22 | GSSA Variable test_update_extend | Node should have one enclosing callable but has 0. |
10473
| test.py:161:1:161:17 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. |
105-
| test.py:161:1:161:17 | Exit node for Function test_truth | Node should have one enclosing callable but has 0. |
106-
| test.py:161:1:161:17 | Exit node for Function test_truth | Node should have one enclosing callable but has 0. |
10774
| test.py:161:5:161:14 | GSSA Variable test_truth | Node should have one enclosing callable but has 0. |
10875
uniqueType
10976
uniqueNodeLocation

0 commit comments

Comments
 (0)