@@ -444,87 +444,100 @@ private DataFlow::LocalSourceNode trackModuleAccess(Module m) {
444
444
result = trackModuleAccess ( m , TypeTracker:: end ( ) )
445
445
}
446
446
447
- pragma [ nomagic]
448
- private DataFlow:: LocalSourceNode trackInstance ( Module tp , boolean exact , TypeTracker t ) {
449
- t .start ( ) and
450
- (
451
- result .asExpr ( ) .getExpr ( ) instanceof NilLiteral and
452
- tp = TResolved ( "NilClass" ) and
453
- exact = true
454
- or
455
- result .asExpr ( ) .getExpr ( ) .( BooleanLiteral ) .isFalse ( ) and
456
- tp = TResolved ( "FalseClass" ) and
457
- exact = true
458
- or
459
- result .asExpr ( ) .getExpr ( ) .( BooleanLiteral ) .isTrue ( ) and
460
- tp = TResolved ( "TrueClass" ) and
461
- exact = true
462
- or
463
- result .asExpr ( ) .getExpr ( ) instanceof IntegerLiteral and
464
- tp = TResolved ( "Integer" ) and
465
- exact = true
466
- or
467
- result .asExpr ( ) .getExpr ( ) instanceof FloatLiteral and
468
- tp = TResolved ( "Float" ) and
469
- exact = true
470
- or
471
- result .asExpr ( ) .getExpr ( ) instanceof RationalLiteral and
472
- tp = TResolved ( "Rational" ) and
473
- exact = true
474
- or
475
- result .asExpr ( ) .getExpr ( ) instanceof ComplexLiteral and
476
- tp = TResolved ( "Complex" ) and
477
- exact = true
478
- or
479
- result .asExpr ( ) .getExpr ( ) instanceof StringlikeLiteral and
480
- tp = TResolved ( "String" ) and
481
- exact = true
482
- or
483
- result .asExpr ( ) instanceof CfgNodes:: ExprNodes:: ArrayLiteralCfgNode and
484
- tp = TResolved ( "Array" ) and
485
- exact = true
486
- or
487
- result .asExpr ( ) instanceof CfgNodes:: ExprNodes:: HashLiteralCfgNode and
488
- tp = TResolved ( "Hash" ) and
489
- exact = true
490
- or
491
- result .asExpr ( ) .getExpr ( ) instanceof MethodBase and
492
- tp = TResolved ( "Symbol" ) and
493
- exact = true
494
- or
495
- result .asParameter ( ) instanceof BlockParameter and
496
- tp = TResolved ( "Proc" ) and
497
- exact = true
447
+ /** Holds if `n` is an instance of type `tp`. */
448
+ private predicate isInstance ( DataFlow:: LocalSourceNode n , Module tp , boolean exact ) {
449
+ n .asExpr ( ) .getExpr ( ) instanceof NilLiteral and
450
+ tp = TResolved ( "NilClass" ) and
451
+ exact = true
452
+ or
453
+ n .asExpr ( ) .getExpr ( ) .( BooleanLiteral ) .isFalse ( ) and
454
+ tp = TResolved ( "FalseClass" ) and
455
+ exact = true
456
+ or
457
+ n .asExpr ( ) .getExpr ( ) .( BooleanLiteral ) .isTrue ( ) and
458
+ tp = TResolved ( "TrueClass" ) and
459
+ exact = true
460
+ or
461
+ n .asExpr ( ) .getExpr ( ) instanceof IntegerLiteral and
462
+ tp = TResolved ( "Integer" ) and
463
+ exact = true
464
+ or
465
+ n .asExpr ( ) .getExpr ( ) instanceof FloatLiteral and
466
+ tp = TResolved ( "Float" ) and
467
+ exact = true
468
+ or
469
+ n .asExpr ( ) .getExpr ( ) instanceof RationalLiteral and
470
+ tp = TResolved ( "Rational" ) and
471
+ exact = true
472
+ or
473
+ n .asExpr ( ) .getExpr ( ) instanceof ComplexLiteral and
474
+ tp = TResolved ( "Complex" ) and
475
+ exact = true
476
+ or
477
+ n .asExpr ( ) .getExpr ( ) instanceof StringlikeLiteral and
478
+ tp = TResolved ( "String" ) and
479
+ exact = true
480
+ or
481
+ n .asExpr ( ) instanceof CfgNodes:: ExprNodes:: ArrayLiteralCfgNode and
482
+ tp = TResolved ( "Array" ) and
483
+ exact = true
484
+ or
485
+ n .asExpr ( ) instanceof CfgNodes:: ExprNodes:: HashLiteralCfgNode and
486
+ tp = TResolved ( "Hash" ) and
487
+ exact = true
488
+ or
489
+ n .asExpr ( ) .getExpr ( ) instanceof MethodBase and
490
+ tp = TResolved ( "Symbol" ) and
491
+ exact = true
492
+ or
493
+ n .asParameter ( ) instanceof BlockParameter and
494
+ tp = TResolved ( "Proc" ) and
495
+ exact = true
496
+ or
497
+ n .asExpr ( ) .getExpr ( ) instanceof Lambda and
498
+ tp = TResolved ( "Proc" ) and
499
+ exact = true
500
+ or
501
+ exists ( CfgNodes:: ExprNodes:: CallCfgNode call , DataFlow:: LocalSourceNode sourceNode |
502
+ flowsToMethodCall ( call , sourceNode , "new" ) and
503
+ exact = true and
504
+ n .asExpr ( ) = call
505
+ |
506
+ // `C.new`
507
+ sourceNode = trackModuleAccess ( tp )
498
508
or
499
- result .asExpr ( ) .getExpr ( ) instanceof Lambda and
500
- tp = TResolved ( "Proc" ) and
501
- exact = true
509
+ // `self.new` inside a module
510
+ selfInModule ( sourceNode .( SsaSelfDefinitionNode ) .getVariable ( ) , tp )
502
511
or
503
- exists ( CfgNodes :: ExprNodes :: CallCfgNode call , DataFlow :: LocalSourceNode sourceNode |
504
- flowsToMethodCall ( call , sourceNode , "new" ) and
505
- exact = true and
506
- result . asExpr ( ) = call
507
- |
508
- // `C.new`
509
- sourceNode = trackModuleAccess ( tp )
510
- or
511
- // ` self.new` inside a module
512
- selfInModule ( sourceNode . ( SsaSelfDefinitionNode ) . getVariable ( ) , tp )
512
+ // `self.new` inside a (singleton) method
513
+ selfInMethod ( sourceNode . ( SsaSelfDefinitionNode ) . getVariable ( ) , tp )
514
+ )
515
+ or
516
+ // `self` reference in method or top-level (but not in module, where instance
517
+ // methods cannot be called; only singleton methods)
518
+ n =
519
+ any ( SsaSelfDefinitionNode self |
520
+ selfInMethod ( self .getVariable ( ) , tp ) and
521
+ exact = false
513
522
or
514
- // ` self.new` inside a (singleton) method
515
- selfInMethod ( sourceNode . ( SsaSelfDefinitionNode ) . getVariable ( ) , tp )
523
+ selfInToplevel ( self .getVariable ( ) , tp ) and
524
+ exact = true
516
525
)
517
- or
518
- // `self` reference in method or top-level (but not in module, where instance
519
- // methods cannot be called; only singleton methods)
520
- result =
521
- any ( SsaSelfDefinitionNode self |
522
- selfInMethod ( self .getVariable ( ) , tp ) and
523
- exact = false
524
- or
525
- selfInToplevel ( self .getVariable ( ) , tp ) and
526
- exact = true
527
- )
526
+ or
527
+ // `in C => c then c.foo`
528
+ asModulePattern ( n , tp ) and
529
+ exact = false
530
+ or
531
+ // `case object when C then object.foo`
532
+ hasAdjacentTypeCheckedReads ( _, _, n .asExpr ( ) , tp ) and
533
+ exact = false
534
+ }
535
+
536
+ pragma [ nomagic]
537
+ private DataFlow:: LocalSourceNode trackInstance ( Module tp , boolean exact , TypeTracker t ) {
538
+ t .start ( ) and
539
+ (
540
+ isInstance ( result , tp , exact )
528
541
or
529
542
exists ( Module m |
530
543
( if m .isClass ( ) then tp = TResolved ( "Class" ) else tp = TResolved ( "Module" ) ) and
@@ -539,14 +552,6 @@ private DataFlow::LocalSourceNode trackInstance(Module tp, boolean exact, TypeTr
539
552
// needed for e.g. `self.puts`
540
553
selfInMethod ( result .( SsaSelfDefinitionNode ) .getVariable ( ) , m )
541
554
)
542
- or
543
- // `in C => c then c.foo`
544
- asModulePattern ( result , tp ) and
545
- exact = false
546
- or
547
- // `case object when C then object.foo`
548
- hasAdjacentTypeCheckedReads ( _, _, result .asExpr ( ) , tp ) and
549
- exact = false
550
555
)
551
556
or
552
557
exists ( TypeTracker t2 , StepSummary summary |
@@ -786,19 +791,77 @@ private DataFlow::Node trackSingletonMethodOnInstance(MethodBase method, string
786
791
result = trackSingletonMethodOnInstance ( method , name , TypeTracker:: end ( ) )
787
792
}
788
793
794
+ /** Same as `isInstance`, but includes local must-flow through SSA definitions. */
795
+ private predicate isInstanceLocalFlow ( DataFlow:: Node n , Module tp , boolean exact ) {
796
+ isInstance ( n , tp , exact )
797
+ or
798
+ exists ( DataFlow:: Node mid | isInstanceLocalFlow ( mid , tp , exact ) |
799
+ n .asExpr ( ) = mid .( SsaDefinitionNode ) .getDefinition ( ) .getARead ( )
800
+ or
801
+ n .( SsaDefinitionNode ) .getDefinition ( ) .( Ssa:: WriteDefinition ) .assigns ( mid .asExpr ( ) )
802
+ )
803
+ }
804
+
805
+ /**
806
+ * Holds if `ctx` targets `c`, which is the enclosing callable of `call`, and
807
+ * the receiver of `call` is a parameter access, where the corresponding argument
808
+ * of `ctx` has type `tp`.
809
+ *
810
+ * `name` is the name of the method being called by `call`, and `exact` is pertaining
811
+ * to the type of the argument.
812
+ */
813
+ pragma [ nomagic]
814
+ private predicate mayBenefitFromCallContext0 (
815
+ CfgNodes:: ExprNodes:: CallCfgNode ctx , CfgNodes:: ExprNodes:: CallCfgNode call , Callable c ,
816
+ Module tp , boolean exact , string name
817
+ ) {
818
+ exists (
819
+ ParameterNodeImpl p , DataFlow:: Node ssaNode , ParameterPosition ppos , ArgumentPosition apos ,
820
+ ArgumentNode arg
821
+ |
822
+ ssaNode = trackInstance ( _, _) and
823
+ LocalFlow:: localFlowSsaParamInput ( p , ssaNode ) and
824
+ flowsToMethodCall ( pragma [ only_bind_into ] ( call ) , pragma [ only_bind_into ] ( ssaNode ) ,
825
+ pragma [ only_bind_into ] ( name ) ) and
826
+ c = call .getScope ( ) and
827
+ p .isParameterOf ( TCfgScope ( c ) , ppos ) and
828
+ getTarget ( ctx ) = c and
829
+ arg .sourceArgumentOf ( ctx , apos ) and
830
+ parameterMatch ( ppos , apos ) and
831
+ isInstanceLocalFlow ( arg , pragma [ only_bind_out ] ( tp ) , exact ) and
832
+ exists ( lookupMethod ( tp , pragma [ only_bind_into ] ( name ) ) )
833
+ )
834
+ }
835
+
789
836
/**
790
837
* Holds if the set of viable implementations that can be called by `call`
791
838
* might be improved by knowing the call context. This is the case if the
792
- * qualifier accesses a parameter of the enclosing callable `c` (including
839
+ * receiver accesses a parameter of the enclosing callable `c` (including
793
840
* the implicit `self` parameter).
794
841
*/
795
- predicate mayBenefitFromCallContext ( DataFlowCall call , DataFlowCallable c ) { none ( ) }
842
+ predicate mayBenefitFromCallContext ( DataFlowCall call , DataFlowCallable c ) {
843
+ call .asCall ( ) =
844
+ any ( CfgNodes:: ExprNodes:: CallCfgNode callNode |
845
+ c .asCallable ( ) = any ( Callable encl | mayBenefitFromCallContext0 ( _, callNode , encl , _, _, _) )
846
+ )
847
+ }
796
848
797
849
/**
798
850
* Gets a viable dispatch target of `call` in the context `ctx`. This is
799
851
* restricted to those `call`s for which a context might make a difference.
800
852
*/
801
- DataFlowCallable viableImplInCallContext ( DataFlowCall call , DataFlowCall ctx ) { none ( ) }
853
+ pragma [ nomagic]
854
+ DataFlowCallable viableImplInCallContext ( DataFlowCall call , DataFlowCall ctx ) {
855
+ exists ( Module tp , Module m , boolean exact , string name |
856
+ result .asCallable ( ) = lookupMethod ( tp , name ) and
857
+ mayBenefitFromCallContext0 ( ctx .asCall ( ) , call .asCall ( ) , _, m , exact , name )
858
+ |
859
+ tp = m
860
+ or
861
+ exact = false and
862
+ tp .getSuperClass + ( ) = m
863
+ )
864
+ }
802
865
803
866
predicate exprNodeReturnedFrom = exprNodeReturnedFromCached / 2 ;
804
867
0 commit comments