diff --git a/python/ql/test/experimental/library-tests/CallGraph/CallGraphTest.qll b/python/ql/test/experimental/library-tests/CallGraph/CallGraphTest.qll index 595a297d2e7..268acca608a 100644 --- a/python/ql/test/experimental/library-tests/CallGraph/CallGraphTest.qll +++ b/python/ql/test/experimental/library-tests/CallGraph/CallGraphTest.qll @@ -2,22 +2,22 @@ import python /** Gets the comment on the line above `ast` */ Comment commentFor(AstNode ast) { - exists(int line | line = ast.getLocation().getStartLine() - 1 | - result - .getLocation() - .hasLocationInfo(ast.getLocation().getFile().getAbsolutePath(), line, _, line, _) - ) + exists(int line | line = ast.getLocation().getStartLine() - 1 | + result + .getLocation() + .hasLocationInfo(ast.getLocation().getFile().getAbsolutePath(), line, _, line, _) + ) } /** Gets the value from `tag:value` in the comment for `ast` */ string getAnnotation(AstNode ast, string tag) { - exists(Comment comment, string match, string theRegex | - theRegex = "([\\w]+):([\\w.]+)" and - comment = commentFor(ast) and - match = comment.getText().regexpFind(theRegex, _, _) and - tag = match.regexpCapture(theRegex, 1) and - result = match.regexpCapture(theRegex, 2) - ) + exists(Comment comment, string match, string theRegex | + theRegex = "([\\w]+):([\\w.]+)" and + comment = commentFor(ast) and + match = comment.getText().regexpFind(theRegex, _, _) and + tag = match.regexpCapture(theRegex, 1) and + result = match.regexpCapture(theRegex, 2) + ) } /** Gets a callable annotated with `name:name` */ @@ -27,121 +27,121 @@ Function annotatedCallable(string name) { name = getAnnotation(result, "name") } Call annotatedCall(string name) { name = getAnnotation(result, "calls") } predicate missingAnnotationForCallable(string name, Call call) { - call = annotatedCall(name) and - not exists(annotatedCallable(name)) + call = annotatedCall(name) and + not exists(annotatedCallable(name)) } predicate nonUniqueAnnotationForCallable(string name, Function callable) { - strictcount(annotatedCallable(name)) > 1 and - callable = annotatedCallable(name) + strictcount(annotatedCallable(name)) > 1 and + callable = annotatedCallable(name) } predicate missingAnnotationForCall(string name, Function callable) { - not exists(annotatedCall(name)) and - callable = annotatedCallable(name) + not exists(annotatedCall(name)) and + callable = annotatedCallable(name) } /** There is an obvious problem with the annotation `name` */ predicate nameInErrorState(string name) { - missingAnnotationForCallable(name, _) - or - nonUniqueAnnotationForCallable(name, _) - or - missingAnnotationForCall(name, _) + missingAnnotationForCallable(name, _) + or + nonUniqueAnnotationForCallable(name, _) + or + missingAnnotationForCall(name, _) } /** Source code has annotation with `name` showing that `call` will call `callable` */ predicate annotatedCallEdge(string name, Call call, Function callable) { - not nameInErrorState(name) and - call = annotatedCall(name) and - callable = annotatedCallable(name) + not nameInErrorState(name) and + call = annotatedCall(name) and + callable = annotatedCallable(name) } // ------------------------- Annotation debug query predicates ------------------------- query predicate debug_missingAnnotationForCallable(Call call, string message) { - exists(string name | - message = - "This call is annotated with '" + name + - "', but no callable with that annotation was extracted. Please fix." and - missingAnnotationForCallable(name, call) - ) + exists(string name | + message = + "This call is annotated with '" + name + + "', but no callable with that annotation was extracted. Please fix." and + missingAnnotationForCallable(name, call) + ) } query predicate debug_nonUniqueAnnotationForCallable(Function callable, string message) { - exists(string name | - message = "Multiple callables are annotated with '" + name + "'. Please fix." and - nonUniqueAnnotationForCallable(name, callable) - ) + exists(string name | + message = "Multiple callables are annotated with '" + name + "'. Please fix." and + nonUniqueAnnotationForCallable(name, callable) + ) } query predicate debug_missingAnnotationForCall(Function callable, string message) { - exists(string name | - message = - "This callable is annotated with '" + name + - "', but no call with that annotation was extracted. Please fix." and - missingAnnotationForCall(name, callable) - ) + exists(string name | + message = + "This callable is annotated with '" + name + + "', but no call with that annotation was extracted. Please fix." and + missingAnnotationForCall(name, callable) + ) } // ------------------------- Call Graph resolution ------------------------- private newtype TCallGraphResolver = - TPointsToResolver() or - TTypeTrackerResolver() + TPointsToResolver() or + TTypeTrackerResolver() /** Describes a method of call graph resolution */ abstract class CallGraphResolver extends TCallGraphResolver { - abstract predicate callEdge(Call call, Function callable); + abstract predicate callEdge(Call call, Function callable); - /** - * Holds if annotations show that `call` will call `callable`, - * but our call graph resolver was not able to figure that out - */ - predicate expectedCallEdgeNotFound(Call call, Function callable) { - annotatedCallEdge(_, call, callable) and - not this.callEdge(call, callable) - } + /** + * Holds if annotations show that `call` will call `callable`, + * but our call graph resolver was not able to figure that out + */ + predicate expectedCallEdgeNotFound(Call call, Function callable) { + annotatedCallEdge(_, call, callable) and + not this.callEdge(call, callable) + } - /** - * Holds if there are no annotations that show that `call` will call `callable` (where at least one of these are annotated), - * but the call graph resolver claims that `call` will call `callable` - */ - predicate unexpectedCallEdgeFound(Call call, Function callable, string message) { - this.callEdge(call, callable) and - not annotatedCallEdge(_, call, callable) and - ( - exists(string name | - message = "Call resolved to the callable named '" + name + "' but was not annotated as such" and - callable = annotatedCallable(name) and - not nameInErrorState(name) - ) - or - exists(string name | - message = "Annotated call resolved to unannotated callable" and - call = annotatedCall(name) and - not nameInErrorState(name) and - not exists( | callable = annotatedCallable(_)) - ) - ) - } + /** + * Holds if there are no annotations that show that `call` will call `callable` (where at least one of these are annotated), + * but the call graph resolver claims that `call` will call `callable` + */ + predicate unexpectedCallEdgeFound(Call call, Function callable, string message) { + this.callEdge(call, callable) and + not annotatedCallEdge(_, call, callable) and + ( + exists(string name | + message = "Call resolved to the callable named '" + name + "' but was not annotated as such" and + callable = annotatedCallable(name) and + not nameInErrorState(name) + ) + or + exists(string name | + message = "Annotated call resolved to unannotated callable" and + call = annotatedCall(name) and + not nameInErrorState(name) and + not exists( | callable = annotatedCallable(_)) + ) + ) + } - string toString() { result = "CallGraphResolver" } + string toString() { result = "CallGraphResolver" } } /** A call graph resolver based on the existing points-to analysis */ class PointsToResolver extends CallGraphResolver, TPointsToResolver { - override predicate callEdge(Call call, Function callable) { - exists(PythonFunctionValue funcValue | - funcValue.getScope() = callable and - call = funcValue.getACall().getNode() - ) - } + override predicate callEdge(Call call, Function callable) { + exists(PythonFunctionValue funcValue | + funcValue.getScope() = callable and + call = funcValue.getACall().getNode() + ) + } - override string toString() { result = "PointsToResolver" } + override string toString() { result = "PointsToResolver" } } /** A call graph resolved based on Type Trackers */ class TypeTrackerResolver extends CallGraphResolver, TTypeTrackerResolver { - override predicate callEdge(Call call, Function callable) { none() } + override predicate callEdge(Call call, Function callable) { none() } - override string toString() { result = "TypeTrackerResolver" } + override string toString() { result = "TypeTrackerResolver" } } diff --git a/python/ql/test/experimental/library-tests/CallGraph/PointsTo.ql b/python/ql/test/experimental/library-tests/CallGraph/PointsTo.ql index 180135385c1..f86842f2fe4 100644 --- a/python/ql/test/experimental/library-tests/CallGraph/PointsTo.ql +++ b/python/ql/test/experimental/library-tests/CallGraph/PointsTo.ql @@ -2,9 +2,9 @@ import python import CallGraphTest query predicate expectedCallEdgeNotFound(Call call, Function callable) { - any(PointsToResolver r).expectedCallEdgeNotFound(call, callable) + any(PointsToResolver r).expectedCallEdgeNotFound(call, callable) } query predicate unexpectedCallEdgeFound(Call call, Function callable, string message) { - any(PointsToResolver r).unexpectedCallEdgeFound(call, callable, message) + any(PointsToResolver r).unexpectedCallEdgeFound(call, callable, message) } diff --git a/python/ql/test/experimental/library-tests/CallGraph/Relative.ql b/python/ql/test/experimental/library-tests/CallGraph/Relative.ql index ba1b17e7d24..f62e4d21cbd 100644 --- a/python/ql/test/experimental/library-tests/CallGraph/Relative.ql +++ b/python/ql/test/experimental/library-tests/CallGraph/Relative.ql @@ -1,15 +1,14 @@ import python - import CallGraphTest query predicate pointsTo_found_typeTracker_notFound(Call call, Function callable) { - annotatedCallEdge(_, call, callable) and - any(PointsToResolver r).callEdge(call, callable) and - not any(TypeTrackerResolver r).callEdge(call, callable) + annotatedCallEdge(_, call, callable) and + any(PointsToResolver r).callEdge(call, callable) and + not any(TypeTrackerResolver r).callEdge(call, callable) } query predicate pointsTo_notFound_typeTracker_found(Call call, Function callable) { - annotatedCallEdge(_, call, callable) and - not any(PointsToResolver r).callEdge(call, callable) and - any(TypeTrackerResolver r).callEdge(call, callable) + annotatedCallEdge(_, call, callable) and + not any(PointsToResolver r).callEdge(call, callable) and + any(TypeTrackerResolver r).callEdge(call, callable) } diff --git a/python/ql/test/experimental/library-tests/CallGraph/TypeTracker.ql b/python/ql/test/experimental/library-tests/CallGraph/TypeTracker.ql index f1fe0398a7e..a62332e3839 100644 --- a/python/ql/test/experimental/library-tests/CallGraph/TypeTracker.ql +++ b/python/ql/test/experimental/library-tests/CallGraph/TypeTracker.ql @@ -2,9 +2,9 @@ import python import CallGraphTest query predicate expectedCallEdgeNotFound(Call call, Function callable) { - any(TypeTrackerResolver r).expectedCallEdgeNotFound(call, callable) + any(TypeTrackerResolver r).expectedCallEdgeNotFound(call, callable) } query predicate unexpectedCallEdgeFound(Call call, Function callable, string message) { - any(TypeTrackerResolver r).unexpectedCallEdgeFound(call, callable, message) + any(TypeTrackerResolver r).unexpectedCallEdgeFound(call, callable, message) } diff --git a/python/ql/test/experimental/library-tests/CallGraph/code/__init__.py b/python/ql/test/experimental/library-tests/CallGraph/code/__init__.py new file mode 100644 index 00000000000..e69de29bb2d