Skip to content

Commit 999af15

Browse files
committed
Python: Show unresolved calls for field-flow tests
1 parent 2d0034c commit 999af15

File tree

4 files changed

+47
-22
lines changed

4 files changed

+47
-22
lines changed
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import python
2+
private import semmle.python.dataflow.new.internal.PrintNode
3+
private import semmle.python.dataflow.new.internal.DataFlowPrivate as DataFlowPrivate
4+
private import semmle.python.ApiGraphs
5+
import TestUtilities.InlineExpectationsTest
6+
7+
class UnresolvedCallExpectations extends InlineExpectationsTest {
8+
UnresolvedCallExpectations() { this = "UnresolvedCallExpectations" }
9+
10+
override string getARelevantTag() { result = ["unresolved_call"] }
11+
12+
override predicate hasActualResult(Location location, string element, string tag, string value) {
13+
exists(location.getFile().getRelativePath()) and
14+
exists(CallNode call |
15+
not exists(DataFlowPrivate::DataFlowCall dfc | dfc.getNode() = call) and
16+
not call = API::builtin(_).getACall().asCfgNode() and
17+
location = call.getLocation() and
18+
tag = "unresolved_call" and
19+
value = prettyExpr(call.getNode()) and
20+
element = call.toString()
21+
)
22+
}
23+
}

python/ql/test/experimental/dataflow/fieldflow/UnresolvedCalls.expected

Whitespace-only changes.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
import python
2+
import experimental.dataflow.TestUtil.UnresolvedCalls

python/ql/test/experimental/dataflow/fieldflow/test.py

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import sys
22
import os
33

4-
sys.path.append(os.path.dirname(os.path.dirname((__file__))))
4+
sys.path.append(os.path.dirname(os.path.dirname((__file__)))) # $ unresolved_call=os.path.dirname(..) unresolved_call=sys.path.append(..)
55
from testlib import *
66

77
# These are defined so that we can evaluate the test code.
@@ -42,7 +42,7 @@ def setFoo(obj, x):
4242
SINK_F(obj.foo)
4343
obj.foo = x
4444

45-
@expects(2)
45+
@expects(2) # $ unresolved_call=expects(..) unresolved_call=expects(..)(..)
4646
def test_indirect_assign():
4747
myobj = MyObj("OK")
4848

@@ -53,7 +53,7 @@ def test_indirect_assign():
5353
def test_indirect_assign_method():
5454
myobj = MyObj("OK")
5555

56-
myobj.setFoo(SOURCE)
56+
myobj.setFoo(SOURCE) # $ unresolved_call=myobj.setFoo(..)
5757
SINK(myobj.foo) # $ MISSING: flow
5858

5959

@@ -79,7 +79,7 @@ def test_direct_if_assign(cond = False):
7979
SINK(myobj.foo) # $ flow="SOURCE, l:-4 -> myobj.foo"
8080

8181

82-
@expects(2)
82+
@expects(2) # $ unresolved_call=expects(..) unresolved_call=expects(..)(..)
8383
def test_direct_if_always_assign(cond = True):
8484
myobj = MyObj(NONSOURCE)
8585
myobj.foo = SOURCE
@@ -157,7 +157,7 @@ def test_nested_obj():
157157
def test_nested_obj_method():
158158
x = SOURCE
159159
a = NestedObj()
160-
a.getObj().foo = x
160+
a.getObj().foo = x # $ unresolved_call=a.getObj()
161161
SINK(a.obj.foo) # $ MISSING: flow
162162

163163
# ------------------------------------------------------------------------------
@@ -173,12 +173,12 @@ def test_nested_obj_method():
173173
# scope tests into multiple functions, since we wouldn't know which one did the initial
174174
# import that does all the printing :|
175175

176-
@expects(18 + 2)
176+
@expects(18 + 2) # $ unresolved_call=expects(..) unresolved_call=expects(..)(..)
177177
def test_global_scope():
178178
import fieldflow.test_global
179179

