Skip to content

Commit a19304a

Browse files
committed
Python: Factor out prettyPrinter and update tests
1 parent dc91406 commit a19304a

File tree

16 files changed

+190
-174
lines changed

16 files changed

+190
-174
lines changed

python/ql/test/experimental/dataflow/FlowTestUtil/FlowTest.qll renamed to python/ql/test/experimental/dataflow/TestUtil/FlowTest.qll

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import python
22
import semmle.python.dataflow.new.DataFlow
33
import TestUtilities.InlineExpectationsTest
4+
import experimental.dataflow.TestUtil.PrintNode
45

56
abstract class FlowTest extends InlineExpectationsTest {
67
bindingset[this]
@@ -17,7 +18,8 @@ abstract class FlowTest extends InlineExpectationsTest {
1718
location = toNode.getLocation() and
1819
tag = this.flowTag() and
1920
value =
20-
"\"" + fromNode.toString() + lineStr(fromNode, toNode) + " -> " + toNode.toString() + "\"" and
21+
"\"" + prettyNode(fromNode).replaceAll("\"", "'") + lineStr(fromNode, toNode) + " -> " +
22+
prettyNode(toNode).replaceAll("\"", "'") + "\"" and
2123
element = toNode.toString()
2224
)
2325
}

python/ql/test/experimental/dataflow/FlowTestUtil/LocalFlowStepTest.qll renamed to python/ql/test/experimental/dataflow/TestUtil/LocalFlowStepTest.qll

File renamed without changes.

python/ql/test/experimental/dataflow/FlowTestUtil/MaximalFlowTest.qll renamed to python/ql/test/experimental/dataflow/TestUtil/MaximalFlowTest.qll

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import python
22
import semmle.python.dataflow.new.DataFlow
3+
private import semmle.python.dataflow.new.internal.DataFlowPrivate
34
import FlowTest
45

