Skip to content

Commit ef6493b

Browse files
committed
Rust: Add abstraction over all kinds of calls
1 parent bf0920f commit ef6493b

File tree

3 files changed

+152
-0
lines changed

3 files changed

+152
-0
lines changed

rust/ql/lib/codeql/rust/controlflow/CfgNodes.qll

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
*/
55

66
private import rust
7+
private import codeql.rust.elements.Call
78
private import ControlFlowGraph
89
private import internal.ControlFlowGraphImpl as CfgImpl
910
private import internal.CfgNodes
@@ -162,6 +163,24 @@ final class CallExprBaseCfgNode extends Nodes::CallExprBaseCfgNode {
162163
*/
163164
final class MethodCallExprCfgNode extends CallExprBaseCfgNode, Nodes::MethodCallExprCfgNode { }
164165

166+
final class CallCfgNode extends ExprCfgNode {
167+
private Call node;
168+
169+
CallCfgNode() { node = this.getAstNode() }
170+
171+
/** Gets the underlying `Call`. */
172+
Call getCall() { result = node }
173+
174+
ExprCfgNode getReceiver() {
175+
any(ChildMapping mapping).hasCfgChild(node, node.getReceiver(), this, result)
176+
}
177+
178+
/** Gets the `i`th argument of this call. */
179+
ExprCfgNode getArgument(int i) {
180+
any(ChildMapping mapping).hasCfgChild(node, node.getArgument(i), this, result)
181+
}
182+
}
183+
165184
/**
166185
* A function call expression. For example:
167186
* ```rust
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
/**
2+
* Call.
3+
*/
4+
5+
private import internal.CallImpl
6+
7+
final class Call = Impl::Call;
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
private import rust
2+
private import codeql.rust.internal.PathResolution
3+
private import codeql.rust.internal.TypeInference as TypeInference
4+
private import codeql.rust.elements.internal.ExprImpl::Impl as ExprImpl
5+
private import codeql.rust.elements.Operation
6+
7+
module Impl {
8+
/**
9+
* An expression that calls a function.
10+
*
11+
* This class abstract over the different ways in which a function can be called in Rust.
12+
*/
13+
abstract class Call extends ExprImpl::Expr {
14+
Call() { this.fromSource() }
15+
16+
/** Gets the number of arguments _excluding_ any `self` argument. */
17+
abstract int getNumberOfArguments();
18+
19+
/** Gets the receiver of this call if it is a method call. */
20+
abstract Expr getReceiver();
21+
22+
/** Holds if the call has a receiver that might be implicitly borrowed. */
23+
abstract predicate receiverImplicitlyBorrowed();
24+
25+
/** Gets the trait targeted by this call, if any. */
26+
abstract Trait getTrait();
27+
28+
abstract string getMethodName();
29+
30+
abstract Expr getArgument(int index);
31+
32+
Function getStaticTarget() {
33+
result = TypeInference::resolveMethodCallTarget(this)
34+
or
35+
not exists(TypeInference::resolveMethodCallTarget(this)) and
36+
result = this.(CallExpr).getStaticTarget()
37+
}
38+
}
39+
40+
/** Holds if the call expression dispatches to a trait method. */
41+
private predicate callIsMethodCall(CallExpr call, Path qualifier, string methodName) {
42+
exists(Path path, Function f |
43+
path = call.getFunction().(PathExpr).getPath() and
44+
f = resolvePath(path) and
45+
f.getParamList().hasSelfParam() and
46+
qualifier = path.getQualifier() and
47+
path.getSegment().getIdentifier().getText() = methodName
48+
)
49+
}
50+
51+
private class CallExprCall extends Call instanceof CallExpr {
52+
CallExprCall() { not callIsMethodCall(this, _, _) }
53+
54+
override string getMethodName() { none() }
55+
56+
override Expr getReceiver() { none() }
57+
58+
override Trait getTrait() { none() }
59+
60+
override predicate receiverImplicitlyBorrowed() { none() }
61+
62+
override int getNumberOfArguments() { result = super.getArgList().getNumberOfArgs() }
63+
64+
override Expr getArgument(int index) { result = super.getArgList().getArg(index) }
65+
}
66+
67+
private class CallExprMethodCall extends Call instanceof CallExpr {
68+
Path qualifier;
69+
string methodName;
70+
71+
CallExprMethodCall() { callIsMethodCall(this, qualifier, methodName) }
72+
73+
override string getMethodName() { result = methodName }
74+
75+
override Expr getReceiver() { result = super.getArgList().getArg(0) }
76+
77+
override Trait getTrait() {
78+
result = resolvePath(qualifier) and
79+
// When the qualifier is `Self` and resolves to a trait, it's inside a
80+
// trait method's default implementation. This is not a dispatch whose
81+
// target is infered from the type of the receiver, but should always
82+
// resolve to the function in the trait block as path resolution does.
83+
qualifier.toString() != "Self"
84+
}
85+
86+
override predicate receiverImplicitlyBorrowed() { none() }
87+
88+
override int getNumberOfArguments() { result = super.getArgList().getNumberOfArgs() - 1 }
89+
90+
override Expr getArgument(int index) { result = super.getArgList().getArg(index + 1) }
91+
}
92+
93+
private class MethodCallExprCall extends Call instanceof MethodCallExpr {
94+
override string getMethodName() { result = super.getIdentifier().getText() }
95+
96+
override Expr getReceiver() { result = this.(MethodCallExpr).getReceiver() }
97+
98+
override Trait getTrait() { none() }
99+
100+
override predicate receiverImplicitlyBorrowed() { any() }
101+
102+
override int getNumberOfArguments() { result = super.getArgList().getNumberOfArgs() }
103+
104+
// override Expr getTypeArgument(int index) { super.getGenericArgList().getTypeArg(index) }
105+
override Expr getArgument(int index) { result = super.getArgList().getArg(index) }
106+
}
107+
108+
private class OperatorCall extends Call instanceof Operation {
109+
Trait trait;
110+
string methodName;
111+
112+
OperatorCall() { super.isOverloaded(trait, methodName) }
113+
114+
override string getMethodName() { result = methodName }
115+
116+
override Expr getReceiver() { result = super.getOperand(0) }
117+
118+
override Trait getTrait() { result = trait }
119+
120+
override predicate receiverImplicitlyBorrowed() { none() }
121+
122+
override int getNumberOfArguments() { result = super.getNumberOfOperands() - 1 }
123+
124+
override Expr getArgument(int index) { result = super.getOperand(1) and index = 0 }
125+
}
126+
}

0 commit comments

Comments
 (0)