@@ -38,6 +38,7 @@ private import DataFlowPrivate
38
38
private import FlowSummaryImpl as FlowSummaryImpl
39
39
private import FlowSummaryImplSpecific as FlowSummaryImplSpecific
40
40
private import semmle.python.internal.CachedStages
41
+ private import semmle.python.dataflow.new.internal.TypeTracker:: CallGraphConstruction as CallGraphConstruction
41
42
42
43
newtype TParameterPosition =
43
44
/** Used for `self` in methods, and `cls` in classmethods. */
@@ -464,137 +465,138 @@ private predicate ignoreForCallGraph(File f) {
464
465
f .getAbsolutePath ( ) .matches ( "%/site-packages/sympy/%" )
465
466
}
466
467
467
- /**
468
- * Gets a reference to the function `func`.
469
- */
470
- private TypeTrackingNode functionTracker ( TypeTracker t , Function func ) {
471
- not ignoreForCallGraph ( result .getLocation ( ) .getFile ( ) ) and
472
- t .start ( ) and
473
- (
474
- result .asExpr ( ) = func .getDefinition ( )
468
+ private module TrackFunctionInput implements CallGraphConstruction:: Simple:: InputSig {
469
+ class State = Function ;
470
+
471
+ predicate start ( Node start , Function func ) {
472
+ start .asExpr ( ) = func .getDefinition ( )
475
473
or
476
474
// when a function is decorated, it's the result of the (last) decorator call that
477
475
// is used
478
- result .asExpr ( ) = func .getDefinition ( ) .( FunctionExpr ) .getADecoratorCall ( )
479
- )
480
- or
481
- not ignoreForCallGraph ( result .getLocation ( ) .getFile ( ) ) and
482
- exists ( TypeTracker t2 | result = functionTracker ( t2 , func ) .track ( t2 , t ) )
476
+ start .asExpr ( ) = func .getDefinition ( ) .( FunctionExpr ) .getADecoratorCall ( )
477
+ }
478
+
479
+ predicate filter ( Node n ) { ignoreForCallGraph ( n .getLocation ( ) .getFile ( ) ) }
483
480
}
484
481
485
482
/**
486
483
* Gets a reference to the function `func`.
487
484
*/
488
- Node functionTracker ( Function func ) { functionTracker ( TypeTracker:: end ( ) , func ) .flowsTo ( result ) }
485
+ Node functionTracker ( Function func ) {
486
+ CallGraphConstruction:: Simple:: Make< TrackFunctionInput > :: track ( func )
487
+ .( LocalSourceNode )
488
+ .flowsTo ( result )
489
+ }
489
490
490
- /**
491
- * Gets a reference to the class `cls`.
492
- */
493
- private TypeTrackingNode classTracker ( TypeTracker t , Class cls ) {
494
- not ignoreForCallGraph ( result .getLocation ( ) .getFile ( ) ) and
495
- t .start ( ) and
496
- (
497
- result .asExpr ( ) = cls .getParent ( )
491
+ private module TrackClassInput implements CallGraphConstruction:: Simple:: InputSig {
492
+ class State = Class ;
493
+
494
+ predicate start ( Node start , Class cls ) {
495
+ start .asExpr ( ) = cls .getParent ( )
498
496
or
499
497
// when a class is decorated, it's the result of the (last) decorator call that
500
498
// is used
501
- result .asExpr ( ) = cls .getParent ( ) .getADecoratorCall ( )
499
+ start .asExpr ( ) = cls .getParent ( ) .getADecoratorCall ( )
502
500
or
503
501
// `type(obj)`, where obj is an instance of this class
504
- result = getTypeCall ( ) and
505
- result .( CallCfgNode ) .getArg ( 0 ) = classInstanceTracker ( cls )
506
- )
507
- or
508
- not ignoreForCallGraph ( result .getLocation ( ) .getFile ( ) ) and
509
- exists ( TypeTracker t2 | result = classTracker ( t2 , cls ) .track ( t2 , t ) ) and
510
- not result .( ParameterNodeImpl ) .isParameterOf ( _, any ( ParameterPosition pp | pp .isSelf ( ) ) )
502
+ start = getTypeCall ( ) and
503
+ start .( CallCfgNode ) .getArg ( 0 ) = classInstanceTracker ( cls )
504
+ }
505
+
506
+ predicate filter ( Node n ) {
507
+ ignoreForCallGraph ( n .getLocation ( ) .getFile ( ) )
508
+ or
509
+ n .( ParameterNodeImpl ) .isParameterOf ( _, any ( ParameterPosition pp | pp .isSelf ( ) ) )
510
+ }
511
511
}
512
512
513
513
/**
514
514
* Gets a reference to the class `cls`.
515
515
*/
516
- Node classTracker ( Class cls ) { classTracker ( TypeTracker:: end ( ) , cls ) .flowsTo ( result ) }
516
+ Node classTracker ( Class cls ) {
517
+ CallGraphConstruction:: Simple:: Make< TrackClassInput > :: track ( cls ) .( LocalSourceNode ) .flowsTo ( result )
518
+ }
517
519
518
- /**
519
- * Gets a reference to an instance of the class `cls`.
520
- */
521
- private TypeTrackingNode classInstanceTracker ( TypeTracker t , Class cls ) {
522
- not ignoreForCallGraph ( result .getLocation ( ) .getFile ( ) ) and
523
- t .start ( ) and
524
- resolveClassCall ( result .( CallCfgNode ) .asCfgNode ( ) , cls )
525
- or
526
- // result of `super().__new__` as used in a `__new__` method implementation
527
- not ignoreForCallGraph ( result .getLocation ( ) .getFile ( ) ) and
528
- t .start ( ) and
529
- exists ( Class classUsedInSuper |
530
- fromSuperNewCall ( result .( CallCfgNode ) .asCfgNode ( ) , classUsedInSuper , _, _) and
531
- classUsedInSuper = getADirectSuperclass * ( cls )
532
- )
533
- or
534
- not ignoreForCallGraph ( result .getLocation ( ) .getFile ( ) ) and
535
- exists ( TypeTracker t2 | result = classInstanceTracker ( t2 , cls ) .track ( t2 , t ) ) and
536
- not result .( ParameterNodeImpl ) .isParameterOf ( _, any ( ParameterPosition pp | pp .isSelf ( ) ) )
520
+ private module TrackClassInstanceInput implements CallGraphConstruction:: Simple:: InputSig {
521
+ class State = Class ;
522
+
523
+ predicate start ( Node start , Class cls ) {
524
+ resolveClassCall ( start .( CallCfgNode ) .asCfgNode ( ) , cls )
525
+ or
526
+ // result of `super().__new__` as used in a `__new__` method implementation
527
+ exists ( Class classUsedInSuper |
528
+ fromSuperNewCall ( start .( CallCfgNode ) .asCfgNode ( ) , classUsedInSuper , _, _) and
529
+ classUsedInSuper = getADirectSuperclass * ( cls )
530
+ )
531
+ }
532
+
533
+ predicate filter ( Node n ) {
534
+ ignoreForCallGraph ( n .getLocation ( ) .getFile ( ) )
535
+ or
536
+ n .( ParameterNodeImpl ) .isParameterOf ( _, any ( ParameterPosition pp | pp .isSelf ( ) ) )
537
+ }
537
538
}
538
539
539
540
/**
540
541
* Gets a reference to an instance of the class `cls`.
541
542
*/
542
543
Node classInstanceTracker ( Class cls ) {
543
- classInstanceTracker ( TypeTracker:: end ( ) , cls ) .flowsTo ( result )
544
+ CallGraphConstruction:: Simple:: Make< TrackClassInstanceInput > :: track ( cls )
545
+ .( LocalSourceNode )
546
+ .flowsTo ( result )
544
547
}
545
548
546
- /**
547
- * Gets a reference to the `self` argument of a method on class `classWithMethod`.
548
- * The method cannot be a `staticmethod` or `classmethod`.
549
- */
550
- private TypeTrackingNode selfTracker ( TypeTracker t , Class classWithMethod ) {
551
- not ignoreForCallGraph ( result . getLocation ( ) . getFile ( ) ) and
552
- t . start ( ) and
553
- exists ( Function func |
554
- func = classWithMethod . getAMethod ( ) and
555
- not isStaticmethod ( func ) and
556
- not isClassmethod ( func )
557
- |
558
- result . asExpr ( ) = func . getArg ( 0 )
559
- )
560
- or
561
- not ignoreForCallGraph ( result . getLocation ( ) . getFile ( ) ) and
562
- exists ( TypeTracker t2 | result = selfTracker ( t2 , classWithMethod ) . track ( t2 , t ) ) and
563
- not result . ( ParameterNodeImpl ) . isParameterOf ( _ , any ( ParameterPosition pp | pp . isSelf ( ) ) )
549
+ private module TrackSelfInput implements CallGraphConstruction :: Simple :: InputSig {
550
+ class State = Class ;
551
+
552
+ predicate start ( Node start , Class classWithMethod ) {
553
+ exists ( Function func |
554
+ func = classWithMethod . getAMethod ( ) and
555
+ not isStaticmethod ( func ) and
556
+ not isClassmethod ( func )
557
+ |
558
+ start . asExpr ( ) = func . getArg ( 0 )
559
+ )
560
+ }
561
+
562
+ predicate filter ( Node n ) {
563
+ ignoreForCallGraph ( n . getLocation ( ) . getFile ( ) )
564
+ or
565
+ n . ( ParameterNodeImpl ) . isParameterOf ( _ , any ( ParameterPosition pp | pp . isSelf ( ) ) )
566
+ }
564
567
}
565
568
566
569
/**
567
570
* Gets a reference to the `self` argument of a method on class `classWithMethod`.
568
571
* The method cannot be a `staticmethod` or `classmethod`.
569
572
*/
570
573
Node selfTracker ( Class classWithMethod ) {
571
- selfTracker ( TypeTracker:: end ( ) , classWithMethod ) .flowsTo ( result )
574
+ CallGraphConstruction:: Simple:: Make< TrackSelfInput > :: track ( classWithMethod )
575
+ .( LocalSourceNode )
576
+ .flowsTo ( result )
572
577
}
573
578
574
- /**
575
- * Gets a reference to the enclosing class `classWithMethod` from within one of its
576
- * methods, either through the `cls` argument from a `classmethod` or from `type(self)`
577
- * from a normal method.
578
- */
579
- private TypeTrackingNode clsArgumentTracker ( TypeTracker t , Class classWithMethod ) {
580
- not ignoreForCallGraph ( result .getLocation ( ) .getFile ( ) ) and
581
- t .start ( ) and
582
- (
579
+ private module TrackClsArgumentInput implements CallGraphConstruction:: Simple:: InputSig {
580
+ class State = Class ;
581
+
582
+ predicate start ( Node start , Class classWithMethod ) {
583
583
exists ( Function func |
584
584
func = classWithMethod .getAMethod ( ) and
585
585
isClassmethod ( func )
586
586
|
587
- result .asExpr ( ) = func .getArg ( 0 )
587
+ start .asExpr ( ) = func .getArg ( 0 )
588
588
)
589
589
or
590
590
// type(self)
591
- result = getTypeCall ( ) and
592
- result .( CallCfgNode ) .getArg ( 0 ) = selfTracker ( classWithMethod )
593
- )
594
- or
595
- not ignoreForCallGraph ( result .getLocation ( ) .getFile ( ) ) and
596
- exists ( TypeTracker t2 | result = clsArgumentTracker ( t2 , classWithMethod ) .track ( t2 , t ) ) and
597
- not result .( ParameterNodeImpl ) .isParameterOf ( _, any ( ParameterPosition pp | pp .isSelf ( ) ) )
591
+ start = getTypeCall ( ) and
592
+ start .( CallCfgNode ) .getArg ( 0 ) = selfTracker ( classWithMethod )
593
+ }
594
+
595
+ predicate filter ( Node n ) {
596
+ ignoreForCallGraph ( n .getLocation ( ) .getFile ( ) )
597
+ or
598
+ n .( ParameterNodeImpl ) .isParameterOf ( _, any ( ParameterPosition pp | pp .isSelf ( ) ) )
599
+ }
598
600
}
599
601
600
602
/**
@@ -603,60 +605,72 @@ private TypeTrackingNode clsArgumentTracker(TypeTracker t, Class classWithMethod
603
605
* from a normal method.
604
606
*/
605
607
Node clsArgumentTracker ( Class classWithMethod ) {
606
- clsArgumentTracker ( TypeTracker:: end ( ) , classWithMethod ) .flowsTo ( result )
608
+ CallGraphConstruction:: Simple:: Make< TrackClsArgumentInput > :: track ( classWithMethod )
609
+ .( LocalSourceNode )
610
+ .flowsTo ( result )
607
611
}
608
612
609
- /**
610
- * Gets a reference to the result of calling `super` without any argument, where the
611
- * call happened in the method `func` (either a method or a classmethod).
612
- */
613
- private TypeTrackingNode superCallNoArgumentTracker ( TypeTracker t , Function func ) {
614
- not ignoreForCallGraph ( result . getLocation ( ) . getFile ( ) ) and
615
- t . start ( ) and
616
- not isStaticmethod ( func ) and
617
- exists ( CallCfgNode call | result = call |
618
- call = getSuperCall ( ) and
619
- not exists ( call . getArg ( _ ) ) and
620
- call . getScope ( ) = func
621
- )
622
- or
623
- not ignoreForCallGraph ( result . getLocation ( ) . getFile ( ) ) and
624
- exists ( TypeTracker t2 | result = superCallNoArgumentTracker ( t2 , func ) . track ( t2 , t ) ) and
625
- not result . ( ParameterNodeImpl ) . isParameterOf ( _ , any ( ParameterPosition pp | pp . isSelf ( ) ) )
613
+ private module TrackSuperCallNoArgumentInput implements CallGraphConstruction :: Simple :: InputSig {
614
+ class State = Function ;
615
+
616
+ predicate start ( Node start , Function func ) {
617
+ not isStaticmethod ( func ) and
618
+ exists ( CallCfgNode call | start = call |
619
+ call = getSuperCall ( ) and
620
+ not exists ( call . getArg ( _ ) ) and
621
+ call . getScope ( ) = func
622
+ )
623
+ }
624
+
625
+ predicate filter ( Node n ) {
626
+ ignoreForCallGraph ( n . getLocation ( ) . getFile ( ) )
627
+ or
628
+ n . ( ParameterNodeImpl ) . isParameterOf ( _ , any ( ParameterPosition pp | pp . isSelf ( ) ) )
629
+ }
626
630
}
627
631
628
632
/**
629
633
* Gets a reference to the result of calling `super` without any argument, where the
630
634
* call happened in the method `func` (either a method or a classmethod).
631
635
*/
632
636
Node superCallNoArgumentTracker ( Function func ) {
633
- superCallNoArgumentTracker ( TypeTracker:: end ( ) , func ) .flowsTo ( result )
637
+ CallGraphConstruction:: Simple:: Make< TrackSuperCallNoArgumentInput > :: track ( func )
638
+ .( LocalSourceNode )
639
+ .flowsTo ( result )
634
640
}
635
641
636
- /**
637
- * Gets a reference to the result of calling `super` with 2 arguments, where the
638
- * first is a reference to the class `cls`, and the second argument is `obj`.
639
- */
640
- private TypeTrackingNode superCallTwoArgumentTracker ( TypeTracker t , Class cls , Node obj ) {
641
- not ignoreForCallGraph ( result .getLocation ( ) .getFile ( ) ) and
642
- t .start ( ) and
643
- exists ( CallCfgNode call | result = call |
642
+ private module TrackSuperCallTwoArgumentInput implements CallGraphConstruction:: Simple:: InputSig {
643
+ additional predicate superCall ( CallCfgNode call , Class cls , Node obj ) {
644
644
call = getSuperCall ( ) and
645
645
call .getArg ( 0 ) = classTracker ( cls ) and
646
646
call .getArg ( 1 ) = obj
647
- )
648
- or
649
- not ignoreForCallGraph ( result .getLocation ( ) .getFile ( ) ) and
650
- exists ( TypeTracker t2 | result = superCallTwoArgumentTracker ( t2 , cls , obj ) .track ( t2 , t ) ) and
651
- not result .( ParameterNodeImpl ) .isParameterOf ( _, any ( ParameterPosition pp | pp .isSelf ( ) ) )
647
+ }
648
+
649
+ class State = CallCfgNode ;
650
+
651
+ predicate start ( Node start , CallCfgNode call ) {
652
+ superCall ( call , _, _) and
653
+ start = call
654
+ }
655
+
656
+ predicate filter ( Node n ) {
657
+ ignoreForCallGraph ( n .getLocation ( ) .getFile ( ) )
658
+ or
659
+ n .( ParameterNodeImpl ) .isParameterOf ( _, any ( ParameterPosition pp | pp .isSelf ( ) ) )
660
+ }
652
661
}
653
662
654
663
/**
655
664
* Gets a reference to the result of calling `super` with 2 arguments, where the
656
665
* first is a reference to the class `cls`, and the second argument is `obj`.
657
666
*/
658
667
Node superCallTwoArgumentTracker ( Class cls , Node obj ) {
659
- superCallTwoArgumentTracker ( TypeTracker:: end ( ) , cls , obj ) .flowsTo ( result )
668
+ exists ( CallCfgNode call |
669
+ TrackSuperCallTwoArgumentInput:: superCall ( call , cls , obj ) and
670
+ CallGraphConstruction:: Simple:: Make< TrackSuperCallTwoArgumentInput > :: track ( call )
671
+ .( LocalSourceNode )
672
+ .flowsTo ( result )
673
+ )
660
674
}
661
675
662
676
// =============================================================================
@@ -800,20 +814,30 @@ Function findFunctionAccordingToMroKnownStartingClass(Class startingClass, strin
800
814
// =============================================================================
801
815
// attribute trackers
802
816
// =============================================================================
803
- /** Gets a reference to the attribute read `attr` */
804
- private TypeTrackingNode attrReadTracker ( TypeTracker t , AttrRead attr ) {
805
- t .start ( ) and
806
- result = attr and
807
- attr .getObject ( ) in [
808
- classTracker ( _) , classInstanceTracker ( _) , selfTracker ( _) , clsArgumentTracker ( _) ,
809
- superCallNoArgumentTracker ( _) , superCallTwoArgumentTracker ( _, _)
810
- ]
811
- or
812
- exists ( TypeTracker t2 | result = attrReadTracker ( t2 , attr ) .track ( t2 , t ) )
817
+ private module TrackAttrReadInput implements CallGraphConstruction:: Simple:: InputSig {
818
+ class State = AttrRead ;
819
+
820
+ predicate start ( Node start , AttrRead attr ) {
821
+ start = attr and
822
+ attr .getObject ( ) in [
823
+ classTracker ( _) , classInstanceTracker ( _) , selfTracker ( _) , clsArgumentTracker ( _) ,
824
+ superCallNoArgumentTracker ( _) , superCallTwoArgumentTracker ( _, _)
825
+ ]
826
+ }
827
+
828
+ predicate filter ( Node n ) {
829
+ ignoreForCallGraph ( n .getLocation ( ) .getFile ( ) )
830
+ or
831
+ n .( ParameterNodeImpl ) .isParameterOf ( _, any ( ParameterPosition pp | pp .isSelf ( ) ) )
832
+ }
813
833
}
814
834
815
835
/** Gets a reference to the attribute read `attr` */
816
- Node attrReadTracker ( AttrRead attr ) { attrReadTracker ( TypeTracker:: end ( ) , attr ) .flowsTo ( result ) }
836
+ Node attrReadTracker ( AttrRead attr ) {
837
+ CallGraphConstruction:: Simple:: Make< TrackAttrReadInput > :: track ( attr )
838
+ .( LocalSourceNode )
839
+ .flowsTo ( result )
840
+ }
817
841
818
842
// =============================================================================
819
843
// call and argument resolution
0 commit comments