Skip to content

Commit ebde0bd

Browse files
committed
Rust: Disambiguate calls to associated functions
1 parent 95c2b9f commit ebde0bd

File tree

6 files changed

+279
-89
lines changed

6 files changed

+279
-89
lines changed

rust/ql/lib/codeql/rust/elements/internal/CallExprBaseImpl.qll

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ private import codeql.rust.elements.Resolvable
1313
*/
1414
module Impl {
1515
private import rust
16+
private import codeql.rust.internal.TypeInference as TypeInference
1617

1718
pragma[nomagic]
1819
Resolvable getCallResolvable(CallExprBase call) {
@@ -27,7 +28,7 @@ module Impl {
2728
*/
2829
class CallExprBase extends Generated::CallExprBase {
2930
/** Gets the static target of this call, if any. */
30-
Callable getStaticTarget() { none() } // overridden by subclasses, but cannot be made abstract
31+
final Function getStaticTarget() { result = TypeInference::resolveCallTarget(this) }
3132

3233
override Expr getArg(int index) { result = this.getArgList().getArg(index) }
3334
}

rust/ql/lib/codeql/rust/elements/internal/CallExprImpl.qll

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ private import codeql.rust.elements.PathExpr
1414
module Impl {
1515
private import rust
1616
private import codeql.rust.internal.PathResolution as PathResolution
17-
private import codeql.rust.internal.TypeInference as TypeInference
1817

1918
pragma[nomagic]
2019
Path getFunctionPath(CallExpr ce) { result = ce.getFunction().(PathExpr).getPath() }
@@ -37,15 +36,6 @@ module Impl {
3736
class CallExpr extends Generated::CallExpr {
3837
override string toStringImpl() { result = this.getFunction().toAbbreviatedString() + "(...)" }
3938

40-
override Callable getStaticTarget() {
41-
// If this call is to a trait method, e.g., `Trait::foo(bar)`, then check
42-
// if type inference can resolve it to the correct trait implementation.
43-
result = TypeInference::resolveMethodCallTarget(this)
44-
or
45-
not exists(TypeInference::resolveMethodCallTarget(this)) and
46-
result = getResolvedFunction(this)
47-
}
48-
4939
/** Gets the struct that this call resolves to, if any. */
5040
Struct getStruct() { result = getResolvedFunction(this) }
5141

rust/ql/lib/codeql/rust/elements/internal/CallImpl.qll

Lines changed: 44 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ module Impl {
4040
/** Gets the trait targeted by this call, if any. */
4141
abstract Trait getTrait();
4242

43+
/** Holds if this call targets a trait. */
44+
predicate hasTrait() { exists(this.getTrait()) }
45+
4346
/** Gets the name of the method called if this call is a method call. */
4447
abstract string getMethodName();
4548

@@ -59,12 +62,7 @@ module Impl {
5962
Expr getReceiver() { result = this.getArgument(TSelfArgumentPosition()) }
6063

6164
/** Gets the static target of this call, if any. */
62-
Function getStaticTarget() {
63-
result = TypeInference::resolveMethodCallTarget(this)
64-
or
65-
not exists(TypeInference::resolveMethodCallTarget(this)) and
66-
result = this.(CallExpr).getStaticTarget()
67-
}
65+
Function getStaticTarget() { result = TypeInference::resolveCallTarget(this) }
6866

6967
/** Gets a runtime target of this call, if any. */
7068
pragma[nomagic]
@@ -78,23 +76,44 @@ module Impl {
7876
}
7977
}
8078

79+
private predicate callHasQualifier(CallExpr call, Path path, Path qualifier) {
80+
path = call.getFunction().(PathExpr).getPath() and
81+
qualifier = path.getQualifier()
82+
}
83+
84+
private predicate callHasTraitQualifier(CallExpr call, Trait qualifier) {
85+
exists(RelevantPath qualifierPath |
86+
callHasQualifier(call, _, qualifierPath) and
87+
qualifier = resolvePath(qualifierPath) and
88+
// When the qualifier is `Self` and resolves to a trait, it's inside a
89+
// trait method's default implementation. This is not a dispatch whose
90+
// target is inferred from the type of the receiver, but should always
91+
// resolve to the function in the trait block as path resolution does.
92+
not qualifierPath.isUnqualified("Self")
93+
)
94+
}
95+
8196
/** Holds if the call expression dispatches to a method. */
82-
private predicate callIsMethodCall(CallExpr call, Path qualifier, string methodName) {
97+
private predicate callIsMethodCall(
98+
CallExpr call, Path qualifier, string methodName, boolean selfIsRef
99+
) {
83100
exists(Path path, Function f |
84-
path = call.getFunction().(PathExpr).getPath() and
101+
callHasQualifier(call, path, qualifier) and
85102
f = resolvePath(path) and
86-
f.getParamList().hasSelfParam() and
87-
qualifier = path.getQualifier() and
88-
path.getSegment().getIdentifier().getText() = methodName
103+
path.getSegment().getIdentifier().getText() = methodName and
104+
exists(SelfParam self |
105+
self = f.getParamList().getSelfParam() and
106+
if self.isRef() then selfIsRef = true else selfIsRef = false
107+
)
89108
)
90109
}
91110

92-
private class CallExprCall extends Call instanceof CallExpr {
93-
CallExprCall() { not callIsMethodCall(this, _, _) }
111+
class CallExprCall extends Call instanceof CallExpr {
112+
CallExprCall() { not callIsMethodCall(this, _, _, _) }
94113

95114
override string getMethodName() { none() }
96115

97-
override Trait getTrait() { none() }
116+
override Trait getTrait() { callHasTraitQualifier(this, result) }
98117

99118
override predicate implicitBorrowAt(ArgumentPosition pos, boolean certain) { none() }
100119

@@ -103,22 +122,23 @@ module Impl {
103122
}
104123
}
105124

106-
private class CallExprMethodCall extends Call instanceof CallExpr {
125+
class CallExprMethodCall extends Call instanceof CallExpr {
107126
Path qualifier;
108127
string methodName;
128+
boolean selfIsRef;
129+
130+
CallExprMethodCall() { callIsMethodCall(this, qualifier, methodName, selfIsRef) }
109131

110-
CallExprMethodCall() { callIsMethodCall(this, qualifier, methodName) }
132+
/**
133+
* Holds if this call must have an explicit borrow for the `self` argument,
134+
* because the corresponding parameter is `&self`. Explicit borrows are not
135+
* needed when using method call syntax.
136+
*/
137+
predicate hasExplicitSelfBorrow() { selfIsRef = true }
111138

112139
override string getMethodName() { result = methodName }
113140

114-
override Trait getTrait() {
115-
result = resolvePath(qualifier) and
116-
// When the qualifier is `Self` and resolves to a trait, it's inside a
117-
// trait method's default implementation. This is not a dispatch whose
118-
// target is inferred from the type of the receiver, but should always
119-
// resolve to the function in the trait block as path resolution does.
120-
qualifier.toString() != "Self"
121-
}
141+
override Trait getTrait() { callHasTraitQualifier(this, result) }
122142

123143
override predicate implicitBorrowAt(ArgumentPosition pos, boolean certain) { none() }
124144

rust/ql/lib/codeql/rust/elements/internal/MethodCallExprImpl.qll

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@
66

77
private import rust
88
private import codeql.rust.elements.internal.generated.MethodCallExpr
9-
private import codeql.rust.internal.PathResolution
10-
private import codeql.rust.internal.TypeInference
119

1210
/**
1311
* INTERNAL: This module contains the customizable definition of `MethodCallExpr` and should not
@@ -23,8 +21,6 @@ module Impl {
2321
* ```
2422
*/
2523
class MethodCallExpr extends Generated::MethodCallExpr {
26-
override Function getStaticTarget() { result = resolveMethodCallTarget(this) }
27-
2824
private string toStringPart(int index) {
2925
index = 0 and
3026
result = this.getReceiver().toAbbreviatedString()

rust/ql/lib/codeql/rust/internal/Type.qll

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,8 @@ final class TraitTypeAbstraction extends TypeAbstraction, Trait {
425425
result.(TypeParamTypeParameter).getTypeParam() = this.getGenericParamList().getATypeParam()
426426
or
427427
result.(AssociatedTypeTypeParameter).getTrait() = this
428+
or
429+
result.(SelfTypeParameter).getTrait() = this
428430
}
429431
}
430432

0 commit comments

Comments
 (0)