180-
fieldflow.test_global.func_defined_before()
181-
fieldflow.test_global.func_defined_after()
180+
fieldflow.test_global.func_defined_before() # $ unresolved_call=fieldflow.test_global.func_defined_before()
181+
fieldflow.test_global.func_defined_after() # $ unresolved_call=fieldflow.test_global.func_defined_after()
182182

183183
# ------------------------------------------------------------------------------
184184
# Global flow cases that doesn't work in this file, but works in test_global.py
@@ -194,40 +194,40 @@ def test_global_scope():
194194

195195
# apparently these if statements below makes a difference :O
196196
# but one is not enough
197-
cond = os.urandom(1)[0] > 128
197+
cond = os.urandom(1)[0] > 128 # $ unresolved_call=os.urandom(..)
198198

199199
if cond:
200200
pass
201201

202202
# def test_constructor_assign():
203-
obj2 = MyObj(SOURCE)
204-
SINK(obj2.foo) # $ MISSING: flow="SOURCE, l:-1 -> obj2.foo"
203+
obj2 = MyObj(SOURCE) # $ unresolved_call=MyObj(..)
204+
SINK(obj2.foo) # $ unresolved_call=SINK(..) MISSING: flow="SOURCE, l:-1 -> obj2.foo"
205205

206206
if cond:
207207
pass
208208

209209
# def test_constructor_assign():
210-
obj2 = MyObj(SOURCE)
211-
SINK(obj2.foo) # $ MISSING: flow="SOURCE, l:-1 -> obj2.foo"
210+
obj2 = MyObj(SOURCE) # $ unresolved_call=MyObj(..)
211+
SINK(obj2.foo) # $ unresolved_call=SINK(..) MISSING: flow="SOURCE, l:-1 -> obj2.foo"
212212

213213
# def test_constructor_assign_kw():
214-
obj3 = MyObj(foo=SOURCE)
215-
SINK(obj3.foo) # $ MISSING: flow="SOURCE, l:-1 -> obj3.foo"
214+
obj3 = MyObj(foo=SOURCE) # $ unresolved_call=MyObj(..)
215+
SINK(obj3.foo) # $ unresolved_call=SINK(..) MISSING: flow="SOURCE, l:-1 -> obj3.foo"
216216

217217
# def test_fields():
218-
SINK(fields_with_local_flow(SOURCE)) # $ MISSING: flow="SOURCE -> fields_with_local_flow(..)"
218+
SINK(fields_with_local_flow(SOURCE)) # $ unresolved_call=fields_with_local_flow(..) unresolved_call=SINK(..) MISSING: flow="SOURCE -> fields_with_local_flow(..)"
219219

220220
# --------------------------------------
221221
# method calls
222222
# --------------------------------------
223223

224224
# def test_indirect_assign_method():
225-
myobj2 = MyObj("OK")
226-
myobj2.setFoo(SOURCE)
227-
SINK(myobj2.foo) # $ MISSING: flow="SOURCE, l:-1 -> myobj2.foo"
225+
myobj2 = MyObj("OK") # $ unresolved_call=MyObj(..)
226+
myobj2.setFoo(SOURCE) # $ unresolved_call=myobj2.setFoo(..)
227+
SINK(myobj2.foo) # $ unresolved_call=SINK(..) MISSING: flow="SOURCE, l:-1 -> myobj2.foo"
228228

229229
# def test_nested_obj_method():
230230
x2 = SOURCE
231-
a2 = NestedObj()
232-
a2.getObj().foo = x2
233-
SINK(a2.obj.foo) # $ MISSING: flow="SOURCE, l:-3 -> a2.obj.foo"
231+
a2 = NestedObj() # $ unresolved_call=NestedObj()
232+
a2.getObj().foo = x2 # $ unresolved_call=a2.getObj()
233+
SINK(a2.obj.foo) # $ unresolved_call=SINK(..) MISSING: flow="SOURCE, l:-3 -> a2.obj.foo"

0 commit comments

Comments
 (0)