diff --git a/python/ql/lib/semmle/python/Flow.qll b/python/ql/lib/semmle/python/Flow.qll index 94caf513aa9..05a9ab6e17d 100644 --- a/python/ql/lib/semmle/python/Flow.qll +++ b/python/ql/lib/semmle/python/Flow.qll @@ -1,7 +1,7 @@ overlay[local] module; -import python +import python as Py private import semmle.python.internal.CachedStages private import codeql.controlflow.BasicBlock as BB @@ -17,7 +17,7 @@ private import codeql.controlflow.BasicBlock as BB */ private predicate augstore(ControlFlowNode load, ControlFlowNode store) { - exists(Expr load_store | exists(AugAssign aa | aa.getTarget() = load_store) | + exists(Py::Expr load_store | exists(Py::AugAssign aa | aa.getTarget() = load_store) | toAst(load) = load_store and toAst(store) = load_store and load.strictlyDominates(store) @@ -25,7 +25,7 @@ private predicate augstore(ControlFlowNode load, ControlFlowNode store) { } /** A non-dispatched getNode() to avoid negative recursion issues */ -private AstNode toAst(ControlFlowNode n) { py_flow_bb_node(n, result, _, _) } +private Py::AstNode toAst(ControlFlowNode n) { py_flow_bb_node(n, result, _, _) } /** * A control flow node. Control flow nodes have a many-to-one relation with syntactic nodes, @@ -35,19 +35,19 @@ private AstNode toAst(ControlFlowNode n) { py_flow_bb_node(n, result, _, _) } class ControlFlowNode extends @py_flow_node { /** Whether this control flow node is a load (including those in augmented assignments) */ predicate isLoad() { - exists(Expr e | e = toAst(this) | py_expr_contexts(_, 3, e) and not augstore(_, this)) + exists(Py::Expr e | e = toAst(this) | py_expr_contexts(_, 3, e) and not augstore(_, this)) } /** Whether this control flow node is a store (including those in augmented assignments) */ predicate isStore() { - exists(Expr e | e = toAst(this) | py_expr_contexts(_, 5, e) or augstore(_, this)) + exists(Py::Expr e | e = toAst(this) | py_expr_contexts(_, 5, e) or augstore(_, this)) } /** Whether this control flow node is a delete */ - predicate isDelete() { exists(Expr e | e = toAst(this) | py_expr_contexts(_, 2, e)) } + predicate isDelete() { exists(Py::Expr e | e = toAst(this) | py_expr_contexts(_, 2, e)) } /** Whether this control flow node is a parameter */ - predicate isParameter() { exists(Expr e | e = toAst(this) | py_expr_contexts(_, 4, e)) } + predicate isParameter() { exists(Py::Expr e | e = toAst(this) | py_expr_contexts(_, 4, e)) } /** Whether this control flow node is a store in an augmented assignment */ predicate isAugStore() { augstore(_, this) } @@ -57,61 +57,61 @@ class ControlFlowNode extends @py_flow_node { /** Whether this flow node corresponds to a literal */ predicate isLiteral() { - toAst(this) instanceof Bytes + toAst(this) instanceof Py::Bytes or - toAst(this) instanceof Dict + toAst(this) instanceof Py::Dict or - toAst(this) instanceof DictComp + toAst(this) instanceof Py::DictComp or - toAst(this) instanceof Set + toAst(this) instanceof Py::Set or - toAst(this) instanceof SetComp + toAst(this) instanceof Py::SetComp or - toAst(this) instanceof Ellipsis + toAst(this) instanceof Py::Ellipsis or - toAst(this) instanceof GeneratorExp + toAst(this) instanceof Py::GeneratorExp or - toAst(this) instanceof Lambda + toAst(this) instanceof Py::Lambda or - toAst(this) instanceof ListComp + toAst(this) instanceof Py::ListComp or - toAst(this) instanceof List + toAst(this) instanceof Py::List or - toAst(this) instanceof Num + toAst(this) instanceof Py::Num or - toAst(this) instanceof Tuple + toAst(this) instanceof Py::Tuple or - toAst(this) instanceof Unicode + toAst(this) instanceof Py::Unicode or - toAst(this) instanceof NameConstant + toAst(this) instanceof Py::NameConstant } /** Whether this flow node corresponds to an attribute expression */ - predicate isAttribute() { toAst(this) instanceof Attribute } + predicate isAttribute() { toAst(this) instanceof Py::Attribute } /** Whether this flow node corresponds to an subscript expression */ - predicate isSubscript() { toAst(this) instanceof Subscript } + predicate isSubscript() { toAst(this) instanceof Py::Subscript } /** Whether this flow node corresponds to an import member */ - predicate isImportMember() { toAst(this) instanceof ImportMember } + predicate isImportMember() { toAst(this) instanceof Py::ImportMember } /** Whether this flow node corresponds to a call */ - predicate isCall() { toAst(this) instanceof Call } + predicate isCall() { toAst(this) instanceof Py::Call } /** Whether this flow node is the first in a module */ - predicate isModuleEntry() { this.isEntryNode() and toAst(this) instanceof Module } + predicate isModuleEntry() { this.isEntryNode() and toAst(this) instanceof Py::Module } /** Whether this flow node corresponds to an import */ - predicate isImport() { toAst(this) instanceof ImportExpr } + predicate isImport() { toAst(this) instanceof Py::ImportExpr } /** Whether this flow node corresponds to a conditional expression */ - predicate isIfExp() { toAst(this) instanceof IfExp } + predicate isIfExp() { toAst(this) instanceof Py::IfExp } /** Whether this flow node corresponds to a function definition expression */ - predicate isFunction() { toAst(this) instanceof FunctionExpr } + predicate isFunction() { toAst(this) instanceof Py::FunctionExpr } /** Whether this flow node corresponds to a class definition expression */ - predicate isClass() { toAst(this) instanceof ClassExpr } + predicate isClass() { toAst(this) instanceof Py::ClassExpr } /** Gets a predecessor of this flow node */ ControlFlowNode getAPredecessor() { this = result.getASuccessor() } @@ -123,25 +123,25 @@ class ControlFlowNode extends @py_flow_node { ControlFlowNode getImmediateDominator() { py_idoms(this, result) } /** Gets the syntactic element corresponding to this flow node */ - AstNode getNode() { py_flow_bb_node(this, result, _, _) } + Py::AstNode getNode() { py_flow_bb_node(this, result, _, _) } /** Gets a textual representation of this element. */ cached string toString() { Stages::AST::ref() and // Since modules can have ambigous names, entry nodes can too, if we do not collate them. - exists(Scope s | s.getEntryNode() = this | + exists(Py::Scope s | s.getEntryNode() = this | result = "Entry node for " + concat( | | s.toString(), ",") ) or - exists(Scope s | s.getANormalExit() = this | result = "Exit node for " + s.toString()) + exists(Py::Scope s | s.getANormalExit() = this | result = "Exit node for " + s.toString()) or - not exists(Scope s | s.getEntryNode() = this or s.getANormalExit() = this) and + not exists(Py::Scope s | s.getEntryNode() = this or s.getANormalExit() = this) and result = "ControlFlowNode for " + this.getNode().toString() } /** Gets the location of this ControlFlowNode */ - Location getLocation() { result = this.getNode().getLocation() } + Py::Location getLocation() { result = this.getNode().getLocation() } /** Whether this flow node is the first in its scope */ predicate isEntryNode() { py_scope_flow(this, _, -1) } @@ -151,9 +151,9 @@ class ControlFlowNode extends @py_flow_node { /** Gets the scope containing this flow node */ cached - Scope getScope() { + Py::Scope getScope() { Stages::AST::ref() and - if this.getNode() instanceof Scope + if this.getNode() instanceof Py::Scope then /* Entry or exit node */ result = this.getNode() @@ -161,7 +161,7 @@ class ControlFlowNode extends @py_flow_node { } /** Gets the enclosing module */ - Module getEnclosingModule() { result = this.getScope().getEnclosingModule() } + Py::Module getEnclosingModule() { result = this.getScope().getEnclosingModule() } /** Gets a successor for this node if the relevant condition is True. */ ControlFlowNode getATrueSuccessor() { @@ -188,7 +188,7 @@ class ControlFlowNode extends @py_flow_node { } /** Whether the scope may be exited as a result of this node raising an exception */ - predicate isExceptionalExit(Scope s) { py_scope_flow(this, s, 1) } + predicate isExceptionalExit(Py::Scope s) { py_scope_flow(this, s, 1) } /** Whether this node is a normal (non-exceptional) exit */ predicate isNormalExit() { py_scope_flow(this, _, 0) or py_scope_flow(this, _, 2) } @@ -198,7 +198,7 @@ class ControlFlowNode extends @py_flow_node { pragma[inline] predicate strictlyDominates(ControlFlowNode other) { // This predicate is gigantic, so it must be inlined. - // About 1.4 billion tuples for OpenStack Cinder. + // About 1.4 billion tuples for OpenStack Py::Cinder. this.getBasicBlock().strictlyDominates(other.getBasicBlock()) or exists(BasicBlock b, int i, int j | this = b.getNode(i) and other = b.getNode(j) and i < j) @@ -236,7 +236,7 @@ class ControlFlowNode extends @py_flow_node { /* join-ordering helper for `getAChild() */ pragma[noinline] private ControlFlowNode getExprChild(BasicBlock dom) { - this.getNode().(Expr).getAChildNode() = result.getNode() and + this.getNode().(Py::Expr).getAChildNode() = result.getNode() and result.getBasicBlock().dominates(dom) and not this instanceof UnaryExprNode } @@ -249,16 +249,16 @@ class ControlFlowNode extends @py_flow_node { */ private class AnyNode extends ControlFlowNode { - override AstNode getNode() { result = super.getNode() } + override Py::AstNode getNode() { result = super.getNode() } } /** A control flow node corresponding to a call expression, such as `func(...)` */ class CallNode extends ControlFlowNode { - CallNode() { toAst(this) instanceof Call } + CallNode() { toAst(this) instanceof Py::Call } /** Gets the flow node corresponding to the function expression for the call corresponding to this flow node */ ControlFlowNode getFunction() { - exists(Call c | + exists(Py::Call c | this.getNode() = c and c.getFunc() = result.getNode() and result.getBasicBlock().dominates(this.getBasicBlock()) @@ -267,7 +267,7 @@ class CallNode extends ControlFlowNode { /** Gets the flow node corresponding to the n'th positional argument of the call corresponding to this flow node */ ControlFlowNode getArg(int n) { - exists(Call c | + exists(Py::Call c | this.getNode() = c and c.getArg(n) = result.getNode() and result.getBasicBlock().dominates(this.getBasicBlock()) @@ -276,7 +276,7 @@ class CallNode extends ControlFlowNode { /** Gets the flow node corresponding to the named argument of the call corresponding to this flow node */ ControlFlowNode getArgByName(string name) { - exists(Call c, Keyword k | + exists(Py::Call c, Py::Keyword k | this.getNode() = c and k = c.getANamedArg() and k.getValue() = result.getNode() and @@ -292,7 +292,7 @@ class CallNode extends ControlFlowNode { result = this.getArgByName(_) } - override Call getNode() { result = super.getNode() } + override Py::Call getNode() { result = super.getNode() } predicate isDecoratorCall() { this.isClassDecoratorCall() @@ -301,11 +301,11 @@ class CallNode extends ControlFlowNode { } predicate isClassDecoratorCall() { - exists(ClassExpr cls | this.getNode() = cls.getADecoratorCall()) + exists(Py::ClassExpr cls | this.getNode() = cls.getADecoratorCall()) } predicate isFunctionDecoratorCall() { - exists(FunctionExpr func | this.getNode() = func.getADecoratorCall()) + exists(Py::FunctionExpr func | this.getNode() = func.getADecoratorCall()) } /** Gets the first tuple (*) argument of this call, if any. */ @@ -323,11 +323,11 @@ class CallNode extends ControlFlowNode { /** A control flow corresponding to an attribute expression, such as `value.attr` */ class AttrNode extends ControlFlowNode { - AttrNode() { toAst(this) instanceof Attribute } + AttrNode() { toAst(this) instanceof Py::Attribute } /** Gets the flow node corresponding to the object of the attribute expression corresponding to this flow node */ ControlFlowNode getObject() { - exists(Attribute a | + exists(Py::Attribute a | this.getNode() = a and a.getObject() = result.getNode() and result.getBasicBlock().dominates(this.getBasicBlock()) @@ -339,7 +339,7 @@ class AttrNode extends ControlFlowNode { * with the matching name */ ControlFlowNode getObject(string name) { - exists(Attribute a | + exists(Py::Attribute a | this.getNode() = a and a.getObject() = result.getNode() and a.getName() = name and @@ -348,57 +348,57 @@ class AttrNode extends ControlFlowNode { } /** Gets the attribute name of the attribute expression corresponding to this flow node */ - string getName() { exists(Attribute a | this.getNode() = a and a.getName() = result) } + string getName() { exists(Py::Attribute a | this.getNode() = a and a.getName() = result) } - override Attribute getNode() { result = super.getNode() } + override Py::Attribute getNode() { result = super.getNode() } } /** A control flow node corresponding to a `from ... import ...` expression */ class ImportMemberNode extends ControlFlowNode { - ImportMemberNode() { toAst(this) instanceof ImportMember } + ImportMemberNode() { toAst(this) instanceof Py::ImportMember } /** * Gets the flow node corresponding to the module in the import-member expression corresponding to this flow node, * with the matching name */ ControlFlowNode getModule(string name) { - exists(ImportMember i | this.getNode() = i and i.getModule() = result.getNode() | + exists(Py::ImportMember i | this.getNode() = i and i.getModule() = result.getNode() | i.getName() = name and result.getBasicBlock().dominates(this.getBasicBlock()) ) } - override ImportMember getNode() { result = super.getNode() } + override Py::ImportMember getNode() { result = super.getNode() } } /** A control flow node corresponding to an artificial expression representing an import */ class ImportExprNode extends ControlFlowNode { - ImportExprNode() { toAst(this) instanceof ImportExpr } + ImportExprNode() { toAst(this) instanceof Py::ImportExpr } - override ImportExpr getNode() { result = super.getNode() } + override Py::ImportExpr getNode() { result = super.getNode() } } /** A control flow node corresponding to a `from ... import *` statement */ class ImportStarNode extends ControlFlowNode { - ImportStarNode() { toAst(this) instanceof ImportStar } + ImportStarNode() { toAst(this) instanceof Py::ImportStar } /** Gets the flow node corresponding to the module in the import-star corresponding to this flow node */ ControlFlowNode getModule() { - exists(ImportStar i | this.getNode() = i and i.getModuleExpr() = result.getNode() | + exists(Py::ImportStar i | this.getNode() = i and i.getModuleExpr() = result.getNode() | result.getBasicBlock().dominates(this.getBasicBlock()) ) } - override ImportStar getNode() { result = super.getNode() } + override Py::ImportStar getNode() { result = super.getNode() } } /** A control flow node corresponding to a subscript expression, such as `value[slice]` */ class SubscriptNode extends ControlFlowNode { - SubscriptNode() { toAst(this) instanceof Subscript } + SubscriptNode() { toAst(this) instanceof Py::Subscript } /** flow node corresponding to the value of the sequence in a subscript operation */ ControlFlowNode getObject() { - exists(Subscript s | + exists(Py::Subscript s | this.getNode() = s and s.getObject() = result.getNode() and result.getBasicBlock().dominates(this.getBasicBlock()) @@ -407,23 +407,23 @@ class SubscriptNode extends ControlFlowNode { /** flow node corresponding to the index in a subscript operation */ ControlFlowNode getIndex() { - exists(Subscript s | + exists(Py::Subscript s | this.getNode() = s and s.getIndex() = result.getNode() and result.getBasicBlock().dominates(this.getBasicBlock()) ) } - override Subscript getNode() { result = super.getNode() } + override Py::Subscript getNode() { result = super.getNode() } } /** A control flow node corresponding to a comparison operation, such as `x DeletionNode -> NameNode('b') -> AttrNode('y') -> DeletionNode`. */ class DeletionNode extends ControlFlowNode { - DeletionNode() { toAst(this) instanceof Delete } + DeletionNode() { toAst(this) instanceof Py::Delete } /** Gets the unique target of this deletion node. */ ControlFlowNode getTarget() { result.getASuccessor() = this } @@ -617,9 +617,9 @@ class DeletionNode extends ControlFlowNode { /** A control flow node corresponding to a sequence (tuple or list) literal */ abstract class SequenceNode extends ControlFlowNode { SequenceNode() { - toAst(this) instanceof Tuple + toAst(this) instanceof Py::Tuple or - toAst(this) instanceof List + toAst(this) instanceof Py::List } /** Gets the control flow node for an element of this sequence */ @@ -632,11 +632,11 @@ abstract class SequenceNode extends ControlFlowNode { /** A control flow node corresponding to a tuple expression such as `( 1, 3, 5, 7, 9 )` */ class TupleNode extends SequenceNode { - TupleNode() { toAst(this) instanceof Tuple } + TupleNode() { toAst(this) instanceof Py::Tuple } override ControlFlowNode getElement(int n) { Stages::AST::ref() and - exists(Tuple t | this.getNode() = t and result.getNode() = t.getElt(n)) and + exists(Py::Tuple t | this.getNode() = t and result.getNode() = t.getElt(n)) and ( result.getBasicBlock().dominates(this.getBasicBlock()) or @@ -647,10 +647,10 @@ class TupleNode extends SequenceNode { /** A control flow node corresponding to a list expression, such as `[ 1, 3, 5, 7, 9 ]` */ class ListNode extends SequenceNode { - ListNode() { toAst(this) instanceof List } + ListNode() { toAst(this) instanceof Py::List } override ControlFlowNode getElement(int n) { - exists(List l | this.getNode() = l and result.getNode() = l.getElt(n)) and + exists(Py::List l | this.getNode() = l and result.getNode() = l.getElt(n)) and ( result.getBasicBlock().dominates(this.getBasicBlock()) or @@ -661,10 +661,10 @@ class ListNode extends SequenceNode { /** A control flow node corresponding to a set expression, such as `{ 1, 3, 5, 7, 9 }` */ class SetNode extends ControlFlowNode { - SetNode() { toAst(this) instanceof Set } + SetNode() { toAst(this) instanceof Py::Set } ControlFlowNode getAnElement() { - exists(Set s | this.getNode() = s and result.getNode() = s.getElt(_)) and + exists(Py::Set s | this.getNode() = s and result.getNode() = s.getElt(_)) and ( result.getBasicBlock().dominates(this.getBasicBlock()) or @@ -675,20 +675,20 @@ class SetNode extends ControlFlowNode { /** A control flow node corresponding to a dictionary literal, such as `{ 'a': 1, 'b': 2 }` */ class DictNode extends ControlFlowNode { - DictNode() { toAst(this) instanceof Dict } + DictNode() { toAst(this) instanceof Py::Dict } /** * Gets a key of this dictionary literal node, for those items that have keys * E.g, in {'a':1, **b} this returns only 'a' */ ControlFlowNode getAKey() { - exists(Dict d | this.getNode() = d and result.getNode() = d.getAKey()) and + exists(Py::Dict d | this.getNode() = d and result.getNode() = d.getAKey()) and result.getBasicBlock().dominates(this.getBasicBlock()) } /** Gets a value of this dictionary literal node */ ControlFlowNode getAValue() { - exists(Dict d | this.getNode() = d and result.getNode() = d.getAValue()) and + exists(Py::Dict d | this.getNode() = d and result.getNode() = d.getAValue()) and result.getBasicBlock().dominates(this.getBasicBlock()) } } @@ -712,21 +712,21 @@ class IterableNode extends ControlFlowNode { } } -private AstNode assigned_value(Expr lhs) { +private Py::AstNode assigned_value(Py::Expr lhs) { /* lhs = result */ - exists(Assign a | a.getATarget() = lhs and result = a.getValue()) + exists(Py::Assign a | a.getATarget() = lhs and result = a.getValue()) or /* lhs := result */ - exists(AssignExpr a | a.getTarget() = lhs and result = a.getValue()) + exists(Py::AssignExpr a | a.getTarget() = lhs and result = a.getValue()) or /* lhs : annotation = result */ - exists(AnnAssign a | a.getTarget() = lhs and result = a.getValue()) + exists(Py::AnnAssign a | a.getTarget() = lhs and result = a.getValue()) or /* import result as lhs */ - exists(Alias a | a.getAsname() = lhs and result = a.getValue()) + exists(Py::Alias a | a.getAsname() = lhs and result = a.getValue()) or /* lhs += x => result = (lhs + x) */ - exists(AugAssign a, BinaryExpr b | b = a.getOperation() and result = b and lhs = b.getLeft()) + exists(Py::AugAssign a, Py::BinaryExpr b | b = a.getOperation() and result = b and lhs = b.getLeft()) or /* * ..., lhs, ... = ..., result, ... @@ -734,31 +734,31 @@ private AstNode assigned_value(Expr lhs) { * ..., (..., lhs, ...), ... = ..., (..., result, ...), ... */ - exists(Assign a | nested_sequence_assign(a.getATarget(), a.getValue(), lhs, result)) + exists(Py::Assign a | nested_sequence_assign(a.getATarget(), a.getValue(), lhs, result)) or /* for lhs in seq: => `result` is the `for` node, representing the `iter(next(seq))` operation. */ - result.(For).getTarget() = lhs + result.(Py::For).getTarget() = lhs or - exists(Parameter param | lhs = param.asName() and result = param.getDefault()) + exists(Py::Parameter param | lhs = param.asName() and result = param.getDefault()) } predicate nested_sequence_assign( - Expr left_parent, Expr right_parent, Expr left_result, Expr right_result + Py::Expr left_parent, Py::Expr right_parent, Py::Expr left_result, Py::Expr right_result ) { - exists(Assign a | + exists(Py::Assign a | a.getATarget().getASubExpression*() = left_parent and a.getValue().getASubExpression*() = right_parent ) and - exists(int i, Expr left_elem, Expr right_elem | + exists(int i, Py::Expr left_elem, Py::Expr right_elem | ( - left_elem = left_parent.(Tuple).getElt(i) + left_elem = left_parent.(Py::Tuple).getElt(i) or - left_elem = left_parent.(List).getElt(i) + left_elem = left_parent.(Py::List).getElt(i) ) and ( - right_elem = right_parent.(Tuple).getElt(i) + right_elem = right_parent.(Py::Tuple).getElt(i) or - right_elem = right_parent.(List).getElt(i) + right_elem = right_parent.(Py::List).getElt(i) ) | left_result = left_elem and right_result = right_elem @@ -769,9 +769,9 @@ predicate nested_sequence_assign( /** A flow node for a `for` statement. */ class ForNode extends ControlFlowNode { - ForNode() { toAst(this) instanceof For } + ForNode() { toAst(this) instanceof Py::For } - override For getNode() { result = super.getNode() } + override Py::For getNode() { result = super.getNode() } /** Holds if this `for` statement causes iteration over `sequence` storing each step of the iteration in `target` */ predicate iterates(ControlFlowNode target, ControlFlowNode sequence) { @@ -782,7 +782,7 @@ class ForNode extends ControlFlowNode { /** Gets the sequence node for this `for` statement. */ ControlFlowNode getSequence() { - exists(For for | + exists(Py::For for | toAst(this) = for and for.getIter() = result.getNode() | @@ -792,7 +792,7 @@ class ForNode extends ControlFlowNode { /** A possible `target` for this `for` statement, not accounting for loop unrolling */ private ControlFlowNode possibleTarget() { - exists(For for | + exists(Py::For for | toAst(this) = for and for.getTarget() = result.getNode() and this.getBasicBlock().dominates(result.getBasicBlock()) @@ -809,11 +809,11 @@ class ForNode extends ControlFlowNode { /** A flow node for a `raise` statement */ class RaiseStmtNode extends ControlFlowNode { - RaiseStmtNode() { toAst(this) instanceof Raise } + RaiseStmtNode() { toAst(this) instanceof Py::Raise } /** Gets the control flow node for the exception raised by this raise statement */ ControlFlowNode getException() { - exists(Raise r | + exists(Py::Raise r | r = toAst(this) and r.getException() = toAst(result) and result.getBasicBlock().dominates(this.getBasicBlock()) @@ -827,36 +827,36 @@ class RaiseStmtNode extends ControlFlowNode { */ class NameNode extends ControlFlowNode { NameNode() { - exists(Name n | py_flow_bb_node(this, n, _, _)) + exists(Py::Name n | py_flow_bb_node(this, n, _, _)) or - exists(PlaceHolder p | py_flow_bb_node(this, p, _, _)) + exists(Py::PlaceHolder p | py_flow_bb_node(this, p, _, _)) } /** Whether this flow node defines the variable `v`. */ - predicate defines(Variable v) { - exists(Name d | this.getNode() = d and d.defines(v)) and + predicate defines(Py::Variable v) { + exists(Py::Name d | this.getNode() = d and d.defines(v)) and not this.isLoad() } /** Whether this flow node deletes the variable `v`. */ - predicate deletes(Variable v) { exists(Name d | this.getNode() = d and d.deletes(v)) } + predicate deletes(Py::Variable v) { exists(Py::Name d | this.getNode() = d and d.deletes(v)) } /** Whether this flow node uses the variable `v`. */ - predicate uses(Variable v) { + predicate uses(Py::Variable v) { this.isLoad() and - exists(Name u | this.getNode() = u and u.uses(v)) + exists(Py::Name u | this.getNode() = u and u.uses(v)) or - exists(PlaceHolder u | - this.getNode() = u and u.getVariable() = v and u.getCtx() instanceof Load + exists(Py::PlaceHolder u | + this.getNode() = u and u.getVariable() = v and u.getCtx() instanceof Py::Load ) or Scopes::use_of_global_variable(this, v.getScope(), v.getId()) } string getId() { - result = this.getNode().(Name).getId() + result = this.getNode().(Py::Name).getId() or - result = this.getNode().(PlaceHolder).getId() + result = this.getNode().(Py::PlaceHolder).getId() } /** Whether this is a use of a local variable. */ @@ -868,37 +868,37 @@ class NameNode extends ControlFlowNode { /** Whether this is a use of a global (including builtin) variable. */ predicate isGlobal() { Scopes::use_of_global_variable(this, _, _) } - predicate isSelf() { exists(SsaVariable selfvar | selfvar.isSelf() and selfvar.getAUse() = this) } + predicate isSelf() { exists(Py::SsaVariable selfvar | selfvar.isSelf() and selfvar.getAUse() = this) } } /** A control flow node corresponding to a named constant, one of `None`, `True` or `False`. */ class NameConstantNode extends NameNode { - NameConstantNode() { exists(NameConstant n | py_flow_bb_node(this, n, _, _)) } + NameConstantNode() { exists(Py::NameConstant n | py_flow_bb_node(this, n, _, _)) } /* * We ought to override uses as well, but that has * a serious performance impact. - * deprecated predicate uses(Variable v) { none() } + * deprecated predicate uses(Py::Variable v) { none() } */ } /** A control flow node corresponding to a starred expression, `*a`. */ class StarredNode extends ControlFlowNode { - StarredNode() { toAst(this) instanceof Starred } + StarredNode() { toAst(this) instanceof Py::Starred } - ControlFlowNode getValue() { toAst(result) = toAst(this).(Starred).getValue() } + ControlFlowNode getValue() { toAst(result) = toAst(this).(Py::Starred).getValue() } } /** The ControlFlowNode for an 'except' statement. */ class ExceptFlowNode extends ControlFlowNode { - ExceptFlowNode() { this.getNode() instanceof ExceptStmt } + ExceptFlowNode() { this.getNode() instanceof Py::ExceptStmt } /** * Gets the type handled by this exception handler. - * `ExceptionType` in `except ExceptionType as e:` + * `Py::ExceptionType` in `except Py::ExceptionType as e:` */ ControlFlowNode getType() { - exists(ExceptStmt ex | + exists(Py::ExceptStmt ex | this.getBasicBlock().dominates(result.getBasicBlock()) and ex = this.getNode() and result = ex.getType().getAFlowNode() @@ -907,10 +907,10 @@ class ExceptFlowNode extends ControlFlowNode { /** * Gets the name assigned to the handled exception, if any. - * `e` in `except ExceptionType as e:` + * `e` in `except Py::ExceptionType as e:` */ ControlFlowNode getName() { - exists(ExceptStmt ex | + exists(Py::ExceptStmt ex | this.getBasicBlock().dominates(result.getBasicBlock()) and ex = this.getNode() and result = ex.getName().getAFlowNode() @@ -920,30 +920,30 @@ class ExceptFlowNode extends ControlFlowNode { /** The ControlFlowNode for an 'except*' statement. */ class ExceptGroupFlowNode extends ControlFlowNode { - ExceptGroupFlowNode() { this.getNode() instanceof ExceptGroupStmt } + ExceptGroupFlowNode() { this.getNode() instanceof Py::ExceptGroupStmt } /** * Gets the type handled by this exception handler. - * `ExceptionType` in `except* ExceptionType as e:` + * `Py::ExceptionType` in `except* Py::ExceptionType as e:` */ ControlFlowNode getType() { this.getBasicBlock().dominates(result.getBasicBlock()) and - result = this.getNode().(ExceptGroupStmt).getType().getAFlowNode() + result = this.getNode().(Py::ExceptGroupStmt).getType().getAFlowNode() } /** * Gets the name assigned to the handled exception, if any. - * `e` in `except* ExceptionType as e:` + * `e` in `except* Py::ExceptionType as e:` */ ControlFlowNode getName() { this.getBasicBlock().dominates(result.getBasicBlock()) and - result = this.getNode().(ExceptGroupStmt).getName().getAFlowNode() + result = this.getNode().(Py::ExceptGroupStmt).getName().getAFlowNode() } } private module Scopes { private predicate fast_local(NameNode n) { - exists(FastLocalVariable v | + exists(Py::FastLocalVariable v | n.uses(v) and v.getScope() = n.getScope() ) @@ -952,15 +952,15 @@ private module Scopes { predicate local(NameNode n) { fast_local(n) or - exists(SsaVariable var | + exists(Py::SsaVariable var | var.getAUse() = n and - n.getScope() instanceof Class and + n.getScope() instanceof Py::Class and exists(var.getDefinition()) ) } predicate non_local(NameNode n) { - exists(FastLocalVariable flv | + exists(Py::FastLocalVariable flv | flv.getALoad() = n.getNode() and not flv.getScope() = n.getScope() ) @@ -968,20 +968,20 @@ private module Scopes { // magic is fine, but we get questionable join-ordering of it pragma[nomagic] - predicate use_of_global_variable(NameNode n, Module scope, string name) { + predicate use_of_global_variable(NameNode n, Py::Module scope, string name) { n.isLoad() and not non_local(n) and - not exists(SsaVariable var | var.getAUse() = n | - var.getVariable() instanceof FastLocalVariable + not exists(Py::SsaVariable var | var.getAUse() = n | + var.getVariable() instanceof Py::FastLocalVariable or - n.getScope() instanceof Class and + n.getScope() instanceof Py::Class and not maybe_undefined(var) ) and name = n.getId() and scope = n.getEnclosingModule() } - private predicate maybe_undefined(SsaVariable var) { + private predicate maybe_undefined(Py::SsaVariable var) { not exists(var.getDefinition()) and not py_ssa_phi(var, _) or var.getDefinition().isDelete() @@ -1058,13 +1058,13 @@ class BasicBlock extends @py_flow_node { private predicate oneNodeBlock() { this.firstNode() = this.getLastNode() } private predicate startLocationInfo(string file, int line, int col) { - if this.firstNode().getNode() instanceof Scope + if this.firstNode().getNode() instanceof Py::Scope then this.firstNode().getASuccessor().getLocation().hasLocationInfo(file, line, col, _, _) else this.firstNode().getLocation().hasLocationInfo(file, line, col, _, _) } private predicate endLocationInfo(int endl, int endc) { - if this.getLastNode().getNode() instanceof Scope and not this.oneNodeBlock() + if this.getLastNode().getNode() instanceof Py::Scope and not this.oneNodeBlock() then this.getLastNode().getAPredecessor().getLocation().hasLocationInfo(_, _, _, endl, endc) else this.getLastNode().getLocation().hasLocationInfo(_, _, _, endl, endc) } @@ -1081,7 +1081,7 @@ class BasicBlock extends @py_flow_node { /** Whether flow from this basic block reaches a normal exit from its scope */ predicate reachesExit() { - exists(Scope s | s.getANormalExit().getBasicBlock() = this) + exists(Py::Scope s | s.getANormalExit().getBasicBlock() = this) or this.getASuccessor().reachesExit() } @@ -1090,7 +1090,7 @@ class BasicBlock extends @py_flow_node { * Holds if this element is at the specified location. * The location spans column `startcolumn` of line `startline` to * column `endcolumn` of line `endline` in file `filepath`. - * For more information, see + * Py::For more information, see * [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/). */ predicate hasLocationInfo( @@ -1122,7 +1122,7 @@ class BasicBlock extends @py_flow_node { /** Gets the scope of this block */ pragma[nomagic] - Scope getScope() { + Py::Scope getScope() { exists(ControlFlowNode n | n.getBasicBlock() = this | /* Take care not to use an entry or exit node as that node's scope will be the outer scope */ not py_scope_flow(n, _, -1) and @@ -1145,17 +1145,17 @@ class BasicBlock extends @py_flow_node { predicate reaches(BasicBlock other) { this = other or this.strictlyReaches(other) } /** - * Gets the `ConditionBlock`, if any, that controls this block and - * does not control any other `ConditionBlock`s that control this block. - * That is the `ConditionBlock` that is closest dominator. + * Gets the `Py::ConditionBlock`, if any, that controls this block and + * does not control any other `Py::ConditionBlock`s that control this block. + * That is the `Py::ConditionBlock` that is closest dominator. */ - ConditionBlock getImmediatelyControllingBlock() { + Py::ConditionBlock getImmediatelyControllingBlock() { result = this.nonControllingImmediateDominator*().getImmediateDominator() } private BasicBlock nonControllingImmediateDominator() { result = this.getImmediateDominator() and - not result.(ConditionBlock).controls(this, _) + not result.(Py::ConditionBlock).controls(this, _) } /** @@ -1175,7 +1175,7 @@ private class ControlFlowNodeAlias = ControlFlowNode; final private class FinalBasicBlock = BasicBlock; -module Cfg implements BB::CfgSig { +module Cfg implements BB::CfgSig { private import codeql.controlflow.SuccessorType class ControlFlowNode = ControlFlowNodeAlias; @@ -1186,7 +1186,7 @@ module Cfg implements BB::CfgSig { // Using the location of the first node is simple // and we just need a way to identify the basic block // during debugging, so this will be serviceable. - Location getLocation() { result = super.getNode(0).getLocation() } + Py::Location getLocation() { result = super.getNode(0).getLocation() } int length() { result = count(int i | exists(this.getNode(i))) }