@@ -229,18 +229,71 @@ class SsaInputNode extends SsaNode {
229229 override CfgScope getCfgScope ( ) { result = node .getDefinitionExt ( ) .getBasicBlock ( ) .getScope ( ) }
230230}
231231
232+ private string getANamedArgument ( Cmd c ) { exists ( c .getNamedArgument ( result ) ) }
233+
234+ private module NamedSetModule = QlBuiltins:: InternSets< Cmd , string , getANamedArgument / 1 > ;
235+
236+ private newtype NamedSet0 =
237+ TEmptyNamedSet ( ) or
238+ TNonEmptyNamedSet ( NamedSetModule:: Set ns )
239+
240+ /** A (possiby empty) set of argument names. */
241+ class NamedSet extends NamedSet0 {
242+ /** Gets the non-empty set of names, if any. */
243+ NamedSetModule:: Set asNonEmpty ( ) { this = TNonEmptyNamedSet ( result ) }
244+
245+ /** Holds if this is the empty set. */
246+ predicate isEmpty ( ) { this = TEmptyNamedSet ( ) }
247+
248+ /** Gets a name in this set. */
249+ string getAName ( ) { this .asNonEmpty ( ) .contains ( result ) }
250+
251+ /** Gets the textual representation of this set. */
252+ string toString ( ) {
253+ result = "{" + strictconcat ( this .getAName ( ) , ", " ) + "}"
254+ or
255+ this .isEmpty ( ) and
256+ result = "{}"
257+ }
258+
259+ /**
260+ * Gets a `Cmd` that provides a named parameter for every name in `this`.
261+ *
262+ * NOTE: The `Cmd` may also provide more names.
263+ */
264+ Cmd getABindingCall ( ) {
265+ forex ( string name | name = this .getAName ( ) | exists ( result .getNamedArgument ( name ) ) )
266+ or
267+ this .isEmpty ( ) and
268+ exists ( result )
269+ }
270+
271+ /**
272+ * Gets a `Cmd` that provides exactly the named parameters represented by
273+ * this set.
274+ */
275+ Cmd getAnExactBindingCall ( ) {
276+ forex ( string name | name = this .getAName ( ) | exists ( result .getNamedArgument ( name ) ) ) and
277+ forex ( string name | exists ( result .getNamedArgument ( name ) ) | name = this .getAName ( ) )
278+ or
279+ this .isEmpty ( ) and
280+ not exists ( result .getNamedArgument ( _) )
281+ }
282+
283+ /** Gets a function that has a parameter for each name in this set. */
284+ Function getAFunction ( ) {
285+ forex ( string name | name = this .getAName ( ) | result .getAParameter ( ) .hasName ( name ) )
286+ or
287+ this .isEmpty ( ) and
288+ exists ( result )
289+ }
290+ }
291+
232292private module ParameterNodes {
233293 abstract class ParameterNodeImpl extends NodeImpl {
234294 abstract Parameter getParameter ( ) ;
235295
236296 abstract predicate isParameterOf ( DataFlowCallable c , ParameterPosition pos ) ;
237-
238- final predicate isSourceParameterOf ( CfgScope c , ParameterPosition pos ) {
239- exists ( DataFlowCallable callable |
240- this .isParameterOf ( callable , pos ) and
241- c = callable .asCfgScope ( )
242- )
243- }
244297 }
245298
246299 /**
@@ -255,8 +308,29 @@ private module ParameterNodes {
255308 override Parameter getParameter ( ) { result = parameter }
256309
257310 override predicate isParameterOf ( DataFlowCallable c , ParameterPosition pos ) {
258- exists ( CfgScope callable , int i |
259- callable = c .asCfgScope ( ) and pos .isPositional ( i ) and callable .getParameter ( i ) = parameter
311+ exists ( CfgScope callable | callable = c .asCfgScope ( ) |
312+ pos .isKeyword ( parameter .getName ( ) )
313+ or
314+ // Given a function f with parameters x, y we map
315+ // x to the positions:
316+ // 1. keyword(x)
317+ // 2. position(0, {y})
318+ // 3. position(0, {})
319+ // Likewise, y is mapped to the positions:
320+ // 1. keyword(y)
321+ // 2. position(0, {x})
322+ // 3. position(1, {})
323+ // The interpretation of `position(i, S)` is the position of the i'th unnamed parameter when the
324+ // keywords in S are specified.
325+ exists ( int i , int j , string name , NamedSet ns , Function f |
326+ pos .isPositional ( j , ns ) and
327+ parameter .getIndex ( ) = i and
328+ f = parameter .getFunction ( ) and
329+ f = ns .getAFunction ( ) and
330+ name = parameter .getName ( ) and
331+ not name = ns .getAName ( ) and
332+ j = i - count ( int k | k < i and f .getParameter ( k ) .getName ( ) = ns .getAName ( ) )
333+ )
260334 )
261335 }
262336
@@ -275,14 +349,29 @@ abstract class ArgumentNode extends Node {
275349 /** Holds if this argument occurs at the given position in the given call. */
276350 abstract predicate argumentOf ( DataFlowCall call , ArgumentPosition pos ) ;
277351
278- abstract predicate sourceArgumentOf ( CfgNodes:: StmtNodes:: CmdCfgNode call , ArgumentPosition pos ) ;
279-
280352 /** Gets the call in which this node is an argument. */
281353 final DataFlowCall getCall ( ) { this .argumentOf ( result , _) }
282354}
283355
284356module ArgumentNodes {
285- // TODO
357+ class ExplicitArgumentNode extends ArgumentNode {
358+ CfgNodes:: ExprNodes:: ArgumentCfgNode arg ;
359+
360+ ExplicitArgumentNode ( ) { this .asExpr ( ) = arg }
361+
362+ override predicate argumentOf ( DataFlowCall call , ArgumentPosition pos ) {
363+ arg .getCmd ( ) = call .asCall ( ) and
364+ (
365+ pos .isKeyword ( arg .getName ( ) )
366+ or
367+ exists ( NamedSet ns , int i |
368+ i = arg .getPosition ( ) and
369+ ns .getAnExactBindingCall ( ) = call .asCall ( ) .getStmt ( ) and
370+ pos .isPositional ( i , ns )
371+ )
372+ )
373+ }
374+ }
286375}
287376
288377import ArgumentNodes
0 commit comments