Python: deprecate AstNode.getAFlowNode() and rewrite internal callers

Preparatory refactor for the shared-CFG dataflow migration.

Deprecates the AstNode.getAFlowNode() cached predicate on the public
Python QL API and rewrites all ~140 internal callers across lib/, src/,
test/, and tools/ from `expr.getAFlowNode() = cfgNode` to
`cfgNode.getNode() = expr`, using ControlFlowNode.getNode() which
already exists in Flow.qll.

The predicate itself is preserved (with a deprecation note pointing at
the new pattern) so external users do not experience churn — they can
migrate at their own pace and the AST/CFG hierarchies still get the
intended untangling once the deprecation eventually elapses.

Semantic noop verified by:
- All 361 lib/ + src/ queries compile clean.
- All 122 ControlFlow + PointsTo library-tests pass.
- All 64 dataflow library-tests pass.
- All 113 Variables/Exceptions/Expressions/Statements/Functions/Imports/
  Security/CWE-798/ModificationOfParameterWithDefault query-tests pass.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
Copilot
2026-06-01 10:53:39 +00:00
committed by yoff
parent 8179bffe64
commit 717ff62d70
68 changed files with 273 additions and 181 deletions

View File

@@ -25,7 +25,7 @@ from
For loop, ControlFlowNodeWithPointsTo iter, Value str, Value seq, ControlFlowNode seq_origin,
ControlFlowNode str_origin
where
loop.getIter().getAFlowNode() = iter and
iter.getNode() = loop.getIter() and
iter.pointsTo(str, str_origin) and
iter.pointsTo(seq, seq_origin) and
has_string_type(str) and

View File

@@ -15,7 +15,7 @@
import python
predicate loop_variable_ssa(For f, Variable v, SsaVariable s) {
f.getTarget().getAFlowNode() = s.getDefinition() and v = s.getVariable()
s.getDefinition().getNode() = f.getTarget() and v = s.getVariable()
}
predicate variableUsedInNestedLoops(For inner, For outer, Variable v, Name n) {

View File

@@ -16,7 +16,7 @@ private import LegacyPointsTo
from For loop, ControlFlowNodeWithPointsTo iter, Value v, ClassValue t, ControlFlowNode origin
where
loop.getIter().getAFlowNode() = iter and
iter.getNode() = loop.getIter() and
iter.pointsTo(_, v, origin) and
v.getClass() = t and
not t.isIterable() and

View File

@@ -24,11 +24,13 @@ predicate func_with_side_effects(Expr e) {
}
predicate call_with_side_effect(Call e) {
e.getAFlowNode() =
API::moduleImport("subprocess")
.getMember(["call", "check_call", "check_output"])
.getACall()
.asCfgNode()
exists(ControlFlowNode eCfg | eCfg.getNode() = e |
eCfg =
API::moduleImport("subprocess")
.getMember(["call", "check_call", "check_output"])
.getACall()
.asCfgNode()
)
}
predicate probable_side_effect(Expr e) {