@@ -678,7 +678,7 @@ private module CallExprBaseMatchingInput implements MatchingInputSig {
678
678
Declaration getTarget ( ) {
679
679
result = CallExprImpl:: getResolvedFunction ( this )
680
680
or
681
- result = resolveMethodCallExpr ( this ) // mutual recursion; resolving method calls requires resolving types and vice versa
681
+ result = inferMethodCallTarget ( this ) // mutual recursion; resolving method calls requires resolving types and vice versa
682
682
}
683
683
}
684
684
@@ -1000,6 +1000,150 @@ private StructType inferLiteralType(LiteralExpr le) {
1000
1000
)
1001
1001
}
1002
1002
1003
+ private module MethodCall {
1004
+ /** An expression that calls a method. */
1005
+ abstract private class MethodCallImpl extends Expr {
1006
+ /** Gets the name of the method targeted. */
1007
+ abstract string getMethodName ( ) ;
1008
+
1009
+ /** Gets the number of arguments _excluding_ the `self` argument. */
1010
+ abstract int getArity ( ) ;
1011
+
1012
+ /** Gets the trait targeted by this method call, if any. */
1013
+ Trait getTrait ( ) { none ( ) }
1014
+
1015
+ /** Gets the type of the receiver of the method call at `path`. */
1016
+ abstract Type getTypeAt ( TypePath path ) ;
1017
+ }
1018
+
1019
+ final class MethodCall = MethodCallImpl ;
1020
+
1021
+ private class MethodCallExprMethodCall extends MethodCallImpl instanceof MethodCallExpr {
1022
+ override string getMethodName ( ) { result = super .getIdentifier ( ) .getText ( ) }
1023
+
1024
+ override int getArity ( ) { result = super .getArgList ( ) .getNumberOfArgs ( ) }
1025
+
1026
+ pragma [ nomagic]
1027
+ override Type getTypeAt ( TypePath path ) {
1028
+ exists ( TypePath path0 | result = inferType ( super .getReceiver ( ) , path0 ) |
1029
+ path0 .isCons ( TRefTypeParameter ( ) , path )
1030
+ or
1031
+ not path0 .isCons ( TRefTypeParameter ( ) , _) and
1032
+ not ( path0 .isEmpty ( ) and result = TRefType ( ) ) and
1033
+ path = path0
1034
+ )
1035
+ }
1036
+ }
1037
+
1038
+ private class CallExprMethodCall extends MethodCallImpl instanceof CallExpr {
1039
+ TraitItemNode trait ;
1040
+ string methodName ;
1041
+ Expr receiver ;
1042
+
1043
+ CallExprMethodCall ( ) {
1044
+ receiver = this .getArgList ( ) .getArg ( 0 ) and
1045
+ exists ( Path path , Function f |
1046
+ path = this .getFunction ( ) .( PathExpr ) .getPath ( ) and
1047
+ f = resolvePath ( path ) and
1048
+ f .getParamList ( ) .hasSelfParam ( ) and
1049
+ trait = resolvePath ( path .getQualifier ( ) ) and
1050
+ trait .getAnAssocItem ( ) = f and
1051
+ path .getSegment ( ) .getIdentifier ( ) .getText ( ) = methodName
1052
+ )
1053
+ }
1054
+
1055
+ override string getMethodName ( ) { result = methodName }
1056
+
1057
+ override int getArity ( ) { result = super .getArgList ( ) .getNumberOfArgs ( ) - 1 }
1058
+
1059
+ override Trait getTrait ( ) { result = trait }
1060
+
1061
+ pragma [ nomagic]
1062
+ override Type getTypeAt ( TypePath path ) { result = inferType ( receiver , path ) }
1063
+ }
1064
+ }
1065
+
1066
+ import MethodCall
1067
+
1068
+ /**
1069
+ * Holds if a method for `type` with the name `name` and the arity `arity`
1070
+ * exists in `impl`.
1071
+ */
1072
+ private predicate methodCandidate ( Type type , string name , int arity , Impl impl ) {
1073
+ type = impl .getSelfTy ( ) .( TypeMention ) .resolveType ( ) and
1074
+ exists ( Function f |
1075
+ f = impl .( ImplItemNode ) .getASuccessor ( name ) and
1076
+ f .getParamList ( ) .hasSelfParam ( ) and
1077
+ arity = f .getParamList ( ) .getNumberOfParams ( )
1078
+ )
1079
+ }
1080
+
1081
+ /**
1082
+ * Holds if a method for `type` for `trait` with the name `name` and the arity
1083
+ * `arity` exists in `impl`.
1084
+ */
1085
+ pragma [ nomagic]
1086
+ private predicate methodCandidateTrait ( Type type , Trait trait , string name , int arity , Impl impl ) {
1087
+ trait = resolvePath ( impl .getTrait ( ) .( PathTypeRepr ) .getPath ( ) ) and
1088
+ methodCandidate ( type , name , arity , impl )
1089
+ }
1090
+
1091
+ private module IsInstantiationOfInput implements IsInstantiationOfInputSig< MethodCall > {
1092
+ pragma [ nomagic]
1093
+ predicate potentialInstantiationOf ( MethodCall mc , TypeAbstraction impl , TypeMention constraint ) {
1094
+ exists ( Type rootType , string name , int arity |
1095
+ rootType = mc .getTypeAt ( TypePath:: nil ( ) ) and
1096
+ name = mc .getMethodName ( ) and
1097
+ arity = mc .getArity ( ) and
1098
+ constraint = impl .( ImplTypeAbstraction ) .getSelfTy ( )
1099
+ |
1100
+ methodCandidateTrait ( rootType , mc .getTrait ( ) , name , arity , impl )
1101
+ or
1102
+ not exists ( mc .getTrait ( ) ) and
1103
+ methodCandidate ( rootType , name , arity , impl )
1104
+ )
1105
+ }
1106
+
1107
+ predicate relevantTypeMention ( TypeMention constraint ) {
1108
+ exists ( Impl impl | methodCandidate ( _, _, _, impl ) and constraint = impl .getSelfTy ( ) )
1109
+ }
1110
+ }
1111
+
1112
+ bindingset [ item, name]
1113
+ pragma [ inline_late]
1114
+ private Function getMethodSuccessor ( ItemNode item , string name ) {
1115
+ result = item .getASuccessor ( name )
1116
+ }
1117
+
1118
+ bindingset [ tp, name]
1119
+ pragma [ inline_late]
1120
+ private Function getTypeParameterMethod ( TypeParameter tp , string name ) {
1121
+ result = getMethodSuccessor ( tp .( TypeParamTypeParameter ) .getTypeParam ( ) , name )
1122
+ or
1123
+ result = getMethodSuccessor ( tp .( SelfTypeParameter ) .getTrait ( ) , name )
1124
+ }
1125
+
1126
+ /** Gets a method from an `impl` block that matches the method call `mc`. */
1127
+ private Function getMethodFromImpl ( MethodCall mc ) {
1128
+ exists ( Impl impl |
1129
+ IsInstantiationOf< MethodCall , IsInstantiationOfInput > :: isInstantiationOf ( mc , impl , _) and
1130
+ result = getMethodSuccessor ( impl , mc .getMethodName ( ) )
1131
+ )
1132
+ }
1133
+
1134
+ /**
1135
+ * Gets a method that the method call `mc` resolves to based on type inference,
1136
+ * if any.
1137
+ */
1138
+ private Function inferMethodCallTarget ( MethodCall mc ) {
1139
+ // The method comes from an `impl` block targeting the type of the receiver.
1140
+ result = getMethodFromImpl ( mc )
1141
+ or
1142
+ // The type of the receiver is a type parameter and the method comes from a
1143
+ // trait bound on the type parameter.
1144
+ result = getTypeParameterMethod ( mc .getTypeAt ( TypePath:: nil ( ) ) , mc .getMethodName ( ) )
1145
+ }
1146
+
1003
1147
cached
1004
1148
private module Cached {
1005
1149
private import codeql.rust.internal.CachedStages
@@ -1026,90 +1170,47 @@ private module Cached {
1026
1170
)
1027
1171
}
1028
1172
1029
- private class ReceiverExpr extends Expr {
1030
- MethodCallExpr mce ;
1031
-
1032
- ReceiverExpr ( ) { mce .getReceiver ( ) = this }
1033
-
1034
- string getField ( ) { result = mce .getIdentifier ( ) .getText ( ) }
1035
-
1036
- int getNumberOfArgs ( ) { result = mce .getArgList ( ) .getNumberOfArgs ( ) }
1037
-
1038
- pragma [ nomagic]
1039
- Type getTypeAt ( TypePath path ) {
1040
- exists ( TypePath path0 | result = inferType ( this , path0 ) |
1041
- path0 .isCons ( TRefTypeParameter ( ) , path )
1042
- or
1043
- not path0 .isCons ( TRefTypeParameter ( ) , _) and
1044
- not ( path0 .isEmpty ( ) and result = TRefType ( ) ) and
1045
- path = path0
1046
- )
1047
- }
1048
- }
1049
-
1050
- /** Holds if a method for `type` with the name `name` and the arity `arity` exists in `impl`. */
1051
- pragma [ nomagic]
1052
- private predicate methodCandidate ( Type type , string name , int arity , Impl impl ) {
1053
- type = impl .getSelfTy ( ) .( TypeReprMention ) .resolveType ( ) and
1054
- exists ( Function f |
1055
- f = impl .( ImplItemNode ) .getASuccessor ( name ) and
1056
- f .getParamList ( ) .hasSelfParam ( ) and
1057
- arity = f .getParamList ( ) .getNumberOfParams ( )
1058
- )
1059
- }
1060
-
1061
- private module IsInstantiationOfInput implements IsInstantiationOfInputSig< ReceiverExpr > {
1062
- pragma [ nomagic]
1063
- predicate potentialInstantiationOf (
1064
- ReceiverExpr receiver , TypeAbstraction impl , TypeMention constraint
1065
- ) {
1066
- methodCandidate ( receiver .getTypeAt ( TypePath:: nil ( ) ) , receiver .getField ( ) ,
1067
- receiver .getNumberOfArgs ( ) , impl ) and
1068
- constraint = impl .( ImplTypeAbstraction ) .getSelfTy ( )
1069
- }
1070
-
1071
- predicate relevantTypeMention ( TypeMention constraint ) {
1072
- exists ( Impl impl | methodCandidate ( _, _, _, impl ) and constraint = impl .getSelfTy ( ) )
1073
- }
1074
- }
1075
-
1076
- bindingset [ item, name]
1077
- pragma [ inline_late]
1078
- private Function getMethodSuccessor ( ItemNode item , string name ) {
1079
- result = item .getASuccessor ( name )
1173
+ private predicate isInherentImplFunction ( Function f ) {
1174
+ f = any ( Impl impl | not impl .hasTrait ( ) ) .( ImplItemNode ) .getAnAssocItem ( )
1080
1175
}
1081
1176
1082
- bindingset [ tp, name]
1083
- pragma [ inline_late]
1084
- private Function getTypeParameterMethod ( TypeParameter tp , string name ) {
1085
- result = getMethodSuccessor ( tp .( TypeParamTypeParameter ) .getTypeParam ( ) , name )
1086
- or
1087
- result = getMethodSuccessor ( tp .( SelfTypeParameter ) .getTrait ( ) , name )
1177
+ private predicate isTraitImplFunction ( Function f ) {
1178
+ f = any ( Impl impl | impl .hasTrait ( ) ) .( ImplItemNode ) .getAnAssocItem ( )
1088
1179
}
1089
1180
1090
- /**
1091
- * Gets the method from an `impl` block with an implementing type that matches
1092
- * the type of `receiver` and with a name of the method call in which
1093
- * `receiver` occurs, if any.
1094
- */
1095
- private Function getMethodFromImpl ( ReceiverExpr receiver ) {
1096
- exists ( Impl impl |
1097
- IsInstantiationOf< ReceiverExpr , IsInstantiationOfInput > :: isInstantiationOf ( receiver , impl , _) and
1098
- result = getMethodSuccessor ( impl , receiver .getField ( ) )
1181
+ private Function resolveMethodCallTargetFrom ( MethodCall mc , boolean fromSource ) {
1182
+ result = inferMethodCallTarget ( mc ) and
1183
+ ( if result .fromSource ( ) then fromSource = true else fromSource = false ) and
1184
+ (
1185
+ // prioritize inherent implementation methods first
1186
+ isInherentImplFunction ( result )
1187
+ or
1188
+ not isInherentImplFunction ( inferMethodCallTarget ( mc ) ) and
1189
+ (
1190
+ // then trait implementation methods
1191
+ isTraitImplFunction ( result )
1192
+ or
1193
+ not isTraitImplFunction ( inferMethodCallTarget ( mc ) ) and
1194
+ (
1195
+ // then trait methods with default implementations
1196
+ result .hasBody ( )
1197
+ or
1198
+ // and finally trait methods without default implementations
1199
+ not inferMethodCallTarget ( mc ) .hasBody ( )
1200
+ )
1201
+ )
1099
1202
)
1100
1203
}
1101
1204
1102
- /** Gets a method that the method call `mce ` resolves to, if any. */
1205
+ /** Gets a method that the method call `mc ` resolves to, if any. */
1103
1206
cached
1104
- Function resolveMethodCallExpr ( MethodCallExpr mce ) {
1105
- exists ( ReceiverExpr receiver | mce .getReceiver ( ) = receiver |
1106
- // The method comes from an `impl` block targeting the type of `receiver`.
1107
- result = getMethodFromImpl ( receiver )
1108
- or
1109
- // The type of `receiver` is a type parameter and the method comes from a
1110
- // trait bound on the type parameter.
1111
- result = getTypeParameterMethod ( receiver .getTypeAt ( TypePath:: nil ( ) ) , receiver .getField ( ) )
1112
- )
1207
+ Function resolveMethodCallTarget ( MethodCall mc ) {
1208
+ // Functions in source code also gets extracted as library code, due to
1209
+ // this duplication we prioritize functions from source code.
1210
+ result = resolveMethodCallTargetFrom ( mc , true )
1211
+ or
1212
+ not exists ( resolveMethodCallTargetFrom ( mc , true ) ) and
1213
+ result = resolveMethodCallTargetFrom ( mc , false )
1113
1214
}
1114
1215
1115
1216
pragma [ inline]
@@ -1243,6 +1344,6 @@ private module Debug {
1243
1344
1244
1345
Function debugResolveMethodCallExpr ( MethodCallExpr mce ) {
1245
1346
mce = getRelevantLocatable ( ) and
1246
- result = resolveMethodCallExpr ( mce )
1347
+ result = resolveMethodCallTarget ( mce )
1247
1348
}
1248
1349
}
0 commit comments