Skip to content

Commit 823811a

Browse files
committed
Rust: Follow-up work to make path resolution and type inference tests pass again
1 parent 841d913 commit 823811a

File tree

15 files changed

+1612
-116
lines changed

15 files changed

+1612
-116
lines changed

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

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ module Impl {
1515
private import rust
1616
private import codeql.rust.elements.internal.generated.ParentChild
1717
private import codeql.rust.controlflow.ControlFlowGraph
18+
private import codeql.rust.elements.internal.MacroCallImpl::Impl as MacroCallImpl
1819

1920
/**
2021
* Gets the immediate parent of a non-`AstNode` element `e`.
@@ -59,10 +60,20 @@ module Impl {
5960
}
6061

6162
/** Holds if this node is inside a macro expansion. */
62-
predicate isInMacroExpansion() {
63-
this = any(MacroCall mc).getMacroCallExpansion()
64-
or
65-
this.getParentNode().isInMacroExpansion()
63+
predicate isInMacroExpansion() { MacroCallImpl::isInMacroExpansion(_, this) }
64+
65+
/**
66+
* Holds if this node exists only as the result of a macro expansion.
67+
*
68+
* This is the same as `isInMacroExpansion()`, but excludes AST nodes corresponding
69+
* to macro arguments.
70+
*/
71+
pragma[nomagic]
72+
predicate isFromMacroExpansion() {
73+
exists(MacroCall mc |
74+
MacroCallImpl::isInMacroExpansion(mc, this) and
75+
not this = mc.getATokenTreeNode()
76+
)
6677
}
6778

6879
/**

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ module Impl {
4343
File getFile() { result = this.getLocation().getFile() }
4444

4545
/** Holds if this element is from source code. */
46-
predicate fromSource() { exists(this.getFile().getRelativePath()) }
46+
predicate fromSource() { this.getFile().fromSource() }
4747
}
4848

4949
private @location_default getDbLocation(Locatable l) {

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

Lines changed: 68 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -77,13 +77,76 @@ module LocationImpl {
7777
)
7878
}
7979

80-
/** Holds if this location starts strictly before the specified location. */
80+
/** Holds if this location starts before location `that`. */
8181
pragma[inline]
82-
predicate strictlyBefore(Location other) {
83-
this.getStartLine() < other.getStartLine()
84-
or
85-
this.getStartLine() = other.getStartLine() and this.getStartColumn() < other.getStartColumn()
82+
predicate startsBefore(Location that) {
83+
exists(string f, int sl1, int sc1, int sl2, int sc2 |
84+
this.hasLocationInfo(f, sl1, sc1, _, _) and
85+
that.hasLocationInfo(f, sl2, sc2, _, _)
86+
|
87+
sl1 < sl2
88+
or
89+
sl1 = sl2 and sc1 <= sc2
90+
)
91+
}
92+
93+
/** Holds if this location starts strictly before location `that`. */
94+
pragma[inline]
95+
predicate startsStrictlyBefore(Location that) {
96+
exists(string f, int sl1, int sc1, int sl2, int sc2 |
97+
this.hasLocationInfo(f, sl1, sc1, _, _) and
98+
that.hasLocationInfo(f, sl2, sc2, _, _)
99+
|
100+
sl1 < sl2
101+
or
102+
sl1 = sl2 and sc1 < sc2
103+
)
104+
}
105+
106+
/** Holds if this location ends after location `that`. */
107+
pragma[inline]
108+
predicate endsAfter(Location that) {
109+
exists(string f, int el1, int ec1, int el2, int ec2 |
110+
this.hasLocationInfo(f, _, _, el1, ec1) and
111+
that.hasLocationInfo(f, _, _, el2, ec2)
112+
|
113+
el1 > el2
114+
or
115+
el1 = el2 and ec1 >= ec2
116+
)
86117
}
118+
119+
/** Holds if this location ends strictly after location `that`. */
120+
pragma[inline]
121+
predicate endsStrictlyAfter(Location that) {
122+
exists(string f, int el1, int ec1, int el2, int ec2 |
123+
this.hasLocationInfo(f, _, _, el1, ec1) and
124+
that.hasLocationInfo(f, _, _, el2, ec2)
125+
|
126+
el1 > el2
127+
or
128+
el1 = el2 and ec1 > ec2
129+
)
130+
}
131+
132+
/**
133+
* Holds if this location contains location `that`, meaning that it starts
134+
* before and ends after it.
135+
*/
136+
pragma[inline]
137+
predicate contains(Location that) { this.startsBefore(that) and this.endsAfter(that) }
138+
139+
/**
140+
* Holds if this location strictlycontains location `that`, meaning that it starts
141+
* strictly before and ends strictly after it.
142+
*/
143+
pragma[inline]
144+
predicate strictlyContains(Location that) {
145+
this.startsStrictlyBefore(that) and this.endsStrictlyAfter(that)
146+
}
147+
148+
/** Holds if this location is from source code. */
149+
predicate fromSource() { this.getFile().fromSource() }
87150
}
88151

89152
class LocationDefault extends Location, TLocationDefault {

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

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,15 @@ private import codeql.rust.elements.internal.generated.MacroCall
1111
* be referenced directly.
1212
*/
1313
module Impl {
14+
private import rust
15+
16+
pragma[nomagic]
17+
predicate isInMacroExpansion(MacroCall mc, AstNode n) {
18+
n = mc.getMacroCallExpansion()
19+
or
20+
isInMacroExpansion(mc, n.getParentNode())
21+
}
22+
1423
// the following QLdoc is generated: if you need to edit it, do it in the schema file
1524
/**
1625
* A MacroCall. For example:
@@ -20,5 +29,12 @@ module Impl {
2029
*/
2130
class MacroCall extends Generated::MacroCall {
2231
override string toStringImpl() { result = this.getPath().toAbbreviatedString() + "!..." }
32+
33+
/** Gets an AST node whose location is inside the token tree belonging to this macro call. */
34+
pragma[nomagic]
35+
AstNode getATokenTreeNode() {
36+
isInMacroExpansion(this, result) and
37+
this.getTokenTree().getLocation().contains(result.getLocation())
38+
}
2339
}
2440
}

rust/ql/lib/codeql/rust/frameworks/stdlib/Stdlib.qll

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ private import codeql.rust.Concepts
77
private import codeql.rust.controlflow.ControlFlowGraph as Cfg
88
private import codeql.rust.controlflow.CfgNodes as CfgNodes
99
private import codeql.rust.dataflow.DataFlow
10+
private import codeql.rust.internal.PathResolution
1011

1112
/**
1213
* A call to the `starts_with` method on a `Path`.
@@ -32,10 +33,8 @@ class OptionEnum extends Enum {
3233
// todo: replace with canonical path, once calculated in QL
3334
exists(Crate core, Module m |
3435
core.getName() = "core" and
35-
m = core.getSourceFile().getAnItem() and
36-
m.getName().getText() = "option" and
37-
this = m.getItemList().getAnItem() and
38-
this.getName().getText() = "Option"
36+
m = core.getSourceFile().(ItemNode).getASuccessor("option") and
37+
this = m.(ItemNode).getASuccessor("Option")
3938
)
4039
}
4140

@@ -53,10 +52,8 @@ class ResultEnum extends Enum {
5352
// todo: replace with canonical path, once calculated in QL
5453
exists(Crate core, Module m |
5554
core.getName() = "core" and
56-
m = core.getSourceFile().getAnItem() and
57-
m.getName().getText() = "result" and
58-
this = m.getItemList().getAnItem() and
59-
this.getName().getText() = "Result"
55+
m = core.getSourceFile().(ItemNode).getASuccessor("result") and
56+
this = m.(ItemNode).getASuccessor("Result")
6057
)
6158
}
6259

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

Lines changed: 21 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -196,11 +196,11 @@ abstract class ItemNode extends Locatable {
196196
this = result.(ImplOrTraitItemNode).getAnItemInSelfScope()
197197
or
198198
name = "crate" and
199-
this = result.(CrateItemNode).getARootModuleNode()
199+
this = result.(CrateItemNode).getASourceFile()
200200
or
201201
// todo: implement properly
202202
name = "$crate" and
203-
result = any(CrateItemNode crate | this = crate.getARootModuleNode()).(Crate).getADependency*() and
203+
result = any(CrateItemNode crate | this = crate.getASourceFile()).(Crate).getADependency*() and
204204
result.(CrateItemNode).isPotentialDollarCrateTarget()
205205
}
206206

@@ -242,12 +242,6 @@ abstract private class ModuleLikeNode extends ItemNode {
242242
not mid instanceof ModuleLikeNode
243243
)
244244
}
245-
246-
/**
247-
* Holds if this is a root module, meaning either a source file or
248-
* the entry module of a crate.
249-
*/
250-
predicate isRoot() { this instanceof SourceFileItemNode }
251245
}
252246

253247
private class SourceFileItemNode extends ModuleLikeNode, SourceFile {
@@ -269,16 +263,13 @@ private class SourceFileItemNode extends ModuleLikeNode, SourceFile {
269263

270264
class CrateItemNode extends ItemNode instanceof Crate {
271265
/**
272-
* Gets the module node that defines this crate.
273-
*
274-
* This is either a source file, when the crate is defined in source code,
275-
* or a module, when the crate is defined in a dependency.
266+
* Gets the source file that defines this crate.
276267
*/
277268
pragma[nomagic]
278-
ModuleLikeNode getModuleNode() { result = super.getSourceFile() }
269+
SourceFileItemNode getSourceFile() { result = super.getSourceFile() }
279270

280271
/**
281-
* Gets a source file that belongs to this crate, if any.
272+
* Gets a source file that belongs to this crate.
282273
*
283274
* This is calculated as those source files that can be reached from the entry
284275
* file of this crate using zero or more `mod` imports, without going through
@@ -296,11 +287,6 @@ class CrateItemNode extends ItemNode instanceof Crate {
296287
)
297288
}
298289

299-
/**
300-
* Gets a root module node belonging to this crate.
301-
*/
302-
ModuleLikeNode getARootModuleNode() { result = this.getASourceFile() }
303-
304290
pragma[nomagic]
305291
predicate isPotentialDollarCrateTarget() {
306292
exists(string name, RelevantPath p |
@@ -657,7 +643,7 @@ private predicate modImport0(Module m, string name, Folder lookup) {
657643
// sibling import
658644
lookup = parent and
659645
(
660-
m.getFile() = any(CrateItemNode c).getModuleNode().(SourceFileItemNode).getFile()
646+
m.getFile() = any(CrateItemNode c).getSourceFile().getFile()
661647
or
662648
m.getFile().getBaseName() = "mod.rs"
663649
)
@@ -745,25 +731,18 @@ private predicate fileImportEdge(Module mod, string name, ItemNode item) {
745731
*/
746732
pragma[nomagic]
747733
private predicate crateDefEdge(CrateItemNode c, string name, ItemNode i) {
748-
i = c.getModuleNode().getASuccessorRec(name) and
734+
i = c.getSourceFile().getASuccessorRec(name) and
749735
not i instanceof Crate
750736
}
751737

752738
/**
753739
* Holds if `m` depends on crate `dep` named `name`.
754740
*/
755741
private predicate crateDependencyEdge(ModuleLikeNode m, string name, CrateItemNode dep) {
756-
exists(CrateItemNode c | dep = c.(Crate).getDependency(name) |
757-
// entry module/entry source file
758-
m = c.getModuleNode()
759-
or
760-
// entry/transitive source file
742+
exists(CrateItemNode c |
743+
dep = c.(Crate).getDependency(name) and
761744
m = c.getASourceFile()
762745
)
763-
or
764-
// paths inside the crate graph use the name of the crate itself as prefix,
765-
// although that is not valid in Rust
766-
dep = any(Crate c | name = c.getName() and m = c.getSourceFile())
767746
}
768747

769748
private predicate useTreeDeclares(UseTree tree, string name) {
@@ -831,9 +810,9 @@ class RelevantPath extends Path {
831810

832811
private predicate isModule(ItemNode m) { m instanceof Module }
833812

834-
/** Holds if root module `root` contains the module `m`. */
835-
private predicate rootHasModule(ItemNode root, ItemNode m) =
836-
doublyBoundedFastTC(hasChild/2, isRoot/1, isModule/1)(root, m)
813+
/** Holds if source file `source` contains the module `m`. */
814+
private predicate rootHasModule(SourceFileItemNode source, ItemNode m) =
815+
doublyBoundedFastTC(hasChild/2, isSourceFile/1, isModule/1)(source, m)
837816

838817
pragma[nomagic]
839818
private ItemNode getOuterScope(ItemNode i) {
@@ -886,14 +865,14 @@ private ItemNode getASuccessorFull(ItemNode pred, string name, Namespace ns) {
886865
ns = result.getNamespace()
887866
}
888867

889-
private predicate isRoot(ItemNode root) { root.(ModuleLikeNode).isRoot() }
868+
private predicate isSourceFile(ItemNode source) { source instanceof SourceFileItemNode }
890869

891870
private predicate hasCratePath(ItemNode i) { any(RelevantPath path).isCratePath(_, i) }
892871

893872
private predicate hasChild(ItemNode parent, ItemNode child) { child.getImmediateParent() = parent }
894873

895-
private predicate rootHasCratePathTc(ItemNode i1, ItemNode i2) =
896-
doublyBoundedFastTC(hasChild/2, isRoot/1, hasCratePath/1)(i1, i2)
874+
private predicate sourceFileHasCratePathTc(ItemNode i1, ItemNode i2) =
875+
doublyBoundedFastTC(hasChild/2, isSourceFile/1, hasCratePath/1)(i1, i2)
897876

898877
/**
899878
* Holds if the unqualified path `p` references a keyword item named `name`, and
@@ -903,10 +882,10 @@ pragma[nomagic]
903882
private predicate keywordLookup(ItemNode encl, string name, Namespace ns, RelevantPath p) {
904883
// For `($)crate`, jump directly to the root module
905884
exists(ItemNode i | p.isCratePath(name, i) |
906-
encl.(ModuleLikeNode).isRoot() and
885+
encl instanceof SourceFile and
907886
encl = i
908887
or
909-
rootHasCratePathTc(encl, i)
888+
sourceFileHasCratePathTc(encl, i)
910889
)
911890
or
912891
name = ["super", "self"] and
@@ -1121,12 +1100,8 @@ private predicate preludeEdge(SourceFile f, string name, ItemNode i) {
11211100
private import codeql.rust.frameworks.stdlib.Bultins as Builtins
11221101

11231102
pragma[nomagic]
1124-
private predicate builtinEdge(ModuleLikeNode m, string name, ItemNode i) {
1125-
(
1126-
m instanceof SourceFile
1127-
or
1128-
m = any(CrateItemNode c).getModuleNode()
1129-
) and
1103+
private predicate builtinEdge(SourceFile source, string name, ItemNode i) {
1104+
exists(source) and
11301105
exists(SourceFileItemNode builtins |
11311106
builtins.getFile().getParentContainer() instanceof Builtins::BuiltinsFolder and
11321107
i = builtins.getASuccessorRec(name)
@@ -1138,8 +1113,8 @@ private module Debug {
11381113
private Locatable getRelevantLocatable() {
11391114
exists(string filepath, int startline, int startcolumn, int endline, int endcolumn |
11401115
result.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) and
1141-
filepath.matches("%/test_logging.rs") and
1142-
startline = 163
1116+
filepath.matches("%/main.rs") and
1117+
startline = 284
11431118
)
11441119
}
11451120

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1190,7 +1190,7 @@ private module Debug {
11901190
exists(string filepath, int startline, int startcolumn, int endline, int endcolumn |
11911191
result.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) and
11921192
filepath.matches("%/main.rs") and
1193-
startline = 28
1193+
startline = 948
11941194
)
11951195
}
11961196

rust/ql/lib/utils/test/PathResolutionInlineExpectationsTest.qll

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ private module ResolveTest implements TestSig {
1818
private predicate commmentAt(string text, string filepath, int line) {
1919
exists(Comment c |
2020
c.getLocation().hasLocationInfo(filepath, line, _, _, _) and
21-
c.getCommentText().trim() = text
21+
c.getCommentText().trim() = text and
22+
c.fromSource()
2223
)
2324
}
2425

@@ -35,6 +36,8 @@ private module ResolveTest implements TestSig {
3536
exists(AstNode n |
3637
not n = any(Path parent).getQualifier() and
3738
location = n.getLocation() and
39+
n.fromSource() and
40+
not n.isFromMacroExpansion() and
3841
element = n.toString() and
3942
tag = "item"
4043
|

0 commit comments

Comments
 (0)