Skip to content

Commit 8996f9e

Browse files
committed
Rust: Follow-up work to make path resolution and type inference tests pass again
1 parent 0bb0a70 commit 8996f9e

File tree

14 files changed

+193
-106
lines changed

14 files changed

+193
-106
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: 1 addition & 0 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`.

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

Lines changed: 19 additions & 44 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

@@ -281,12 +281,6 @@ abstract private class ModuleLikeNode extends ItemNode {
281281
not mid instanceof ModuleLikeNode
282282
)
283283
}
284-
285-
/**
286-
* Holds if this is a root module, meaning either a source file or
287-
* the entry module of a crate.
288-
*/
289-
predicate isRoot() { this instanceof SourceFileItemNode }
290284
}
291285

292286
private class SourceFileItemNode extends ModuleLikeNode, SourceFile {
@@ -312,16 +306,13 @@ private class SourceFileItemNode extends ModuleLikeNode, SourceFile {
312306

313307
class CrateItemNode extends ItemNode instanceof Crate {
314308
/**
315-
* Gets the module node that defines this crate.
316-
*
317-
* This is either a source file, when the crate is defined in source code,
318-
* or a module, when the crate is defined in a dependency.
309+
* Gets the source file that defines this crate.
319310
*/
320311
pragma[nomagic]
321-
ModuleLikeNode getModuleNode() { result = super.getSourceFile() }
312+
SourceFileItemNode getSourceFile() { result = super.getSourceFile() }
322313

323314
/**
324-
* Gets a source file that belongs to this crate, if any.
315+
* Gets a source file that belongs to this crate.
325316
*
326317
* This is calculated as those source files that can be reached from the entry
327318
* file of this crate using zero or more `mod` imports, without going through
@@ -339,11 +330,6 @@ class CrateItemNode extends ItemNode instanceof Crate {
339330
)
340331
}
341332

342-
/**
343-
* Gets a root module node belonging to this crate.
344-
*/
345-
ModuleLikeNode getARootModuleNode() { result = this.getASourceFile() }
346-
347333
pragma[nomagic]
348334
predicate isPotentialDollarCrateTarget() {
349335
exists(string name, RelevantPath p |
@@ -985,7 +971,7 @@ private predicate modImport0(Module m, string name, Folder lookup) {
985971
// sibling import
986972
lookup = parent and
987973
(
988-
m.getFile() = any(CrateItemNode c).getModuleNode().(SourceFileItemNode).getFile()
974+
m.getFile() = any(CrateItemNode c).getSourceFile().getFile()
989975
or
990976
m.getFile().getBaseName() = "mod.rs"
991977
)
@@ -1073,25 +1059,18 @@ private predicate fileImportEdge(Module mod, string name, ItemNode item) {
10731059
*/
10741060
pragma[nomagic]
10751061
private predicate crateDefEdge(CrateItemNode c, string name, ItemNode i) {
1076-
i = c.getModuleNode().getASuccessorRec(name) and
1062+
i = c.getSourceFile().getASuccessorRec(name) and
10771063
not i instanceof Crate
10781064
}
10791065

10801066
/**
10811067
* Holds if `m` depends on crate `dep` named `name`.
10821068
*/
10831069
private predicate crateDependencyEdge(ModuleLikeNode m, string name, CrateItemNode dep) {
1084-
exists(CrateItemNode c | dep = c.(Crate).getDependency(name) |
1085-
// entry module/entry source file
1086-
m = c.getModuleNode()
1087-
or
1088-
// entry/transitive source file
1070+
exists(CrateItemNode c |
1071+
dep = c.(Crate).getDependency(name) and
10891072
m = c.getASourceFile()
10901073
)
1091-
or
1092-
// paths inside the crate graph use the name of the crate itself as prefix,
1093-
// although that is not valid in Rust
1094-
dep = any(Crate c | name = c.getName() and m = c.getSourceFile())
10951074
}
10961075

10971076
private predicate useTreeDeclares(UseTree tree, string name) {
@@ -1159,9 +1138,9 @@ class RelevantPath extends Path {
11591138

11601139
private predicate isModule(ItemNode m) { m instanceof Module }
11611140

1162-
/** Holds if root module `root` contains the module `m`. */
1163-
private predicate rootHasModule(ItemNode root, ItemNode m) =
1164-
doublyBoundedFastTC(hasChild/2, isRoot/1, isModule/1)(root, m)
1141+
/** Holds if source file `source` contains the module `m`. */
1142+
private predicate rootHasModule(SourceFileItemNode source, ItemNode m) =
1143+
doublyBoundedFastTC(hasChild/2, isSourceFile/1, isModule/1)(source, m)
11651144

11661145
pragma[nomagic]
11671146
private ItemNode getOuterScope(ItemNode i) {
@@ -1214,14 +1193,14 @@ private ItemNode getASuccessorFull(ItemNode pred, string name, Namespace ns) {
12141193
ns = result.getNamespace()
12151194
}
12161195

1217-
private predicate isRoot(ItemNode root) { root.(ModuleLikeNode).isRoot() }
1196+
private predicate isSourceFile(ItemNode source) { source instanceof SourceFileItemNode }
12181197

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

12211200
private predicate hasChild(ItemNode parent, ItemNode child) { child.getImmediateParent() = parent }
12221201

1223-
private predicate rootHasCratePathTc(ItemNode i1, ItemNode i2) =
1224-
doublyBoundedFastTC(hasChild/2, isRoot/1, hasCratePath/1)(i1, i2)
1202+
private predicate sourceFileHasCratePathTc(ItemNode i1, ItemNode i2) =
1203+
doublyBoundedFastTC(hasChild/2, isSourceFile/1, hasCratePath/1)(i1, i2)
12251204

12261205
/**
12271206
* Holds if the unqualified path `p` references a keyword item named `name`, and
@@ -1231,10 +1210,10 @@ pragma[nomagic]
12311210
private predicate keywordLookup(ItemNode encl, string name, Namespace ns, RelevantPath p) {
12321211
// For `($)crate`, jump directly to the root module
12331212
exists(ItemNode i | p.isCratePath(name, i) |
1234-
encl.(ModuleLikeNode).isRoot() and
1213+
encl instanceof SourceFile and
12351214
encl = i
12361215
or
1237-
rootHasCratePathTc(encl, i)
1216+
sourceFileHasCratePathTc(encl, i)
12381217
)
12391218
or
12401219
name = ["super", "self"] and
@@ -1449,12 +1428,8 @@ private predicate preludeEdge(SourceFile f, string name, ItemNode i) {
14491428
private import codeql.rust.frameworks.stdlib.Bultins as Builtins
14501429

14511430
pragma[nomagic]
1452-
private predicate builtinEdge(ModuleLikeNode m, string name, ItemNode i) {
1453-
(
1454-
m instanceof SourceFile
1455-
or
1456-
m = any(CrateItemNode c).getModuleNode()
1457-
) and
1431+
private predicate builtinEdge(SourceFile source, string name, ItemNode i) {
1432+
exists(source) and
14581433
exists(SourceFileItemNode builtins |
14591434
builtins.getFile().getParentContainer() instanceof Builtins::BuiltinsFolder and
14601435
i = builtins.getASuccessorRec(name)

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1232,7 +1232,7 @@ private module Debug {
12321232
exists(string filepath, int startline, int startcolumn, int endline, int endcolumn |
12331233
result.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) and
12341234
filepath.matches("%/main.rs") and
1235-
startline = 28
1235+
startline = 948
12361236
)
12371237
}
12381238

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
|

rust/ql/test/TestUtils.qll

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,20 @@
11
private import rust
22

3-
predicate toBeTested(Element e) { not e instanceof CrateElement and not e instanceof Builtin }
3+
predicate toBeTested(Element e) {
4+
not e instanceof CrateElement and
5+
not e instanceof Builtin and
6+
(
7+
not e instanceof Locatable
8+
or
9+
e.(Locatable).fromSource()
10+
) and
11+
not e.(AstNode).isFromMacroExpansion()
12+
}
413

514
class CrateElement extends Element {
615
CrateElement() {
716
this instanceof Crate or
8-
this instanceof NamedCrate or
9-
any(Crate c).getSourceFile() = this.(AstNode).getParentNode*()
17+
this instanceof NamedCrate
1018
}
1119
}
1220

rust/ql/test/library-tests/path-resolution/my.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,21 +16,21 @@ mod my4 {
1616
}
1717

1818
pub use my4::my5::f as nested_f; // $ item=I201
19-
19+
#[rustfmt::skip]
2020
type Result<
2121
T, // T
2222
> = ::std::result::Result<
2323
T, // $ item=T
24-
String,
25-
>; // my::Result
24+
String,> // $ item=Result
25+
; // my::Result
2626

2727
fn int_div(
2828
x: i32, // $ item=i32
2929
y: i32, // $ item=i32
3030
) -> Result<i32> // $ item=my::Result $ item=i32
3131
{
3232
if y == 0 {
33-
return Err("Div by zero".to_string());
33+
return Err("Div by zero".to_string()); // $ item=Err
3434
}
35-
Ok(x / y)
35+
Ok(x / y) // $ item=Ok
3636
}

0 commit comments

Comments
 (0)