@@ -279,6 +279,20 @@ module CallGraph {
279
279
StepSummary:: step ( getAnAllocationSiteRef ( node ) , result , objectWithMethodsStep ( ) )
280
280
}
281
281
282
+ /**
283
+ * Holds if `function` flows to a property of `host` via non-local data flow.
284
+ */
285
+ pragma [ nomagic]
286
+ private predicate complexMethodInstallation (
287
+ DataFlow:: SourceNode host , DataFlow:: FunctionNode function
288
+ ) {
289
+ not function = getAMethodOnObject ( _) and
290
+ exists ( DataFlow:: TypeTracker t |
291
+ getAFunctionReference ( function , 0 , t ) = host .getAPropertySource ( ) and
292
+ t .start ( ) // require call bit to be false
293
+ )
294
+ }
295
+
282
296
/**
283
297
* Holds if `pred` is assumed to flow to `succ` because a method is stored on an object that is assumed
284
298
* to be the receiver of calls to that method.
@@ -291,9 +305,18 @@ module CallGraph {
291
305
*/
292
306
cached
293
307
predicate impliedReceiverStep ( DataFlow:: SourceNode pred , DataFlow:: SourceNode succ ) {
308
+ // To avoid double-recursion, we handle either complex flow for the host object, or for the function, but not both.
294
309
exists ( DataFlow:: SourceNode host |
310
+ // Complex flow for the host object
295
311
pred = getAnAllocationSiteRef ( host ) and
296
312
succ = getAMethodOnObject ( host ) .getReceiver ( )
313
+ or
314
+ // Complex flow for the function
315
+ exists ( DataFlow:: FunctionNode function |
316
+ complexMethodInstallation ( host , function ) and
317
+ pred = host and
318
+ succ = function .getReceiver ( )
319
+ )
297
320
)
298
321
}
299
322
}
0 commit comments