@@ -558,15 +558,19 @@ DataFlowCallable nodeGetEnclosingCallable(Node node) {
558
558
559
559
newtype TDataFlowType =
560
560
TFunctionType ( Function f ) or
561
+ TInstanceType ( DataFlow:: ClassNode cls ) or
561
562
TAnyType ( )
562
563
563
564
class DataFlowType extends TDataFlowType {
564
565
string toDebugString ( ) {
565
- this instanceof TFunctionType and
566
566
result =
567
567
"TFunctionType(" + this .asFunction ( ) .toString ( ) + ") at line " +
568
568
this .asFunction ( ) .getLocation ( ) .getStartLine ( )
569
569
or
570
+ result =
571
+ "TInstanceType(" + this .asInstanceOfClass ( ) .toString ( ) + ") at line " +
572
+ this .asInstanceOfClass ( ) .getLocation ( ) .getStartLine ( )
573
+ or
570
574
this instanceof TAnyType and result = "TAnyType"
571
575
}
572
576
@@ -575,13 +579,20 @@ class DataFlowType extends TDataFlowType {
575
579
}
576
580
577
581
Function asFunction ( ) { this = TFunctionType ( result ) }
582
+
583
+ DataFlow:: ClassNode asInstanceOfClass ( ) { this = TInstanceType ( result ) }
578
584
}
579
585
580
586
/**
581
587
* Holds if `t1` is strictly stronger than `t2`.
582
588
*/
583
589
predicate 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 ( )
585
596
}
586
597
587
598
private DataFlowType getPreciseType ( Node node ) {
@@ -590,6 +601,9 @@ private DataFlowType getPreciseType(Node node) {
590
601
result = TFunctionType ( f )
591
602
)
592
603
or
604
+ result .asInstanceOfClass ( ) =
605
+ unique( DataFlow:: ClassNode cls | cls .getAnInstanceReference ( ) .getALocalUse ( ) = node )
606
+ or
593
607
result = getPreciseType ( node .getImmediatePredecessor ( ) )
594
608
or
595
609
result = getPreciseType ( node .( PostUpdateNode ) .getPreUpdateNode ( ) )
@@ -683,18 +697,27 @@ predicate neverSkipInPathGraph(Node node) {
683
697
string ppReprType ( DataFlowType t ) { none ( ) }
684
698
685
699
pragma [ inline]
686
- private predicate compatibleTypesNonSymRefl ( DataFlowType t1 , DataFlowType t2 ) {
700
+ private predicate compatibleTypesWithAny ( DataFlowType t1 , DataFlowType t2 ) {
687
701
t1 != TAnyType ( ) and
688
702
t2 = TAnyType ( )
689
703
}
690
704
705
+ pragma [ nomagic]
706
+ private predicate compatibleTypes1 ( DataFlowType t1 , DataFlowType t2 ) {
707
+ t1 .asInstanceOfClass ( ) .getADirectSubClass + ( ) = t2 .asInstanceOfClass ( )
708
+ }
709
+
691
710
pragma [ inline]
692
711
predicate compatibleTypes ( DataFlowType t1 , DataFlowType t2 ) {
693
712
t1 = t2
694
713
or
695
- compatibleTypesNonSymRefl ( t1 , t2 )
714
+ compatibleTypesWithAny ( t1 , t2 )
715
+ or
716
+ compatibleTypesWithAny ( t2 , t1 )
696
717
or
697
- compatibleTypesNonSymRefl ( t2 , t1 )
718
+ compatibleTypes1 ( t1 , t2 )
719
+ or
720
+ compatibleTypes1 ( t2 , t1 )
698
721
}
699
722
700
723
predicate forceHighPrecision ( Content c ) { none ( ) }
@@ -1061,17 +1084,54 @@ DataFlowCallable viableCallable(DataFlowCall node) {
1061
1084
result .asSourceCallableNotExterns ( ) = node .asImpliedLambdaCall ( )
1062
1085
}
1063
1086
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
+
1064
1103
/**
1065
1104
* Holds if the set of viable implementations that can be called by `call`
1066
1105
* might be improved by knowing the call context.
1067
1106
*/
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
+ }
1069
1124
1070
1125
/**
1071
1126
* Gets a viable dispatch target of `call` in the context `ctx`. This is
1072
1127
* restricted to those `call`s for which a context might make a difference.
1073
1128
*/
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
+ }
1075
1135
1076
1136
bindingset [ node, fun]
1077
1137
pragma [ inline_late]
0 commit comments