Skip to content

Commit e0418c1

Browse files
committed
Rust: Handle unqualified UseTrees in path resolution
1 parent 46288a0 commit e0418c1

File tree

3 files changed

+60
-7
lines changed

3 files changed

+60
-7
lines changed

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

Lines changed: 52 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,31 @@ private ItemNode resolveUseTreeListItemQualifier(
19892010
name = path.getText()
19902011
}
19912012

2013+
private UseTree getAUseUseTree(Use use) {
2014+
exists(UseTree root | root = use.getUseTree() |
2015+
result = root
2016+
or
2017+
not root.hasPath() and
2018+
result = getAUseTreeUseTree(root)
2019+
)
2020+
}
2021+
19922022
pragma[nomagic]
19932023
private ItemNode resolveUseTreeListItem(Use use, UseTree tree) {
19942024
exists(Path path | path = tree.getPath() |
1995-
tree = use.getUseTree() and
2025+
tree = getAUseUseTree(use) and
19962026
result = resolvePathCand(path)
19972027
or
19982028
result = resolveUseTreeListItem(use, tree, path, _)
19992029
)
2030+
or
2031+
exists(UseTree midTree |
2032+
// `use foo::{bar, *}`; midTree = `foo` and tree = `*`
2033+
result = resolveUseTreeListItem(use, midTree) and
2034+
tree = getAUseTreeUseTree(midTree) and
2035+
tree.isGlob() and
2036+
not tree.hasPath()
2037+
)
20002038
}
20012039

20022040
/** Holds if `use` imports `item` as `name`. */
@@ -2138,6 +2176,16 @@ private module Debug {
21382176
result = resolvePath(path)
21392177
}
21402178

2179+
ItemNode debugResolveUseTreeListItem(Use use, UseTree tree, RelevantPath path, SuccessorKind kind) {
2180+
use = getRelevantLocatable() and
2181+
result = resolveUseTreeListItem(use, tree, path, kind)
2182+
}
2183+
2184+
ItemNode debugResolveUseTreeListItem(Use use, UseTree tree) {
2185+
use = getRelevantLocatable() and
2186+
result = resolveUseTreeListItem(use, tree)
2187+
}
2188+
21412189
predicate debugUseImportEdge(Use use, string name, ItemNode item, SuccessorKind kind) {
21422190
use = getRelevantLocatable() and
21432191
useImportEdge(use, name, item, kind)

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

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

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

66
use my::nested::nested1::nested2::*; // $ item=I3
77

@@ -816,8 +816,8 @@ fn main() {
816816
nested6::f(); // $ item=I116
817817
nested8::f(); // $ item=I119
818818
my3::f(); // $ item=I200
819-
nested_f(); // $ MISSING: item=I201
820-
my_alias::nested_f(); // $ MISSING: item=I201
819+
nested_f(); // $ item=I201
820+
my_alias::nested_f(); // $ item=I201
821821
m18::m19::m20::g(); // $ item=I103
822822
m23::f(); // $ item=I108
823823
m24::f(); // $ item=I121

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ mod
4747
| my/nested.rs:1:1:17:1 | mod nested1 |
4848
| my/nested.rs:2:5:11:5 | mod nested2 |
4949
resolvePath
50+
| main.rs:4:8:4:9 | my | main.rs:1:1:1:7 | mod my |
51+
| main.rs:4:14:4:17 | self | main.rs:1:1:1:7 | mod my |
5052
| main.rs:6:5:6:6 | my | main.rs:1:1:1:7 | mod my |
5153
| main.rs:6:5:6:14 | ...::nested | my.rs:1:1:1:15 | mod nested |
5254
| main.rs:6:5:6:23 | ...::nested1 | my/nested.rs:1:1:17:1 | mod nested1 |
@@ -447,6 +449,9 @@ resolvePath
447449
| main.rs:817:5:817:14 | ...::f | my2/nested2.rs:23:9:25:9 | fn f |
448450
| main.rs:818:5:818:7 | my3 | my2/mod.rs:20:1:20:12 | mod my3 |
449451
| main.rs:818:5:818:10 | ...::f | my2/my3/mod.rs:1:1:5:1 | fn f |
452+
| main.rs:819:5:819:12 | nested_f | my/my4/my5/mod.rs:1:1:3:1 | fn f |
453+
| main.rs:820:5:820:12 | my_alias | main.rs:1:1:1:7 | mod my |
454+
| main.rs:820:5:820:22 | ...::nested_f | my/my4/my5/mod.rs:1:1:3:1 | fn f |
450455
| main.rs:821:5:821:7 | m18 | main.rs:555:1:573:1 | mod m18 |
451456
| main.rs:821:5:821:12 | ...::m19 | main.rs:560:5:572:5 | mod m19 |
452457
| main.rs:821:5:821:17 | ...::m20 | main.rs:565:9:571:9 | mod m20 |

0 commit comments

Comments
 (0)