@@ -64,7 +64,14 @@ newtype TParameterPosition =
64
64
index = any ( Parameter p ) .getPosition ( ) + 1
65
65
} or
66
66
TSynthStarArgsElementParameterPosition ( int index ) { exists ( TStarArgsParameterPosition ( index ) ) } or
67
- TDictSplatParameterPosition ( )
67
+ TDictSplatParameterPosition ( ) or
68
+ // To get flow from a **kwargs argument to a keyword parameter, we add a read-step
69
+ // from a synthetic **kwargs parameter. We need this separate synthetic ParameterNode,
70
+ // since we clear content of the normal **kwargs parameter for the names that
71
+ // correspond to normal keyword parameters. Since we cannot re-use the same parameter
72
+ // position for multiple parameter nodes in the same callable, we introduce this
73
+ // synthetic parameter position.
74
+ TSynthDictSplatParameterPosition ( )
68
75
69
76
/** A parameter position. */
70
77
class ParameterPosition extends TParameterPosition {
@@ -92,6 +99,12 @@ class ParameterPosition extends TParameterPosition {
92
99
/** Holds if this position represents a `**kwargs` parameter. */
93
100
predicate isDictSplat ( ) { this = TDictSplatParameterPosition ( ) }
94
101
102
+ /**
103
+ * Holds if this position represents a **synthetic** `**kwargs` parameter
104
+ * (see comment for `TSynthDictSplatParameterPosition`).
105
+ */
106
+ predicate isSynthDictSplat ( ) { this = TSynthDictSplatParameterPosition ( ) }
107
+
95
108
/** Gets a textual representation of this element. */
96
109
string toString ( ) {
97
110
this .isSelf ( ) and result = "self"
@@ -108,6 +121,8 @@ class ParameterPosition extends TParameterPosition {
108
121
)
109
122
or
110
123
this .isDictSplat ( ) and result = "**"
124
+ or
125
+ this .isSynthDictSplat ( ) and result = "synthetic **"
111
126
}
112
127
}
113
128
@@ -179,6 +194,8 @@ predicate parameterMatch(ParameterPosition ppos, ArgumentPosition apos) {
179
194
)
180
195
or
181
196
ppos .isDictSplat ( ) and apos .isDictSplat ( )
197
+ or
198
+ ppos .isSynthDictSplat ( ) and apos .isDictSplat ( )
182
199
}
183
200
184
201
// =============================================================================
@@ -324,16 +341,9 @@ abstract class DataFlowFunction extends DataFlowCallable, TFunction {
324
341
)
325
342
or
326
343
// `**kwargs`
327
- // since the dataflow library has the restriction that we can only have ONE result per
328
- // parameter position, if there is both a synthetic **kwargs and a real **kwargs
329
- // parameter, we only give the result for the synthetic, and add local flow from the
330
- // synthetic to the real. It might seem more natural to do it in the other
331
- // direction, but since we have a clearStep on the real **kwargs parameter, we would have that
332
- // content-clearing would also affect the synthetic parameter, which we don't want.
333
- ppos .isDictSplat ( ) and
334
- if exists ( func .getArgByName ( _) )
335
- then result = TSynthDictSplatParameterNode ( this )
336
- else result .getParameter ( ) = func .getKwarg ( )
344
+ ppos .isDictSplat ( ) and result .getParameter ( ) = func .getKwarg ( )
345
+ or
346
+ ppos .isSynthDictSplat ( ) and result = TSynthDictSplatParameterNode ( this )
337
347
}
338
348
}
339
349
@@ -1460,16 +1470,7 @@ class SummaryParameterNode extends ParameterNodeImpl, TSummaryParameterNode {
1460
1470
override Parameter getParameter ( ) { none ( ) }
1461
1471
1462
1472
override predicate isParameterOf ( DataFlowCallable c , ParameterPosition ppos ) {
1463
- sc = c .asLibraryCallable ( ) and
1464
- ppos = pos and
1465
- // avoid overlap with `SynthDictSplatParameterNode`
1466
- not (
1467
- pos .isDictSplat ( ) and
1468
- exists ( ParameterPosition keywordPos |
1469
- FlowSummaryImpl:: Private:: summaryParameterNodeRange ( sc , keywordPos ) and
1470
- keywordPos .isKeyword ( _)
1471
- )
1472
- )
1473
+ sc = c .asLibraryCallable ( ) and ppos = pos
1473
1474
}
1474
1475
1475
1476
override DataFlowCallable getEnclosingCallable ( ) { result .asLibraryCallable ( ) = sc }
0 commit comments