@@ -558,15 +558,19 @@ DataFlowCallable nodeGetEnclosingCallable(Node node) {
558558
559559newtype TDataFlowType =
560560 TFunctionType ( Function f ) or
561+ TInstanceType ( DataFlow:: ClassNode cls ) or
561562 TAnyType ( )
562563
563564class DataFlowType extends TDataFlowType {
564565 string toDebugString ( ) {
565- this instanceof TFunctionType and
566566 result =
567567 "TFunctionType(" + this .asFunction ( ) .toString ( ) + ") at line " +
568568 this .asFunction ( ) .getLocation ( ) .getStartLine ( )
569569 or
570+ result =
571+ "TInstanceType(" + this .asInstanceOfClass ( ) .toString ( ) + ") at line " +
572+ this .asInstanceOfClass ( ) .getLocation ( ) .getStartLine ( )
573+ or
570574 this instanceof TAnyType and result = "TAnyType"
571575 }
572576
@@ -575,13 +579,20 @@ class DataFlowType extends TDataFlowType {
575579 }
576580
577581 Function asFunction ( ) { this = TFunctionType ( result ) }
582+
583+ DataFlow:: ClassNode asInstanceOfClass ( ) { this = TInstanceType ( result ) }
578584}
579585
580586/**
581587 * Holds if `t1` is strictly stronger than `t2`.
582588 */
583589predicate typeStrongerThan ( DataFlowType t1 , DataFlowType t2 ) {
584- t1 instanceof TFunctionType and t2 = TAnyType ( )
590+ // 't1' is a subclass of 't2'
591+ t1 .asInstanceOfClass ( ) = t2 .asInstanceOfClass ( ) .getADirectSubClass + ( )
592+ or
593+ // Ensure all types are stronger than 'any'
594+ not t1 = TAnyType ( ) and
595+ t2 = TAnyType ( )
585596}
586597
587598private DataFlowType getPreciseType ( Node node ) {
@@ -590,6 +601,9 @@ private DataFlowType getPreciseType(Node node) {
590601 result = TFunctionType ( f )
591602 )
592603 or
604+ result .asInstanceOfClass ( ) =
605+ unique( DataFlow:: ClassNode cls | cls .getAnInstanceReference ( ) .getALocalUse ( ) = node )
606+ or
593607 result = getPreciseType ( node .getImmediatePredecessor ( ) )
594608 or
595609 result = getPreciseType ( node .( PostUpdateNode ) .getPreUpdateNode ( ) )
@@ -683,18 +697,27 @@ predicate neverSkipInPathGraph(Node node) {
683697string ppReprType ( DataFlowType t ) { none ( ) }
684698
685699pragma [ inline]
686- private predicate compatibleTypesNonSymRefl ( DataFlowType t1 , DataFlowType t2 ) {
700+ private predicate compatibleTypesWithAny ( DataFlowType t1 , DataFlowType t2 ) {
687701 t1 != TAnyType ( ) and
688702 t2 = TAnyType ( )
689703}
690704
705+ pragma [ nomagic]
706+ private predicate compatibleTypes1 ( DataFlowType t1 , DataFlowType t2 ) {
707+ t1 .asInstanceOfClass ( ) .getADirectSubClass + ( ) = t2 .asInstanceOfClass ( )
708+ }
709+
691710pragma [ inline]
692711predicate compatibleTypes ( DataFlowType t1 , DataFlowType t2 ) {
693712 t1 = t2
694713 or
695- compatibleTypesNonSymRefl ( t1 , t2 )
714+ compatibleTypesWithAny ( t1 , t2 )
715+ or
716+ compatibleTypesWithAny ( t2 , t1 )
696717 or
697- compatibleTypesNonSymRefl ( t2 , t1 )
718+ compatibleTypes1 ( t1 , t2 )
719+ or
720+ compatibleTypes1 ( t2 , t1 )
698721}
699722
700723predicate forceHighPrecision ( Content c ) { none ( ) }
@@ -1061,17 +1084,54 @@ DataFlowCallable viableCallable(DataFlowCall node) {
10611084 result .asSourceCallableNotExterns ( ) = node .asImpliedLambdaCall ( )
10621085}
10631086
1087+ private DataFlowCall getACallOnThis ( DataFlow:: ClassNode cls ) {
1088+ result .asOrdinaryCall ( ) = cls .getAReceiverNode ( ) .getAPropertyRead ( ) .getACall ( )
1089+ or
1090+ result .asAccessorCall ( ) = cls .getAReceiverNode ( ) .getAPropertyRead ( )
1091+ or
1092+ result .asPartialCall ( ) .getACallbackNode ( ) = cls .getAReceiverNode ( ) .getAPropertyRead ( )
1093+ }
1094+
1095+ private predicate downwardCall ( DataFlowCall call ) {
1096+ exists ( DataFlow:: ClassNode cls |
1097+ call = getACallOnThis ( cls ) and
1098+ viableCallable ( call ) .asSourceCallable ( ) =
1099+ cls .getADirectSubClass + ( ) .getAnInstanceMember ( ) .getFunction ( )
1100+ )
1101+ }
1102+
10641103/**
10651104 * Holds if the set of viable implementations that can be called by `call`
10661105 * might be improved by knowing the call context.
10671106 */
1068- predicate mayBenefitFromCallContext ( DataFlowCall call ) { none ( ) }
1107+ predicate mayBenefitFromCallContext ( DataFlowCall call ) { downwardCall ( call ) }
1108+
1109+ /** Gets the type of the receiver of `call`. */
1110+ private DataFlowType getThisArgumentType ( DataFlowCall call ) {
1111+ exists ( DataFlow:: Node node |
1112+ isArgumentNodeImpl ( node , call , MkThisParameter ( ) ) and
1113+ result = getNodeType ( node )
1114+ )
1115+ }
1116+
1117+ /** Gets the type of the 'this' parameter of `call`. */
1118+ private DataFlowType getThisParameterType ( DataFlowCallable callable ) {
1119+ exists ( DataFlow:: Node node |
1120+ isParameterNodeImpl ( node , callable , MkThisParameter ( ) ) and
1121+ result = getNodeType ( node )
1122+ )
1123+ }
10691124
10701125/**
10711126 * Gets a viable dispatch target of `call` in the context `ctx`. This is
10721127 * restricted to those `call`s for which a context might make a difference.
10731128 */
1074- DataFlowCallable viableImplInCallContext ( DataFlowCall call , DataFlowCall ctx ) { none ( ) }
1129+ DataFlowCallable viableImplInCallContext ( DataFlowCall call , DataFlowCall ctx ) {
1130+ mayBenefitFromCallContext ( call ) and
1131+ result = viableCallable ( call ) and
1132+ viableCallable ( ctx ) = call .getEnclosingCallable ( ) and
1133+ compatibleTypes ( getThisArgumentType ( ctx ) , getThisParameterType ( result ) )
1134+ }
10751135
10761136bindingset [ node, fun]
10771137pragma [ inline_late]
0 commit comments