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

@@ -213,9 +213,11 @@ class ExprWithPointsTo extends Expr {
* Gets what this expression might "refer-to" in the given `context`.
*/
predicate refersTo(Context context, Object obj, ClassObject cls, AstNode origin) {
this.getAFlowNode()
.(ControlFlowNodeWithPointsTo)
.refersTo(context, obj, cls, origin.getAFlowNode())
exists(ControlFlowNode this_, ControlFlowNode origin_ |
this_.getNode() = this and origin_.getNode() = origin
|
this_.(ControlFlowNodeWithPointsTo).refersTo(context, obj, cls, origin_)
)
}
/**
@@ -226,7 +228,11 @@ class ExprWithPointsTo extends Expr {
*/
pragma[nomagic]
predicate refersTo(Object obj, AstNode origin) {
this.getAFlowNode().(ControlFlowNodeWithPointsTo).refersTo(obj, origin.getAFlowNode())
exists(ControlFlowNode this_, ControlFlowNode origin_ |
this_.getNode() = this and origin_.getNode() = origin
|
this_.(ControlFlowNodeWithPointsTo).refersTo(obj, origin_)
)
}
/**
@@ -240,16 +246,22 @@ class ExprWithPointsTo extends Expr {
* in the given `context`.
*/
predicate pointsTo(Context context, Value value, AstNode origin) {
this.getAFlowNode()
.(ControlFlowNodeWithPointsTo)
.pointsTo(context, value, origin.getAFlowNode())
exists(ControlFlowNode this_, ControlFlowNode origin_ |
this_.getNode() = this and origin_.getNode() = origin
|
this_.(ControlFlowNodeWithPointsTo).pointsTo(context, value, origin_)
)
}
/**
* Holds if this expression might "point-to" to `value` which is from `origin`.
*/
predicate pointsTo(Value value, AstNode origin) {
this.getAFlowNode().(ControlFlowNodeWithPointsTo).pointsTo(value, origin.getAFlowNode())
exists(ControlFlowNode this_, ControlFlowNode origin_ |
this_.getNode() = this and origin_.getNode() = origin
|
this_.(ControlFlowNodeWithPointsTo).pointsTo(value, origin_)
)
}
/**
@@ -475,7 +487,10 @@ class FunctionMetricsWithPointsTo extends FunctionMetrics {
not non_coupling_method(result) and
exists(Call call | call.getScope() = this |
exists(FunctionObject callee | callee.getFunction() = result |
call.getAFlowNode().getFunction().(ControlFlowNodeWithPointsTo).refersTo(callee)
exists(CallNode call_ |
call_.getNode() = call and
call_.getFunction().(ControlFlowNodeWithPointsTo).refersTo(callee)
)
)
or
exists(Attribute a | call.getFunc() = a |

View File

@@ -64,7 +64,7 @@ private predicate jump_to_defn(ControlFlowNode use, Definition defn) {
private predicate preferred_jump_to_defn(Expr use, Definition def) {
not use instanceof ClassExpr and
not use instanceof FunctionExpr and
jump_to_defn(use.getAFlowNode(), def)
exists(ControlFlowNode useNode | useNode.getNode() = use | jump_to_defn(useNode, def))
}
private predicate unique_jump_to_defn(Expr use, Definition def) {
@@ -452,7 +452,7 @@ private predicate self_parameter_jump_to_defn_attribute(
* This exists primarily for testing use `getPreferredDefinition()` instead.
*/
Definition getADefinition(Expr use) {
jump_to_defn(use.getAFlowNode(), result) and
exists(ControlFlowNode useNode | useNode.getNode() = use | jump_to_defn(useNode, result)) and
not use instanceof Call and
not use.isArtificial() and
// Not the use itself

View File

@@ -0,0 +1,5 @@
---
category: deprecated
---
* The `AstNode.getAFlowNode()` predicate has been deprecated. Use `ControlFlowNode.getNode()` from the other direction instead: replace `e.getAFlowNode() = n` with `n.getNode() = e`. This is a preparatory step towards migrating the dataflow library off the legacy CFG; it has no semantic effect.

View File

@@ -17,12 +17,17 @@ abstract class AstNode extends AstNode_ {
abstract Scope getScope();
/**
* DEPRECATED: use `ControlFlowNode.getNode()` from the other direction instead;
* that is, replace `e.getAFlowNode() = n` with `n.getNode() = e`. This API is
* being removed to untangle the AST and CFG hierarchies in preparation for
* migrating the dataflow library off the legacy CFG.
*
* Gets a flow node corresponding directly to this node.
* NOTE: For some statements and other purely syntactic elements,
* there may not be a `ControlFlowNode`
* there may not be a `ControlFlowNode`.
*/
cached
ControlFlowNode getAFlowNode() {
deprecated ControlFlowNode getAFlowNode() {
Stages::AST::ref() and
py_flow_bb_node(result, this, _, _)
}

View File

@@ -28,7 +28,9 @@ class Expr extends Expr_, AstNode {
/** Whether this expression may have a side effect (as determined purely from its syntax) */
predicate hasSideEffects() {
/* If an exception raised by this expression handled, count that as a side effect */
this.getAFlowNode().getASuccessor().getNode() instanceof ExceptStmt
exists(ControlFlowNode n | n.getNode() = this |
n.getASuccessor().getNode() instanceof ExceptStmt
)
or
this.getASubExpression().hasSideEffects()
}
@@ -68,7 +70,7 @@ class Attribute extends Attribute_ {
/* syntax: Expr.name */
override Expr getASubExpression() { result = this.getObject() }
override AttrNode getAFlowNode() { result = super.getAFlowNode() }
deprecated override AttrNode getAFlowNode() { result = super.getAFlowNode() }
/** Gets the name of this attribute. That is the `name` in `obj.name` */
string getName() { result = Attribute_.super.getAttr() }
@@ -97,7 +99,7 @@ class Subscript extends Subscript_ {
Expr getObject() { result = Subscript_.super.getValue() }
override SubscriptNode getAFlowNode() { result = super.getAFlowNode() }
deprecated override SubscriptNode getAFlowNode() { result = super.getAFlowNode() }
}
/** A call expression, such as `func(...)` */
@@ -113,7 +115,7 @@ class Call extends Call_ {
override string toString() { result = this.getFunc().toString() + "()" }
override CallNode getAFlowNode() { result = super.getAFlowNode() }
deprecated override CallNode getAFlowNode() { result = super.getAFlowNode() }
/** Gets a tuple (*) argument of this call. */
Expr getStarargs() { result = this.getAPositionalArg().(Starred).getValue() }
@@ -201,7 +203,7 @@ class IfExp extends IfExp_ {
result = this.getTest() or result = this.getBody() or result = this.getOrelse()
}
override IfExprNode getAFlowNode() { result = super.getAFlowNode() }
deprecated override IfExprNode getAFlowNode() { result = super.getAFlowNode() }
}
/** A starred expression, such as the `*rest` in the assignment `first, *rest = seq` */
@@ -411,7 +413,7 @@ class PlaceHolder extends PlaceHolder_ {
override string toString() { result = "$" + this.getId() }
override NameNode getAFlowNode() { result = super.getAFlowNode() }
deprecated override NameNode getAFlowNode() { result = super.getAFlowNode() }
}
/** A tuple expression such as `( 1, 3, 5, 7, 9 )` */
@@ -478,7 +480,7 @@ class Name extends Name_ {
override string toString() { result = this.getId() }
override NameNode getAFlowNode() { result = super.getAFlowNode() }
deprecated override NameNode getAFlowNode() { result = super.getAFlowNode() }
override predicate isArtificial() {
/* Artificial variable names in comprehensions all start with "." */
@@ -585,7 +587,7 @@ abstract class NameConstant extends Name, ImmutableLiteral {
override predicate isConstant() { any() }
override NameConstantNode getAFlowNode() { result = Name.super.getAFlowNode() }
deprecated override NameConstantNode getAFlowNode() { result = Name.super.getAFlowNode() }
override predicate isArtificial() { none() }
}

View File

@@ -555,27 +555,27 @@ class DefinitionNode extends ControlFlowNode {
cached
DefinitionNode() {
Stages::AST::ref() and
exists(Assign a | a.getATarget().getAFlowNode() = this)
exists(Assign a | this.getNode() = a.getATarget())
or
exists(AssignExpr a | a.getTarget().getAFlowNode() = this)
exists(AssignExpr a | this.getNode() = a.getTarget())
or
exists(AnnAssign a | a.getTarget().getAFlowNode() = this and exists(a.getValue()))
exists(AnnAssign a | this.getNode() = a.getTarget() and exists(a.getValue()))
or
exists(Alias a | a.getAsname().getAFlowNode() = this)
exists(Alias a | this.getNode() = a.getAsname())
or
augstore(_, this)
or
// `x, y = 1, 2` where LHS is a combination of list or tuples
exists(Assign a | list_or_tuple_nested_element(a.getATarget()).getAFlowNode() = this)
exists(Assign a | this.getNode() = list_or_tuple_nested_element(a.getATarget()))
or
exists(For for | for.getTarget().getAFlowNode() = this)
exists(For for | this.getNode() = for.getTarget())
or
exists(Parameter param | this = param.asName().getAFlowNode() and exists(param.getDefault()))
exists(Parameter param | this.getNode() = param.asName() and exists(param.getDefault()))
}
/** flow node corresponding to the value assigned for the definition corresponding to this flow node */
ControlFlowNode getValue() {
result = assigned_value(this.getNode()).getAFlowNode() and
result.getNode() = assigned_value(this.getNode()) and
(
result.getBasicBlock().dominates(this.getBasicBlock())
or
@@ -584,7 +584,7 @@ class DefinitionNode extends ControlFlowNode {
// since the default value for a parameter is evaluated in the same basic block as
// the function definition, but the parameter belongs to the basic block of the function,
// there is no dominance relationship between the two.
exists(Parameter param | this = param.asName().getAFlowNode())
exists(Parameter param | this.getNode() = param.asName())
)
}
}
@@ -901,7 +901,7 @@ class ExceptFlowNode extends ControlFlowNode {
exists(ExceptStmt ex |
this.getBasicBlock().dominates(result.getBasicBlock()) and
ex = this.getNode() and
result = ex.getType().getAFlowNode()
result.getNode() = ex.getType()
)
}
@@ -913,7 +913,7 @@ class ExceptFlowNode extends ControlFlowNode {
exists(ExceptStmt ex |
this.getBasicBlock().dominates(result.getBasicBlock()) and
ex = this.getNode() and
result = ex.getName().getAFlowNode()
result.getNode() = ex.getName()
)
}
}
@@ -928,7 +928,7 @@ class ExceptGroupFlowNode extends ControlFlowNode {
*/
ControlFlowNode getType() {
this.getBasicBlock().dominates(result.getBasicBlock()) and
result = this.getNode().(ExceptGroupStmt).getType().getAFlowNode()
result.getNode() = this.getNode().(ExceptGroupStmt).getType()
}
/**
@@ -937,7 +937,7 @@ class ExceptGroupFlowNode extends ControlFlowNode {
*/
ControlFlowNode getName() {
this.getBasicBlock().dominates(result.getBasicBlock()) and
result = this.getNode().(ExceptGroupStmt).getName().getAFlowNode()
result.getNode() = this.getNode().(ExceptGroupStmt).getName()
}
}

View File

@@ -163,7 +163,7 @@ class ImportMember extends ImportMember_ {
result = this.getModule().(ImportExpr).getImportedModuleName() + "." + this.getName()
}
override ImportMemberNode getAFlowNode() { result = super.getAFlowNode() }
deprecated override ImportMemberNode getAFlowNode() { result = super.getAFlowNode() }
}
/** An import statement */

View File

@@ -46,20 +46,23 @@ class SelfAttributeRead extends SelfAttribute {
}
predicate guardedByHasattr() {
exists(Variable var, ControlFlowNode n |
var.getAUse() = this.getObject().getAFlowNode() and
exists(Variable var, ControlFlowNode n, ControlFlowNode this_, ControlFlowNode obj_ |
this_.getNode() = this and obj_.getNode() = this.getObject()
|
var.getAUse() = obj_ and
hasattr(n, var.getAUse(), this.getName()) and
n.strictlyDominates(this.getAFlowNode())
n.strictlyDominates(this_)
)
}
pragma[noinline]
predicate locallyDefined() {
exists(SelfAttributeStore store |
this.getName() = store.getName() and
this.getScope() = store.getScope()
exists(SelfAttributeStore store, ControlFlowNode store_, ControlFlowNode this_ |
store_.getNode() = store and this_.getNode() = this
|
store.getAFlowNode().strictlyDominates(this.getAFlowNode())
this.getName() = store.getName() and
this.getScope() = store.getScope() and
store_.strictlyDominates(this_)
)
}
}

View File

@@ -5,24 +5,30 @@ private import semmle.python.dataflow.new.DataFlow
private predicate constCompare(DataFlow::GuardNode g, ControlFlowNode node, boolean branch) {
exists(CompareNode cn | cn = g |
exists(ImmutableLiteral const, Cmpop op |
op = any(Eq eq) and branch = true
or
op = any(NotEq ne) and branch = false
exists(ImmutableLiteral const, Cmpop op, ControlFlowNode c |
c.getNode() = const and
(
op = any(Eq eq) and branch = true
or
op = any(NotEq ne) and branch = false
)
|
cn.operands(const.getAFlowNode(), op, node)
cn.operands(c, op, node)
or
cn.operands(node, op, const.getAFlowNode())
cn.operands(node, op, c)
)
or
exists(NameConstant const, Cmpop op |
op = any(Is is_) and branch = true
or
op = any(IsNot isn) and branch = false
exists(NameConstant const, Cmpop op, ControlFlowNode c |
c.getNode() = const and
(
op = any(Is is_) and branch = true
or
op = any(IsNot isn) and branch = false
)
|
cn.operands(const.getAFlowNode(), op, node)
cn.operands(c, op, node)
or
cn.operands(node, op, const.getAFlowNode())
cn.operands(node, op, c)
)
or
exists(IterableNode const_iterable, Cmpop op |

View File

@@ -228,7 +228,7 @@ private class ClassDefinitionAsAttrWrite extends AttrWrite, CfgNode {
override Node getValue() { result.asCfgNode() = node.getValue() }
override Node getObject() { result.asCfgNode() = cls.getAFlowNode() }
override Node getObject() { result.asCfgNode().getNode() = cls }
override ExprNode getAttributeNameExpr() { none() }

View File

@@ -1913,8 +1913,8 @@ abstract class ReturnNode extends Node {
class ExtractedReturnNode extends ReturnNode, CfgNode {
// See `TaintTrackingImplementation::returnFlowStep`
ExtractedReturnNode() {
node = any(Return ret).getValue().getAFlowNode() or
node = any(Yield yield).getAFlowNode()
node.getNode() = any(Return ret).getValue() or
node.getNode() = any(Yield yield)
}
override ReturnKind getKind() { any() }
@@ -1932,7 +1932,7 @@ class ExtractedReturnNode extends ReturnNode, CfgNode {
class YieldNodeInContextManagerFunction extends ReturnNode, CfgNode {
YieldNodeInContextManagerFunction() {
hasContextmanagerDecorator(node.getScope()) and
node = any(Yield yield).getValue().getAFlowNode()
node.getNode() = any(Yield yield).getValue()
}
override ReturnKind getKind() { any() }

View File

@@ -185,8 +185,8 @@ private predicate synthDictSplatArgumentNodeStoreStep(
*/
predicate yieldStoreStep(Node nodeFrom, Content c, Node nodeTo) {
exists(Yield yield |
nodeTo.asCfgNode() = yield.getAFlowNode() and
nodeFrom.asCfgNode() = yield.getValue().getAFlowNode() and
nodeTo.asCfgNode().getNode() = yield and
nodeFrom.asCfgNode().getNode() = yield.getValue() and
// TODO: Consider if this will also need to transfer dictionary content
// once dictionary comprehensions are supported.
c instanceof ListElementContent

View File

@@ -485,7 +485,7 @@ class ModuleVariableNode extends Node, TModuleVariableNode {
/** Gets a node that reads this variable, excluding reads that happen through `from ... import *`. */
Node getALocalRead() {
result.asCfgNode() = var.getALoad().getAFlowNode() and
result.asCfgNode().getNode() = var.getALoad() and
not result.getScope() = mod
}

View File

@@ -61,7 +61,7 @@ private module CaptureInput implements Shared::InputSig<Location, Cfg::BasicBloc
class VariableWrite extends ControlFlowNode {
CapturedVariable v;
VariableWrite() { this = v.getAStore().getAFlowNode().(DefinitionNode).getValue() }
VariableWrite() { exists(DefinitionNode d | d.getNode() = v.getAStore() | this = d.getValue()) }
CapturedVariable getVariable() { result = v }
@@ -71,7 +71,7 @@ private module CaptureInput implements Shared::InputSig<Location, Cfg::BasicBloc
class VariableRead extends Expr {
CapturedVariable v;
VariableRead() { this = v.getALoad().getAFlowNode() }
VariableRead() { this.getNode() = v.getALoad() }
CapturedVariable getVariable() { result = v }
}

View File

@@ -448,8 +448,7 @@ class TaintTrackingImplementation extends string instanceof TaintTracking::Confi
context = TNoParam() and
src = TTaintTrackingNode_(retval, TNoParam(), path, kind, this) and
node.asCfgNode() = call and
retval.asCfgNode() =
any(Return ret | ret.getScope() = pyfunc.getScope()).getValue().getAFlowNode()
retval.asCfgNode().getNode() = any(Return ret | ret.getScope() = pyfunc.getScope()).getValue()
) and
edgeLabel = "return"
}
@@ -471,8 +470,7 @@ class TaintTrackingImplementation extends string instanceof TaintTracking::Confi
this.callContexts(call, src, pyfunc, context, callee) and
retnode = TTaintTrackingNode_(retval, callee, path, kind, this) and
node.asCfgNode() = call and
retval.asCfgNode() =
any(Return ret | ret.getScope() = pyfunc.getScope()).getValue().getAFlowNode()
retval.asCfgNode().getNode() = any(Return ret | ret.getScope() = pyfunc.getScope()).getValue()
) and
edgeLabel = "call"
}
@@ -716,8 +714,10 @@ private class EssaTaintTracking extends string instanceof TaintTracking::Configu
src = TTaintTrackingNode_(srcnode, context, path, srckind, this) and
path.noAttribute()
|
assign.getValue().getAFlowNode() = srcnode.asCfgNode() and
depth = iterable_unpacking_descent(assign.getATarget().getAFlowNode(), defn.getDefiningNode()) and
srcnode.asCfgNode().getNode() = assign.getValue() and
exists(SequenceNode left_parent | left_parent.getNode() = assign.getATarget() |
depth = iterable_unpacking_descent(left_parent, defn.getDefiningNode())
) and
kind = taint_at_depth(srckind, depth)
)
}
@@ -964,7 +964,7 @@ private TaintKind taint_at_depth(SequenceKind parent_kind, int depth) {
* - with `left_defn` = `*y`, `left_parent` = `((x, *y), ...)`, result = 1
*/
int iterable_unpacking_descent(SequenceNode left_parent, ControlFlowNode left_defn) {
exists(Assign a | a.getATarget().getASubExpression*().getAFlowNode() = left_parent) and
exists(Assign a | left_parent.getNode() = a.getATarget().getASubExpression*()) and
left_parent.getAnElement() = left_defn and
// Handle `a, *b = some_iterable`
if left_defn instanceof StarredNode then result = 0 else result = 1

View File

@@ -56,7 +56,7 @@ module SsaSource {
predicate with_definition(Variable v, ControlFlowNode defn) {
exists(With with, Name var |
with.getOptionalVars() = var and
var.getAFlowNode() = defn
defn.getNode() = var
|
var = v.getAStore()
)
@@ -67,7 +67,7 @@ module SsaSource {
predicate pattern_capture_definition(Variable v, ControlFlowNode defn) {
exists(MatchCapturePattern capture, Name var |
capture.getVariable() = var and
var.getAFlowNode() = defn
defn.getNode() = var
|
var = v.getAStore()
)
@@ -78,7 +78,7 @@ module SsaSource {
predicate pattern_alias_definition(Variable v, ControlFlowNode defn) {
exists(MatchAsPattern pattern, Name var |
pattern.getAlias() = var and
var.getAFlowNode() = defn
defn.getNode() = var
|
var = v.getAStore()
)

View File

@@ -59,7 +59,7 @@ module Bottle {
override Parameter getARoutedParameter() { none() }
override Function getARequestHandler() { result.getADecorator().getAFlowNode() = node }
override Function getARequestHandler() { node.getNode() = result.getADecorator() }
}
}

View File

@@ -129,7 +129,7 @@ module FastApi {
result in [this.getArg(0), this.getArgByName("path")]
}
override Function getARequestHandler() { result.getADecorator().getAFlowNode() = node }
override Function getARequestHandler() { node.getNode() = result.getADecorator() }
override string getFramework() { result = "FastAPI" }

View File

@@ -371,7 +371,7 @@ module Flask {
result in [this.getArg(0), this.getArgByName("rule")]
}
override Function getARequestHandler() { result.getADecorator().getAFlowNode() = node }
override Function getARequestHandler() { node.getNode() = result.getADecorator() }
}
/**
@@ -536,7 +536,7 @@ module Flask {
FlaskRouteHandlerReturn() {
exists(Function routeHandler |
routeHandler = any(FlaskRouteSetup rs).getARequestHandler() and
node = routeHandler.getAReturnValueFlowNode() and
exists(Return ret | ret.getScope() = routeHandler and node.getNode() = ret.getValue()) and
not this instanceof Flask::Response::InstanceSource
)
}

View File

@@ -38,7 +38,7 @@ private module FlaskAdmin {
result in [this.getArg(0), this.getArgByName("url")]
}
override Function getARequestHandler() { result.getADecorator().getAFlowNode() = node }
override Function getARequestHandler() { node.getNode() = result.getADecorator() }
}
/**
@@ -71,7 +71,7 @@ private module FlaskAdmin {
override Function getARequestHandler() {
exists(Flask::FlaskViewClass cls |
cls.getADecorator().getAFlowNode() = node and
node.getNode() = cls.getADecorator() and
result = cls.getARequestHandler()
)
}

View File

@@ -77,7 +77,7 @@ module Stages {
or
exists(any(AstExtended::AstNode n).getParentNode())
or
exists(any(AstExtended::AstNode n).getAFlowNode())
exists(PyFlow::ControlFlowNode cfg, AstExtended::AstNode n | cfg.getNode() = n)
or
exists(any(PyFlow::BasicBlock b).getImmediateDominator())
or

View File

@@ -56,8 +56,9 @@ abstract class CallableObjectInternal extends ObjectInternal {
/** A Python function. */
class PythonFunctionObjectInternal extends CallableObjectInternal, TPythonFunctionObject {
override Function getScope() {
exists(CallableExpr expr |
this = TPythonFunctionObject(expr.getAFlowNode()) and
exists(CallableExpr expr, ControlFlowNode exprCfg |
exprCfg.getNode() = expr and
this = TPythonFunctionObject(exprCfg) and
result = expr.getInnerScope()
)
}
@@ -160,10 +161,11 @@ class PythonFunctionObjectInternal extends CallableObjectInternal, TPythonFuncti
}
private BasicBlock blockReturningNone(Function func) {
exists(Return ret |
exists(Return ret, ControlFlowNode ret_ |
not exists(ret.getValue()) and
ret.getScope() = func and
result = ret.getAFlowNode().getBasicBlock()
ret_.getNode() = ret and
result = ret_.getBasicBlock()
)
}

View File

@@ -113,8 +113,9 @@ abstract class ClassObjectInternal extends ObjectInternal {
class PythonClassObjectInternal extends ClassObjectInternal, TPythonClassObject {
/** Gets the scope for this Python class */
Class getScope() {
exists(ClassExpr expr |
this = TPythonClassObject(expr.getAFlowNode()) and
exists(ClassExpr expr, ControlFlowNode exprCfg |
exprCfg.getNode() = expr and
this = TPythonClassObject(exprCfg) and
result = expr.getInnerScope()
)
}

View File

@@ -387,7 +387,7 @@ private PythonClassObjectInternal abcMetaClassObject() {
private predicate neither_class_nor_static_method(Function f) {
not exists(f.getADecorator())
or
exists(ControlFlowNode deco | deco = f.getADecorator().getAFlowNode() |
exists(ControlFlowNode deco | deco.getNode() = f.getADecorator() |
exists(ObjectInternal o | PointsToInternal::pointsTo(deco, _, o, _) |
o != ObjectInternal::staticMethod() and
o != ObjectInternal::classMethod()

View File

@@ -711,7 +711,7 @@ private module InterModulePointsTo {
ControlFlowNode f, PointsToContext context, ObjectInternal value, ControlFlowNode origin
) {
exists(string name, ImportExpr i |
i.getAFlowNode() = f and
f.getNode() = i and
i.getImportedModuleName() = name and
PointsToInternal::module_imported_as(value, name) and
origin = f and
@@ -2118,8 +2118,9 @@ module Types {
result.getBuiltin() = cls.getBuiltin().getBaseClass() and n = 0
or
exists(Class pycls | pycls = cls.(PythonClassObjectInternal).getScope() |
exists(ObjectInternal base |
PointsToInternal::pointsTo(pycls.getBase(n).getAFlowNode(), _, base, _)
exists(ObjectInternal base, ControlFlowNode baseNode |
baseNode.getNode() = pycls.getBase(n) and
PointsToInternal::pointsTo(baseNode, _, base, _)
|
result = base and base != ObjectInternal::unknown()
or
@@ -2223,7 +2224,10 @@ module Types {
}
private ControlFlowNode decorator_call_callee(PythonClassObjectInternal cls) {
result = cls.getScope().getADecorator().getAFlowNode().(CallNode).getFunction()
exists(CallNode deco |
deco.getNode() = cls.getScope().getADecorator() and
result = deco.getFunction()
)
}
private boolean has_six_add_metaclass(PythonClassObjectInternal cls) {
@@ -2262,7 +2266,7 @@ module Types {
}
private EssaVariable metaclass_var(Class cls) {
result.getASourceUse() = cls.getMetaClass().getAFlowNode()
result.getASourceUse().getNode() = cls.getMetaClass()
or
major_version() = 2 and
not exists(cls.getMetaClass()) and

View File

@@ -181,7 +181,7 @@ class ClassObject extends Object {
)
}
ControlFlowNode declaredMetaClass() { result = this.getPyClass().getMetaClass().getAFlowNode() }
ControlFlowNode declaredMetaClass() { result.getNode() = this.getPyClass().getMetaClass() }
/** Has type inference failed to compute the full class hierarchy for this class for the reason given. */
predicate failedInference(string reason) { Types::failedInference(this.theClass(), reason) }
@@ -195,8 +195,9 @@ class ClassObject extends Object {
* It is guaranteed that getProbableSingletonInstance() returns at most one Object for each ClassObject.
*/
Object getProbableSingletonInstance() {
exists(ControlFlowNodeWithPointsTo use, Expr origin |
use.refersTo(result, this, origin.getAFlowNode())
exists(ControlFlowNodeWithPointsTo use, Expr origin, ControlFlowNode origin_ |
origin_.getNode() = origin and
use.refersTo(result, this, origin_)
|
this.hasStaticallyUniqueInstance() and
/* Ensure that original expression will be executed only one. */

View File

@@ -427,7 +427,7 @@ class ExceptFlowNodeWithPointsTo extends ExceptFlowNode {
}
private ControlFlowNodeWithPointsTo element_from_tuple_objectapi(Object tuple) {
exists(Tuple t | t = tuple.getOrigin() and result = t.getAnElt().getAFlowNode())
exists(Tuple t | t = tuple.getOrigin() and result.getNode() = t.getAnElt())
}
/**

View File

@@ -36,8 +36,8 @@ class RangeIterationVariableFact extends PointsToExtension {
RangeIterationVariableFact() {
exists(For f, ControlFlowNode iterable |
iterable.getBasicBlock().dominates(this.(ControlFlowNode).getBasicBlock()) and
f.getIter().getAFlowNode() = iterable and
f.getTarget().getAFlowNode() = this and
iterable.getNode() = f.getIter() and
this.(ControlFlowNode).getNode() = f.getTarget() and
exists(ObjectInternal range |
PointsTo::pointsTo(iterable, _, range, _) and
range.getClass() = ObjectInternal::builtin("range")

View File

@@ -170,7 +170,7 @@ class PyFunctionObject extends FunctionObject {
predicate unconditionallyReturnsParameter(int n) {
exists(SsaVariable pvar |
exists(Parameter p | p = this.getFunction().getArg(n) |
p.asName().getAFlowNode() = pvar.getDefinition()
pvar.getDefinition().getNode() = p.asName()
) and
exists(NameNode rval |
rval = pvar.getAUse() and

View File

@@ -337,7 +337,7 @@ class TupleObject extends SequenceObject {
or
this instanceof TupleNode
or
exists(Function func | func.getVararg().getAFlowNode() = this)
exists(Function func | this.(ControlFlowNode).getNode() = func.getVararg())
}
}
@@ -352,7 +352,9 @@ module TupleObject {
}
class NonEmptyTupleObject extends TupleObject {
NonEmptyTupleObject() { exists(Function func | func.getVararg().getAFlowNode() = this) }
NonEmptyTupleObject() {
exists(Function func | this.(ControlFlowNode).getNode() = func.getVararg())
}
override boolean booleanValue() { result = true }
}