Skip to content

Commit 6262c52

Browse files
committed
Rust: Path resolution before variable resolution
1 parent 1d42d26 commit 6262c52

File tree

17 files changed

+227
-156
lines changed

17 files changed

+227
-156
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/FormatTemplateVariableAccessImpl.qll

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ module Impl {
3131

3232
override string toStringImpl() { result = this.getName() }
3333

34+
override string getAPrimaryQlClass() { result = "FormatTemplateVariableAccess" }
35+
3436
/** Gets the name of the variable */
3537
string getName() { result = argument.getName() }
3638

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

Lines changed: 7 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,11 @@ module Impl {
2526
override string toStringImpl() { result = this.toAbbreviatedString() }
2627

2728
override string toAbbreviatedString() { result = this.getPath().toStringImpl() }
29+
30+
override string getAPrimaryQlClass() {
31+
if this instanceof VariableAccess
32+
then result = "VariableAccess"
33+
else result = super.getAPrimaryQlClass()
34+
}
2835
}
2936
}

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

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
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
5-
private import codeql.rust.elements.internal.PathExprBaseImpl::Impl as PathExprBaseImpl
67
private import codeql.rust.elements.internal.FormatTemplateVariableAccessImpl::Impl as FormatTemplateVariableAccessImpl
78
private import codeql.util.DenseRank
89

@@ -98,7 +99,7 @@ module Impl {
9899
* pattern.
99100
*/
100101
cached
101-
private predicate variableDecl(AstNode definingNode, Name name, string text) {
102+
predicate variableDecl(AstNode definingNode, Name name, string text) {
102103
Cached::ref() and
103104
exists(SelfParam sp |
104105
name = sp.getName() and
@@ -117,11 +118,7 @@ module Impl {
117118
not exists(getOutermostEnclosingOrPat(pat)) and definingNode = name
118119
) and
119120
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
121+
not PathResolution::identPatIsResolvable(pat) and
125122
// exclude parameters from functions without a body as these are trait method declarations
126123
// without implementations
127124
not exists(Function f | not f.hasBody() and f.getAParam().getPat() = pat) and
@@ -666,7 +663,7 @@ module Impl {
666663
}
667664

668665
/** A variable access. */
669-
class VariableAccess extends PathExprBaseImpl::PathExprBase {
666+
class VariableAccess extends PathExprBase {
670667
private string name;
671668
private Variable v;
672669

@@ -677,10 +674,6 @@ module Impl {
677674

678675
/** Holds if this access is a capture. */
679676
predicate isCapture() { this.getEnclosingCfgScope() != v.getEnclosingCfgScope() }
680-
681-
override string toStringImpl() { result = name }
682-
683-
override string getAPrimaryQlClass() { result = "VariableAccess" }
684677
}
685678

686679
/** Holds if `e` occurs in the LHS of an assignment or compound assignment. */
@@ -722,7 +715,7 @@ module Impl {
722715
}
723716

724717
/** A nested function access. */
725-
class NestedFunctionAccess extends PathExprBaseImpl::PathExprBase {
718+
class NestedFunctionAccess extends PathExprBase {
726719
private Function f;
727720

728721
NestedFunctionAccess() { nestedFunctionAccess(_, f, this) }

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)