Python: abandon synthetic node

for `CapturingClosureArgumentNode`.

Unless we define it for every single `CallNode`, we need a more
sophisticated mutual recursion with the call graph construction.
There is built-in support for that, but we are currently not using it.
This commit is contained in:
Rasmus Lerchedahl Petersen
2023-12-15 23:42:29 +01:00
parent e36b079e0f
commit 4a1fcde649
3 changed files with 23 additions and 8 deletions

View File

@@ -179,6 +179,8 @@ class ArgumentPosition extends TArgumentPosition {
string toString() {
this.isSelf() and result = "self"
or
this.isLambdaSelf() and result = "lambda self"
or
exists(int pos | this.isPositional(pos) and result = "position " + pos)
or
exists(string name | this.isKeyword(name) and result = "keyword " + name)
@@ -1647,23 +1649,34 @@ private class SynthCapturePostUpdateNode extends PostUpdateNodeImpl, SynthCaptur
* separate node and parameter/argument positions in order to distinguish
* "lambda self" from "normal self", as lambdas may also access outer `self`
* variables (through variable capture).
*
* TODO:
* We might want a synthetic node here, but currently that incurs problems
* with non-monotonic recursion, because of the use of `resolveCall` in the
* char pred. This may be solvable by using
* `CallGraphConstruction::Make` in staed of
* `CallGraphConstruction::Simple::Make` appropriately.
*/
class SynthCaptureArgumentNode extends TSynthCapturingClosureArgumentNode, ArgumentNode {
class CapturingClosureArgumentNode extends CfgNode, ArgumentNode {
CallNode callNode;
SynthCaptureArgumentNode() {
this = TSynthCapturingClosureArgumentNode(callNode) and
// We would prefer to put this restriction in the charpred for the branch,
// but that incurs non-monotonic recursion.
CapturingClosureArgumentNode() {
this.getNode() = callNode.getFunction() and
exists(Function target | resolveCall(callNode, target, _) |
target = any(VariableCapture::CapturedVariable v).getACapturingScope()
)
}
override string toString() { result = "Capturing closure argument" }
// final override Location getLocation() { result = callNode.getLocation() }
override predicate argumentOf(DataFlowCall call, ArgumentPosition pos) {
callNode = call.getNode() and
pos.isLambdaSelf()
}
/** Gets the `CallNode` that is being passed as an argument to itself. */
CallNode getCallNode() { result = callNode }
}
/** Gets a viable run-time target for the call `call`. */

View File

@@ -120,9 +120,7 @@ newtype TNode =
/** A synthetic node representing the heap of a function. Used for variable capture. */
TSynthCapturingClosureParameterNode(Function f) {
f = any(VariableCapture::CapturedVariable v).getACapturingScope()
} or
/** A synthetic node representing the heap of a function. Used for variable capture. */
TSynthCapturingClosureArgumentNode(CallNode callNode)
}
private import semmle.python.internal.CachedStages

View File

@@ -188,4 +188,8 @@ private module Debug {
Flow::localFlowStep(closureNodeFrom, closureNodeTo) and
not flowValueStep(_, closureNodeFrom, closureNodeTo, _)
}
predicate unmappedFlowClosureNode(Flow::ClosureNode closureNode) {
not exists(Node node | closureNode = asClosureNode(node))
}
}