Skip to content

Commit 1ba06ab

Browse files
authored
Merge pull request #19216 from hvitved/rust/path-resolution-path-attr
Rust: Handle path attributes in path resolution
2 parents ef00655 + 52401aa commit 1ba06ab

File tree

6 files changed

+93
-8
lines changed

6 files changed

+93
-8
lines changed

rust/ql/lib/codeql/files/FileSystem.qll

+2
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ class Container = Impl::Container;
3434

3535
class Folder = Impl::Folder;
3636

37+
module Folder = Impl::Folder;
38+
3739
/** A file. */
3840
class File extends Container, Impl::File {
3941
/** Holds if this file was extracted from ordinary source code. */

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

+26-6
Original file line numberDiff line numberDiff line change
@@ -655,6 +655,16 @@ private predicate fileModule(SourceFile f, string name, Folder folder) {
655655
)
656656
}
657657

658+
/**
659+
* Gets the `Meta` of the module `m`'s [path attribute][1].
660+
*
661+
* [1]: https://doc.rust-lang.org/reference/items/modules.html#r-items.mod.outlined.path
662+
*/
663+
private Meta getPathAttrMeta(Module m) {
664+
result = m.getAnAttr().getMeta() and
665+
result.getPath().getText() = "path"
666+
}
667+
658668
/**
659669
* Holds if `m` is a `mod name;` module declaration, where the corresponding
660670
* module file needs to be looked up in `lookup` or one of its descandants.
@@ -663,12 +673,7 @@ private predicate modImport0(Module m, string name, Folder lookup) {
663673
exists(File f, Folder parent, string fileName |
664674
f = m.getFile() and
665675
not m.hasItemList() and
666-
// TODO: handle
667-
// ```
668-
// #[path = "foo.rs"]
669-
// mod bar;
670-
// ```
671-
not m.getAnAttr().getMeta().getPath().getText() = "path" and
676+
not exists(getPathAttrMeta(m)) and
672677
name = m.getName().getText() and
673678
parent = f.getParentContainer() and
674679
fileName = f.getStem()
@@ -717,6 +722,16 @@ private predicate modImportNestedLookup(Module m, ModuleItemNode ancestor, Folde
717722
)
718723
}
719724

725+
private predicate pathAttrImport(Folder f, Module m, string relativePath) {
726+
exists(Meta meta |
727+
f = m.getFile().getParentContainer() and
728+
meta = getPathAttrMeta(m) and
729+
relativePath = meta.getExpr().(LiteralExpr).getTextValue().regexpCapture("\"(.+)\"", 1)
730+
)
731+
}
732+
733+
private predicate shouldAppend(Folder f, string relativePath) { pathAttrImport(f, _, relativePath) }
734+
720735
/** Holds if `m` is a `mod name;` item importing file `f`. */
721736
private predicate fileImport(Module m, SourceFile f) {
722737
exists(string name, Folder parent |
@@ -730,6 +745,11 @@ private predicate fileImport(Module m, SourceFile f) {
730745
// `m` is inside a nested module
731746
modImportNestedLookup(m, m, parent)
732747
)
748+
or
749+
exists(Folder folder, string relativePath |
750+
pathAttrImport(folder, m, relativePath) and
751+
f.getFile() = Folder::Append<shouldAppend/2>::append(folder, relativePath)
752+
)
733753
}
734754

735755
/**

rust/ql/test/library-tests/path-resolution/my2/mod.rs

+5
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,8 @@ pub use nested2::nested5::*; // $ item=I114
1010
pub use nested2::nested7::nested8::{self}; // $ item=I118
1111

1212
pub mod my3;
13+
14+
#[path = "renamed.rs"]
15+
mod mymod;
16+
17+
use mymod::f; // $ item=I1001
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
pub fn f() {} // I1001

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

+5-2
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ mod
3030
| main.rs:523:1:548:1 | mod m23 |
3131
| my2/mod.rs:1:1:1:16 | mod nested2 |
3232
| my2/mod.rs:12:1:12:12 | mod my3 |
33+
| my2/mod.rs:14:1:15:10 | mod mymod |
3334
| my2/nested2.rs:1:1:11:1 | mod nested3 |
3435
| my2/nested2.rs:2:5:10:5 | mod nested4 |
3536
| my2/nested2.rs:13:1:19:1 | mod nested5 |
@@ -306,12 +307,14 @@ resolvePath
306307
| my2/mod.rs:10:9:10:24 | ...::nested7 | my2/nested2.rs:21:1:27:1 | mod nested7 |
307308
| my2/mod.rs:10:9:10:33 | ...::nested8 | my2/nested2.rs:22:5:26:5 | mod nested8 |
308309
| my2/mod.rs:10:37:10:40 | self | my2/nested2.rs:22:5:26:5 | mod nested8 |
310+
| my2/mod.rs:17:5:17:9 | mymod | my2/mod.rs:14:1:15:10 | mod mymod |
311+
| my2/mod.rs:17:5:17:12 | ...::f | my2/renamed.rs:1:1:1:13 | fn f |
309312
| my2/my3/mod.rs:3:5:3:5 | g | my2/mod.rs:3:1:6:1 | fn g |
310313
| my2/my3/mod.rs:4:5:4:5 | h | main.rs:50:1:69:1 | fn h |
311-
| my2/my3/mod.rs:7:5:7:9 | super | my2/mod.rs:1:1:12:13 | SourceFile |
314+
| my2/my3/mod.rs:7:5:7:9 | super | my2/mod.rs:1:1:17:30 | SourceFile |
312315
| my2/my3/mod.rs:7:5:7:16 | ...::super | main.rs:1:1:578:2 | SourceFile |
313316
| my2/my3/mod.rs:7:5:7:19 | ...::h | main.rs:50:1:69:1 | fn h |
314-
| my2/my3/mod.rs:8:5:8:9 | super | my2/mod.rs:1:1:12:13 | SourceFile |
317+
| my2/my3/mod.rs:8:5:8:9 | super | my2/mod.rs:1:1:17:30 | SourceFile |
315318
| my2/my3/mod.rs:8:5:8:12 | ...::g | my2/mod.rs:3:1:6:1 | fn g |
316319
| my.rs:3:5:3:10 | nested | my.rs:1:1:1:15 | mod nested |
317320
| my.rs:3:5:3:13 | ...::g | my/nested.rs:19:1:22:1 | fn g |

shared/util/codeql/util/FileSystem.qll

+54
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,60 @@ module Make<InputSig Input> {
218218
/** Gets the URL of this file. */
219219
override string getURL() { result = "file://" + this.getAbsolutePath() + ":0:0:0:0" }
220220
}
221+
222+
/** Provides logic related to `Folder`s. */
223+
module Folder {
224+
/** Holds if `relativePath` needs to be appended to `f`. */
225+
signature predicate shouldAppendSig(Folder f, string relativePath);
226+
227+
/** Provides the `append` predicate for appending a relative path onto a folder. */
228+
module Append<shouldAppendSig/2 shouldAppend> {
229+
pragma[nomagic]
230+
private string getComponent(string relativePath, int i) {
231+
shouldAppend(_, relativePath) and
232+
result = relativePath.replaceAll("\\", "/").regexpFind("[^/]+", i, _)
233+
}
234+
235+
private int getNumberOfComponents(string relativePath) {
236+
result = strictcount(int i | exists(getComponent(relativePath, i)) | i)
237+
or
238+
relativePath = "" and
239+
result = 0
240+
}
241+
242+
pragma[nomagic]
243+
private Container appendStep(Folder f, string relativePath, int i) {
244+
i = -1 and
245+
shouldAppend(f, relativePath) and
246+
result = f
247+
or
248+
exists(Container mid, string comp |
249+
mid = appendStep(f, relativePath, i - 1) and
250+
comp = getComponent(relativePath, i) and
251+
if comp = ".."
252+
then result = mid.getParentContainer()
253+
else
254+
if comp = "."
255+
then result = mid
256+
else (
257+
result = mid.getAChildContainer() and
258+
result.getBaseName() = comp
259+
)
260+
)
261+
}
262+
263+
/**
264+
* Gets the file or folder obtained by appending `relativePath` onto `f`.
265+
*/
266+
pragma[nomagic]
267+
Container append(Folder f, string relativePath) {
268+
exists(int last |
269+
last = getNumberOfComponents(relativePath) - 1 and
270+
result = appendStep(f, relativePath, last)
271+
)
272+
}
273+
}
274+
}
221275
}
222276

223277
/** A file. */

0 commit comments

Comments
 (0)