@@ -252,8 +252,8 @@ module API {
252252 * Holds if `ref` is a use of a node that should have an incoming edge from the root
253253 * node labeled `lbl` in the API graph.
254254 */
255- cached
256- predicate useRoot ( string lbl , DataFlow:: Node ref ) {
255+ pragma [ nomagic ]
256+ private predicate useRoot ( string lbl , DataFlow:: Node ref ) {
257257 exists ( string name , ExprNodes:: ConstantAccessCfgNode access , ConstantReadAccess read |
258258 access = ref .asExpr ( ) and
259259 lbl = Label:: member ( read .getName ( ) ) and
@@ -268,64 +268,48 @@ module API {
268268 }
269269
270270 /**
271- * Holds if `ref` is a use of a node that should have an incoming edge from use node
272- * `base` labeled `lbl` in the API graph .
271+ * Holds if `ref` is a use of a node that should have an incoming edge labeled `lbl`,
272+ * from a use node that flows to `node` .
273273 */
274- cached
275- predicate useUse ( DataFlow:: LocalSourceNode base , string lbl , DataFlow:: Node ref ) {
276- exists ( ExprCfgNode node |
277- // First, we find a predecessor of the node `ref` that we want to determine. The predecessor
278- // is any node that is a type-tracked use of a data flow node (`src`), which is itself a
279- // reference to the API node `base`. Thus, `pred` and `src` both represent uses of `base`.
280- //
281- // Once we have identified the predecessor, we define its relation to the successor `ref` as
282- // well as the label on the edge from `pred` to `ref`. This label describes the nature of
283- // the relationship between `pred` and `ref`.
284- useExpr ( node , base )
285- |
286- // // Referring to an attribute on a node that is a use of `base`:
287- // pred = `Rails` part of `Rails::Whatever`
288- // lbl = `Whatever`
289- // ref = `Rails::Whatever`
290- exists ( ExprNodes:: ConstantAccessCfgNode c , ConstantReadAccess read |
291- not exists ( resolveTopLevel ( read ) ) and
292- node = c .getScopeExpr ( ) and
293- lbl = Label:: member ( read .getName ( ) ) and
294- ref .asExpr ( ) = c and
295- read = c .getExpr ( )
296- )
297- or
298- // Calling a method on a node that is a use of `base`
299- exists ( ExprNodes:: MethodCallCfgNode call , string name |
300- node = call .getReceiver ( ) and
301- name = call .getExpr ( ) .getMethodName ( ) and
302- lbl = Label:: return ( name ) and
303- name != "new" and
304- ref .asExpr ( ) = call
305- )
306- or
307- // Calling the `new` method on a node that is a use of `base`, which creates a new instance
308- exists ( ExprNodes:: MethodCallCfgNode call |
309- node = call .getReceiver ( ) and
310- lbl = Label:: instance ( ) and
311- call .getExpr ( ) .getMethodName ( ) = "new" and
312- ref .asExpr ( ) = call
313- )
274+ private predicate useStep ( string lbl , ExprCfgNode node , DataFlow:: Node ref ) {
275+ // // Referring to an attribute on a node that is a use of `base`:
276+ // pred = `Rails` part of `Rails::Whatever`
277+ // lbl = `Whatever`
278+ // ref = `Rails::Whatever`
279+ exists ( ExprNodes:: ConstantAccessCfgNode c , ConstantReadAccess read |
280+ not exists ( resolveTopLevel ( read ) ) and
281+ node = c .getScopeExpr ( ) and
282+ lbl = Label:: member ( read .getName ( ) ) and
283+ ref .asExpr ( ) = c and
284+ read = c .getExpr ( )
285+ )
286+ or
287+ // Calling a method on a node that is a use of `base`
288+ exists ( ExprNodes:: MethodCallCfgNode call , string name |
289+ node = call .getReceiver ( ) and
290+ name = call .getExpr ( ) .getMethodName ( ) and
291+ lbl = Label:: return ( name ) and
292+ name != "new" and
293+ ref .asExpr ( ) = call
294+ )
295+ or
296+ // Calling the `new` method on a node that is a use of `base`, which creates a new instance
297+ exists ( ExprNodes:: MethodCallCfgNode call |
298+ node = call .getReceiver ( ) and
299+ lbl = Label:: instance ( ) and
300+ call .getExpr ( ) .getMethodName ( ) = "new" and
301+ ref .asExpr ( ) = call
314302 )
315303 }
316304
317305 pragma [ nomagic]
318306 private predicate isUse ( DataFlow:: Node nd ) {
319307 useRoot ( _, nd )
320308 or
321- useUse ( _, _, nd )
322- }
323-
324- pragma [ nomagic]
325- private predicate useExpr ( ExprCfgNode node , DataFlow:: LocalSourceNode src ) {
326- exists ( DataFlow:: LocalSourceNode pred |
327- pred = trackUseNode ( src ) and
328- pred .flowsTo ( any ( DataFlow:: ExprNode n | n .getExprNode ( ) = node ) )
309+ exists ( ExprCfgNode node , DataFlow:: LocalSourceNode pred |
310+ pred = useCandFwd ( ) and
311+ pred .flowsTo ( any ( DataFlow:: ExprNode n | n .getExprNode ( ) = node ) ) and
312+ useStep ( _, node , nd )
329313 )
330314 }
331315
@@ -335,26 +319,54 @@ module API {
335319 cached
336320 predicate use ( TApiNode nd , DataFlow:: Node ref ) { nd = MkUse ( ref ) }
337321
322+ private DataFlow:: LocalSourceNode useCandFwd ( TypeTracker t ) {
323+ t .start ( ) and
324+ isUse ( result )
325+ or
326+ exists ( TypeTracker t2 | result = useCandFwd ( t2 ) .track ( t2 , t ) )
327+ }
328+
329+ private DataFlow:: LocalSourceNode useCandFwd ( ) { result = useCandFwd ( TypeTracker:: end ( ) ) }
330+
331+ private DataFlow:: Node useCandRev ( TypeBackTracker tb ) {
332+ result = useCandFwd ( ) and
333+ tb .start ( )
334+ or
335+ exists ( TypeBackTracker tb2 , DataFlow:: LocalSourceNode mid , TypeTracker t |
336+ mid = useCandRev ( tb2 ) and
337+ result = mid .backtrack ( tb2 , tb ) and
338+ pragma [ only_bind_out ] ( result ) = useCandFwd ( t ) and
339+ pragma [ only_bind_out ] ( t ) = pragma [ only_bind_out ] ( tb ) .getACompatibleTypeTracker ( )
340+ )
341+ }
342+
343+ private DataFlow:: LocalSourceNode useCandRev ( ) {
344+ result = useCandRev ( TypeBackTracker:: end ( ) ) and
345+ isUse ( result )
346+ }
347+
338348 /**
339349 * Gets a data-flow node to which `src`, which is a use of an API-graph node, flows.
340350 *
341- * The flow from `src` to that node may be inter-procedural.
351+ * The flow from `src` to the returned node may be inter-procedural.
342352 */
343- private DataFlow:: LocalSourceNode trackUseNode ( DataFlow:: Node src , TypeTracker t ) {
344- // Declaring `src` to be a `LocalSourceNode` currently causes a redundant check in the
345- // recursive case, so instead we check it explicitly here.
346- src instanceof DataFlow:: LocalSourceNode and
347- t .start ( ) and
348- isUse ( src ) and
349- result = src
353+ private DataFlow:: Node trackUseNode ( DataFlow:: LocalSourceNode src , TypeTracker t ) {
354+ result = src and
355+ result = useCandRev ( ) and
356+ t .start ( )
350357 or
351- exists ( TypeTracker t2 | result = trackUseNode ( src , t2 ) .track ( t2 , t ) )
358+ exists ( TypeTracker t2 , DataFlow:: LocalSourceNode mid , TypeBackTracker tb |
359+ mid = trackUseNode ( src , t2 ) and
360+ result = mid .track ( t2 , t ) and
361+ pragma [ only_bind_out ] ( result ) = useCandRev ( tb ) and
362+ pragma [ only_bind_out ] ( t ) = pragma [ only_bind_out ] ( tb ) .getACompatibleTypeTracker ( )
363+ )
352364 }
353365
354366 /**
355367 * Gets a data-flow node to which `src`, which is a use of an API-graph node, flows.
356368 *
357- * The flow from `src` to that node may be inter-procedural.
369+ * The flow from `src` to the returned node may be inter-procedural.
358370 */
359371 cached
360372 DataFlow:: LocalSourceNode trackUseNode ( DataFlow:: LocalSourceNode src ) {
@@ -371,9 +383,10 @@ module API {
371383 pred = MkRoot ( ) and
372384 useRoot ( lbl , ref )
373385 or
374- exists ( DataFlow:: Node nd |
375- pred = MkUse ( nd ) and
376- useUse ( nd , lbl , ref )
386+ exists ( ExprCfgNode node , DataFlow:: Node src |
387+ pred = MkUse ( src ) and
388+ trackUseNode ( src ) .flowsTo ( any ( DataFlow:: ExprNode n | n .getExprNode ( ) = node ) ) and
389+ useStep ( lbl , node , ref )
377390 )
378391 )
379392 }
0 commit comments