Skip to content

Commit b86183f

Browse files
committed
Rust: Make Call class part of the AST type hierarchy
1 parent 338990b commit b86183f

File tree

10 files changed

+71
-166
lines changed

10 files changed

+71
-166
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,7 @@ final class CallCfgNode extends ExprCfgNode {
238238

239239
/** Gets the receiver of this call if it is a method call. */
240240
ExprCfgNode getReceiver() {
241-
any(ChildMapping mapping).hasCfgChild(node, node.getReceiver(), this, result)
241+
any(ChildMapping mapping).hasCfgChild(node, node.getReceiverArgument(), this, result)
242242
}
243243

244244
/** Gets the `i`th argument of this call, if any. */

rust/ql/lib/codeql/rust/dataflow/internal/DataFlowImpl.qll

Lines changed: 7 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -136,27 +136,16 @@ final class ArgumentPosition extends TArgumentPosition {
136136
/** Gets the argument of `call` at this position, if any. */
137137
Expr getArgument(Call call) {
138138
this.isReceiver() and
139-
(
140-
result = call.(MethodCallExpr).getReceiver()
141-
or
142-
result = call.(Operation).getOperand(0)
143-
or
144-
result = call.(IndexExpr).getBase()
145-
)
139+
result = call.getReceiverArgument()
146140
or
147-
exists(boolean inMethodCall, int pos | this.getPosition(inMethodCall) = pos |
148-
result = call.(CallExpr).getArg(pos) and
141+
exists(boolean inMethodCall, int pos |
142+
this.getPosition(inMethodCall) = pos and
143+
result = call.getPositionalArgument(pos)
144+
|
145+
call instanceof CallExpr and
149146
inMethodCall = false
150147
or
151-
result = call.(MethodCallExpr).getArg(pos) and
152-
inMethodCall = true
153-
or
154-
result = call.(Operation).getOperand(pos + 1) and
155-
pos >= 0 and
156-
inMethodCall = true
157-
or
158-
result = call.(IndexExpr).getIndex() and
159-
pos = 0 and
148+
(call instanceof MethodCallExpr or call instanceof Operation or call instanceof IndexExpr) and
160149
inMethodCall = true
161150
)
162151
}

rust/ql/lib/codeql/rust/elements/Call.qll

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

55
private import internal.CallImpl
66

7-
final class ArgumentPosition = Impl::ArgumentPosition;
8-
97
final class Call = Impl::Call;

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,15 @@ private import codeql.rust.elements.internal.generated.CallExprBase
1313
module Impl {
1414
private import rust
1515
private import codeql.rust.internal.TypeInference as TypeInference
16+
private import codeql.rust.elements.internal.CallImpl::Impl as CallImpl
1617

1718
// the following QLdoc is generated: if you need to edit it, do it in the schema file
1819
/**
1920
* A function or method call expression. See `CallExpr` and `MethodCallExpr` for further details.
2021
*/
21-
class CallExprBase extends Generated::CallExprBase {
22-
/** Gets the static target (function or tuple struct/variant) of this call, if any. */
23-
final Addressable getStaticTarget() { result = TypeInference::resolveCallTarget(this) }
24-
22+
class CallExprBase extends Generated::CallExprBase, CallImpl::Call {
2523
override Expr getArg(int index) { result = this.getArgList().getArg(index) }
24+
25+
override Expr getPositionalArgument(int i) { result = this.getArg(i) }
2626
}
2727
}
Lines changed: 12 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,27 @@
11
private import rust
2-
private import codeql.rust.internal.PathResolution
32
private import codeql.rust.internal.TypeInference as TypeInference
43
private import codeql.rust.elements.internal.ExprImpl::Impl as ExprImpl
5-
private import codeql.rust.elements.Operation
64

75
module Impl {
8-
newtype TArgumentPosition =
9-
TPositionalArgumentPosition(int i) {
10-
i in [0 .. max([any(ParamList l).getNumberOfParams(), any(ArgList l).getNumberOfArgs()]) - 1]
11-
} or
12-
TSelfArgumentPosition()
13-
14-
/** An argument position in a call. */
15-
class ArgumentPosition extends TArgumentPosition {
16-
/** Gets the index of the argument in the call, if this is a positional argument. */
17-
int asPosition() { this = TPositionalArgumentPosition(result) }
18-
19-
/** Holds if this call position is a self argument. */
20-
predicate isSelf() { this instanceof TSelfArgumentPosition }
21-
22-
/** Gets a string representation of this argument position. */
23-
string toString() {
24-
result = this.asPosition().toString()
25-
or
26-
this.isSelf() and result = "self"
27-
}
28-
}
29-
306
/**
317
* An expression that calls a function.
328
*
33-
* This class abstracts over the different ways in which a function can be
34-
* called in Rust.
9+
* Either a `CallExprBase`, an `Operation`, or an `IndexExpr`.
3510
*/
3611
abstract class Call extends ExprImpl::Expr {
37-
/** Gets the argument at the given position, if any. */
38-
abstract Expr getArgument(ArgumentPosition pos);
39-
40-
/** Gets the number of arguments _excluding_ any `self` argument. */
41-
int getNumberOfArguments() { result = count(this.getArgument(TPositionalArgumentPosition(_))) }
42-
43-
/** Gets the `i`th argument of this call, if any. */
44-
Expr getPositionalArgument(int i) { result = this.getArgument(TPositionalArgumentPosition(i)) }
12+
/** Gets the `i`th positional argument of this call, if any. */
13+
Expr getPositionalArgument(int i) { none() }
4514

46-
/** Gets the receiver of this call if it is a method call. */
47-
Expr getReceiver() { result = this.getArgument(TSelfArgumentPosition()) }
15+
/**
16+
* Gets the receiver of this call, if any.
17+
*
18+
* This is either an actual receiver of a method call, the first operand of an operation,
19+
* or the base expression of an index expression.
20+
*/
21+
Expr getReceiverArgument() { none() }
4822

49-
/** Gets the static target of this call, if any. */
50-
Function getStaticTarget() { result = TypeInference::resolveCallTarget(this) }
23+
/** Gets the static target (function or tuple struct/variant) of this call, if any. */
24+
final Addressable getStaticTarget() { result = TypeInference::resolveCallTarget(this) }
5125

5226
/** Gets a runtime target of this call, if any. */
5327
pragma[nomagic]
@@ -60,82 +34,4 @@ module Impl {
6034
)
6135
}
6236
}
63-
64-
private predicate callHasQualifier(CallExpr call, Path path, Path qualifier) {
65-
path = call.getFunction().(PathExpr).getPath() and
66-
qualifier = path.getQualifier()
67-
}
68-
69-
/** Holds if the call expression dispatches to a method. */
70-
private predicate callIsMethodCall(
71-
CallExpr call, Path qualifier, string methodName, boolean selfIsRef
72-
) {
73-
exists(Path path, Function f |
74-
callHasQualifier(call, path, qualifier) and
75-
f = resolvePath(path) and
76-
path.getSegment().getIdentifier().getText() = methodName and
77-
exists(SelfParam self |
78-
self = f.getSelfParam() and
79-
if self.isRef() then selfIsRef = true else selfIsRef = false
80-
)
81-
)
82-
}
83-
84-
class CallExprCall extends Call instanceof CallExpr {
85-
CallExprCall() { not callIsMethodCall(this, _, _, _) }
86-
87-
override Expr getArgument(ArgumentPosition pos) {
88-
result = super.getArgList().getArg(pos.asPosition())
89-
}
90-
}
91-
92-
class CallExprMethodCall extends Call instanceof CallExpr {
93-
string methodName;
94-
boolean selfIsRef;
95-
96-
CallExprMethodCall() { callIsMethodCall(this, _, methodName, selfIsRef) }
97-
98-
/**
99-
* Holds if this call must have an explicit borrow for the `self` argument,
100-
* because the corresponding parameter is `&self`. Explicit borrows are not
101-
* needed when using method call syntax.
102-
*/
103-
predicate hasExplicitSelfBorrow() { selfIsRef = true }
104-
105-
override Expr getArgument(ArgumentPosition pos) {
106-
pos.isSelf() and result = super.getArgList().getArg(0)
107-
or
108-
result = super.getArgList().getArg(pos.asPosition() + 1)
109-
}
110-
}
111-
112-
private class MethodCallExprCall extends Call instanceof MethodCallExpr {
113-
override Expr getArgument(ArgumentPosition pos) {
114-
pos.isSelf() and result = this.(MethodCallExpr).getReceiver()
115-
or
116-
result = super.getArgList().getArg(pos.asPosition())
117-
}
118-
}
119-
120-
private class OperatorCall extends Call instanceof Operation {
121-
Trait trait;
122-
string methodName;
123-
int borrows;
124-
125-
OperatorCall() { super.isOverloaded(trait, methodName, borrows) }
126-
127-
override Expr getArgument(ArgumentPosition pos) {
128-
pos.isSelf() and result = super.getOperand(0)
129-
or
130-
pos.asPosition() = 0 and result = super.getOperand(1)
131-
}
132-
}
133-
134-
private class IndexCall extends Call instanceof IndexExpr {
135-
override Expr getArgument(ArgumentPosition pos) {
136-
pos.isSelf() and result = super.getBase()
137-
or
138-
pos.asPosition() = 0 and result = super.getIndex()
139-
}
140-
}
14137
}

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

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ private import codeql.rust.elements.internal.generated.IndexExpr
1111
* be referenced directly.
1212
*/
1313
module Impl {
14+
private import codeql.rust.elements.internal.CallImpl::Impl as CallImpl
15+
1416
// the following QLdoc is generated: if you need to edit it, do it in the schema file
1517
/**
1618
* An index expression. For example:
@@ -19,10 +21,14 @@ module Impl {
1921
* list[42] = 1;
2022
* ```
2123
*/
22-
class IndexExpr extends Generated::IndexExpr {
24+
class IndexExpr extends Generated::IndexExpr, CallImpl::Call {
2325
override string toStringImpl() {
2426
result =
2527
this.getBase().toAbbreviatedString() + "[" + this.getIndex().toAbbreviatedString() + "]"
2628
}
29+
30+
override Expr getPositionalArgument(int i) { i = 0 and result = this.getIndex() }
31+
32+
override Expr getReceiverArgument() { result = this.getBase() }
2733
}
2834
}

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ module Impl {
3939
result = strictconcat(int i | | this.toStringPart(i) order by i)
4040
}
4141

42-
/** Gets the static target of this method call, if any. */
43-
final Function getStaticTarget() { result = super.getStaticTarget() }
42+
override Expr getReceiverArgument() { result = super.getReceiver() }
4443
}
4544
}

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

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ private import codeql.rust.elements.internal.ExprImpl::Impl as ExprImpl
1212
* be referenced directly.
1313
*/
1414
module Impl {
15+
private import codeql.rust.elements.internal.CallImpl::Impl as CallImpl
16+
1517
/**
1618
* Holds if the operator `op` with arity `arity` is overloaded to a trait with
1719
* the canonical path `path` and the method name `method`, and if it borrows its
@@ -100,13 +102,17 @@ module Impl {
100102
/**
101103
* An operation, for example `&&`, `+=`, `!` or `*`.
102104
*/
103-
abstract class Operation extends ExprImpl::Expr {
105+
abstract class Operation extends CallImpl::Call {
104106
/** Gets the operator name of this operation, if it exists. */
105107
abstract string getOperatorName();
106108

107109
/** Gets the `n`th operand of this operation, if any. */
108110
abstract Expr getOperand(int n);
109111

112+
override Expr getPositionalArgument(int i) { result = this.getOperand(i + 1) and i >= 0 }
113+
114+
override Expr getReceiverArgument() { result = this.getOperand(0) }
115+
110116
/**
111117
* Gets the number of operands of this operation.
112118
*

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

Lines changed: 10 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1368,10 +1368,15 @@ private module MethodResolution {
13681368
*
13691369
* [1]: https://doc.rust-lang.org/std/ops/trait.Index.html
13701370
*/
1371-
abstract class MethodCall extends Expr {
1371+
abstract class MethodCall extends Call {
13721372
abstract predicate hasNameAndArity(string name, int arity);
13731373

1374-
abstract Expr getArgument(ArgumentPosition pos);
1374+
Expr getArgument(ArgumentPosition pos) {
1375+
result = this.getPositionalArgument(pos.asPosition())
1376+
or
1377+
pos.isSelf() and
1378+
result = this.getReceiverArgument()
1379+
}
13751380

13761381
abstract predicate supportsAutoDerefAndBorrow();
13771382

@@ -1614,12 +1619,12 @@ private module MethodResolution {
16141619

16151620
predicate receiverHasImplicitDeref(AstNode receiver) {
16161621
exists(this.resolveCallTarget(_, ".ref", false)) and
1617-
receiver = this.getArgument(CallImpl::TSelfArgumentPosition())
1622+
receiver = this.getArgument(any(ArgumentPosition pos | pos.isSelf()))
16181623
}
16191624

16201625
predicate argumentHasImplicitBorrow(AstNode arg) {
16211626
exists(this.resolveCallTarget(_, "", true)) and
1622-
arg = this.getArgument(CallImpl::TSelfArgumentPosition())
1627+
arg = this.getArgument(any(ArgumentPosition pos | pos.isSelf()))
16231628
}
16241629
}
16251630

@@ -1630,13 +1635,6 @@ private module MethodResolution {
16301635
arity = super.getArgList().getNumberOfArgs()
16311636
}
16321637

1633-
override Expr getArgument(ArgumentPosition pos) {
1634-
pos.isSelf() and
1635-
result = MethodCallExpr.super.getReceiver()
1636-
or
1637-
result = super.getArgList().getArg(pos.asPosition())
1638-
}
1639-
16401638
override predicate supportsAutoDerefAndBorrow() { any() }
16411639

16421640
override Trait getTrait() { none() }
@@ -1649,14 +1647,6 @@ private module MethodResolution {
16491647
arity = 1
16501648
}
16511649

1652-
override Expr getArgument(ArgumentPosition pos) {
1653-
pos.isSelf() and
1654-
result = this.getBase()
1655-
or
1656-
pos.asPosition() = 0 and
1657-
result = this.getIndex()
1658-
}
1659-
16601650
override predicate supportsAutoDerefAndBorrow() { any() }
16611651

16621652
override Trait getTrait() { result.getCanonicalPath() = "core::ops::index::Index" }
@@ -1690,6 +1680,7 @@ private module MethodResolution {
16901680
arity = this.getArgList().getNumberOfArgs() - 1
16911681
}
16921682

1683+
// todo: comment
16931684
override Expr getArgument(ArgumentPosition pos) {
16941685
pos.isSelf() and
16951686
result = this.getArg(0)
@@ -1714,8 +1705,6 @@ private module MethodResolution {
17141705
arity = this.getNumberOfOperands() - 1
17151706
}
17161707

1717-
override Expr getArgument(ArgumentPosition pos) { result = this.(Call).getArgument(pos) }
1718-
17191708
private predicate implicitBorrowAt(ArgumentPosition pos) {
17201709
exists(int borrows | this.isOverloaded(_, _, borrows) |
17211710
pos.isSelf() and borrows >= 1

rust/ql/lib/codeql/rust/internal/typeinference/FunctionType.qll

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,28 @@ private import codeql.rust.internal.Type
55
private import codeql.rust.internal.TypeMention
66
private import codeql.rust.elements.Call
77

8+
private newtype TArgumentPosition =
9+
TPositionalArgumentPosition(int i) {
10+
i in [0 .. max([any(ParamList l).getNumberOfParams(), any(ArgList l).getNumberOfArgs()]) - 1]
11+
} or
12+
TSelfArgumentPosition()
13+
14+
/** An argument position in a call. */
15+
class ArgumentPosition extends TArgumentPosition {
16+
/** Gets the index of the argument in the call, if this is a positional argument. */
17+
int asPosition() { this = TPositionalArgumentPosition(result) }
18+
19+
/** Holds if this call position is a self argument. */
20+
predicate isSelf() { this instanceof TSelfArgumentPosition }
21+
22+
/** Gets a string representation of this argument position. */
23+
string toString() {
24+
result = this.asPosition().toString()
25+
or
26+
this.isSelf() and result = "self"
27+
}
28+
}
29+
830
private newtype TFunctionPosition =
931
TArgumentFunctionPosition(ArgumentPosition pos) or
1032
TReturnFunctionPosition()

0 commit comments

Comments
 (0)