Skip to content

Commit c911761

Browse files
committed
Rust: Cross-crate path resolution
1 parent bd4c85a commit c911761

File tree

6 files changed

+137
-6
lines changed

6 files changed

+137
-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: 118 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.(CrateItemNode).getASourceFile()
184188
}
185189

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

221+
class CrateItemNode extends ItemNode instanceof Crate {
222+
/**
223+
* Gets the module node that defines this crate.
224+
*
225+
* This is either a source file, when the crate is defined in source code,
226+
* or a module, when the crate is defined in a dependency.
227+
*/
228+
pragma[nomagic]
229+
ModuleLikeNode getModuleNode() {
230+
result = super.getSourceFile()
231+
or
232+
not exists(super.getSourceFile()) and
233+
result = super.getModule()
234+
}
235+
236+
/**
237+
* Gets a source file that belongs to this crate, if any.
238+
*
239+
* This is calculated as those source files that can be reached from the entry
240+
* file of this crate using zero or more `mod` imports, without going through
241+
* the entry point of some other crate.
242+
*/
243+
pragma[nomagic]
244+
SourceFileItemNode getASourceFile() {
245+
result = super.getSourceFile()
246+
or
247+
exists(SourceFileItemNode mid, Module mod |
248+
mid = this.getASourceFile() and
249+
mod.getFile() = mid.getFile() and
250+
fileImport(mod, result) and
251+
not result = any(Crate other).getSourceFile()
252+
)
253+
}
254+
255+
override string getName() { result = Crate.super.getName() }
256+
257+
override Namespace getNamespace() {
258+
result.isType() // can be referenced with `crate`
259+
}
260+
261+
override Visibility getVisibility() { none() }
262+
263+
override TypeParam getTypeParam(int i) { none() }
264+
}
265+
217266
/** An item that can occur in a trait or an `impl` block. */
218267
abstract private class AssocItemNode extends ItemNode, AssocItem {
219268
/** Holds if this associated item has an implementation. */
@@ -595,6 +644,28 @@ private predicate fileImportEdge(Module mod, string name, ItemNode item) {
595644
)
596645
}
597646

647+
/**
648+
* Holds if crate `c` defines the item `i` named `name`.
649+
*/
650+
pragma[nomagic]
651+
private predicate crateDefEdge(CrateItemNode c, string name, ItemNode i) {
652+
i = c.getModuleNode().getASuccessor(name) and
653+
not i instanceof Crate
654+
}
655+
656+
/**
657+
* Holds if `m` depends on crate `dep` named `name`.
658+
*/
659+
private predicate crateDependencyEdge(ModuleLikeNode m, string name, CrateItemNode dep) {
660+
exists(CrateItemNode c | dep = c.(Crate).getDependency(name) |
661+
// entry module/entry source file
662+
m = c.getModuleNode()
663+
or
664+
// entry/transitive source file
665+
m = c.getASourceFile()
666+
)
667+
}
668+
598669
private predicate useTreeDeclares(UseTree tree, string name) {
599670
not tree.isGlob() and
600671
not exists(tree.getUseTreeList()) and
@@ -832,3 +903,48 @@ private predicate useImportEdge(Use use, string name, ItemNode item) {
832903
name != "_"
833904
)
834905
}
906+
907+
/** Provides predicates for debugging the path resolution implementation. */
908+
private module Debug {
909+
private Locatable getRelevantLocatable() {
910+
exists(string filepath, int startline, int startcolumn, int endline, int endcolumn |
911+
result.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) and
912+
// filepath.matches("%/compile.rs") and
913+
// startline = 1986
914+
// filepath.matches("%/build_steps/mod.rs") and
915+
// startline = 17
916+
filepath.matches("%/main.rs") and
917+
startline = 1
918+
)
919+
}
920+
921+
predicate debugUnqualifiedPathLookup(RelevantPath p, string name, Namespace ns, ItemNode encl) {
922+
p = getRelevantLocatable() and
923+
unqualifiedPathLookup(p, name, ns, encl)
924+
}
925+
926+
ItemNode debugResolvePath(RelevantPath path) {
927+
path = getRelevantLocatable() and
928+
result = resolvePath(path)
929+
}
930+
931+
predicate debugUseImportEdge(Use use, string name, ItemNode item) {
932+
use = getRelevantLocatable() and
933+
useImportEdge(use, name, item)
934+
}
935+
936+
ItemNode debugGetASuccessorRec(ItemNode i, string name) {
937+
i = getRelevantLocatable() and
938+
result = i.getASuccessor(name)
939+
}
940+
941+
predicate debugFileImportEdge(Module mod, string name, ItemNode item) {
942+
mod = getRelevantLocatable() and
943+
fileImportEdge(mod, name, item)
944+
}
945+
946+
predicate debugFileImport(Module m, SourceFile f) {
947+
m = getRelevantLocatable() and
948+
fileImport(m, f)
949+
}
950+
}
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:0:0:0:0 | Crate([email protected]) |
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([email protected]) |
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)