Rust: More path resolution improvements

This commit is contained in:
Tom Hvitved
2025-03-27 15:10:25 +01:00
parent f6ac82aff0
commit 605cf35970
4 changed files with 84 additions and 23 deletions

View File

@@ -116,7 +116,7 @@ abstract class ItemNode extends Locatable {
}
pragma[nomagic]
private ItemNode getASuccessorRec(string name) {
ItemNode getASuccessorRec(string name) {
sourceFileEdge(this, name, result)
or
this = result.getImmediateParent() and
@@ -613,11 +613,11 @@ private predicate fileModule(SourceFile f, string name, Folder folder) {
}
/**
* Holds if `m` is a `mod name;` module declaration happening in a file named
* `fileName.rs`, inside the folder `parent`.
* Holds if `m` is a `mod name;` module declaration, where the corresponding
* module file needs to be looked up in `lookup` or one of its descandants.
*/
private predicate modImport(Module m, string fileName, string name, Folder parent) {
exists(File f |
private predicate modImport0(Module m, string name, Folder lookup) {
exists(File f, Folder parent, string fileName |
f = m.getFile() and
not m.hasItemList() and
// TODO: handle
@@ -629,17 +629,63 @@ private predicate modImport(Module m, string fileName, string name, Folder paren
name = m.getName().getText() and
parent = f.getParentContainer() and
fileName = f.getStem()
|
// sibling import
lookup = parent and
(
m.getFile() = any(CrateItemNode c).getModuleNode().(SourceFileItemNode).getFile()
or
m.getFile().getBaseName() = "mod.rs"
)
or
// child import
lookup = parent.getFolder(fileName)
)
}
/**
* Holds if `m` is a `mod name;` module declaration, which happens inside a
* nested module, and `pred -> succ` is a module edge leading to `m`.
*/
private predicate modImportNested(ModuleItemNode m, ModuleItemNode pred, ModuleItemNode succ) {
pred.getAnItemInScope() = succ and
(
modImport0(m, _, _) and
succ = m
or
modImportNested(m, succ, _)
)
}
/**
* Holds if `m` is a `mod name;` module declaration, which happens inside a
* nested module, where `ancestor` is a reflexive transitive ancestor module
* of `m` with corresponding lookup folder `lookup`.
*/
private predicate modImportNestedLookup(Module m, ModuleItemNode ancestor, Folder lookup) {
modImport0(m, _, lookup) and
modImportNested(m, ancestor, _) and
not modImportNested(m, _, ancestor)
or
exists(ModuleItemNode m1, Folder mid |
modImportNestedLookup(m, m1, mid) and
modImportNested(m, m1, ancestor) and
lookup = mid.getFolder(m1.getName())
)
}
/** Holds if `m` is a `mod name;` item importing file `f`. */
private predicate fileImport(Module m, SourceFile f) {
exists(string fileName, string name, Folder parent | modImport(m, fileName, name, parent) |
// sibling import
exists(string name, Folder parent |
modImport0(m, name, _) and
fileModule(f, name, parent)
|
// `m` is not inside a nested module
modImport0(m, name, parent) and
not modImportNested(m, _, _)
or
// child import
fileModule(f, name, parent.getFolder(fileName))
// `m` is inside a nested module
modImportNestedLookup(m, m, parent)
)
}
@@ -651,7 +697,7 @@ pragma[nomagic]
private predicate fileImportEdge(Module mod, string name, ItemNode item) {
exists(SourceFileItemNode f |
fileImport(mod, f) and
item = f.getASuccessor(name)
item = f.getASuccessorRec(name)
)
}
@@ -660,7 +706,7 @@ private predicate fileImportEdge(Module mod, string name, ItemNode item) {
*/
pragma[nomagic]
private predicate crateDefEdge(CrateItemNode c, string name, ItemNode i) {
i = c.getModuleNode().getASuccessor(name) and
i = c.getModuleNode().getASuccessorRec(name) and
not i instanceof Crate
}
@@ -742,7 +788,16 @@ private predicate unqualifiedPathLookup(RelevantPath p, string name, Namespace n
// lookup in an outer scope, but only if the item is not declared in inner scope
exists(ItemNode mid |
unqualifiedPathLookup(p, name, ns, mid) and
not declares(mid, ns, name)
not declares(mid, ns, name) and
not name = ["super", "self"] and
not (
name = "Self" and
mid = any(ImplOrTraitItemNode i).getAnItemInSelfScope()
) and
not (
name = "crate" and
mid = any(CrateItemNode i).getASourceFile()
)
|
// nested modules do not have unqualified access to items from outer modules,
// except for items declared at top-level in the source file
@@ -943,15 +998,19 @@ private predicate useImportEdge(Use use, string name, ItemNode item) {
encl.getADescendant() = use and
item = getASuccessor(used, name, ns) and
// glob imports can be shadowed
not declares(encl, ns, name)
not declares(encl, ns, name) and
not name = ["super", "self", "Self", "crate"]
)
else item = used
|
not tree.hasRename() and
name = item.getName()
or
name = tree.getRename().getName().getText() and
name != "_"
else (
item = used and
(
not tree.hasRename() and
name = item.getName()
or
name = tree.getRename().getName().getText() and
name != "_"
)
)
)
}
@@ -961,7 +1020,7 @@ private module Debug {
exists(string filepath, int startline, int startcolumn, int endline, int endcolumn |
result.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) and
filepath.matches("%/main.rs") and
startline = 1
startline = [1, 3]
)
}

View File

@@ -518,6 +518,6 @@ fn main() {
nested6::f(); // $ item=I116
nested8::f(); // $ item=I119
my3::f(); // $ item=I200
nested_f(); // $ MISSING: item=I201
nested_f(); // $ item=I201
m18::m19::m20::g(); // $ item=I103
}

View File

@@ -15,4 +15,4 @@ mod my4 {
pub mod my5;
}
pub use my4::my5::f as nested_f; // $ MISSING: item=I201
pub use my4::my5::f as nested_f; // $ item=I201

View File

@@ -270,6 +270,7 @@ resolvePath
| main.rs:519:5:519:14 | ...::f | my2/nested2.rs:23:9:25:9 | fn f |
| main.rs:520:5:520:7 | my3 | my2/mod.rs:12:1:12:12 | mod my3 |
| main.rs:520:5:520:10 | ...::f | my2/my3/mod.rs:1:1:5:1 | fn f |
| main.rs:521:5:521:12 | nested_f | my/my4/my5/mod.rs:1:1:3:1 | fn f |
| main.rs:522:5:522:7 | m18 | main.rs:476:1:494:1 | mod m18 |
| main.rs:522:5:522:12 | ...::m19 | main.rs:481:5:493:5 | mod m19 |
| main.rs:522:5:522:17 | ...::m20 | main.rs:486:9:492:9 | mod m20 |
@@ -296,6 +297,7 @@ resolvePath
| my.rs:11:5:11:5 | g | my/nested.rs:19:1:22:1 | fn g |
| my.rs:18:9:18:11 | my4 | my.rs:14:1:16:1 | mod my4 |
| my.rs:18:9:18:16 | ...::my5 | my.rs:15:5:15:16 | mod my5 |
| my.rs:18:9:18:19 | ...::f | my/my4/my5/mod.rs:1:1:3:1 | fn f |
| my/nested.rs:9:13:9:13 | f | my/nested.rs:3:9:5:9 | fn f |
| my/nested.rs:15:9:15:15 | nested2 | my/nested.rs:2:5:11:5 | mod nested2 |
| my/nested.rs:15:9:15:18 | ...::f | my/nested.rs:3:9:5:9 | fn f |