Skip to content

Commit c778df7

Browse files
committed
Rust: Path resolution before variable resolution
1 parent e11739e commit c778df7

File tree

24 files changed

+245
-304
lines changed

24 files changed

+245
-304
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/AstNodeImpl.qll

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,24 @@ module Impl {
2929
result = getImmediateParent(e)
3030
}
3131

32+
/**
33+
* Holds if `n` is superseded by an attribute macro expansion. That is, `n` is
34+
* an item or a transitive child of an item with an attribute macro expansion.
35+
*/
36+
predicate supersededByAttributeMacroExpansion(AstNode n) {
37+
n.(Item).hasAttributeMacroExpansion()
38+
or
39+
exists(AstNode parent |
40+
n.getParentNode() = parent and
41+
supersededByAttributeMacroExpansion(parent) and
42+
// Don't exclude expansions themselves as they supercede other nodes.
43+
not n = parent.(Item).getAttributeMacroExpansion() and
44+
// Don't consider attributes themselves to be superseded. E.g., in `#[a] fn
45+
// f() {}` the macro expansion supercedes `fn f() {}` but not `#[a]`.
46+
not n instanceof Attr
47+
)
48+
}
49+
3250
class AstNode extends Generated::AstNode {
3351
/**
3452
* Gets the nearest enclosing parent of this node, which is also an `AstNode`,

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/MacroCallImpl.qll

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,6 @@ module Impl {
2020
or
2121
n = root.(Adt).getDeriveMacroExpansion(_)
2222
or
23-
n = root.(Item).getAttributeMacroExpansion()
24-
or
2523
isInMacroExpansion(root, n.getParentNode())
2624
}
2725

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: 29 additions & 28 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,35 +100,34 @@ 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
103-
exists(SelfParam sp |
104-
name = sp.getName() and
105-
definingNode = name and
106-
text = name.getText() and
107-
// exclude self parameters from functions without a body as these are
108-
// trait method declarations without implementations
109-
not exists(Function f | not f.hasBody() and f.getSelfParam() = sp)
110-
)
111-
or
112-
exists(IdentPat pat |
113-
name = pat.getName() and
114-
(
115-
definingNode = getOutermostEnclosingOrPat(pat)
116-
or
117-
not exists(getOutermostEnclosingOrPat(pat)) and definingNode = name
118-
) and
119-
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
125-
// exclude parameters from functions without a body as these are trait method declarations
126-
// without implementations
127-
not exists(Function f | not f.hasBody() and f.getAParam().getPat() = pat) and
128-
// exclude parameters from function pointer types (e.g. `x` in `fn(x: i32) -> i32`)
129-
not exists(FnPtrTypeRepr fp | fp.getParamList().getAParam().getPat() = pat)
105+
not AstNodeImpl::supersededByAttributeMacroExpansion(definingNode) and
106+
(
107+
exists(SelfParam sp |
108+
name = sp.getName() and
109+
definingNode = name and
110+
text = name.getText() and
111+
// exclude self parameters from functions without a body as these are
112+
// trait method declarations without implementations
113+
not exists(Function f | not f.hasBody() and f.getSelfParam() = sp)
114+
)
115+
or
116+
exists(IdentPat pat |
117+
name = pat.getName() and
118+
(
119+
definingNode = getOutermostEnclosingOrPat(pat)
120+
or
121+
not exists(getOutermostEnclosingOrPat(pat)) and definingNode = name
122+
) and
123+
text = name.getText() and
124+
not PathResolution::identPatIsResolvable(pat) and
125+
// exclude parameters from functions without a body as these are trait method declarations
126+
// without implementations
127+
not exists(Function f | not f.hasBody() and f.getAParam().getPat() = pat) and
128+
// exclude parameters from function pointer types (e.g. `x` in `fn(x: i32) -> i32`)
129+
not exists(FnPtrTypeRepr fp | fp.getParamList().getAParam().getPat() = pat)
130+
)
130131
)
131132
}
132133

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)