Skip to content

Commit 2bbdba6

Browse files
committed
Rust: Cross-crate path resolution
1 parent 91ee094 commit 2bbdba6

File tree

6 files changed

+146
-6
lines changed

6 files changed

+146
-6
lines changed
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
use lib::a_module::hello; // $ MISSING: item=HELLO
1+
use lib::a_module::hello; // $ item=HELLO
22

33
mod a_module;
44

55
fn main() {
6-
hello(); // $ MISSING: item=HELLO
6+
hello(); // $ item=HELLO
77
}

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ private import codeql.rust.elements.internal.generated.Crate
1313
module Impl {
1414
private import rust
1515
private import codeql.rust.elements.internal.NamedCrate
16+
private import codeql.rust.internal.PathResolution
1617

1718
class Crate extends Generated::Crate {
1819
override string toStringImpl() {
@@ -58,6 +59,14 @@ module Impl {
5859
*/
5960
Crate getADependency() { result = this.getDependency(_) }
6061

62+
/** Gets the source file that defines this crate, if any. */
63+
SourceFile getSourceFile() { result.getFile() = this.getModule().getFile() }
64+
65+
/**
66+
* Gets a source file that belongs to this crate, if any.
67+
*/
68+
SourceFile getASourceFile() { result = this.(CrateItemNode).getASourceFile() }
69+
6170
override Location getLocation() { result = this.getModule().getLocation() }
6271
}
6372
}

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

Lines changed: 127 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ final class Namespace extends TNamespace {
7373
* - https://doc.rust-lang.org/reference/visibility-and-privacy.html
7474
* - https://doc.rust-lang.org/reference/names/namespaces.html
7575
*/
76-
abstract class ItemNode extends AstNode {
76+
abstract class ItemNode extends Locatable {
7777
/** Gets the (original) name of this item. */
7878
abstract string getName();
7979

@@ -96,6 +96,18 @@ abstract class ItemNode extends AstNode {
9696
Element getADescendant() {
9797
getImmediateParent(result) = this
9898
or
99+
// for path resolution, we pretend that the crate is the immediate parent of the
100+
// entry module/source file, which means that lookup via crate dependencies will
101+
// only happen when inner scopes do not shadow
102+
this =
103+
any(CrateItemNode c |
104+
// entry module/entry source file
105+
result = c.getModuleNode()
106+
or
107+
// entry/transitive source file
108+
result = c.getASourceFile()
109+
)
110+
or
99111
exists(Element mid |
100112
mid = this.getADescendant() and
101113
getImmediateParent(result) = mid and
@@ -122,6 +134,10 @@ abstract class ItemNode extends AstNode {
122134
or
123135
useImportEdge(this, name, result)
124136
or
137+
crateDefEdge(this, name, result)
138+
or
139+
crateDependencyEdge(this, name, result)
140+
or
125141
// items made available through `use` are available to nodes that contain the `use`
126142
exists(UseItemNode use |
127143
use = this.getASuccessorRec(_) and
@@ -180,7 +196,10 @@ abstract class ItemNode extends AstNode {
180196
this = result.(ImplOrTraitItemNode).getAnItemInSelfScope()
181197
or
182198
name = "crate" and
183-
result.(SourceFileItemNode).getFile() = this.getFile()
199+
exists(CrateItemNode crate |
200+
this = crate.getASourceFile() and
201+
result = crate.getModuleNode()
202+
)
184203
}
185204

186205
/** Gets the location of this item. */
@@ -214,6 +233,51 @@ private class SourceFileItemNode extends ModuleLikeNode, SourceFile {
214233
override TypeParam getTypeParam(int i) { none() }
215234
}
216235

236+
class CrateItemNode extends ItemNode instanceof Crate {
237+
/**
238+
* Gets the module node that defines this crate.
239+
*
240+
* This is either a source file, when the crate is defined in source code,
241+
* or a module, when the crate is defined in a dependency.
242+
*/
243+
pragma[nomagic]
244+
ModuleLikeNode getModuleNode() {
245+
result = super.getSourceFile()
246+
or
247+
not exists(super.getSourceFile()) and
248+
result = super.getModule()
249+
}
250+
251+
/**
252+
* Gets a source file that belongs to this crate, if any.
253+
*
254+
* This is calculated as those source files that can be reached from the entry
255+
* file of this crate using zero or more `mod` imports, without going through
256+
* the entry point of some other crate.
257+
*/
258+
pragma[nomagic]
259+
SourceFileItemNode getASourceFile() {
260+
result = super.getSourceFile()
261+
or
262+
exists(SourceFileItemNode mid, Module mod |
263+
mid = this.getASourceFile() and
264+
mod.getFile() = mid.getFile() and
265+
fileImport(mod, result) and
266+
not result = any(Crate other).getSourceFile()
267+
)
268+
}
269+
270+
override string getName() { result = Crate.super.getName() }
271+
272+
override Namespace getNamespace() {
273+
result.isType() // can be referenced with `crate`
274+
}
275+
276+
override Visibility getVisibility() { none() }
277+
278+
override TypeParam getTypeParam(int i) { none() }
279+
}
280+
217281
/** An item that can occur in a trait or an `impl` block. */
218282
abstract private class AssocItemNode extends ItemNode, AssocItem {
219283
/** Holds if this associated item has an implementation. */
@@ -595,6 +659,22 @@ private predicate fileImportEdge(Module mod, string name, ItemNode item) {
595659
)
596660
}
597661

662+
/**
663+
* Holds if crate `c` defines the item `i` named `name`.
664+
*/
665+
pragma[nomagic]
666+
private predicate crateDefEdge(CrateItemNode c, string name, ItemNode i) {
667+
i = c.getModuleNode().getASuccessor(name) and
668+
i.isPublic()
669+
}
670+
671+
/**
672+
* Holds if `source` depends on crate `dep` named `name`.
673+
*/
674+
private predicate crateDependencyEdge(Crate source, string name, CrateItemNode dep) {
675+
dep = source.getDependency(name)
676+
}
677+
598678
private predicate useTreeDeclares(UseTree tree, string name) {
599679
not tree.isGlob() and
600680
not exists(tree.getUseTreeList()) and
@@ -832,3 +912,48 @@ private predicate useImportEdge(Use use, string name, ItemNode item) {
832912
name != "_"
833913
)
834914
}
915+
916+
/** Provides predicates for debugging the path resolution implementation. */
917+
private module Debug {
918+
private Locatable getRelevantLocatable() {
919+
exists(string filepath, int startline, int startcolumn, int endline, int endcolumn |
920+
result.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) and
921+
// filepath.matches("%/compile.rs") and
922+
// startline = 1986
923+
// filepath.matches("%/build_steps/mod.rs") and
924+
// startline = 17
925+
filepath.matches("%/main.rs") and
926+
startline = 1
927+
)
928+
}
929+
930+
predicate debugUnqualifiedPathLookup(RelevantPath p, string name, Namespace ns, ItemNode encl) {
931+
p = getRelevantLocatable() and
932+
unqualifiedPathLookup(p, name, ns, encl)
933+
}
934+
935+
ItemNode debugResolvePath(RelevantPath path) {
936+
path = getRelevantLocatable() and
937+
result = resolvePath(path)
938+
}
939+
940+
predicate debugUseImportEdge(Use use, string name, ItemNode item) {
941+
use = getRelevantLocatable() and
942+
useImportEdge(use, name, item)
943+
}
944+
945+
ItemNode debugGetASuccessorRec(ItemNode i, string name) {
946+
i = getRelevantLocatable() and
947+
result = i.getASuccessor(name)
948+
}
949+
950+
predicate debugFileImportEdge(Module mod, string name, ItemNode item) {
951+
mod = getRelevantLocatable() and
952+
fileImportEdge(mod, name, item)
953+
}
954+
955+
predicate debugFileImport(Module m, SourceFile f) {
956+
m = getRelevantLocatable() and
957+
fileImport(m, f)
958+
}
959+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
multipleStaticCallTargets
2+
| regular.rs:29:5:29:9 | s.g(...) | anonymous.rs:15:9:15:22 | fn g |
3+
| regular.rs:29:5:29:9 | s.g(...) | regular.rs:13:5:13:18 | fn g |
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
multipleStaticCallTargets
2+
| regular.rs:32:5:32:9 | s.g(...) | anonymous.rs:18:9:18:22 | fn g |
3+
| regular.rs:32:5:32:9 | s.g(...) | regular.rs:16:5:16:18 | fn g |

rust/ql/test/library-tests/path-resolution/path-resolution.expected

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ resolvePath
129129
| main.rs:274:16:274:16 | T | main.rs:268:7:268:7 | T |
130130
| main.rs:275:14:275:17 | Self | main.rs:266:5:276:5 | trait MyParamTrait |
131131
| main.rs:275:14:275:33 | ...::AssociatedType | main.rs:270:9:270:28 | TypeAlias |
132-
| main.rs:284:13:284:17 | crate | main.rs:1:1:499:2 | SourceFile |
132+
| main.rs:284:13:284:17 | crate | main.rs:1:1:500:2 | SourceFile |
133133
| main.rs:284:13:284:22 | ...::m13 | main.rs:279:1:292:1 | mod m13 |
134134
| main.rs:284:13:284:25 | ...::f | main.rs:280:5:280:17 | fn f |
135135
| main.rs:284:13:284:25 | ...::f | main.rs:280:19:281:19 | struct f |
@@ -220,7 +220,7 @@ resolvePath
220220
| main.rs:479:5:479:32 | ...::f | my2/nested2.rs:3:9:5:9 | fn f |
221221
| main.rs:480:5:480:5 | f | my2/nested2.rs:3:9:5:9 | fn f |
222222
| main.rs:481:5:481:5 | g | my2/nested2.rs:7:9:9:9 | fn g |
223-
| main.rs:482:5:482:9 | crate | main.rs:1:1:499:2 | SourceFile |
223+
| main.rs:482:5:482:9 | crate | main.rs:1:1:500:2 | SourceFile |
224224
| main.rs:482:5:482:12 | ...::h | main.rs:50:1:69:1 | fn h |
225225
| main.rs:483:5:483:6 | m1 | main.rs:13:1:37:1 | mod m1 |
226226
| main.rs:483:5:483:10 | ...::m2 | main.rs:18:5:36:5 | mod m2 |

0 commit comments

Comments
 (0)