mirror of
https://github.com/github/codeql.git
synced 2026-04-27 01:35:13 +02:00
Rust: Add abstraction over all kinds of calls
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
*/
|
||||
|
||||
private import rust
|
||||
private import codeql.rust.elements.Call
|
||||
private import ControlFlowGraph
|
||||
private import internal.ControlFlowGraphImpl as CfgImpl
|
||||
private import internal.CfgNodes
|
||||
@@ -162,6 +163,30 @@ final class CallExprBaseCfgNode extends Nodes::CallExprBaseCfgNode {
|
||||
*/
|
||||
final class MethodCallExprCfgNode extends CallExprBaseCfgNode, Nodes::MethodCallExprCfgNode { }
|
||||
|
||||
/**
|
||||
* A CFG node that calls a function.
|
||||
*
|
||||
* This class abstract over the different ways in which a function can be called in Rust.
|
||||
*/
|
||||
final class CallCfgNode extends ExprCfgNode {
|
||||
private Call node;
|
||||
|
||||
CallCfgNode() { node = this.getAstNode() }
|
||||
|
||||
/** Gets the underlying `Call`. */
|
||||
Call getCall() { result = node }
|
||||
|
||||
/** Gets the receiver of this call if it is a method call. */
|
||||
ExprCfgNode getReceiver() {
|
||||
any(ChildMapping mapping).hasCfgChild(node, node.getReceiver(), this, result)
|
||||
}
|
||||
|
||||
/** Gets the `i`th argument of this call, if any. */
|
||||
ExprCfgNode getArgument(int i) {
|
||||
any(ChildMapping mapping).hasCfgChild(node, node.getArgument(i), this, result)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A function call expression. For example:
|
||||
* ```rust
|
||||
|
||||
7
rust/ql/lib/codeql/rust/elements/Call.qll
Normal file
7
rust/ql/lib/codeql/rust/elements/Call.qll
Normal file
@@ -0,0 +1,7 @@
|
||||
/**
|
||||
* Call.
|
||||
*/
|
||||
|
||||
private import internal.CallImpl
|
||||
|
||||
final class Call = Impl::Call;
|
||||
128
rust/ql/lib/codeql/rust/elements/internal/CallImpl.qll
Normal file
128
rust/ql/lib/codeql/rust/elements/internal/CallImpl.qll
Normal file
@@ -0,0 +1,128 @@
|
||||
private import rust
|
||||
private import codeql.rust.internal.PathResolution
|
||||
private import codeql.rust.internal.TypeInference as TypeInference
|
||||
private import codeql.rust.elements.internal.ExprImpl::Impl as ExprImpl
|
||||
private import codeql.rust.elements.Operation
|
||||
|
||||
module Impl {
|
||||
/**
|
||||
* An expression that calls a function.
|
||||
*
|
||||
* This class abstract over the different ways in which a function can be called in Rust.
|
||||
*/
|
||||
abstract class Call extends ExprImpl::Expr {
|
||||
Call() { this.fromSource() }
|
||||
|
||||
/** Gets the number of arguments _excluding_ any `self` argument. */
|
||||
abstract int getNumberOfArguments();
|
||||
|
||||
/** Gets the receiver of this call if it is a method call. */
|
||||
abstract Expr getReceiver();
|
||||
|
||||
/** Holds if the call has a receiver that might be implicitly borrowed. */
|
||||
abstract predicate receiverImplicitlyBorrowed();
|
||||
|
||||
/** Gets the trait targeted by this call, if any. */
|
||||
abstract Trait getTrait();
|
||||
|
||||
/** Gets the name of the method called if this call is a method call. */
|
||||
abstract string getMethodName();
|
||||
|
||||
/** Gets the `i`th argument of this call, if any. */
|
||||
abstract Expr getArgument(int i);
|
||||
|
||||
/** 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()
|
||||
}
|
||||
}
|
||||
|
||||
/** Holds if the call expression dispatches to a trait method. */
|
||||
private predicate callIsMethodCall(CallExpr call, Path qualifier, string methodName) {
|
||||
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
|
||||
)
|
||||
}
|
||||
|
||||
private class CallExprCall extends Call instanceof CallExpr {
|
||||
CallExprCall() { not callIsMethodCall(this, _, _) }
|
||||
|
||||
override string getMethodName() { none() }
|
||||
|
||||
override Expr getReceiver() { none() }
|
||||
|
||||
override Trait getTrait() { none() }
|
||||
|
||||
override predicate receiverImplicitlyBorrowed() { none() }
|
||||
|
||||
override int getNumberOfArguments() { result = super.getArgList().getNumberOfArgs() }
|
||||
|
||||
override Expr getArgument(int i) { result = super.getArgList().getArg(i) }
|
||||
}
|
||||
|
||||
private class CallExprMethodCall extends Call instanceof CallExpr {
|
||||
Path qualifier;
|
||||
string methodName;
|
||||
|
||||
CallExprMethodCall() { callIsMethodCall(this, qualifier, methodName) }
|
||||
|
||||
override string getMethodName() { result = methodName }
|
||||
|
||||
override Expr getReceiver() { result = super.getArgList().getArg(0) }
|
||||
|
||||
override Trait getTrait() {
|
||||
result = resolvePath(qualifier) and
|
||||
// When the qualifier is `Self` and resolves to a trait, it's inside a
|
||||
// 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"
|
||||
}
|
||||
|
||||
override predicate receiverImplicitlyBorrowed() { none() }
|
||||
|
||||
override int getNumberOfArguments() { result = super.getArgList().getNumberOfArgs() - 1 }
|
||||
|
||||
override Expr getArgument(int i) { result = super.getArgList().getArg(i + 1) }
|
||||
}
|
||||
|
||||
private class MethodCallExprCall extends Call instanceof MethodCallExpr {
|
||||
override string getMethodName() { result = super.getIdentifier().getText() }
|
||||
|
||||
override Expr getReceiver() { result = this.(MethodCallExpr).getReceiver() }
|
||||
|
||||
override Trait getTrait() { none() }
|
||||
|
||||
override predicate receiverImplicitlyBorrowed() { any() }
|
||||
|
||||
override int getNumberOfArguments() { result = super.getArgList().getNumberOfArgs() }
|
||||
|
||||
override Expr getArgument(int i) { result = super.getArgList().getArg(i) }
|
||||
}
|
||||
|
||||
private class OperatorCall extends Call instanceof Operation {
|
||||
Trait trait;
|
||||
string methodName;
|
||||
|
||||
OperatorCall() { super.isOverloaded(trait, methodName) }
|
||||
|
||||
override string getMethodName() { result = methodName }
|
||||
|
||||
override Expr getReceiver() { result = super.getOperand(0) }
|
||||
|
||||
override Trait getTrait() { result = trait }
|
||||
|
||||
override predicate receiverImplicitlyBorrowed() { none() }
|
||||
|
||||
override int getNumberOfArguments() { result = super.getNumberOfOperands() - 1 }
|
||||
|
||||
override Expr getArgument(int i) { result = super.getOperand(1) and i = 0 }
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user