@@ -375,17 +375,10 @@ private module Cached {
375
375
private predicate selfInSingletonMethodFlowsToMethodCallReceiver (
376
376
RelevantCall call , Module m , string method
377
377
) {
378
- exists ( SsaSelfDefinitionNode self , Module target , MethodBase caller |
378
+ exists ( SsaSelfDefinitionNode self , MethodBase caller |
379
379
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 , _, _)
389
382
)
390
383
}
391
384
@@ -441,20 +434,22 @@ private module Cached {
441
434
// M.extend(M)
442
435
// M.instance # <- call
443
436
// ```
444
- exists ( Module m | result = lookupSingletonMethod ( m , method ) |
437
+ exists ( Module m , boolean exact | result = lookupSingletonMethod ( m , method , exact ) |
445
438
// ```rb
446
439
// def C.singleton; end # <- result
447
440
// C.singleton # <- call
448
441
// ```
449
- moduleFlowsToMethodCallReceiver ( call , m , method )
442
+ moduleFlowsToMethodCallReceiver ( call , m , method ) and
443
+ exact = true
450
444
or
451
445
// ```rb
452
446
// class C
453
447
// def self.singleton; end # <- result
454
448
// self.singleton # <- call
455
449
// end
456
450
// ```
457
- selfInModuleFlowsToMethodCallReceiver ( call , m , method )
451
+ selfInModuleFlowsToMethodCallReceiver ( call , m , method ) and
452
+ exact = true
458
453
or
459
454
// ```rb
460
455
// class C
@@ -464,7 +459,8 @@ private module Cached {
464
459
// end
465
460
// end
466
461
// ```
467
- selfInSingletonMethodFlowsToMethodCallReceiver ( call , m , method )
462
+ selfInSingletonMethodFlowsToMethodCallReceiver ( call , m , method ) and
463
+ exact = false
468
464
)
469
465
)
470
466
or
@@ -796,26 +792,54 @@ private predicate singletonMethodOnModule(MethodBase method, string name, Module
796
792
)
797
793
}
798
794
799
- /**
800
- * Holds if `method` is a singleton method named `name`, defined on module
801
- * `m`, or any transitive base class of `m`.
802
- */
803
795
pragma [ nomagic]
804
- private MethodBase lookupSingletonMethod ( Module m , string name ) {
796
+ private MethodBase lookupSingletonMethodDirect ( Module m , string name ) {
805
797
singletonMethodOnModule ( result , name , m )
806
798
or
807
- // cannot be part of `singletonMethodOnModule` because it would introduce
808
- // negative recursion below
809
799
exists ( DataFlow:: LocalSourceNode sourceNode |
810
800
sourceNode = trackModuleAccess ( m ) and
811
801
not m = resolveConstantReadAccess ( sourceNode .asExpr ( ) .getExpr ( ) ) and
812
802
flowsToSingletonMethodObject ( sourceNode , result , name )
813
803
)
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 )
814
813
or
814
+ // cannot use `lookupSingletonMethodDirect` because it would introduce
815
+ // negative recursion
815
816
not singletonMethodOnModule ( _, name , m ) and
816
817
result = lookupSingletonMethod ( m .getSuperClass ( ) , name )
817
818
}
818
819
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
+
819
843
/**
820
844
* Holds if `method` is a singleton method named `name`, defined on expression
821
845
* `object`, where `object` is not likely to resolve to a module:
0 commit comments