Skip to content

Commit 627c235

Browse files
committed
Rust: Implement basic type inference in QL
1 parent e13b16f commit 627c235

39 files changed

+3369
-167
lines changed

rust/ql/.generated.list

Lines changed: 0 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rust/ql/.gitattributes

Lines changed: 0 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

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

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -239,9 +239,8 @@ final class RecordExprCfgNode extends Nodes::RecordExprCfgNode {
239239
pragma[nomagic]
240240
ExprCfgNode getFieldExpr(string field) {
241241
exists(RecordExprField ref |
242-
ref = node.getRecordExprFieldList().getAField() and
243-
any(ChildMapping mapping).hasCfgChild(node, ref.getExpr(), this, result) and
244-
field = ref.getFieldName()
242+
ref = node.getFieldExpr(field) and
243+
any(ChildMapping mapping).hasCfgChild(node, ref.getExpr(), this, result)
245244
)
246245
}
247246
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -847,7 +847,7 @@ class TupleFieldContent extends FieldContent, TTupleFieldContent {
847847

848848
predicate isStructField(Struct s, int pos) { field.isStructField(s, pos) }
849849

850-
override FieldExprCfgNode getAnAccess() { none() } // TODO
850+
override FieldExprCfgNode getAnAccess() { field = result.getFieldExpr().getTupleField() }
851851

852852
final override string toString() {
853853
exists(Variant v, int pos, string vname |
@@ -878,7 +878,7 @@ class RecordFieldContent extends FieldContent, TRecordFieldContent {
878878

879879
predicate isStructField(Struct s, string name) { field.isStructField(s, name) }
880880

881-
override FieldExprCfgNode getAnAccess() { none() } // TODO
881+
override FieldExprCfgNode getAnAccess() { field = result.getFieldExpr().getRecordField() }
882882

883883
final override string toString() {
884884
exists(Variant v, string name, string vname |

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

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,7 @@ private import codeql.rust.elements.Resolvable
1212
* be referenced directly.
1313
*/
1414
module Impl {
15-
private import codeql.rust.elements.internal.CallableImpl::Impl
16-
private import codeql.rust.elements.internal.MethodCallExprImpl::Impl
17-
private import codeql.rust.elements.internal.CallExprImpl::Impl
18-
private import codeql.rust.elements.internal.PathExprImpl::Impl
19-
private import codeql.rust.elements.internal.PathResolution
15+
private import rust
2016

2117
pragma[nomagic]
2218
Resolvable getCallResolvable(CallExprBase call) {
@@ -30,14 +26,7 @@ module Impl {
3026
* A function or method call expression. See `CallExpr` and `MethodCallExpr` for further details.
3127
*/
3228
class CallExprBase extends Generated::CallExprBase {
33-
/**
34-
* Gets the target callable of this call, if a unique such target can
35-
* be statically resolved.
36-
*/
37-
Callable getStaticTarget() {
38-
getCallResolvable(this).resolvesAsItem(result)
39-
or
40-
result = resolvePath(this.(CallExpr).getFunction().(PathExpr).getPath())
41-
}
29+
/** Gets the static target of this call, if any. */
30+
Callable getStaticTarget() { none() }
4231
}
4332
}

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

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,14 @@ module Impl {
1515
private import rust
1616
private import PathResolution as PathResolution
1717

18+
pragma[nomagic]
19+
Path getFunctionPath(CallExpr ce) { result = ce.getFunction().(PathExpr).getPath() }
20+
21+
pragma[nomagic]
22+
PathResolution::ItemNode getResolvedFunction(CallExpr ce) {
23+
result = PathResolution::resolvePath(getFunctionPath(ce))
24+
}
25+
1826
// the following QLdoc is generated: if you need to edit it, do it in the schema file
1927
/**
2028
* A function call expression. For example:
@@ -28,9 +36,17 @@ module Impl {
2836
class CallExpr extends Generated::CallExpr {
2937
override string toString() { result = this.getFunction().toAbbreviatedString() + "(...)" }
3038

39+
override Callable getStaticTarget() { result = getResolvedFunction(this) }
40+
41+
/** Gets the struct that this call resolves to, if any. */
42+
Struct getStruct() { result = getResolvedFunction(this) }
43+
44+
/** Gets the variant that this call resolves to, if any. */
45+
Variant getVariant() { result = getResolvedFunction(this) }
46+
3147
pragma[nomagic]
32-
private PathResolution::ItemNode getResolvedFunction(int pos) {
33-
result = PathResolution::resolvePath(this.getFunction().(PathExpr).getPath()) and
48+
private PathResolution::ItemNode getResolvedFunctionAndPos(int pos) {
49+
result = getResolvedFunction(this) and
3450
exists(this.getArgList().getArg(pos))
3551
}
3652

@@ -42,7 +58,7 @@ module Impl {
4258
*/
4359
pragma[nomagic]
4460
TupleField getTupleField(int pos) {
45-
exists(PathResolution::ItemNode i | i = this.getResolvedFunction(pos) |
61+
exists(PathResolution::ItemNode i | i = this.getResolvedFunctionAndPos(pos) |
4662
result.isStructField(i, pos) or
4763
result.isVariantField(i, pos)
4864
)

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ private import codeql.rust.elements.internal.generated.FieldExpr
1111
* be referenced directly.
1212
*/
1313
module Impl {
14+
private import rust
15+
private import TypeInference as TypeInference
16+
1417
// the following QLdoc is generated: if you need to edit it, do it in the schema file
1518
/**
1619
* A field access expression. For example:
@@ -26,5 +29,11 @@ module Impl {
2629
if abbr = "..." then result = "... ." + name else result = abbr + "." + name
2730
)
2831
}
32+
33+
/** Gets the record field that this access references, if any. */
34+
RecordField getRecordField() { result = TypeInference::resolveRecordFieldExpr(this) }
35+
36+
/** Gets the tuple field that this access references, if any. */
37+
TupleField getTupleField() { result = TypeInference::resolveTupleFieldExpr(this) }
2938
}
3039
}

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

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ private import codeql.rust.elements.internal.generated.GenericArgList
1111
* be referenced directly.
1212
*/
1313
module Impl {
14+
private import rust
15+
1416
// the following QLdoc is generated: if you need to edit it, do it in the schema file
1517
/**
1618
* The base class for generic arguments.
@@ -22,5 +24,18 @@ module Impl {
2224
override string toString() { result = this.toAbbreviatedString() }
2325

2426
override string toAbbreviatedString() { result = "<...>" }
27+
28+
/** Gets the `i`th type argument of this list. */
29+
TypeRepr getTypeArgument(int i) {
30+
result =
31+
rank[i + 1](TypeRepr res, int j |
32+
res = this.getGenericArg(j).(TypeArg).getTypeRepr()
33+
|
34+
res order by j
35+
)
36+
}
37+
38+
/** Gets a type argument of this list. */
39+
TypeRepr getATypeArgument() { result = this.getTypeArgument(_) }
2540
}
2641
}

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

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
// generated by codegen, remove this comment if you wish to edit this file
21
/**
32
* This module provides a hand-modifiable wrapper around the generated class `GenericParamList`.
43
*
@@ -12,11 +11,26 @@ private import codeql.rust.elements.internal.generated.GenericParamList
1211
* be referenced directly.
1312
*/
1413
module Impl {
14+
private import rust
15+
16+
// the following QLdoc is generated: if you need to edit it, do it in the schema file
1517
/**
1618
* A GenericParamList. For example:
1719
* ```rust
1820
* todo!()
1921
* ```
2022
*/
21-
class GenericParamList extends Generated::GenericParamList { }
23+
class GenericParamList extends Generated::GenericParamList {
24+
override string toString() { result = this.toAbbreviatedString() }
25+
26+
override string toAbbreviatedString() { result = "<...>" }
27+
28+
/** Gets the `i`th type parameter of this list. */
29+
TypeParam getTypeParam(int i) {
30+
result = rank[i + 1](TypeParam res, int j | res = this.getGenericParam(j) | res order by j)
31+
}
32+
33+
/** Gets a type parameter of this list. */
34+
TypeParam getATypeParam() { result = this.getTypeParam(_) }
35+
}
2236
}

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

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,18 @@
44
* INTERNAL: Do not use.
55
*/
66

7+
private import rust
78
private import codeql.rust.elements.internal.generated.MethodCallExpr
9+
private import codeql.rust.elements.internal.PathResolution
10+
private import codeql.rust.elements.internal.TypeInference
811

912
/**
1013
* INTERNAL: This module contains the customizable definition of `MethodCallExpr` and should not
1114
* be referenced directly.
1215
*/
1316
module Impl {
17+
private predicate isImplFunction(Function f) { f = any(ImplItemNode impl).getAnAssocItem() }
18+
1419
// the following QLdoc is generated: if you need to edit it, do it in the schema file
1520
/**
1621
* A method call expression. For example:
@@ -20,6 +25,23 @@ module Impl {
2025
* ```
2126
*/
2227
class MethodCallExpr extends Generated::MethodCallExpr {
28+
override Function getStaticTarget() {
29+
result = resolveMethodCallExpr(this) and
30+
(
31+
// prioritize `impl` methods first
32+
isImplFunction(result)
33+
or
34+
not isImplFunction(resolveMethodCallExpr(this)) and
35+
(
36+
// then trait methods with default implementations
37+
result.hasBody()
38+
or
39+
// and finally trait methods without default implementations
40+
not resolveMethodCallExpr(this).hasBody()
41+
)
42+
)
43+
}
44+
2345
override string toString() {
2446
exists(string base, string separator |
2547
base = this.getReceiver().toAbbreviatedString() and

0 commit comments

Comments
 (0)