Python: Rewrite call-graph tests to be inline expectation (1/2)

This adds inline expectations, next commit will remove old annotations
code... but I thought it would be easier to review like this.
This commit is contained in:
Rasmus Wriedt Larsen
2022-06-24 16:00:40 +02:00
parent e8fdff7a3b
commit 4caaa3a396
6 changed files with 67 additions and 14 deletions

View File

@@ -0,0 +1,4 @@
failures
debug_callableNotUnique
| code/class_advanced.py:18:5:18:18 | Function arg | Qualified function name 'B.arg' is not unique. Please fix. |
| code/class_advanced.py:23:5:23:25 | Function arg | Qualified function name 'B.arg' is not unique. Please fix. |

View File

@@ -0,0 +1,49 @@
import python
import TestUtilities.InlineExpectationsTest
/** Holds when `call` is resolved to `callable` using points-to based call-graph. */
predicate pointsToCallEdge(CallNode call, Function callable) {
exists(PythonFunctionValue funcValue |
funcValue.getScope() = callable and
call = funcValue.getACall()
)
}
/** Holds when `call` is resolved to `callable` using type-tracking based call-graph. */
predicate typeTrackerCallEdge(CallNode call, Function callable) { none() }
class CallGraphTest extends InlineExpectationsTest {
CallGraphTest() { this = "CallGraphTest" }
override string getARelevantTag() { result in ["pt", "tt"] }
override predicate hasActualResult(Location location, string element, string tag, string value) {
exists(location.getFile().getRelativePath()) and
exists(CallNode call, Function target |
tag = "tt" and
typeTrackerCallEdge(call, target)
or
tag = "pt" and
pointsToCallEdge(call, target)
|
location = call.getLocation() and
element = call.toString() and
(
// note: `target.getQualifiedName` for Lambdas is just "lambda", so is not very useful :|
not target.isLambda() and
value = target.getQualifiedName()
or
target.isLambda() and
value =
"lambda[" + target.getLocation().getFile().getShortName() + ":" +
target.getLocation().getStartLine() + ":" + target.getLocation().getStartColumn() + "]"
)
)
}
}
query predicate debug_callableNotUnique(Function callable, string message) {
exists(Function f | f != callable and f.getQualifiedName() = callable.getQualifiedName()) and
message =
"Qualified function name '" + callable.getQualifiedName() + "' is not unique. Please fix."
}

View File

@@ -25,13 +25,13 @@ class A(object):
a = A(42)
# calls:A.some_method
a.some_method()
a.some_method() # $ pt=A.some_method
# calls:A.some_staticmethod
a.some_staticmethod()
a.some_staticmethod() # $ pt=A.some_staticmethod
# calls:A.some_classmethod
a.some_classmethod()
a.some_classmethod() # $ pt=A.some_classmethod
# calls:A.some_staticmethod
A.some_staticmethod()
A.some_staticmethod() # $ pt=A.some_staticmethod
# calls:A.some_classmethod
A.some_classmethod()
A.some_classmethod() # $ pt=A.some_classmethod

View File

@@ -18,7 +18,7 @@ else:
func = rd_bar
# calls:rd_foo calls:rd_bar
func()
func() # $ pt=rd_foo pt=rd_bar
# Random doesn't work with points-to :O
if random.random() < 0.5:
@@ -27,4 +27,4 @@ else:
func2 = rd_bar
# calls:rd_foo calls:rd_bar
func2()
func2() # $ pt=rd_foo pt=rd_bar

View File

@@ -16,12 +16,12 @@ lam = lambda: print("lambda called")
# calls:foo
foo()
foo() # $ pt=foo
# calls:foo
indirect_foo()
indirect_foo() # $ pt=foo
# calls:bar
bar()
bar() # $ pt=bar
# calls:lam
lam()
lam() # $ pt=lambda[simple.py:15:7]
# python -m trace --trackcalls simple.py

View File

@@ -18,11 +18,11 @@ def _ignored():
def _works_since_called():
print('_works_since_called')
# calls:some_function
some_function()
some_function() # $ pt=some_function
def works_even_though_not_called():
# calls:some_function
some_function()
some_function() # $ pt=some_function
globals()['_ignored']()
_works_since_called()
_works_since_called() # $ pt=_works_since_called