@@ -43,6 +43,11 @@ module API {
4343 */
4444 DataFlow:: LocalSourceNode getAnImmediateUse ( ) { Impl:: use ( this , result ) }
4545
46+ /**
47+ * Gets a data-flow node corresponding the value flowing into this API component.
48+ */
49+ DataFlow:: Node getARhs ( ) { Impl:: def ( this , result ) }
50+
4651 /**
4752 * Gets a call to a method on the receiver represented by this API component.
4853 */
@@ -97,6 +102,30 @@ module API {
97102 result = this .getASubclass ( ) .getASuccessor ( Label:: return ( method ) )
98103 }
99104
105+ private predicate hasParameterIndex ( int n ) {
106+ exists ( string str |
107+ exists ( this .getASuccessor ( Label:: parameterByStr ( str ) ) ) and
108+ n = str .toInt ( )
109+ )
110+ }
111+
112+ /** Gets an API node representing the `n`th positional parameter. */
113+ Node getParameter ( int n ) {
114+ result = this .getASuccessor ( Label:: parameter ( n ) ) and this .hasParameterIndex ( n )
115+ }
116+
117+ private predicate hasKeywordParameter ( string name ) {
118+ exists ( this .getASuccessor ( Label:: keywordParameter ( name ) ) )
119+ }
120+
121+ /** Gets an API node representing the given keyword parameter. */
122+ Node getKeywordParameter ( string name ) {
123+ result = this .getASuccessor ( Label:: keywordParameter ( name ) ) and this .hasKeywordParameter ( name )
124+ }
125+
126+ /** Gets an API node representing the block parameter. */
127+ Node getBlock ( ) { result = this .getASuccessor ( Label:: blockParameter ( ) ) }
128+
100129 /**
101130 * Gets a `new` call to the function represented by this API component.
102131 */
@@ -260,7 +289,9 @@ module API {
260289 /** The root of the API graph. */
261290 MkRoot ( ) or
262291 /** A use of an API member at the node `nd`. */
263- MkUse ( DataFlow:: Node nd ) { isUse ( nd ) }
292+ MkUse ( DataFlow:: Node nd ) { isUse ( nd ) } or
293+ /** A value that escapes into an API at the node `nd` */
294+ MkDef ( DataFlow:: Node nd ) { isDef ( nd ) }
264295
265296 private string resolveTopLevel ( ConstantReadAccess read ) {
266297 TResolved ( result ) = resolveConstantReadAccess ( read ) and
@@ -319,6 +350,8 @@ module API {
319350 useCandFwd ( ) .flowsTo ( node ) and
320351 useStep ( _, node , nd )
321352 )
353+ or
354+ parameterStep ( _, defCand ( ) , nd )
322355 }
323356
324357 /**
@@ -327,13 +360,21 @@ module API {
327360 cached
328361 predicate use ( TApiNode nd , DataFlow:: Node ref ) { nd = MkUse ( ref ) }
329362
363+ /**
364+ * Holds if `ref` is a RHS of node `nd`.
365+ */
366+ cached
367+ predicate def ( TApiNode nd , DataFlow:: Node rhs ) { nd = MkDef ( rhs ) }
368+
369+ /** Gets a node reachable from a use-node. */
330370 private DataFlow:: LocalSourceNode useCandFwd ( TypeTracker t ) {
331371 t .start ( ) and
332372 isUse ( result )
333373 or
334374 exists ( TypeTracker t2 | result = useCandFwd ( t2 ) .track ( t2 , t ) )
335375 }
336376
377+ /** Gets a node reachable from a use-node. */
337378 private DataFlow:: LocalSourceNode useCandFwd ( ) { result = useCandFwd ( TypeTracker:: end ( ) ) }
338379
339380 private DataFlow:: Node useCandRev ( TypeBackTracker tb ) {
@@ -353,6 +394,73 @@ module API {
353394 isUse ( result )
354395 }
355396
397+ private predicate isDef ( DataFlow:: Node rhs ) {
398+ exists ( DataFlow:: Node use |
399+ useCandFwd ( ) .flowsTo ( use ) and
400+ argumentStep ( _, use , rhs )
401+ )
402+ }
403+
404+ /** Gets a data flow node that flows to the RHS of a def-node. */
405+ private DataFlow:: LocalSourceNode defCand ( TypeBackTracker t ) {
406+ t .start ( ) and
407+ exists ( DataFlow:: Node rhs |
408+ isDef ( rhs ) and
409+ result = rhs .getALocalSource ( )
410+ )
411+ or
412+ exists ( TypeBackTracker t2 | result = defCand ( t2 ) .backtrack ( t2 , t ) )
413+ }
414+
415+ /** Gets a data flow node that flows to the RHS of a def-node. */
416+ private DataFlow:: LocalSourceNode defCand ( ) { result = defCand ( TypeBackTracker:: end ( ) ) }
417+
418+ /**
419+ * Holds if there should be a `lbl`-edge from the given call to an argument.
420+ */
421+ pragma [ nomagic]
422+ private predicate argumentStep ( string lbl , DataFlow:: CallNode call , DataFlow:: Node argument ) {
423+ exists ( int n |
424+ argument = call .getArgument ( n ) and
425+ lbl = Label:: parameter ( n )
426+ )
427+ or
428+ exists ( string name |
429+ argument = call .getKeywordArgument ( name ) and
430+ lbl = Label:: keywordParameter ( name )
431+ )
432+ or
433+ argument = call .getBlock ( ) and
434+ lbl = Label:: blockParameter ( )
435+ }
436+
437+ /**
438+ * Holds if there should be a `lbl`-edge from the given callable to a parameter.
439+ */
440+ pragma [ nomagic]
441+ private predicate parameterStep ( string lbl , DataFlow:: Node callable , DataFlow:: Node paramNode ) {
442+ exists ( Parameter param |
443+ paramNode .asParameter ( ) = param and
444+ callable .asExpr ( ) .getExpr ( ) .( Callable ) .getAParameter ( ) = param and
445+ lbl = getLabelFromParameter ( param )
446+ )
447+ }
448+
449+ private string getLabelFromParameter ( Parameter param ) {
450+ result = Label:: keywordParameter ( param .( KeywordParameter ) .getName ( ) )
451+ or
452+ param instanceof BlockParameter and
453+ result = Label:: blockParameter ( )
454+ or
455+ // TODO: the index can be offset by preceding non-positional parameters; translate correctly
456+ (
457+ param instanceof SimpleParameter
458+ or
459+ param instanceof OptionalParameter
460+ ) and
461+ result = Label:: parameter ( param .getPosition ( ) )
462+ }
463+
356464 /**
357465 * Gets a data-flow node to which `src`, which is a use of an API-graph node, flows.
358466 *
@@ -381,6 +489,21 @@ module API {
381489 result = trackUseNode ( src , TypeTracker:: end ( ) )
382490 }
383491
492+ /** Gets a data flow node reaching the RHS of the given def node. */
493+ private DataFlow:: LocalSourceNode trackDefNode ( DataFlow:: Node rhs , TypeBackTracker t ) {
494+ t .start ( ) and
495+ isDef ( rhs ) and
496+ result = rhs .getALocalSource ( )
497+ or
498+ exists ( TypeBackTracker t2 | result = trackDefNode ( rhs , t2 ) .backtrack ( t2 , t ) )
499+ }
500+
501+ /** Gets a data flow node reaching the RHS of the given def node. */
502+ cached
503+ DataFlow:: LocalSourceNode trackDefNode ( DataFlow:: Node rhs ) {
504+ result = trackDefNode ( rhs , TypeBackTracker:: end ( ) )
505+ }
506+
384507 /**
385508 * Holds if there is an edge from `pred` to `succ` in the API graph that is labeled with `lbl`.
386509 */
@@ -408,6 +531,17 @@ module API {
408531 c .getSuperclassExpr ( ) = a .asExpr ( ) .getExpr ( ) and
409532 lbl = Label:: subclass ( )
410533 )
534+ or
535+ exists ( DataFlow:: Node use , DataFlow:: Node base , DataFlow:: Node rhs |
536+ pred = MkUse ( use ) and
537+ trackUseNode ( use ) .flowsTo ( base ) and
538+ argumentStep ( lbl , base , rhs ) and
539+ succ = MkDef ( rhs )
540+ or
541+ pred = MkDef ( rhs ) and
542+ parameterStep ( lbl , trackDefNode ( rhs ) , use ) and
543+ succ = MkUse ( use )
544+ )
411545 }
412546
413547 /**
@@ -436,4 +570,21 @@ private module Label {
436570 string return ( string m ) { result = "getReturn(\"" + m + "\")" }
437571
438572 string subclass ( ) { result = "getASubclass()" }
573+
574+ /** Gets the label representing the given keword argument/parameter. */
575+ bindingset [ name]
576+ bindingset [ result ]
577+ string keywordParameter ( string name ) { result = "getKeywordParameter(\"" + name + "\")" }
578+
579+ /** Gets the label representing the `n`th positional argument/parameter. */
580+ bindingset [ n]
581+ string parameter ( int n ) { result = parameterByStr ( n .toString ( ) ) }
582+
583+ /** Gets the label representing the `n`th positional argument/parameter. */
584+ bindingset [ n]
585+ bindingset [ result ]
586+ string parameterByStr ( string n ) { result = "getParameter(" + n + ")" }
587+
588+ /** Gets the label representing the block argument/parameter. */
589+ string blockParameter ( ) { result = "getBlock()" }
439590}
0 commit comments