Skip to content

Commit fda6207

Browse files
committed
Rust: Cross-crate path resolution
1 parent 9a18481 commit fda6207

6 files changed

Lines changed: 140 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: 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: 121 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,10 @@ abstract class ItemNode extends AstNode {
180184
this = result.(ImplOrTraitItemNode).getAnItemInSelfScope()
181185
or
182186
name = "crate" and
183-
result.(SourceFileItemNode).getFile() = this.getFile()
187+
exists(CrateItemNode crate |
188+
this = crate.getASourceFile() and
189+
result = crate.getModuleNode()
190+
)
184191
}
185192

186193
/** Gets the location of this item. */
@@ -214,6 +221,51 @@ private class SourceFileItemNode extends ModuleLikeNode, SourceFile {
214221
override TypeParam getTypeParam(int i) { none() }
215222
}
216223

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

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