Skip to content

Commit bfa3562

Browse files
authored
Merge pull request #20744 from hvitved/rust/path-resolution-unqualified-use-tree
Rust: Handle unqualified `UseTree`s in path resolution
2 parents 467bd54 + c6164b3 commit bfa3562

File tree

4 files changed

+509
-459
lines changed

4 files changed

+509
-459
lines changed

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

Lines changed: 49 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1436,6 +1436,24 @@ private predicate crateDependencyEdge(SourceFileItemNode file, string name, Crat
14361436
not hasDeclOrDep(file, name)
14371437
}
14381438

1439+
/**
1440+
* Gets a `UseTree` that is nested under `tree`, and which needs to be resolved
1441+
* relative to the path of `tree`.
1442+
*
1443+
* `tree` is restricted to either having a path or being a direct child of some
1444+
* `use` statement without a path.
1445+
*/
1446+
private UseTree getAUseTreeUseTree(UseTree tree) {
1447+
result = tree.getUseTreeList().getAUseTree() and
1448+
(if tree.hasPath() then any() else tree = any(Use u).getUseTree())
1449+
or
1450+
exists(UseTree mid |
1451+
mid = getAUseTreeUseTree(tree) and
1452+
not mid.hasPath() and
1453+
result = mid.getUseTreeList().getAUseTree()
1454+
)
1455+
}
1456+
14391457
private predicate useTreeDeclares(UseTree tree, string name) {
14401458
not tree.isGlob() and
14411459
not exists(tree.getUseTreeList()) and
@@ -1449,7 +1467,7 @@ private predicate useTreeDeclares(UseTree tree, string name) {
14491467
or
14501468
exists(UseTree mid |
14511469
useTreeDeclares(mid, name) and
1452-
mid = tree.getUseTreeList().getAUseTree()
1470+
mid = getAUseTreeUseTree(tree)
14531471
)
14541472
}
14551473

@@ -1490,7 +1508,10 @@ class RelevantPath extends Path {
14901508
pragma[nomagic]
14911509
predicate isUnqualified(string name) {
14921510
not exists(this.getQualifier()) and
1493-
not this = any(UseTreeList list).getAUseTree().getPath().getQualifier*() and
1511+
not exists(UseTree tree |
1512+
tree.hasPath() and
1513+
this = getAUseTreeUseTree(tree).getPath().getQualifier*()
1514+
) and
14941515
name = this.getText()
14951516
}
14961517

@@ -1969,7 +1990,7 @@ private ItemNode resolveUseTreeListItem(Use use, UseTree tree, RelevantPath path
19691990
exists(UseOption useOpt | checkQualifiedVisibility(use, result, kind, useOpt) |
19701991
exists(UseTree midTree, ItemNode mid, string name |
19711992
mid = resolveUseTreeListItem(use, midTree) and
1972-
tree = midTree.getUseTreeList().getAUseTree() and
1993+
tree = getAUseTreeUseTree(midTree) and
19731994
isUseTreeSubPathUnqualified(tree, path, pragma[only_bind_into](name)) and
19741995
result = mid.getASuccessor(pragma[only_bind_into](name), kind, useOpt)
19751996
)
@@ -1989,14 +2010,28 @@ private ItemNode resolveUseTreeListItemQualifier(
19892010
name = path.getText()
19902011
}
19912012

2013+
private UseTree getAUseUseTree(Use use) {
2014+
exists(UseTree root | root = use.getUseTree() |
2015+
if root.hasPath() then result = root else result = getAUseTreeUseTree(root)
2016+
)
2017+
}
2018+
19922019
pragma[nomagic]
19932020
private ItemNode resolveUseTreeListItem(Use use, UseTree tree) {
19942021
exists(Path path | path = tree.getPath() |
1995-
tree = use.getUseTree() and
2022+
tree = getAUseUseTree(use) and
19962023
result = resolvePathCand(path)
19972024
or
19982025
result = resolveUseTreeListItem(use, tree, path, _)
19992026
)
2027+
or
2028+
exists(UseTree midTree |
2029+
// `use foo::{bar, *}`; midTree = `foo` and tree = `*`
2030+
result = resolveUseTreeListItem(use, midTree) and
2031+
tree = getAUseTreeUseTree(midTree) and
2032+
tree.isGlob() and
2033+
not tree.hasPath()
2034+
)
20002035
}
20012036

20022037
/** Holds if `use` imports `item` as `name`. */
@@ -2138,6 +2173,16 @@ private module Debug {
21382173
result = resolvePath(path)
21392174
}
21402175

2176+
ItemNode debugResolveUseTreeListItem(Use use, UseTree tree, RelevantPath path, SuccessorKind kind) {
2177+
use = getRelevantLocatable() and
2178+
result = resolveUseTreeListItem(use, tree, path, kind)
2179+
}
2180+
2181+
ItemNode debugResolveUseTreeListItem(Use use, UseTree tree) {
2182+
use = getRelevantLocatable() and
2183+
result = resolveUseTreeListItem(use, tree)
2184+
}
2185+
21412186
predicate debugUseImportEdge(Use use, string name, ItemNode item, SuccessorKind kind) {
21422187
use = getRelevantLocatable() and
21432188
useImportEdge(use, name, item, kind)
Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
multipleCallTargets
2-
| main.rs:125:9:125:11 | f(...) |
3-
| main.rs:365:9:367:16 | ...::f(...) |
4-
| main.rs:368:9:370:16 | ...::f(...) |
5-
| main.rs:447:9:451:16 | ...::f(...) |
6-
| main.rs:452:9:456:16 | ...::f(...) |
2+
| main.rs:126:9:126:11 | f(...) |
3+
| main.rs:366:9:368:16 | ...::f(...) |
4+
| main.rs:369:9:371:16 | ...::f(...) |
5+
| main.rs:448:9:452:16 | ...::f(...) |
6+
| main.rs:453:9:457:16 | ...::f(...) |

rust/ql/test/library-tests/path-resolution/main.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
mod my; // I1
22

3-
use my::*; // $ item=I1
3+
#[rustfmt::skip]
4+
use {{{my::{{self as my_alias, *}}}}}; // $ item=I1
45

56
use my::nested::nested1::nested2::*; // $ item=I3
67

@@ -816,6 +817,7 @@ fn main() {
816817
nested8::f(); // $ item=I119
817818
my3::f(); // $ item=I200
818819
nested_f(); // $ item=I201
820+
my_alias::nested_f(); // $ item=I201
819821
m18::m19::m20::g(); // $ item=I103
820822
m23::f(); // $ item=I108
821823
m24::f(); // $ item=I121

0 commit comments

Comments
 (0)