mirror of
https://github.com/github/codeql.git
synced 2026-05-27 17:41:24 +02:00
Python: SSA adapter: add MultiAssignmentDefinition, definedBy, useOfDef
Extends the ESSA-shaped adapter on top of the new shared SSA with the
remaining APIs consumed by the dataflow library:
* MultiAssignmentDefinition: matches the AST pattern 'a, b = ...' where
the LHS is a Tuple/List and the Name being defined is a sub-element.
Used by IterableUnpacking.qll to recognise unpacking assignments.
* EssaNodeDefinition.definedBy(var, defNode): a flatter equivalent of
'getSourceVariable() = var and getDefiningNode() = defNode', matching
legacy ESSA's signature. Used by DataFlowPublic.qll's
ModuleVariableNode to enumerate writes of a global.
* AdjacentUses::useOfDef(def, use): all reachable uses of a definition
(firstUse plus transitive use-use adjacency). Used by guards in
DataFlowPublic.qll.
These complete the API surface enumerated by grep across the dataflow
library. The remaining items (EssaNodeRefinement, EssaImportStep) are
ImportResolution-specific and will need separate treatment, possibly via
a different abstraction since the SSA library does not model heap-state
refinements like 'foo.bar = X'.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -238,6 +238,15 @@ class EssaNodeDefinition extends Ssa::WriteDefinition {
|
||||
Py::Scope getScope() {
|
||||
exists(Cfg::ControlFlowNode n | n = this.getDefiningNode() | result = n.getScope())
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this definition defines source variable `v` at CFG node
|
||||
* `defNode`. Flatter form of `getSourceVariable()` +
|
||||
* `getDefiningNode()`, matching legacy ESSA's `definedBy`.
|
||||
*/
|
||||
predicate definedBy(SsaSourceVariable v, Cfg::ControlFlowNode defNode) {
|
||||
v = this.getSourceVariable() and defNode = this.getDefiningNode()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -301,6 +310,23 @@ class WithDefinition extends EssaNodeDefinition {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An assignment where the LHS is a tuple/list and the RHS is unpacked:
|
||||
* `a, b = (1, 2)` or `a, *rest = xs`. The defining node for each
|
||||
* captured Name is the Name itself.
|
||||
*/
|
||||
class MultiAssignmentDefinition extends EssaNodeDefinition {
|
||||
MultiAssignmentDefinition() {
|
||||
exists(Cfg::NameNode n | n = this.getDefiningNode() |
|
||||
exists(Py::Assign a, Py::Expr lhs |
|
||||
a.getATarget() = lhs and
|
||||
(lhs instanceof Py::Tuple or lhs instanceof Py::List) and
|
||||
lhs.getASubExpression+() = n.getNode()
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An implicit entry definition for a non-local / captured / global /
|
||||
* builtin variable read in a scope but not defined there.
|
||||
@@ -384,4 +410,14 @@ module AdjacentUses {
|
||||
use = bb.getNode(i)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `use` is any reachable use of definition `def`. Combines
|
||||
* `firstUse` with transitive use-use adjacency.
|
||||
*/
|
||||
predicate useOfDef(Ssa::Definition def, Cfg::NameNode use) {
|
||||
firstUse(def, use)
|
||||
or
|
||||
exists(Cfg::NameNode mid | useOfDef(def, mid) and adjacentUseUse(mid, use))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user