From 1ab83460268fcd0cfe1c1841b4aaa1ba1da7b273 Mon Sep 17 00:00:00 2001 From: Taus Date: Wed, 4 Jun 2025 14:40:07 +0000 Subject: [PATCH 1/2] Python: Support type annotations in call graph Adds support for tracking instances via type annotations. Also adds a convenience method to the newly added `Annotation` class, `getAnnotatedExpression`, that returns the expression that is annotated with the given type. For return annotations this is any value returned from the annotated function in question. Co-authored-by: Napalys Klicius --- python/ql/lib/semmle/python/Exprs.qll | 11 +++++++++++ .../python/dataflow/new/internal/DataFlowDispatch.qll | 5 +++++ 2 files changed, 16 insertions(+) diff --git a/python/ql/lib/semmle/python/Exprs.qll b/python/ql/lib/semmle/python/Exprs.qll index accc370481aa..9e00e4f794b3 100644 --- a/python/ql/lib/semmle/python/Exprs.qll +++ b/python/ql/lib/semmle/python/Exprs.qll @@ -762,6 +762,17 @@ class Annotation extends Expr { or this = any(FunctionExpr f).getReturns() } + + /** Gets the expression that this annotation annotates. */ + Expr getAnnotatedExpression() { + result = any(AnnAssign a | a.getAnnotation() = this).getTarget() + or + result = any(Parameter p | p.getAnnotation() = this) + or + exists(FunctionExpr f | + this = f.getReturns() and result = f.getInnerScope().getReturnNode().getNode() + ) + } } /* Expression Contexts */ diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll index 1a38593bce48..781023a9658b 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll @@ -580,6 +580,11 @@ private module TrackClassInstanceInput implements CallGraphConstruction::Simple: class State = Class; predicate start(Node start, Class cls) { + exists(Annotation ann | + ann = classTracker(cls).asExpr() and + start.asExpr() = ann.getAnnotatedExpression() + ) + or resolveClassCall(start.(CallCfgNode).asCfgNode(), cls) or // result of `super().__new__` as used in a `__new__` method implementation From 5378f25ab460fe40bd840da8499d096f2c04c662 Mon Sep 17 00:00:00 2001 From: Taus Date: Wed, 4 Jun 2025 14:44:32 +0000 Subject: [PATCH 2/2] Python: Add change note Co-authored-by: Napalys Klicius --- .../change-notes/2025-06-04-call-graph-type-annotations.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 python/ql/lib/change-notes/2025-06-04-call-graph-type-annotations.md diff --git a/python/ql/lib/change-notes/2025-06-04-call-graph-type-annotations.md b/python/ql/lib/change-notes/2025-06-04-call-graph-type-annotations.md new file mode 100644 index 000000000000..2aa17e576326 --- /dev/null +++ b/python/ql/lib/change-notes/2025-06-04-call-graph-type-annotations.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* Type annotations such as `foo : Bar` are now treated by the call graph as an indication that `foo` may be an instance of `Bar`.