Python: rename synthetic lambda nodes

This commit is contained in:
Rasmus Lerchedahl Petersen
2023-12-15 12:55:26 +01:00
parent 5b6ea15028
commit d3b237bf7e
3 changed files with 27 additions and 11 deletions

View File

@@ -1520,7 +1520,7 @@ abstract class ParameterNodeImpl extends Node {
}
/**
* The value of a lambda itself at function entry, viewed as a node in a data
* The value of a closure itself at function entry, viewed as a node in a data
* flow graph.
*
* This is used for tracking flow through captured variables, and we use a
@@ -1528,11 +1528,13 @@ abstract class ParameterNodeImpl extends Node {
* "lambda self" from "normal self", as lambdas may also access outer `self`
* variables (through variable capture).
*/
class LambdaSelfReferenceNode extends ParameterNodeImpl, TLambdaSelfReferenceNode {
class SynthCapturingClosureParameterNode extends ParameterNodeImpl,
TSynthCapturingClosureParameterNode
{
private Function callable;
LambdaSelfReferenceNode() {
this = TLambdaSelfReferenceNode(callable) and
SynthCapturingClosureParameterNode() {
this = TSynthCapturingClosureParameterNode(callable) and
// TODO: Remove this restriction when adding proper support for captured variables in the body of the function we generate for comprehensions
exists(TFunction(callable))
}
@@ -1635,11 +1637,22 @@ private class SynthCapturePostUpdateNode extends PostUpdateNodeImpl, SynthCaptur
override Node getPreUpdateNode() { result = pre }
}
class CaptureArgumentNode extends CfgNode, ArgumentNode {
/**
* The value of a closure itself being passed to the funciton, viewed as a node in a data
* flow graph.
*
* This is used for tracking flow through captured variables, and we use a
* 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).
*/
class SynthCaptureArgumentNode extends TSynthCapturingClosureArgumentNode, ArgumentNode {
CallNode callNode;
CaptureArgumentNode() {
this.getNode() = callNode.getFunction() and
SynthCaptureArgumentNode() {
this = TSynthCapturingClosureArgumentNode(callNode) and
// We would prefer to put this restriction in the charpred for the branch,
// but that incurs non-monotonic recursion.
exists(Function target | resolveCall(callNode, target, _) |
target = any(VariableCapture::CapturedVariable v).getACapturingScope()
)

View File

@@ -504,7 +504,8 @@ module VariableCapture {
or
result.(Flow::ParameterNode).getParameter().getCfgNode() = n.(CfgNode).getNode()
or
result.(Flow::ThisParameterNode).getCallable() = n.(LambdaSelfReferenceNode).getCallable()
result.(Flow::ThisParameterNode).getCallable() =
n.(SynthCapturingClosureParameterNode).getCallable()
}
predicate storeStep(Node nodeFrom, CapturedVariableContent c, Node nodeTo) {
@@ -1244,7 +1245,7 @@ predicate allowParameterReturnInSelf(ParameterNode p) {
or
exists(Function f |
VariableCapture::Flow::heuristicAllowInstanceParameterReturnInSelf(f) and
p = TLambdaSelfReferenceNode(f)
p = TSynthCapturingClosureParameterNode(f)
)
}

View File

@@ -118,9 +118,11 @@ newtype TNode =
/** A synthetic node representing a captured variable. */
TSynthCaptureNode(VariableCapture::Flow::SynthesizedCaptureNode cn) or
/** A synthetic node representing the heap of a function. Used for variable capture. */
TLambdaSelfReferenceNode(Function f) {
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