@@ -42,6 +42,13 @@ private import semmle.python.dataflow.new.internal.TypeTrackingImpl::CallGraphCo
42
42
newtype TParameterPosition =
43
43
/** Used for `self` in methods, and `cls` in classmethods. */
44
44
TSelfParameterPosition ( ) or
45
+ /**
46
+ * This is used for tracking flow through captured variables, and
47
+ * we use separate parameter/argument positions in order to distinguish
48
+ * "lambda self" from "normal self", as lambdas may also access outer `self`
49
+ * variables (through variable capture).
50
+ */
51
+ TLambdaSelfParameterPosition ( ) or
45
52
TPositionalParameterPosition ( int index ) {
46
53
index = any ( Parameter p ) .getPosition ( )
47
54
or
@@ -78,6 +85,9 @@ class ParameterPosition extends TParameterPosition {
78
85
/** Holds if this position represents a `self`/`cls` parameter. */
79
86
predicate isSelf ( ) { this = TSelfParameterPosition ( ) }
80
87
88
+ /** Holds if this position represents a reference to a lambda itself. Only used for tracking flow through captured variables. */
89
+ predicate isLambdaSelf ( ) { this = TLambdaSelfParameterPosition ( ) }
90
+
81
91
/** Holds if this position represents a positional parameter at (0-based) `index`. */
82
92
predicate isPositional ( int index ) { this = TPositionalParameterPosition ( index ) }
83
93
@@ -109,6 +119,8 @@ class ParameterPosition extends TParameterPosition {
109
119
string toString ( ) {
110
120
this .isSelf ( ) and result = "self"
111
121
or
122
+ this .isLambdaSelf ( ) and result = "lambda self"
123
+ or
112
124
exists ( int index | this .isPositional ( index ) and result = "position " + index )
113
125
or
114
126
exists ( string name | this .isKeyword ( name ) and result = "keyword " + name )
@@ -129,6 +141,13 @@ class ParameterPosition extends TParameterPosition {
129
141
newtype TArgumentPosition =
130
142
/** Used for `self` in methods, and `cls` in classmethods. */
131
143
TSelfArgumentPosition ( ) or
144
+ /**
145
+ * This is used for tracking flow through captured variables, and
146
+ * we use separate parameter/argument positions in order to distinguish
147
+ * "lambda self" from "normal self", as lambdas may also access outer `self`
148
+ * variables (through variable capture).
149
+ */
150
+ TLambdaSelfArgumentPosition ( ) or
132
151
TPositionalArgumentPosition ( int index ) {
133
152
exists ( any ( CallNode c ) .getArg ( index ) )
134
153
or
@@ -153,6 +172,9 @@ class ArgumentPosition extends TArgumentPosition {
153
172
/** Holds if this position represents a `self`/`cls` argument. */
154
173
predicate isSelf ( ) { this = TSelfArgumentPosition ( ) }
155
174
175
+ /** Holds if this position represents a lambda `self` argument. Only used for tracking flow through captured variables. */
176
+ predicate isLambdaSelf ( ) { this = TLambdaSelfArgumentPosition ( ) }
177
+
156
178
/** Holds if this position represents a positional argument at (0-based) `index`. */
157
179
predicate isPositional ( int index ) { this = TPositionalArgumentPosition ( index ) }
158
180
@@ -169,6 +191,8 @@ class ArgumentPosition extends TArgumentPosition {
169
191
string toString ( ) {
170
192
this .isSelf ( ) and result = "self"
171
193
or
194
+ this .isLambdaSelf ( ) and result = "lambda self"
195
+ or
172
196
exists ( int pos | this .isPositional ( pos ) and result = "position " + pos )
173
197
or
174
198
exists ( string name | this .isKeyword ( name ) and result = "keyword " + name )
@@ -183,6 +207,8 @@ class ArgumentPosition extends TArgumentPosition {
183
207
predicate parameterMatch ( ParameterPosition ppos , ArgumentPosition apos ) {
184
208
ppos .isSelf ( ) and apos .isSelf ( )
185
209
or
210
+ ppos .isLambdaSelf ( ) and apos .isLambdaSelf ( )
211
+ or
186
212
exists ( int index | ppos .isPositional ( index ) and apos .isPositional ( index ) )
187
213
or
188
214
exists ( string name | ppos .isKeyword ( name ) and apos .isKeyword ( name ) )
@@ -1506,6 +1532,37 @@ abstract class ParameterNodeImpl extends Node {
1506
1532
}
1507
1533
}
1508
1534
1535
+ /**
1536
+ * A synthetic parameter representing the values of the variables captured
1537
+ * by the callable being called. This parameter represents a single object
1538
+ * where all the values are stored as attributes.
1539
+ * This is also known as the environment part of a closure.
1540
+ *
1541
+ * This is used for tracking flow through captured variables.
1542
+ */
1543
+ class SynthCapturedVariablesParameterNode extends ParameterNodeImpl ,
1544
+ TSynthCapturedVariablesParameterNode
1545
+ {
1546
+ private Function callable ;
1547
+
1548
+ SynthCapturedVariablesParameterNode ( ) { this = TSynthCapturedVariablesParameterNode ( callable ) }
1549
+
1550
+ final Function getCallable ( ) { result = callable }
1551
+
1552
+ override Parameter getParameter ( ) { none ( ) }
1553
+
1554
+ override predicate isParameterOf ( DataFlowCallable c , ParameterPosition pos ) {
1555
+ c = TFunction ( callable ) and
1556
+ pos .isLambdaSelf ( )
1557
+ }
1558
+
1559
+ override Scope getScope ( ) { result = callable }
1560
+
1561
+ override Location getLocation ( ) { result = callable .getLocation ( ) }
1562
+
1563
+ override string toString ( ) { result = "lambda self in " + callable }
1564
+ }
1565
+
1509
1566
/** A parameter for a library callable with a flow summary. */
1510
1567
class SummaryParameterNode extends ParameterNodeImpl , FlowSummaryNode {
1511
1568
SummaryParameterNode ( ) {
@@ -1580,6 +1637,39 @@ private class SummaryPostUpdateNode extends FlowSummaryNode, PostUpdateNodeImpl
1580
1637
override Node getPreUpdateNode ( ) { result = pre }
1581
1638
}
1582
1639
1640
+ /**
1641
+ * A synthetic argument representing the values of the variables captured
1642
+ * by the callable being called. This argument represents a single object
1643
+ * where all the values are stored as attributes.
1644
+ * This is also known as the environment part of a closure.
1645
+ *
1646
+ * This is used for tracking flow through captured variables.
1647
+ *
1648
+ * TODO:
1649
+ * We might want a synthetic node here, but currently that incurs problems
1650
+ * with non-monotonic recursion, because of the use of `resolveCall` in the
1651
+ * char pred. This may be solvable by using
1652
+ * `CallGraphConstruction::Make` in stead of
1653
+ * `CallGraphConstruction::Simple::Make` appropriately.
1654
+ */
1655
+ class CapturedVariablesArgumentNode extends CfgNode , ArgumentNode {
1656
+ CallNode callNode ;
1657
+
1658
+ CapturedVariablesArgumentNode ( ) {
1659
+ node = callNode .getFunction ( ) and
1660
+ exists ( Function target | resolveCall ( callNode , target , _) |
1661
+ target = any ( VariableCapture:: CapturedVariable v ) .getACapturingScope ( )
1662
+ )
1663
+ }
1664
+
1665
+ override string toString ( ) { result = "Capturing closure argument" }
1666
+
1667
+ override predicate argumentOf ( DataFlowCall call , ArgumentPosition pos ) {
1668
+ callNode = call .getNode ( ) and
1669
+ pos .isLambdaSelf ( )
1670
+ }
1671
+ }
1672
+
1583
1673
/** Gets a viable run-time target for the call `call`. */
1584
1674
DataFlowCallable viableCallable ( DataFlowCall call ) {
1585
1675
call instanceof ExtractedDataFlowCall and
0 commit comments