@@ -279,6 +279,20 @@ module CallGraph {
279279 StepSummary:: step ( getAnAllocationSiteRef ( node ) , result , objectWithMethodsStep ( ) )
280280 }
281281
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+
282296 /**
283297 * Holds if `pred` is assumed to flow to `succ` because a method is stored on an object that is assumed
284298 * to be the receiver of calls to that method.
@@ -291,9 +305,18 @@ module CallGraph {
291305 */
292306 cached
293307 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.
294309 exists ( DataFlow:: SourceNode host |
310+ // Complex flow for the host object
295311 pred = getAnAllocationSiteRef ( host ) and
296312 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+ )
297320 )
298321 }
299322}
0 commit comments