Skip to content

Commit cbf6f94

Browse files
committed
Rust: Handle path attributes in path resolution
1 parent 28dd4fc commit cbf6f94

File tree

5 files changed

+77
-9
lines changed

5 files changed

+77
-9
lines changed

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

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

3535
class Folder = Impl::Folder;
3636

37+
/** Holds if `relativePath` needs to be appended to `f`. */
38+
signature predicate appendSig(Folder f, string relativePath);
39+
40+
/** Provides the `append` predicate for appending a relative path onto a folder. */
41+
module FolderAppend<appendSig/2 app> {
42+
import Impl::FolderAppend<app/2>
43+
}
44+
3745
/** A file. */
3846
class File extends Container, Impl::File {
3947
/** Holds if this file was extracted from ordinary source code. */

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

+21-6
Original file line numberDiff line numberDiff line change
@@ -654,6 +654,11 @@ private predicate fileModule(SourceFile f, string name, Folder folder) {
654654
)
655655
}
656656

657+
private Meta getPathAttrMeta(Module m) {
658+
result = m.getAnAttr().getMeta() and
659+
result.getPath().getText() = "path"
660+
}
661+
657662
/**
658663
* Holds if `m` is a `mod name;` module declaration, where the corresponding
659664
* module file needs to be looked up in `lookup` or one of its descandants.
@@ -662,12 +667,7 @@ private predicate modImport0(Module m, string name, Folder lookup) {
662667
exists(File f, Folder parent, string fileName |
663668
f = m.getFile() and
664669
not m.hasItemList() and
665-
// TODO: handle
666-
// ```
667-
// #[path = "foo.rs"]
668-
// mod bar;
669-
// ```
670-
not m.getAnAttr().getMeta().getPath().getText() = "path" and
670+
not exists(getPathAttrMeta(m)) and
671671
name = m.getName().getText() and
672672
parent = f.getParentContainer() and
673673
fileName = f.getStem()
@@ -716,6 +716,16 @@ private predicate modImportNestedLookup(Module m, ModuleItemNode ancestor, Folde
716716
)
717717
}
718718

719+
private predicate pathAttrImport(Folder f, Module m, string relativePath) {
720+
exists(Meta meta |
721+
f = m.getFile().getParentContainer() and
722+
meta = getPathAttrMeta(m) and
723+
relativePath = meta.getExpr().(LiteralExpr).getTextValue().regexpCapture("\"(.+)\"", 1)
724+
)
725+
}
726+
727+
private predicate append(Folder f, string relativePath) { pathAttrImport(f, _, relativePath) }
728+
719729
/** Holds if `m` is a `mod name;` item importing file `f`. */
720730
private predicate fileImport(Module m, SourceFile f) {
721731
exists(string name, Folder parent |
@@ -729,6 +739,11 @@ private predicate fileImport(Module m, SourceFile f) {
729739
// `m` is inside a nested module
730740
modImportNestedLookup(m, m, parent)
731741
)
742+
or
743+
exists(Folder folder, string relativePath |
744+
pathAttrImport(folder, m, relativePath) and
745+
f.getFile() = FolderAppend<append/2>::append(folder, relativePath)
746+
)
732747
}
733748

734749
/**

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,4 @@ pub mod my3;
1414
#[path = "renamed.rs"]
1515
mod mymod;
1616

17-
use mymod::f; // $ MISSING: item=I1001
17+
use mymod::f; // $ item=I1001

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

+3-2
Original file line numberDiff line numberDiff line change
@@ -301,12 +301,13 @@ resolvePath
301301
| my2/mod.rs:10:9:10:33 | ...::nested8 | my2/nested2.rs:22:5:26:5 | mod nested8 |
302302
| my2/mod.rs:10:37:10:40 | self | my2/nested2.rs:22:5:26:5 | mod nested8 |
303303
| my2/mod.rs:17:5:17:9 | mymod | my2/mod.rs:14:1:15:10 | mod mymod |
304+
| my2/mod.rs:17:5:17:12 | ...::f | my2/renamed.rs:1:1:1:13 | fn f |
304305
| my2/my3/mod.rs:3:5:3:5 | g | my2/mod.rs:3:1:6:1 | fn g |
305306
| my2/my3/mod.rs:4:5:4:5 | h | main.rs:50:1:69:1 | fn h |
306-
| my2/my3/mod.rs:7:5:7:9 | super | my2/mod.rs:1:1:17:39 | SourceFile |
307+
| my2/my3/mod.rs:7:5:7:9 | super | my2/mod.rs:1:1:17:30 | SourceFile |
307308
| my2/my3/mod.rs:7:5:7:16 | ...::super | main.rs:1:1:550:2 | SourceFile |
308309
| my2/my3/mod.rs:7:5:7:19 | ...::h | main.rs:50:1:69:1 | fn h |
309-
| my2/my3/mod.rs:8:5:8:9 | super | my2/mod.rs:1:1:17:39 | SourceFile |
310+
| my2/my3/mod.rs:8:5:8:9 | super | my2/mod.rs:1:1:17:30 | SourceFile |
310311
| my2/my3/mod.rs:8:5:8:12 | ...::g | my2/mod.rs:3:1:6:1 | fn g |
311312
| my.rs:3:5:3:10 | nested | my.rs:1:1:1:15 | mod nested |
312313
| my.rs:3:5:3:13 | ...::g | my/nested.rs:19:1:22:1 | fn g |

shared/util/codeql/util/FileSystem.qll

+44
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,50 @@ 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+
/** Holds if `relativePath` needs to be appended to `f`. */
223+
signature predicate appendSig(Folder f, string relativePath);
224+
225+
/** Provides the `append` predicate for appending a relative path onto a folder. */
226+
module FolderAppend<appendSig/2 app> {
227+
pragma[nomagic]
228+
private string getComponent(string relativePath, int i) {
229+
app(_, relativePath) and
230+
result = relativePath.replaceAll("\\", "/").regexpFind("[^/]+", i, _)
231+
}
232+
233+
pragma[nomagic]
234+
private Container appendStep(Folder f, string relativePath, int i) {
235+
i = -1 and
236+
app(f, relativePath) and
237+
result = f
238+
or
239+
exists(Container mid, string comp |
240+
mid = appendStep(f, relativePath, i - 1) and
241+
comp = getComponent(relativePath, i) and
242+
if comp = ".."
243+
then result = mid.getParentContainer()
244+
else
245+
if comp = "."
246+
then result = mid
247+
else (
248+
result = mid.getAChildContainer() and
249+
result.getBaseName() = comp
250+
)
251+
)
252+
}
253+
254+
/**
255+
* Gets the file or folder obtained by appending `relativePath` onto `f`.
256+
*/
257+
pragma[nomagic]
258+
Container append(Folder f, string relativePath) {
259+
exists(int components |
260+
components = (-1).maximum(max(int comp | exists(getComponent(relativePath, comp)) | comp)) and
261+
result = appendStep(f, relativePath, components)
262+
)
263+
}
264+
}
221265
}
222266

223267
/** A file. */

0 commit comments

Comments
 (0)