56
class MaximalFlowTest extends FlowTest {
@@ -21,14 +22,21 @@ class MaximalFlowsConfig extends DataFlow::Configuration {
2122
MaximalFlowsConfig() { this = "MaximalFlowsConfig" }
2223

2324
override predicate isSource(DataFlow::Node node) {
25+
exists(node.getLocation().getFile().getRelativePath()) and
2426
not node.asCfgNode() instanceof CallNode and
2527
not node.asCfgNode().getNode() instanceof Return and
2628
not node instanceof DataFlow::ParameterNode and
29+
not node instanceof DataFlow::PostUpdateNode and
30+
// not node.asExpr() instanceof FunctionExpr and
31+
// not node.asExpr() instanceof ClassExpr and
2732
not exists(DataFlow::Node pred | DataFlow::localFlowStep(pred, node))
2833
}
2934

3035
override predicate isSink(DataFlow::Node node) {
36+
exists(node.getLocation().getFile().getRelativePath()) and
3137
not any(CallNode c).getArg(_) = node.asCfgNode() and
38+
not node instanceof ArgumentNode and
39+
not node.asCfgNode().(NameNode).getId().matches("SINK%") and
3240
not exists(DataFlow::Node succ | DataFlow::localFlowStep(node, succ))
3341
}
3442
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import python
2+
import semmle.python.dataflow.new.DataFlow
3+
4+
string prettyExp(Expr e) {
5+
not e instanceof Num and
6+
not e instanceof StrConst and
7+
not e instanceof Subscript and
8+
not e instanceof Call and
9+
not e instanceof Attribute and
10+
result = e.toString()
11+
or
12+
result = e.(Num).getN()
13+
or
14+
result =
15+
e.(StrConst).getPrefix() + e.(StrConst).getText() +
16+
e.(StrConst).getPrefix().regexpReplaceAll("[a-zA-Z]+", "")
17+
or
18+
result = prettyExp(e.(Subscript).getObject()) + "[" + prettyExp(e.(Subscript).getIndex()) + "]"
19+
or
20+
(
21+
if exists(e.(Call).getAnArg()) or exists(e.(Call).getANamedArg())
22+
then result = prettyExp(e.(Call).getFunc()) + "(..)"
23+
else result = prettyExp(e.(Call).getFunc()) + "()"
24+
)
25+
or
26+
result = prettyExp(e.(Attribute).getObject()) + "." + e.(Attribute).getName()
27+
}
28+
29+
string prettyNode(DataFlow::Node node) {
30+
if exists(node.asExpr()) then result = prettyExp(node.asExpr()) else result = node.toString()
31+
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
import experimental.dataflow.FlowTestUtil.LocalFlowStepTest
1+
import experimental.dataflow.TestUtil.LocalFlowStepTest
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
import experimental.dataflow.FlowTestUtil.MaximalFlowTest
1+
import experimental.dataflow.TestUtil.MaximalFlowTest
Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
def obfuscated_id(x): #$ step="ControlFlowNode for FunctionExpr -> GSSA Variable obfuscated_id"
2-
y = x #$ step="ControlFlowNode for x -> SSA variable y" step="SSA variable x, l:1 -> ControlFlowNode for x"
3-
z = y #$ step="ControlFlowNode for y -> SSA variable z" step="SSA variable y, l:2 -> ControlFlowNode for y"
4-
return z #$ flow="ControlFlowNode for IntegerLiteral, l:6 -> ControlFlowNode for z" step="SSA variable z, l:3 -> ControlFlowNode for z"
1+
def obfuscated_id(x): #$ step="FunctionExpr -> GSSA Variable obfuscated_id"
2+
y = x #$ step="x -> SSA variable y" step="SSA variable x, l:1 -> x"
3+
z = y #$ step="y -> SSA variable z" step="SSA variable y, l:2 -> y"
4+
return z #$ flow="42, l:6 -> z" step="SSA variable z, l:3 -> z"
55

6-
a = 42 #$ step="ControlFlowNode for IntegerLiteral -> GSSA Variable a"
7-
b = obfuscated_id(a) #$ flow="ControlFlowNode for IntegerLiteral, l:6 -> GSSA Variable b" flow="ControlFlowNode for FunctionExpr, l:1 -> ControlFlowNode for obfuscated_id" step="ControlFlowNode for obfuscated_id() -> GSSA Variable b" step="GSSA Variable obfuscated_id, l:1 -> ControlFlowNode for obfuscated_id" step="GSSA Variable a, l:6 -> ControlFlowNode for a"
6+
a = 42 #$ step="42 -> GSSA Variable a"
7+
b = obfuscated_id(a) #$ flow="42, l:6 -> GSSA Variable b" flow="FunctionExpr, l:1 -> obfuscated_id" step="obfuscated_id(..) -> GSSA Variable b" step="GSSA Variable obfuscated_id, l:1 -> obfuscated_id" step="GSSA Variable a, l:6 -> a"

python/ql/test/experimental/dataflow/coverage/argumentPassing.py

Lines changed: 25 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -72,14 +72,14 @@ def argument_passing(
7272
f,
7373
**g,
7474
):
75-
SINK1(a) #$ arg1="ControlFlowNode for arg1, l:89 -> ControlFlowNode for a" arg1="ControlFlowNode for arg1, l:94 -> ControlFlowNode for a"
76-
SINK2(b) #$ arg2="ControlFlowNode for arg2, l:94 -> ControlFlowNode for b" MISSING:arg2="ControlFlowNode for arg2, l:89 -> ControlFlowNode for b"
77-
SINK3(c) #$ arg3="ControlFlowNode for arg3, l:94 -> ControlFlowNode for c" MISSING: arg3="ControlFlowNode for arg3, l:89 -> ControlFlowNode for c"
78-
SINK4(d) #$ MISSING: arg4="ControlFlowNode for arg4, l:89 -> ControlFlowNode for d"
79-
SINK5(e) #$ MISSING: arg5="ControlFlowNode for arg5, l:89 -> ControlFlowNode for e"
80-
SINK6(f) #$ MISSING: arg6="ControlFlowNode for arg6, l:89 -> ControlFlowNode for f"
75+
SINK1(a) #$ arg1="arg1, l:89 -> a" arg1="arg1, l:94 -> a"
76+
SINK2(b) #$ arg2="arg2, l:94 -> b" MISSING:arg2="arg2, l:89 -> b"
77+
SINK3(c) #$ arg3="arg3, l:94 -> c" MISSING: arg3="arg3, l:89 -> c"
78+
SINK4(d) #$ MISSING: arg4="arg4, l:89 -> d"
79+
SINK5(e) #$ MISSING: arg5="arg5, l:89 -> e"
80+
SINK6(f) #$ MISSING: arg6="arg6, l:89 -> f"
8181
try:
82-
SINK7(g["g"]) #$ arg7="ControlFlowNode for arg7, l:89 -> ControlFlowNode for Subscript"
82+
SINK7(g["g"]) #$ arg7="arg7, l:89 -> g['g']"
8383
except:
8484
print("OK")
8585

@@ -95,8 +95,8 @@ def test_argument_passing2():
9595

9696

9797
def with_pos_only(a, /, b):
98-
SINK1(a) #$ arg1="ControlFlowNode for arg1, l:104 -> ControlFlowNode for a" arg1="ControlFlowNode for arg1, l:105 -> ControlFlowNode for a" arg1="ControlFlowNode for arg1, l:106 -> ControlFlowNode for a"
99-
SINK2(b) #$ arg2="ControlFlowNode for arg2, l:104 -> ControlFlowNode for b" arg2="ControlFlowNode for arg2, l:105 -> ControlFlowNode for b" MISSING: arg2="ControlFlowNode for arg2, l:106 -> ControlFlowNode for b"
98+
SINK1(a) #$ arg1="arg1, l:104 -> a" arg1="arg1, l:105 -> a" arg1="arg1, l:106 -> a"
99+
SINK2(b) #$ arg2="arg2, l:104 -> b" arg2="arg2, l:105 -> b" MISSING: arg2="arg2, l:106 -> b"
100100

101101

102102
@expects(6)
@@ -107,9 +107,9 @@ def test_pos_only():
107107

108108

109109
def with_multiple_kw_args(a, b, c):
110-
SINK1(a) #$ arg1="ControlFlowNode for arg1, l:117 -> ControlFlowNode for a" arg1="ControlFlowNode for arg1, l:118 -> ControlFlowNode for a" arg1="ControlFlowNode for arg1, l:119 -> ControlFlowNode for a" arg1="ControlFlowNode for arg1, l:120 -> ControlFlowNode for a"
111-
SINK2(b) #$ arg2="ControlFlowNode for arg2, l:117 -> ControlFlowNode for b" arg2="ControlFlowNode for arg2, l:120 -> ControlFlowNode for b" MISSING: arg2="ControlFlowNode for arg2, l:118 -> ControlFlowNode for b" arg2="ControlFlowNode for arg2, l:119 -> ControlFlowNode for b"
112-
SINK3(c) #$ arg3="ControlFlowNode for arg3, l:117 -> ControlFlowNode for c" arg3="ControlFlowNode for arg3, l:119 -> ControlFlowNode for c" arg3="ControlFlowNode for arg3, l:120 -> ControlFlowNode for c" MISSING: arg3="ControlFlowNode for arg3, l:118 -> ControlFlowNode for c"
110+
SINK1(a) #$ arg1="arg1, l:117 -> a" arg1="arg1, l:118 -> a" arg1="arg1, l:119 -> a" arg1="arg1, l:120 -> a"
111+
SINK2(b) #$ arg2="arg2, l:117 -> b" arg2="arg2, l:120 -> b" MISSING: arg2="arg2, l:118 -> b" arg2="arg2, l:119 -> b"
112+
SINK3(c) #$ arg3="arg3, l:117 -> c" arg3="arg3, l:119 -> c" arg3="arg3, l:120 -> c" MISSING: arg3="arg3, l:118 -> c"
113113

114114

115115
@expects(9)
@@ -121,9 +121,9 @@ def test_multiple_kw_args():
121121

122122

123123
def with_default_arguments(a=arg1, b=arg2, c=arg3):
124-
SINK1(a) #$ arg1="ControlFlowNode for arg1, l:132 -> ControlFlowNode for a" MISSING:arg1="ControlFlowNode for arg1, l:123 -> ControlFlowNode for a"
125-
SINK2(b) #$ arg2="ControlFlowNode for arg2, l:133 -> ControlFlowNode for b" MISSING: arg2="ControlFlowNode for arg2, l:123 -> ControlFlowNode for b"
126-
SINK3(c) #$ arg3="ControlFlowNode for arg3, l:134 -> ControlFlowNode for c" MISSING: arg3="ControlFlowNode for arg3, l:123 -> ControlFlowNode for c"
124+
SINK1(a) #$ arg1="arg1, l:132 -> a" MISSING:arg1="arg1, l:123 -> a"
125+
SINK2(b) #$ arg2="arg2, l:133 -> b" MISSING: arg2="arg2, l:123 -> b"
126+
SINK3(c) #$ arg3="arg3, l:134 -> c" MISSING: arg3="arg3, l:123 -> c"
127127

128128

129129
@expects(12)
@@ -136,14 +136,14 @@ def test_default_arguments():
136136

137137
# Nested constructor pattern
138138
def grab_foo_bar_baz(foo, **kwargs):
139-
SINK1(foo) #$ arg1="ControlFlowNode for arg1, l:160 -> ControlFlowNode for foo"
139+
SINK1(foo) #$ arg1="arg1, l:160 -> foo"
140140
grab_bar_baz(**kwargs)
141141

142142

143143
# It is not possible to pass `bar` into `kwargs`,
144144
# since `bar` is a valid keyword argument.
145145
def grab_bar_baz(bar, **kwargs):
146-
SINK2(bar) #$ arg2="ControlFlowNode for arg2, l:160 -> ControlFlowNode for bar"
146+
SINK2(bar) #$ arg2="arg2, l:160 -> bar"
147147
try:
148148
SINK2_F(kwargs["bar"])
149149
except:
@@ -152,7 +152,7 @@ def grab_bar_baz(bar, **kwargs):
152152

153153

154154
def grab_baz(baz):
155-
SINK3(baz) #$ arg3="ControlFlowNode for arg3, l:160 -> ControlFlowNode for baz"
155+
SINK3(baz) #$ arg3="arg3, l:160 -> baz"
156156

157157

158158
@expects(4)
@@ -163,49 +163,49 @@ def test_grab():
163163
# All combinations
164164
def test_pos_pos():
165165
def with_pos(a):
166-
SINK1(a) #$ arg1="ControlFlowNode for arg1, l:168 -> ControlFlowNode for a"
166+
SINK1(a) #$ arg1="arg1, l:168 -> a"
167167

168168
with_pos(arg1)
169169

170170

171171
def test_pos_pos_only():
172172
def with_pos_only(a, /):
173-
SINK1(a) #$ arg1="ControlFlowNode for arg1, l:175 -> ControlFlowNode for a"
173+
SINK1(a) #$ arg1="arg1, l:175 -> a"
174174

175175
with_pos_only(arg1)
176176

177177

178178
def test_pos_star():
179179
def with_star(*a):
180180
if len(a) > 0:
181-
SINK1(a[0]) #$ arg1="ControlFlowNode for arg1, l:183 -> ControlFlowNode for Subscript"
181+
SINK1(a[0]) #$ arg1="arg1, l:183 -> a[0]"
182182

183183
with_star(arg1)
184184

185185

186186
def test_pos_kw():
187187
def with_kw(a=""):
188-
SINK1(a) #$ arg1="ControlFlowNode for arg1, l:190 -> ControlFlowNode for a"
188+
SINK1(a) #$ arg1="arg1, l:190 -> a"
189189

190190
with_kw(arg1)
191191

192192

193193
def test_kw_pos():
194194
def with_pos(a):
195-
SINK1(a) #$ arg1="ControlFlowNode for arg1, l:197 -> ControlFlowNode for a"
195+
SINK1(a) #$ arg1="arg1, l:197 -> a"
196196

197197
with_pos(a=arg1)
198198

199199

200200
def test_kw_kw():
201201
def with_kw(a=""):
202-
SINK1(a) #$ arg1="ControlFlowNode for arg1, l:204 -> ControlFlowNode for a"
202+
SINK1(a) #$ arg1="arg1, l:204 -> a"
203203

204204
with_kw(a=arg1)
205205

206206

207207
def test_kw_doublestar():
208208
def with_doublestar(**a):
209-
SINK1(a["a"]) #$ arg1="ControlFlowNode for arg1, l:211 -> ControlFlowNode for Subscript"
209+
SINK1(a["a"]) #$ arg1="arg1, l:211 -> a['a']"
210210

211211
with_doublestar(a=arg1)

python/ql/test/experimental/dataflow/coverage/argumentRoutingTest.ql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import python
22
import semmle.python.dataflow.new.DataFlow
33
private import semmle.python.dataflow.new.internal.DataFlowPrivate as DataFlowPrivate
4-
import experimental.dataflow.FlowTestUtil.FlowTest
4+
import experimental.dataflow.TestUtil.FlowTest
55

66
class Argument1RoutingTest extends FlowTest {
77
Argument1RoutingTest() { this = "Argument1RoutingTest" }

0 commit comments

Comments
 (0)