Skip to content

Rust: Disambiguate associated function calls #19995

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 5 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ private import codeql.rust.elements.Resolvable
*/
module Impl {
private import rust
private import codeql.rust.internal.TypeInference as TypeInference

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

override Expr getArg(int index) { result = this.getArgList().getArg(index) }
}
Expand Down
10 changes: 0 additions & 10 deletions rust/ql/lib/codeql/rust/elements/internal/CallExprImpl.qll
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ private import codeql.rust.elements.PathExpr
module Impl {
private import rust
private import codeql.rust.internal.PathResolution as PathResolution
private import codeql.rust.internal.TypeInference as TypeInference

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

override Callable getStaticTarget() {
// If this call is to a trait method, e.g., `Trait::foo(bar)`, then check
// if type inference can resolve it to the correct trait implementation.
result = TypeInference::resolveMethodCallTarget(this)
or
not exists(TypeInference::resolveMethodCallTarget(this)) and
result = getResolvedFunction(this)
}

/** Gets the struct that this call resolves to, if any. */
Struct getStruct() { result = getResolvedFunction(this) }

Expand Down
34 changes: 21 additions & 13 deletions rust/ql/lib/codeql/rust/elements/internal/CallImpl.qll
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,7 @@ module Impl {
Expr getReceiver() { result = this.getArgument(TSelfArgumentPosition()) }

/** Gets the static target of this call, if any. */
Function getStaticTarget() {
result = TypeInference::resolveMethodCallTarget(this)
or
not exists(TypeInference::resolveMethodCallTarget(this)) and
result = this.(CallExpr).getStaticTarget()
}
Function getStaticTarget() { result = TypeInference::resolveCallTarget(this) }

/** Gets a runtime target of this call, if any. */
pragma[nomagic]
Expand All @@ -79,18 +74,23 @@ module Impl {
}

/** Holds if the call expression dispatches to a method. */
private predicate callIsMethodCall(CallExpr call, Path qualifier, string methodName) {
private predicate callIsMethodCall(
CallExpr call, Path qualifier, string methodName, boolean selfIsRef
) {
exists(Path path, Function f |
path = call.getFunction().(PathExpr).getPath() and
f = resolvePath(path) and
f.getParamList().hasSelfParam() and
qualifier = path.getQualifier() and
path.getSegment().getIdentifier().getText() = methodName
path.getSegment().getIdentifier().getText() = methodName and
exists(SelfParam self |
self = f.getParamList().getSelfParam() and
if self.isRef() then selfIsRef = true else selfIsRef = false
)
)
}

private class CallExprCall extends Call instanceof CallExpr {
CallExprCall() { not callIsMethodCall(this, _, _) }
CallExprCall() { not callIsMethodCall(this, _, _, _) }

override string getMethodName() { none() }

Expand All @@ -103,11 +103,19 @@ module Impl {
}
}

private class CallExprMethodCall extends Call instanceof CallExpr {
class CallExprMethodCall extends Call instanceof CallExpr {
Path qualifier;
string methodName;
boolean selfIsRef;

CallExprMethodCall() { callIsMethodCall(this, qualifier, methodName, selfIsRef) }

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

override string getMethodName() { result = methodName }

Expand All @@ -117,7 +125,7 @@ module Impl {
// trait method's default implementation. This is not a dispatch whose
// target is inferred from the type of the receiver, but should always
// resolve to the function in the trait block as path resolution does.
qualifier.toString() != "Self"
not qualifier.(RelevantPath).isUnqualified("Self")
}

override predicate implicitBorrowAt(ArgumentPosition pos, boolean certain) { none() }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@

private import rust
private import codeql.rust.elements.internal.generated.MethodCallExpr
private import codeql.rust.internal.PathResolution
private import codeql.rust.internal.TypeInference

/**
* INTERNAL: This module contains the customizable definition of `MethodCallExpr` and should not
Expand All @@ -23,8 +21,6 @@ module Impl {
* ```
*/
class MethodCallExpr extends Generated::MethodCallExpr {
override Function getStaticTarget() { result = resolveMethodCallTarget(this) }

private string toStringPart(int index) {
index = 0 and
result = this.getReceiver().toAbbreviatedString()
Expand Down
2 changes: 2 additions & 0 deletions rust/ql/lib/codeql/rust/internal/Type.qll
Original file line number Diff line number Diff line change
Expand Up @@ -425,6 +425,8 @@ final class TraitTypeAbstraction extends TypeAbstraction, Trait {
result.(TypeParamTypeParameter).getTypeParam() = this.getGenericParamList().getATypeParam()
or
result.(AssociatedTypeTypeParameter).getTrait() = this
or
result.(SelfTypeParameter).getTrait() = this
}
}

Expand Down
Loading