@@ -38,6 +38,7 @@ private import DataFlowPrivate
3838private import FlowSummaryImpl as FlowSummaryImpl
3939private import FlowSummaryImplSpecific as FlowSummaryImplSpecific
4040private import semmle.python.internal.CachedStages
41+ private import semmle.python.dataflow.new.internal.TypeTracker:: CallGraphConstruction as CallGraphConstruction
4142
4243newtype TParameterPosition =
4344 /** Used for `self` in methods, and `cls` in classmethods. */
@@ -464,137 +465,138 @@ private predicate ignoreForCallGraph(File f) {
464465 f .getAbsolutePath ( ) .matches ( "%/site-packages/sympy/%" )
465466}
466467
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 ( )
475473 or
476474 // when a function is decorated, it's the result of the (last) decorator call that
477475 // 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 ( ) ) }
483480}
484481
485482/**
486483 * Gets a reference to the function `func`.
487484 */
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+ }
489490
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 ( )
498496 or
499497 // when a class is decorated, it's the result of the (last) decorator call that
500498 // is used
501- result .asExpr ( ) = cls .getParent ( ) .getADecoratorCall ( )
499+ start .asExpr ( ) = cls .getParent ( ) .getADecoratorCall ( )
502500 or
503501 // `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+ }
511511}
512512
513513/**
514514 * Gets a reference to the class `cls`.
515515 */
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+ }
517519
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+ }
537538}
538539
539540/**
540541 * Gets a reference to an instance of the class `cls`.
541542 */
542543Node classInstanceTracker ( Class cls ) {
543- classInstanceTracker ( TypeTracker:: end ( ) , cls ) .flowsTo ( result )
544+ CallGraphConstruction:: Simple:: Make< TrackClassInstanceInput > :: track ( cls )
545+ .( LocalSourceNode )
546+ .flowsTo ( result )
544547}
545548
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+ }
564567}
565568
566569/**
567570 * Gets a reference to the `self` argument of a method on class `classWithMethod`.
568571 * The method cannot be a `staticmethod` or `classmethod`.
569572 */
570573Node selfTracker ( Class classWithMethod ) {
571- selfTracker ( TypeTracker:: end ( ) , classWithMethod ) .flowsTo ( result )
574+ CallGraphConstruction:: Simple:: Make< TrackSelfInput > :: track ( classWithMethod )
575+ .( LocalSourceNode )
576+ .flowsTo ( result )
572577}
573578
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 ) {
583583 exists ( Function func |
584584 func = classWithMethod .getAMethod ( ) and
585585 isClassmethod ( func )
586586 |
587- result .asExpr ( ) = func .getArg ( 0 )
587+ start .asExpr ( ) = func .getArg ( 0 )
588588 )
589589 or
590590 // 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+ }
598600}
599601
600602/**
@@ -603,60 +605,72 @@ private TypeTrackingNode clsArgumentTracker(TypeTracker t, Class classWithMethod
603605 * from a normal method.
604606 */
605607Node clsArgumentTracker ( Class classWithMethod ) {
606- clsArgumentTracker ( TypeTracker:: end ( ) , classWithMethod ) .flowsTo ( result )
608+ CallGraphConstruction:: Simple:: Make< TrackClsArgumentInput > :: track ( classWithMethod )
609+ .( LocalSourceNode )
610+ .flowsTo ( result )
607611}
608612
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+ }
626630}
627631
628632/**
629633 * Gets a reference to the result of calling `super` without any argument, where the
630634 * call happened in the method `func` (either a method or a classmethod).
631635 */
632636Node superCallNoArgumentTracker ( Function func ) {
633- superCallNoArgumentTracker ( TypeTracker:: end ( ) , func ) .flowsTo ( result )
637+ CallGraphConstruction:: Simple:: Make< TrackSuperCallNoArgumentInput > :: track ( func )
638+ .( LocalSourceNode )
639+ .flowsTo ( result )
634640}
635641
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 ) {
644644 call = getSuperCall ( ) and
645645 call .getArg ( 0 ) = classTracker ( cls ) and
646646 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+ }
652661}
653662
654663/**
655664 * Gets a reference to the result of calling `super` with 2 arguments, where the
656665 * first is a reference to the class `cls`, and the second argument is `obj`.
657666 */
658667Node 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+ )
660674}
661675
662676// =============================================================================
@@ -800,20 +814,30 @@ Function findFunctionAccordingToMroKnownStartingClass(Class startingClass, strin
800814// =============================================================================
801815// attribute trackers
802816// =============================================================================
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+ }
813833}
814834
815835/** 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+ }
817841
818842// =============================================================================
819843// call and argument resolution
0 commit comments