@@ -389,7 +389,7 @@ private module Cached {
389389 // ```
390390 exists ( DataFlow:: Node sourceNode , Module m |
391391 flowsToMethodCall ( call , sourceNode , method ) and
392- singletonMethodOnModule ( result , method , m )
392+ result = lookupSingletonMethod ( m , method )
393393 |
394394 // ```rb
395395 // def C.singleton; end # <- result
@@ -725,14 +725,33 @@ private predicate singletonMethodOnModule(MethodBase method, string name, Module
725725 selfInModule ( object .( SelfVariableReadAccess ) .getVariable ( ) , m )
726726 )
727727 or
728- flowsToSingletonMethodObject ( trackModuleAccess ( m ) , method , name )
728+ exists ( DataFlow:: LocalSourceNode sourceNode |
729+ m = resolveConstantReadAccess ( sourceNode .asExpr ( ) .getExpr ( ) ) and
730+ flowsToSingletonMethodObject ( sourceNode , method , name )
731+ )
729732 or
730733 exists ( Module other |
731734 extendCallModule ( m , other ) and
732735 method = lookupMethod ( other , name )
733736 )
734737}
735738
739+ pragma [ nomagic]
740+ private MethodBase lookupSingletonMethod ( Module m , string name ) {
741+ singletonMethodOnModule ( result , name , m )
742+ or
743+ // cannot be part of `singletonMethodOnModule` because it would introduce
744+ // negative recursion below
745+ exists ( DataFlow:: LocalSourceNode sourceNode |
746+ sourceNode = trackModuleAccess ( m ) and
747+ not m = resolveConstantReadAccess ( sourceNode .asExpr ( ) .getExpr ( ) ) and
748+ flowsToSingletonMethodObject ( sourceNode , result , name )
749+ )
750+ or
751+ not singletonMethodOnModule ( _, name , m ) and
752+ result = lookupSingletonMethod ( m .getSuperClass ( ) , name )
753+ }
754+
736755/**
737756 * Holds if `method` is a singleton method named `name`, defined on expression
738757 * `object`, where `object` is not likely to resolve to a module:
0 commit comments