@@ -699,7 +699,7 @@ private module CallExprBaseMatchingInput implements MatchingInputSig {
699
699
}
700
700
701
701
Declaration getTarget ( ) {
702
- result = inferMethodCallTarget ( this ) // mutual recursion; resolving method calls requires resolving types and vice versa
702
+ result = resolveMethodCallTarget ( this ) // mutual recursion; resolving method calls requires resolving types and vice versa
703
703
or
704
704
result = CallExprImpl:: getResolvedFunction ( this )
705
705
}
@@ -1178,14 +1178,14 @@ private predicate methodCandidateTrait(Type type, Trait trait, string name, int
1178
1178
methodCandidate ( type , name , arity , impl )
1179
1179
}
1180
1180
1181
- private module IsInstantiationOfInput implements IsInstantiationOfInputSig< MethodCall > {
1182
- pragma [ nomagic]
1183
- private predicate isMethodCall ( MethodCall mc , Type rootType , string name , int arity ) {
1184
- rootType = mc .getTypeAt ( TypePath:: nil ( ) ) and
1185
- name = mc .getMethodName ( ) and
1186
- arity = mc .getNumberOfArguments ( )
1187
- }
1181
+ pragma [ nomagic]
1182
+ private predicate isMethodCall ( MethodCall mc , Type rootType , string name , int arity ) {
1183
+ rootType = mc .getTypeAt ( TypePath:: nil ( ) ) and
1184
+ name = mc .getMethodName ( ) and
1185
+ arity = mc .getNumberOfArguments ( )
1186
+ }
1188
1187
1188
+ private module IsInstantiationOfInput implements IsInstantiationOfInputSig< MethodCall > {
1189
1189
pragma [ nomagic]
1190
1190
predicate potentialInstantiationOf ( MethodCall mc , TypeAbstraction impl , TypeMention constraint ) {
1191
1191
exists ( Type rootType , string name , int arity |
@@ -1334,17 +1334,46 @@ private predicate methodResolutionDependsOnArgument(
1334
1334
)
1335
1335
}
1336
1336
1337
+ /**
1338
+ * Holds if the method call `mc` has no inherent target, i.e., it does not
1339
+ * resolve to a method in an `impl` block for the type of the receiver.
1340
+ */
1341
+ pragma [ nomagic]
1342
+ private predicate methodCallHasNoInherentTarget ( MethodCall mc ) {
1343
+ exists ( Type rootType , string name , int arity |
1344
+ isMethodCall ( mc , rootType , name , arity ) and
1345
+ forall ( Impl impl |
1346
+ methodCandidate ( rootType , name , arity , impl ) and
1347
+ not impl .hasTrait ( )
1348
+ |
1349
+ IsInstantiationOf< MethodCall , IsInstantiationOfInput > :: isNotInstantiationOf ( mc , impl , _)
1350
+ )
1351
+ )
1352
+ }
1353
+
1354
+ pragma [ nomagic]
1355
+ private predicate methodCallHasImplCandidate ( MethodCall mc , Impl impl ) {
1356
+ IsInstantiationOf< MethodCall , IsInstantiationOfInput > :: isInstantiationOf ( mc , impl , _) and
1357
+ if impl .hasTrait ( ) and not exists ( mc .getTrait ( ) )
1358
+ then
1359
+ // inherent methods take precedence over trait methods, so only allow
1360
+ // trait methods when there are no matching inherent methods
1361
+ methodCallHasNoInherentTarget ( mc )
1362
+ else any ( )
1363
+ }
1364
+
1337
1365
/** Gets a method from an `impl` block that matches the method call `mc`. */
1366
+ pragma [ nomagic]
1338
1367
private Function getMethodFromImpl ( MethodCall mc ) {
1339
- exists ( Impl impl |
1340
- IsInstantiationOf< MethodCall , IsInstantiationOfInput > :: isInstantiationOf ( mc , impl , _) and
1341
- result = getMethodSuccessor ( impl , mc .getMethodName ( ) )
1368
+ exists ( Impl impl , string name |
1369
+ methodCallHasImplCandidate ( mc , impl ) and
1370
+ name = mc .getMethodName ( ) and
1371
+ result = getMethodSuccessor ( impl , name )
1342
1372
|
1343
- not methodResolutionDependsOnArgument ( impl , _, _, _, _, _) and
1344
- result = getMethodSuccessor ( impl , mc .getMethodName ( ) )
1373
+ not methodResolutionDependsOnArgument ( impl , _, _, _, _, _)
1345
1374
or
1346
1375
exists ( int pos , TypePath path , Type type |
1347
- methodResolutionDependsOnArgument ( impl , mc . getMethodName ( ) , result , pos , path , type ) and
1376
+ methodResolutionDependsOnArgument ( impl , name , result , pos , path , type ) and
1348
1377
inferType ( mc .getPositionalArgument ( pos ) , path ) = type
1349
1378
)
1350
1379
)
@@ -1356,22 +1385,6 @@ private Function getTraitMethod(ImplTraitReturnType trait, string name) {
1356
1385
result = getMethodSuccessor ( trait .getImplTraitTypeRepr ( ) , name )
1357
1386
}
1358
1387
1359
- /**
1360
- * Gets a method that the method call `mc` resolves to based on type inference,
1361
- * if any.
1362
- */
1363
- private Function inferMethodCallTarget ( MethodCall mc ) {
1364
- // The method comes from an `impl` block targeting the type of the receiver.
1365
- result = getMethodFromImpl ( mc )
1366
- or
1367
- // The type of the receiver is a type parameter and the method comes from a
1368
- // trait bound on the type parameter.
1369
- result = getTypeParameterMethod ( mc .getTypeAt ( TypePath:: nil ( ) ) , mc .getMethodName ( ) )
1370
- or
1371
- // The type of the receiver is an `impl Trait` type.
1372
- result = getTraitMethod ( mc .getTypeAt ( TypePath:: nil ( ) ) , mc .getMethodName ( ) )
1373
- }
1374
-
1375
1388
cached
1376
1389
private module Cached {
1377
1390
private import codeql.rust.internal.CachedStages
@@ -1400,47 +1413,18 @@ private module Cached {
1400
1413
)
1401
1414
}
1402
1415
1403
- private predicate isInherentImplFunction ( Function f ) {
1404
- f = any ( Impl impl | not impl .hasTrait ( ) ) .( ImplItemNode ) .getAnAssocItem ( )
1405
- }
1406
-
1407
- private predicate isTraitImplFunction ( Function f ) {
1408
- f = any ( Impl impl | impl .hasTrait ( ) ) .( ImplItemNode ) .getAnAssocItem ( )
1409
- }
1410
-
1411
- private Function resolveMethodCallTargetFrom ( MethodCall mc , boolean fromSource ) {
1412
- result = inferMethodCallTarget ( mc ) and
1413
- ( if result .fromSource ( ) then fromSource = true else fromSource = false ) and
1414
- (
1415
- // prioritize inherent implementation methods first
1416
- isInherentImplFunction ( result )
1417
- or
1418
- not isInherentImplFunction ( inferMethodCallTarget ( mc ) ) and
1419
- (
1420
- // then trait implementation methods
1421
- isTraitImplFunction ( result )
1422
- or
1423
- not isTraitImplFunction ( inferMethodCallTarget ( mc ) ) and
1424
- (
1425
- // then trait methods with default implementations
1426
- result .hasBody ( )
1427
- or
1428
- // and finally trait methods without default implementations
1429
- not inferMethodCallTarget ( mc ) .hasBody ( )
1430
- )
1431
- )
1432
- )
1433
- }
1434
-
1435
1416
/** Gets a method that the method call `mc` resolves to, if any. */
1436
1417
cached
1437
1418
Function resolveMethodCallTarget ( MethodCall mc ) {
1438
- // Functions in source code also gets extracted as library code, due to
1439
- // this duplication we prioritize functions from source code.
1440
- result = resolveMethodCallTargetFrom ( mc , true )
1419
+ // The method comes from an `impl` block targeting the type of the receiver.
1420
+ result = getMethodFromImpl ( mc )
1421
+ or
1422
+ // The type of the receiver is a type parameter and the method comes from a
1423
+ // trait bound on the type parameter.
1424
+ result = getTypeParameterMethod ( mc .getTypeAt ( TypePath:: nil ( ) ) , mc .getMethodName ( ) )
1441
1425
or
1442
- not exists ( resolveMethodCallTargetFrom ( mc , true ) ) and
1443
- result = resolveMethodCallTargetFrom ( mc , false )
1426
+ // The type of the receiver is an `impl Trait` type.
1427
+ result = getTraitMethod ( mc . getTypeAt ( TypePath :: nil ( ) ) , mc . getMethodName ( ) )
1444
1428
}
1445
1429
1446
1430
pragma [ inline]
0 commit comments