Python: Add simple test of DataFlowCall

Notice the strange thing with treating `mypkg.foo(42)` as a ClassCall,
but completely ignoring `mypkg.subpkg.bar(43)` -- due to having the two
`ClassValue`s:

- `Missing module attribute mypkg.foo`
- `Missing module attribute mypkg.subpkg`

But not `Missing module attribute mypkg.subpkg` with the current import
structure.
This commit is contained in:
Rasmus Wriedt Larsen
2022-02-03 01:20:04 +01:00
parent 48aa07d67a
commit a5c2341204
3 changed files with 71 additions and 0 deletions

View File

@@ -0,0 +1,34 @@
import python
import semmle.python.dataflow.new.DataFlow
import semmle.python.dataflow.new.internal.DataFlowPrivate
import TestUtilities.InlineExpectationsTest
private import semmle.python.dataflow.new.internal.PrintNode
class DataFlowCallTest extends InlineExpectationsTest {
DataFlowCallTest() { this = "DataFlowCallTest" }
override string getARelevantTag() {
result in ["call", "qlclass"]
or
result = "arg_" + [0 .. 10]
}
override predicate hasActualResult(Location location, string element, string tag, string value) {
exists(location.getFile().getRelativePath()) and
exists(DataFlowCall call |
location = call.getLocation() and
element = call.toString()
|
value = prettyExpr(call.getNode().getNode()) and
tag = "call"
or
value = call.getAQlClass() and
tag = "qlclass"
or
exists(int n, DataFlow::Node arg | arg = call.getArg(n) |
value = prettyNodeForInlineTest(arg) and
tag = "arg_" + n
)
)
}
}

View File

@@ -0,0 +1,37 @@
# A very basic test of DataFlowCall
#
# see `coverage/argumentRoutingTest.ql` for a more in depth test of argument routing
# handling.
def func(arg):
pass
class MyClass(object):
def __init__(self, arg):
pass
def my_method(self, arg):
pass
def __getitem__(self, key):
pass
func("foo") # $ call=func(..) qlclass=FunctionCall arg_0="foo"
x = MyClass(1) # $ call=MyClass(..) qlclass=ClassCall arg_0=[pre]MyClass(..) arg_1=1
x.my_method(2) # $ call=x.my_method(..) qlclass=MethodCall arg_0=x arg_1=2
mm = x.my_method
mm(2) # $ call=mm(..) qlclass=MethodCall arg_1=2 MISSING: arg_0=x
x[3] # $ call=x[3] qlclass=SpecialCall arg_0=x arg_1=3
try:
# These are included to show how we handle absent things with points-to where
# `mypkg.foo` is a `missing module variable`, but `mypkg.subpkg.bar` is compeltely
# ignored.
import mypkg
mypkg.foo(42) # $ call=mypkg.foo(..) qlclass=ClassCall arg_0=[pre]mypkg.foo(..)
mypkg.subpkg.bar(43)
except:
pass