Skip to content

Commit e845ff0

Browse files
committed
Rust: Path resolution before variable resolution
1 parent 9a21ff0 commit e845ff0

File tree

16 files changed

+222
-149
lines changed

16 files changed

+222
-149
lines changed

rust/ql/integration-tests/hello-workspace/path-resolution.ql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import rust
22
import codeql.rust.internal.PathResolution
33
import utils.test.PathResolutionInlineExpectationsTest
44

5-
query predicate resolveDollarCrate(RelevantPath p, Crate c) {
5+
query predicate resolveDollarCrate(PathExt p, Crate c) {
66
c = resolvePath(p) and
77
p.isDollarCrate() and
88
p.fromSource() and

rust/ql/lib/codeql/rust/controlflow/internal/Completion.qll

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
private import codeql.util.Boolean
22
private import codeql.rust.controlflow.ControlFlowGraph
3+
private import codeql.rust.elements.internal.VariableImpl::Impl as VariableImpl
34
private import rust
45

56
newtype TCompletion =
@@ -123,13 +124,7 @@ class BooleanCompletion extends ConditionalCompletion, TBooleanCompletion {
123124
*/
124125
private predicate cannotCauseMatchFailure(Pat pat) {
125126
pat instanceof RangePat or
126-
// Identifier patterns that are in fact path patterns can cause failures. For
127-
// instance `None`. Only if an `@ ...` part is present can we be sure that
128-
// it's an actual identifier pattern. As a heuristic, if the identifier starts
129-
// with a lower case letter, then we assume that it's an identifier. This
130-
// works for code that follows the Rust naming convention for enums and
131-
// constants.
132-
pat = any(IdentPat p | p.hasPat() or p.getName().getText().charAt(0).isLowercase()) or
127+
pat = any(IdentPat p | p.hasPat() or VariableImpl::variableDecl(_, p.getName(), _)) or
133128
pat instanceof WildcardPat or
134129
pat instanceof RestPat or
135130
pat instanceof RefPat or

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ module Impl {
8282
}
8383

8484
private predicate callHasTraitQualifier(CallExpr call, Trait qualifier) {
85-
exists(RelevantPath qualifierPath |
85+
exists(PathExt qualifierPath |
8686
callHasQualifier(call, _, qualifierPath) and
8787
qualifier = resolvePath(qualifierPath) and
8888
// When the qualifier is `Self` and resolves to a trait, it's inside a

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

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
*/
66

77
private import codeql.rust.elements.internal.generated.Const
8+
private import codeql.rust.elements.internal.AstNodeImpl::Impl as AstNodeImpl
9+
private import codeql.rust.elements.internal.IdentPatImpl::Impl as IdentPatImpl
810
private import codeql.rust.elements.internal.PathExprImpl::Impl as PathExprImpl
911
private import codeql.rust.internal.PathResolution
1012

@@ -36,14 +38,30 @@ module Impl {
3638
* }
3739
* ```
3840
*/
39-
class ConstAccess extends PathExprImpl::PathExpr {
41+
abstract class ConstAccess extends AstNodeImpl::AstNode {
42+
/** Gets the constant being accessed. */
43+
abstract Const getConst();
44+
45+
override string getAPrimaryQlClass() { result = "ConstAccess" }
46+
}
47+
48+
private class PathExprConstAccess extends ConstAccess, PathExprImpl::PathExpr {
4049
private Const c;
4150

42-
ConstAccess() { c = resolvePath(this.getPath()) }
51+
PathExprConstAccess() { c = resolvePath(this.getPath()) }
4352

44-
/** Gets the constant being accessed. */
45-
Const getConst() { result = c }
53+
override Const getConst() { result = c }
4654

47-
override string getAPrimaryQlClass() { result = "ConstAccess" }
55+
override string getAPrimaryQlClass() { result = ConstAccess.super.getAPrimaryQlClass() }
56+
}
57+
58+
private class IdentPatConstAccess extends ConstAccess, IdentPatImpl::IdentPat {
59+
private Const c;
60+
61+
IdentPatConstAccess() { c = resolvePath(this) }
62+
63+
override Const getConst() { result = c }
64+
65+
override string getAPrimaryQlClass() { result = ConstAccess.super.getAPrimaryQlClass() }
4866
}
4967
}

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

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

7+
private import rust
78
private import codeql.rust.elements.internal.generated.PathExpr
89

910
/**
@@ -25,5 +26,10 @@ module Impl {
2526
override string toStringImpl() { result = this.toAbbreviatedString() }
2627

2728
override string toAbbreviatedString() { result = this.getPath().toStringImpl() }
29+
30+
override string getAPrimaryQlClass() {
31+
result = super.getAPrimaryQlClass() and
32+
not this instanceof VariableAccess
33+
}
2834
}
2935
}

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

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
private import rust
22
private import codeql.rust.controlflow.ControlFlowGraph
3+
private import codeql.rust.internal.PathResolution as PathResolution
34
private import codeql.rust.elements.internal.generated.ParentChild as ParentChild
5+
private import codeql.rust.elements.internal.AstNodeImpl::Impl as AstNodeImpl
46
private import codeql.rust.elements.internal.PathImpl::Impl as PathImpl
57
private import codeql.rust.elements.internal.PathExprBaseImpl::Impl as PathExprBaseImpl
68
private import codeql.rust.elements.internal.FormatTemplateVariableAccessImpl::Impl as FormatTemplateVariableAccessImpl
@@ -98,7 +100,7 @@ module Impl {
98100
* pattern.
99101
*/
100102
cached
101-
private predicate variableDecl(AstNode definingNode, Name name, string text) {
103+
predicate variableDecl(AstNode definingNode, Name name, string text) {
102104
Cached::ref() and
103105
exists(SelfParam sp |
104106
name = sp.getName() and
@@ -117,11 +119,7 @@ module Impl {
117119
not exists(getOutermostEnclosingOrPat(pat)) and definingNode = name
118120
) and
119121
text = name.getText() and
120-
// exclude for now anything starting with an uppercase character, which may be a reference to
121-
// an enum constant (e.g. `None`). This excludes static and constant variables (UPPERCASE),
122-
// which we don't appear to recognize yet anyway. This also assumes programmers follow the
123-
// naming guidelines, which they generally do, but they're not enforced.
124-
not text.charAt(0).isUppercase() and
122+
not PathResolution::identPatIsResolvable(pat) and
125123
// exclude parameters from functions without a body as these are trait method declarations
126124
// without implementations
127125
not exists(Function f | not f.hasBody() and f.getAParam().getPat() = pat) and

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,14 +37,17 @@ private module Cached {
3737
TFormatArgsArgIndex(Expr e) { e = any(FormatArgsArg a).getExpr() } or
3838
TItemNode(ItemNode i)
3939

40+
pragma[nomagic]
41+
private predicate isMacroCallLocation(Location loc) { loc = any(MacroCall m).getLocation() }
42+
4043
/**
4144
* Gets an element, of kind `kind`, that element `use` uses, if any.
4245
*/
4346
cached
4447
Definition definitionOf(Use use, string kind) {
4548
result = use.getDefinition() and
4649
kind = use.getUseType() and
47-
not result.getLocation() = any(MacroCall m).getLocation()
50+
not isMacroCallLocation(result.getLocation())
4851
}
4952
}
5053

0 commit comments

Comments
 (0)