Skip to content

Commit 1da1cd4

Browse files
committed
Rust: Cross-crate path resolution
1 parent 5f53eff commit 1da1cd4

4 files changed

Lines changed: 116 additions & 6 deletions

File tree

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: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,25 @@ module Impl {
3030
i = 4 and result = ")"
3131
}
3232

33+
/** Gets the source file that defines this crate, if any. */
34+
SourceFile getSourceFile() { result.getFile() = this.getModule().getFile() }
35+
36+
/**
37+
* Gets a source file that belongs to this crate, if any.
38+
*
39+
* For now, this is a simple heuristic that returns any source file that is in
40+
* a reflexive transitive subfolder of the folder containing the source file of
41+
* the crate.
42+
*/
43+
pragma[nomagic]
44+
SourceFile getASourceFile() {
45+
result.getFile().getParentContainer*() = this.getSourceFile().getFile().getParentContainer() and
46+
not exists(Crate other |
47+
result = other.getSourceFile() and
48+
other != this
49+
)
50+
}
51+
3352
override Location getLocation() { result = this.getModule().getLocation() }
3453
}
3554
}

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

Lines changed: 93 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

@@ -122,6 +122,10 @@ abstract class ItemNode extends AstNode {
122122
or
123123
useImportEdge(this, name, result)
124124
or
125+
crateDefEdge(this, name, result)
126+
or
127+
crateDependencyEdge(this, name, result)
128+
or
125129
// items made available through `use` are available to nodes that contain the `use`
126130
exists(UseItemNode use |
127131
use = this.getASuccessorRec(_) and
@@ -180,7 +184,7 @@ abstract class ItemNode extends AstNode {
180184
this = result.(ImplOrTraitItemNode).getAnItemInSelfScope()
181185
or
182186
name = "crate" and
183-
result.(SourceFileItemNode).getFile() = this.getFile()
187+
this = result.(Crate).getASourceFile()
184188
}
185189

186190
/** Gets the location of this item. */
@@ -214,6 +218,27 @@ private class SourceFileItemNode extends ModuleLikeNode, SourceFile {
214218
override TypeParam getTypeParam(int i) { none() }
215219
}
216220

221+
private class CrateItemNode extends ItemNode instanceof Crate {
222+
/** Gets the module node that defines this crate. */
223+
pragma[nomagic]
224+
ModuleLikeNode getModuleNode() {
225+
result = super.getSourceFile()
226+
or
227+
not exists(super.getSourceFile()) and
228+
result = super.getModule()
229+
}
230+
231+
override string getName() { result = "(crate)" }
232+
233+
override Namespace getNamespace() {
234+
result.isType() // can be referenced with `crate`
235+
}
236+
237+
override Visibility getVisibility() { none() }
238+
239+
override TypeParam getTypeParam(int i) { none() }
240+
}
241+
217242
/** An item that can occur in a trait or an `impl` block. */
218243
abstract private class AssocItemNode extends ItemNode, AssocItem {
219244
/** Holds if this associated item has an implementation. */
@@ -600,6 +625,31 @@ private predicate fileImportEdge(Module mod, string name, ItemNode item) {
600625
)
601626
}
602627

628+
/**
629+
* Holds if crate `c` defines the item `i` named `name`.
630+
*/
631+
pragma[nomagic]
632+
private predicate crateDefEdge(CrateItemNode c, string name, ItemNode i) {
633+
i = c.getModuleNode().getASuccessor(name)
634+
}
635+
636+
/**
637+
* Holds if `source` depends on crate `dep` named `name`.
638+
*
639+
* Does not yet take dependency renaming into account.
640+
*/
641+
pragma[nomagic]
642+
private predicate crateDependencyEdge(ModuleLikeNode source, string name, Crate dep) {
643+
exists(CrateItemNode c |
644+
dep = c.(Crate).getADependency() and
645+
dep.getName() = name
646+
|
647+
source = c.getModuleNode()
648+
or
649+
source = c.(Crate).getASourceFile()
650+
)
651+
}
652+
603653
private predicate useTreeDeclares(UseTree tree, string name) {
604654
not tree.isGlob() and
605655
not exists(tree.getUseTreeList()) and
@@ -837,3 +887,44 @@ private predicate useImportEdge(Use use, string name, ItemNode item) {
837887
name != "_"
838888
)
839889
}
890+
891+
/** Provides predicates for debugging the path resolution implementation. */
892+
private module Debug {
893+
private Locatable getRelevantLocatable() {
894+
exists(string filepath, int startline, int startcolumn, int endline, int endcolumn |
895+
result.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) and
896+
filepath.matches("%/build_steps/mod.rs") and
897+
startline = 17
898+
)
899+
}
900+
901+
ItemNode debugResolvePath(RelevantPath path) {
902+
path = getRelevantLocatable() and
903+
result = resolvePath(path)
904+
}
905+
906+
predicate debugCrateDependencyEdge(ModuleLikeNode source, string name, Crate dep) {
907+
source = getRelevantLocatable() and
908+
crateDependencyEdge(source, name, dep)
909+
}
910+
911+
predicate debugUseImportEdge(Use use, string name, ItemNode item) {
912+
use = getRelevantLocatable() and
913+
useImportEdge(use, name, item)
914+
}
915+
916+
ItemNode debugGetASuccessorRec(ItemNode i, string name) {
917+
i = getRelevantLocatable() and
918+
result = i.getASuccessor(name)
919+
}
920+
921+
predicate debugFileImportEdge(Module mod, string name, ItemNode item) {
922+
mod = getRelevantLocatable() and
923+
fileImportEdge(mod, name, item)
924+
}
925+
926+
predicate debugFileImport(Module m, SourceFile f) {
927+
m = getRelevantLocatable() and
928+
fileImport(m, f)
929+
}
930+
}

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:0:0:0:0 | Crate(main@0.0.1) |
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:0:0:0:0 | Crate(main@0.0.1) |
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)