Skip to content

Commit 4f723dd

Browse files
committed
Rust: Implement basic type inference in QL
1 parent 0b2e307 commit 4f723dd

File tree

25 files changed

+1144
-86
lines changed

25 files changed

+1144
-86
lines changed

rust/ql/lib/codeql/rust/AstConsistency.qll

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,9 +78,33 @@ private import codeql.rust.elements.internal.PathResolution
7878
/** Holds if `p` may resolve to multiple items including `i`. */
7979
query predicate multiplePathResolutions(Path p, ItemNode i) {
8080
i = resolvePath(p) and
81+
// `use foo::bar` may use both a type `bar` and a value `bar`
82+
not p =
83+
any(UseTree use |
84+
not use.isGlob() and
85+
not use.hasUseTreeList()
86+
).getPath() and
8187
strictcount(resolvePath(p)) > 1
8288
}
8389

90+
/** Holds if `call` has multiple static call targets including `target`. */
91+
query predicate multipleStaticCallTargets(CallExprBase call, Callable target) {
92+
target = call.getStaticTarget() and
93+
strictcount(call.getStaticTarget()) > 1
94+
}
95+
96+
/** Holds if `fe` resolves to multiple record fields including `field`. */
97+
query predicate multipleRecordFields(FieldExpr fe, RecordField field) {
98+
field = fe.getRecordField() and
99+
strictcount(fe.getRecordField()) > 1
100+
}
101+
102+
/** Holds if `fe` resolves to multiple tuple fields including `field`. */
103+
query predicate multipleTupleFields(FieldExpr fe, TupleField field) {
104+
field = fe.getTupleField() and
105+
strictcount(fe.getTupleField()) > 1
106+
}
107+
84108
/**
85109
* Gets counts of abstract syntax tree inconsistencies of each type.
86110
*/
@@ -109,4 +133,13 @@ int getAstInconsistencyCounts(string type) {
109133
or
110134
type = "Multiple path resolutions" and
111135
result = count(Path p | multiplePathResolutions(p, _) | p)
136+
or
137+
type = "Multiple static call targets" and
138+
result = count(CallExprBase call | multipleStaticCallTargets(call, _) | call)
139+
or
140+
type = "Multiple record fields" and
141+
result = count(FieldExpr fe | multipleRecordFields(fe, _) | fe)
142+
or
143+
type = "Multiple tuple fields" and
144+
result = count(FieldExpr fe | multipleTupleFields(fe, _) | fe)
112145
}

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

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

757757
predicate isStructField(Struct s, int pos) { field.isStructField(s, pos) }
758758

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

761761
final override string toString() {
762762
exists(Variant v, int pos, string vname |
@@ -787,7 +787,7 @@ class RecordFieldContent extends FieldContent, TRecordFieldContent {
787787

788788
predicate isStructField(Struct s, string name) { field.isStructField(s, name) }
789789

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

792792
final override string toString() {
793793
exists(Variant v, string name, string vname |

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

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ module Impl {
1717
private import codeql.rust.elements.internal.CallExprImpl::Impl
1818
private import codeql.rust.elements.internal.PathExprImpl::Impl
1919
private import codeql.rust.elements.internal.PathResolution
20+
private import codeql.rust.elements.internal.TypeInference
2021

2122
pragma[nomagic]
2223
Resolvable getCallResolvable(CallExprBase call) {
@@ -35,9 +36,11 @@ module Impl {
3536
* be statically resolved.
3637
*/
3738
Callable getStaticTarget() {
38-
getCallResolvable(this).resolvesAsItem(result)
39+
// getCallResolvable(this).resolvesAsItem(result)
40+
// or
41+
result = resolveValuePath(this.(CallExpr).getFunction().(PathExpr).getPath())
3942
or
40-
result = resolvePath(this.(CallExpr).getFunction().(PathExpr).getPath())
43+
result = resolveMethodCallExpr(this)
4144
}
4245
}
4346
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ module Impl {
3030

3131
pragma[nomagic]
3232
private PathResolution::ItemNode getResolvedFunction(int pos) {
33-
result = PathResolution::resolvePath(this.getFunction().(PathExpr).getPath()) and
33+
result = PathResolution::resolveValuePath(this.getFunction().(PathExpr).getPath()) and
3434
exists(this.getArgList().getArg(pos))
3535
}
3636

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
}

0 commit comments

Comments
 (0)