Skip to content

Commit

Permalink
Rust: Implement basic type inference in QL
Browse files Browse the repository at this point in the history
  • Loading branch information
hvitved committed Feb 10, 2025
1 parent 0b2e307 commit 4f723dd
Show file tree
Hide file tree
Showing 25 changed files with 1,144 additions and 86 deletions.
33 changes: 33 additions & 0 deletions rust/ql/lib/codeql/rust/AstConsistency.qll
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,33 @@ private import codeql.rust.elements.internal.PathResolution
/** Holds if `p` may resolve to multiple items including `i`. */
query predicate multiplePathResolutions(Path p, ItemNode i) {
i = resolvePath(p) and
// `use foo::bar` may use both a type `bar` and a value `bar`
not p =
any(UseTree use |
not use.isGlob() and
not use.hasUseTreeList()
).getPath() and
strictcount(resolvePath(p)) > 1
}

/** Holds if `call` has multiple static call targets including `target`. */
query predicate multipleStaticCallTargets(CallExprBase call, Callable target) {
target = call.getStaticTarget() and
strictcount(call.getStaticTarget()) > 1
}

/** Holds if `fe` resolves to multiple record fields including `field`. */
query predicate multipleRecordFields(FieldExpr fe, RecordField field) {
field = fe.getRecordField() and
strictcount(fe.getRecordField()) > 1
}

/** Holds if `fe` resolves to multiple tuple fields including `field`. */
query predicate multipleTupleFields(FieldExpr fe, TupleField field) {
field = fe.getTupleField() and
strictcount(fe.getTupleField()) > 1
}

/**
* Gets counts of abstract syntax tree inconsistencies of each type.
*/
Expand Down Expand Up @@ -109,4 +133,13 @@ int getAstInconsistencyCounts(string type) {
or
type = "Multiple path resolutions" and
result = count(Path p | multiplePathResolutions(p, _) | p)
or
type = "Multiple static call targets" and
result = count(CallExprBase call | multipleStaticCallTargets(call, _) | call)
or
type = "Multiple record fields" and
result = count(FieldExpr fe | multipleRecordFields(fe, _) | fe)
or
type = "Multiple tuple fields" and
result = count(FieldExpr fe | multipleTupleFields(fe, _) | fe)
}
4 changes: 2 additions & 2 deletions rust/ql/lib/codeql/rust/dataflow/internal/DataFlowImpl.qll
Original file line number Diff line number Diff line change
Expand Up @@ -756,7 +756,7 @@ class TupleFieldContent extends FieldContent, TTupleFieldContent {

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

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

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

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

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

final override string toString() {
exists(Variant v, string name, string vname |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ module Impl {
private import codeql.rust.elements.internal.CallExprImpl::Impl
private import codeql.rust.elements.internal.PathExprImpl::Impl
private import codeql.rust.elements.internal.PathResolution
private import codeql.rust.elements.internal.TypeInference

pragma[nomagic]
Resolvable getCallResolvable(CallExprBase call) {
Expand All @@ -35,9 +36,11 @@ module Impl {
* be statically resolved.
*/
Callable getStaticTarget() {
getCallResolvable(this).resolvesAsItem(result)
// getCallResolvable(this).resolvesAsItem(result)
// or
result = resolveValuePath(this.(CallExpr).getFunction().(PathExpr).getPath())
or
result = resolvePath(this.(CallExpr).getFunction().(PathExpr).getPath())
result = resolveMethodCallExpr(this)
}
}
}
2 changes: 1 addition & 1 deletion rust/ql/lib/codeql/rust/elements/internal/CallExprImpl.qll
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ module Impl {

pragma[nomagic]
private PathResolution::ItemNode getResolvedFunction(int pos) {
result = PathResolution::resolvePath(this.getFunction().(PathExpr).getPath()) and
result = PathResolution::resolveValuePath(this.getFunction().(PathExpr).getPath()) and
exists(this.getArgList().getArg(pos))
}

Expand Down
9 changes: 9 additions & 0 deletions rust/ql/lib/codeql/rust/elements/internal/FieldExprImpl.qll
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ private import codeql.rust.elements.internal.generated.FieldExpr
* be referenced directly.
*/
module Impl {
private import rust
private import TypeInference as TypeInference

// the following QLdoc is generated: if you need to edit it, do it in the schema file
/**
* A field access expression. For example:
Expand All @@ -26,5 +29,11 @@ module Impl {
if abbr = "..." then result = "... ." + name else result = abbr + "." + name
)
}

/** Gets the record field that this access references, if any. */
RecordField getRecordField() { result = TypeInference::resolveRecordFieldExpr(this) }

/** Gets the tuple field that this access references, if any. */
TupleField getTupleField() { result = TypeInference::resolveTupleFieldExpr(this) }
}
}
Loading

0 comments on commit 4f723dd

Please sign in to comment.