@@ -375,17 +375,10 @@ private module Cached {
375375 private predicate selfInSingletonMethodFlowsToMethodCallReceiver (
376376 RelevantCall call , Module m , string method
377377 ) {
378- exists ( SsaSelfDefinitionNode self , Module target , MethodBase caller |
378+ exists ( SsaSelfDefinitionNode self , MethodBase caller |
379379 flowsToMethodCallReceiver ( call , self , method ) and
380- target = m .getSuperClass * ( ) and
381- selfInMethod ( self .getVariable ( ) , caller , target ) and
382- singletonMethod ( caller , _, _) and
383- // Singleton methods declared in a block in the top-level may spuriously end up being seen as singleton
384- // methods on Object, if the block is actually evaluated in the context of another class.
385- // The 'self' inside such a singleton method could then be any class, leading to self-calls
386- // being resolved to arbitrary singleton methods.
387- // To remedy this, we do not allow following super-classes all the way to Object.
388- not ( m != target and target = TResolved ( "Object" ) )
380+ selfInMethod ( self .getVariable ( ) , caller , m ) and
381+ singletonMethod ( caller , _, _)
389382 )
390383 }
391384
@@ -441,20 +434,22 @@ private module Cached {
441434 // M.extend(M)
442435 // M.instance # <- call
443436 // ```
444- exists ( Module m | result = lookupSingletonMethod ( m , method ) |
437+ exists ( Module m , boolean exact | result = lookupSingletonMethod ( m , method , exact ) |
445438 // ```rb
446439 // def C.singleton; end # <- result
447440 // C.singleton # <- call
448441 // ```
449- moduleFlowsToMethodCallReceiver ( call , m , method )
442+ moduleFlowsToMethodCallReceiver ( call , m , method ) and
443+ exact = true
450444 or
451445 // ```rb
452446 // class C
453447 // def self.singleton; end # <- result
454448 // self.singleton # <- call
455449 // end
456450 // ```
457- selfInModuleFlowsToMethodCallReceiver ( call , m , method )
451+ selfInModuleFlowsToMethodCallReceiver ( call , m , method ) and
452+ exact = true
458453 or
459454 // ```rb
460455 // class C
@@ -464,7 +459,8 @@ private module Cached {
464459 // end
465460 // end
466461 // ```
467- selfInSingletonMethodFlowsToMethodCallReceiver ( call , m , method )
462+ selfInSingletonMethodFlowsToMethodCallReceiver ( call , m , method ) and
463+ exact = false
468464 )
469465 )
470466 or
@@ -796,26 +792,54 @@ private predicate singletonMethodOnModule(MethodBase method, string name, Module
796792 )
797793}
798794
799- /**
800- * Holds if `method` is a singleton method named `name`, defined on module
801- * `m`, or any transitive base class of `m`.
802- */
803795pragma [ nomagic]
804- private MethodBase lookupSingletonMethod ( Module m , string name ) {
796+ private MethodBase lookupSingletonMethodDirect ( Module m , string name ) {
805797 singletonMethodOnModule ( result , name , m )
806798 or
807- // cannot be part of `singletonMethodOnModule` because it would introduce
808- // negative recursion below
809799 exists ( DataFlow:: LocalSourceNode sourceNode |
810800 sourceNode = trackModuleAccess ( m ) and
811801 not m = resolveConstantReadAccess ( sourceNode .asExpr ( ) .getExpr ( ) ) and
812802 flowsToSingletonMethodObject ( sourceNode , result , name )
813803 )
804+ }
805+
806+ /**
807+ * Holds if `method` is a singleton method named `name`, defined on module
808+ * `m`, or any transitive base class of `m`.
809+ */
810+ pragma [ nomagic]
811+ private MethodBase lookupSingletonMethod ( Module m , string name ) {
812+ result = lookupSingletonMethodDirect ( m , name )
814813 or
814+ // cannot use `lookupSingletonMethodDirect` because it would introduce
815+ // negative recursion
815816 not singletonMethodOnModule ( _, name , m ) and
816817 result = lookupSingletonMethod ( m .getSuperClass ( ) , name )
817818}
818819
820+ pragma [ nomagic]
821+ private MethodBase lookupSingletonMethodInSubClasses ( Module m , string name ) {
822+ // Singleton methods declared in a block in the top-level may spuriously end up being seen as singleton
823+ // methods on Object, if the block is actually evaluated in the context of another class.
824+ // The 'self' inside such a singleton method could then be any class, leading to self-calls
825+ // being resolved to arbitrary singleton methods.
826+ // To remedy this, we do not allow following super-classes all the way to Object.
827+ not m = TResolved ( "Object" ) and
828+ exists ( Module sub | sub .getSuperClass ( ) = m |
829+ result = lookupSingletonMethodDirect ( sub , name ) or
830+ result = lookupSingletonMethodInSubClasses ( sub , name )
831+ )
832+ }
833+
834+ pragma [ nomagic]
835+ private MethodBase lookupSingletonMethod ( Module m , string name , boolean exact ) {
836+ result = lookupSingletonMethod ( m , name ) and
837+ exact in [ false , true ]
838+ or
839+ result = lookupSingletonMethodInSubClasses ( m , name ) and
840+ exact = false
841+ }
842+
819843/**
820844 * Holds if `method` is a singleton method named `name`, defined on expression
821845 * `object`, where `object` is not likely to resolve to a module:
0 commit comments