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 7a3f546587
commit db1e5035b4
68 changed files with 274 additions and 198 deletions

View File

@@ -48,9 +48,11 @@ class CheckClass extends ClassObject {
self_dict = sub.getObject()
or
/* Indirect assignment via temporary variable */
exists(SsaVariable v |
v.getAUse() = sub.getObject().getAFlowNode() and
v.getDefinition().(DefinitionNode).getValue() = self_dict.getAFlowNode()
exists(SsaVariable v, ControlFlowNode subObjCfg, ControlFlowNode selfDictCfg |
subObjCfg.getNode() = sub.getObject() and selfDictCfg.getNode() = self_dict
|
v.getAUse() = subObjCfg and
v.getDefinition().(DefinitionNode).getValue() = selfDictCfg
)
) and
a.getATarget() = sub and
@@ -62,9 +64,10 @@ class CheckClass extends ClassObject {
pragma[nomagic]
private predicate monkeyPatched(string name) {
exists(Attribute a |
exists(Attribute a, ControlFlowNode objCfg |
objCfg.getNode() = a.getObject() and
a.getCtx() instanceof Store and
PointsTo::points_to(a.getObject().getAFlowNode(), _, this, _, _) and
PointsTo::points_to(objCfg, _, this, _, _) and
a.getName() = name
)
}
@@ -84,9 +87,9 @@ class CheckClass extends ClassObject {
}
predicate interestingUndefined(SelfAttributeRead a) {
exists(string name | name = a.getName() |
exists(string name, ControlFlowNode aCfg | name = a.getName() and aCfg.getNode() = a |
this.interestingContext(a, name) and
not this.definedInBlock(a.getAFlowNode().getBasicBlock(), name)
not this.definedInBlock(aCfg.getBasicBlock(), name)
)
}
@@ -109,8 +112,9 @@ class CheckClass extends ClassObject {
pragma[nomagic]
private predicate definitionInBlock(BasicBlock b, string name) {
exists(SelfAttributeStore sa |
sa.getAFlowNode().getBasicBlock() = b and
exists(SelfAttributeStore sa, ControlFlowNode saCfg |
saCfg.getNode() = sa and
saCfg.getBasicBlock() = b and
sa.getName() = name and
sa.getClass() = this.getPyClass()
)