Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 52 additions & 4 deletions rust/ql/lib/codeql/rust/internal/PathResolution.qll
Original file line number Diff line number Diff line change
Expand Up @@ -1457,6 +1457,24 @@ private predicate crateDependencyEdge(SourceFileItemNode file, string name, Crat
not hasDeclOrDep(file, name)
}

/**
* Gets a `UseTree` that is nested under `tree`, and which needs to be resolved
* relative to the path of `tree`.
*
* `tree` is restricted to either having a path or being a direct child of some
* `use` statement without a path.
*/
private UseTree getAUseTreeUseTree(UseTree tree) {
result = tree.getUseTreeList().getAUseTree() and
(if tree.hasPath() then any() else tree = any(Use u).getUseTree())
or
exists(UseTree mid |
mid = getAUseTreeUseTree(tree) and
not mid.hasPath() and
result = mid.getUseTreeList().getAUseTree()
)
}

private predicate useTreeDeclares(UseTree tree, string name) {
not tree.isGlob() and
not exists(tree.getUseTreeList()) and
Expand All @@ -1470,7 +1488,7 @@ private predicate useTreeDeclares(UseTree tree, string name) {
or
exists(UseTree mid |
useTreeDeclares(mid, name) and
mid = tree.getUseTreeList().getAUseTree()
mid = getAUseTreeUseTree(tree)
)
}

Expand Down Expand Up @@ -1511,7 +1529,10 @@ class RelevantPath extends Path {
pragma[nomagic]
predicate isUnqualified(string name) {
not exists(this.getQualifier()) and
not this = any(UseTreeList list).getAUseTree().getPath().getQualifier*() and
not exists(UseTree tree |
tree.hasPath() and
this = getAUseTreeUseTree(tree).getPath().getQualifier*()
) and
name = this.getText()
}

Expand Down Expand Up @@ -1990,7 +2011,7 @@ private ItemNode resolveUseTreeListItem(Use use, UseTree tree, RelevantPath path
exists(UseOption useOpt | checkQualifiedVisibility(use, result, kind, useOpt) |
exists(UseTree midTree, ItemNode mid, string name |
mid = resolveUseTreeListItem(use, midTree) and
tree = midTree.getUseTreeList().getAUseTree() and
tree = getAUseTreeUseTree(midTree) and
isUseTreeSubPathUnqualified(tree, path, pragma[only_bind_into](name)) and
result = mid.getASuccessor(pragma[only_bind_into](name), kind, useOpt)
)
Expand All @@ -2010,14 +2031,31 @@ private ItemNode resolveUseTreeListItemQualifier(
name = path.getText()
}

private UseTree getAUseUseTree(Use use) {
exists(UseTree root | root = use.getUseTree() |
result = root
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the overlap in the disjunction here intended? If not we could do if root.hasPath() then ... else ....

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, we may as well; this predicate is only called in one place, and it expects the result to have a path.

or
not root.hasPath() and
result = getAUseTreeUseTree(root)
)
}

pragma[nomagic]
private ItemNode resolveUseTreeListItem(Use use, UseTree tree) {
exists(Path path | path = tree.getPath() |
tree = use.getUseTree() and
tree = getAUseUseTree(use) and
result = resolvePathCand(path)
or
result = resolveUseTreeListItem(use, tree, path, _)
)
or
exists(UseTree midTree |
// `use foo::{bar, *}`; midTree = `foo` and tree = `*`
result = resolveUseTreeListItem(use, midTree) and
tree = getAUseTreeUseTree(midTree) and
tree.isGlob() and
not tree.hasPath()
)
}

/** Holds if `use` imports `item` as `name`. */
Expand Down Expand Up @@ -2159,6 +2197,16 @@ private module Debug {
result = resolvePath(path)
}

ItemNode debugResolveUseTreeListItem(Use use, UseTree tree, RelevantPath path, SuccessorKind kind) {
use = getRelevantLocatable() and
result = resolveUseTreeListItem(use, tree, path, kind)
}

ItemNode debugResolveUseTreeListItem(Use use, UseTree tree) {
use = getRelevantLocatable() and
result = resolveUseTreeListItem(use, tree)
}

predicate debugUseImportEdge(Use use, string name, ItemNode item, SuccessorKind kind) {
use = getRelevantLocatable() and
useImportEdge(use, name, item, kind)
Expand Down
6 changes: 3 additions & 3 deletions rust/ql/test/library-tests/path-resolution/main.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
mod my; // I1

#[rustfmt::skip]
use {{{my::{{self as my_alias, *}}}}}; // $ MISSING: item=I1
use {{{my::{{self as my_alias, *}}}}}; // $ item=I1
Comment thread
paldepind marked this conversation as resolved.

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

Expand Down Expand Up @@ -816,8 +816,8 @@ fn main() {
nested6::f(); // $ item=I116
nested8::f(); // $ item=I119
my3::f(); // $ item=I200
nested_f(); // $ MISSING: item=I201
my_alias::nested_f(); // $ MISSING: item=I201
nested_f(); // $ item=I201
my_alias::nested_f(); // $ item=I201
m18::m19::m20::g(); // $ item=I103
m23::f(); // $ item=I108
m24::f(); // $ item=I121
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ mod
| my/nested.rs:1:1:17:1 | mod nested1 |
| my/nested.rs:2:5:11:5 | mod nested2 |
resolvePath
| main.rs:4:8:4:9 | my | main.rs:1:1:1:7 | mod my |
| main.rs:4:14:4:17 | self | main.rs:1:1:1:7 | mod my |
| main.rs:6:5:6:6 | my | main.rs:1:1:1:7 | mod my |
| main.rs:6:5:6:14 | ...::nested | my.rs:1:1:1:15 | mod nested |
| main.rs:6:5:6:23 | ...::nested1 | my/nested.rs:1:1:17:1 | mod nested1 |
Expand Down Expand Up @@ -447,6 +449,9 @@ resolvePath
| main.rs:817:5:817:14 | ...::f | my2/nested2.rs:23:9:25:9 | fn f |
| main.rs:818:5:818:7 | my3 | my2/mod.rs:20:1:20:12 | mod my3 |
| main.rs:818:5:818:10 | ...::f | my2/my3/mod.rs:1:1:5:1 | fn f |
| main.rs:819:5:819:12 | nested_f | my/my4/my5/mod.rs:1:1:3:1 | fn f |
| main.rs:820:5:820:12 | my_alias | main.rs:1:1:1:7 | mod my |
| main.rs:820:5:820:22 | ...::nested_f | my/my4/my5/mod.rs:1:1:3:1 | fn f |
| main.rs:821:5:821:7 | m18 | main.rs:555:1:573:1 | mod m18 |
| main.rs:821:5:821:12 | ...::m19 | main.rs:560:5:572:5 | mod m19 |
| main.rs:821:5:821:17 | ...::m20 | main.rs:565:9:571:9 | mod m20 |
Expand Down