Skip to content

Commit 5d3b542

Browse files
authored
Merge pull request #20453 from hvitved/rust/path-resolution-use-reexport
Rust: Path resolution improvements
2 parents b85ab3c + f6bdfba commit 5d3b542

File tree

9 files changed

+923
-818
lines changed

9 files changed

+923
-818
lines changed

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

Lines changed: 47 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -72,9 +72,9 @@ private ItemNode getAChildSuccessor(ItemNode item, string name, SuccessorKind ki
7272
if item instanceof ImplOrTraitItemNode and result instanceof AssocItem
7373
then kind.isExternal()
7474
else
75-
if result instanceof Use
76-
then kind.isInternal()
77-
else kind.isBoth()
75+
if result.isPublic()
76+
then kind.isBoth()
77+
else kind.isInternal()
7878
)
7979
}
8080

@@ -165,6 +165,20 @@ abstract class ItemNode extends Locatable {
165165
/** Gets the visibility of this item, if any. */
166166
abstract Visibility getVisibility();
167167

168+
/**
169+
* Holds if this item is public.
170+
*
171+
* This is the case when this item either has `pub` visibility (but is not
172+
* a `use`; a `use` itself is not visible from the outside), or when this
173+
* item is a variant.
174+
*/
175+
predicate isPublic() {
176+
exists(this.getVisibility()) and
177+
not this instanceof Use
178+
or
179+
this instanceof Variant
180+
}
181+
168182
/** Gets the `i`th type parameter of this item, if any. */
169183
abstract TypeParam getTypeParam(int i);
170184

@@ -380,9 +394,7 @@ abstract private class ModuleLikeNode extends ItemNode {
380394

381395
private class SourceFileItemNode extends ModuleLikeNode, SourceFile {
382396
pragma[nomagic]
383-
ModuleLikeNode getSuper() {
384-
result = any(ModuleItemNode mod | fileImport(mod, this)).getASuccessor("super")
385-
}
397+
ModuleLikeNode getSuper() { fileImport(result.getAnItemInScope(), this) }
386398

387399
override string getName() { result = "(source file)" }
388400

@@ -1300,7 +1312,8 @@ private predicate useTreeDeclares(UseTree tree, string name) {
13001312
*/
13011313
pragma[nomagic]
13021314
private predicate declaresDirectly(ItemNode item, Namespace ns, string name) {
1303-
exists(ItemNode child, SuccessorKind kind | child = getAChildSuccessor(item, name, kind) |
1315+
exists(ItemNode child, SuccessorKind kind |
1316+
child = getAChildSuccessor(item, name, kind) and
13041317
child.getNamespace() = ns and
13051318
kind.isInternalOrBoth()
13061319
)
@@ -1491,6 +1504,13 @@ private ItemNode resolvePathCandQualifier(RelevantPath qualifier, RelevantPath p
14911504
name = path.getText()
14921505
}
14931506

1507+
pragma[nomagic]
1508+
private Crate getCrate0(Locatable l) { result.getASourceFile().getFile() = l.getFile() }
1509+
1510+
bindingset[l]
1511+
pragma[inline_late]
1512+
private Crate getCrate(Locatable l) { result = getCrate0(l) }
1513+
14941514
/**
14951515
* Gets the item that `path` resolves to in `ns` when `qualifier` is the
14961516
* qualifier of `path` and `qualifier` resolves to `q`, if any.
@@ -1501,8 +1521,17 @@ private ItemNode resolvePathCandQualified(
15011521
) {
15021522
exists(string name, SuccessorKind kind |
15031523
q = resolvePathCandQualifier(qualifier, path, name) and
1504-
result = getASuccessor(q, name, ns, kind) and
1524+
result = getASuccessor(q, name, ns, kind)
1525+
|
15051526
kind.isExternalOrBoth()
1527+
or
1528+
// Non-public items are visible to paths in descendant modules of the declaring
1529+
// module; the declaration may happen via a `use` statement, where the item
1530+
// being used is _not_ itself in an ancestor module, and we currently don't track
1531+
// that information in `getASuccessor`. So, for simplicity, we allow for non-public
1532+
// items when the path and the item are in the same crate.
1533+
getCrate(path) = getCrate(result) and
1534+
not result instanceof TypeParam
15061535
)
15071536
}
15081537

@@ -1646,10 +1675,12 @@ private ItemNode resolveUseTreeListItemQualifier(
16461675

16471676
pragma[nomagic]
16481677
private ItemNode resolveUseTreeListItem(Use use, UseTree tree) {
1649-
tree = use.getUseTree() and
1650-
result = resolvePathCand(tree.getPath())
1651-
or
1652-
result = resolveUseTreeListItem(use, tree, tree.getPath(), _)
1678+
exists(Path path | path = tree.getPath() |
1679+
tree = use.getUseTree() and
1680+
result = resolvePathCand(path)
1681+
or
1682+
result = resolveUseTreeListItem(use, tree, path, _)
1683+
)
16531684
}
16541685

16551686
/** Holds if `use` imports `item` as `name`. */
@@ -1673,7 +1704,10 @@ private predicate useImportEdge(Use use, string name, ItemNode item, SuccessorKi
16731704
item = used and
16741705
(
16751706
not tree.hasRename() and
1676-
name = item.getName()
1707+
exists(string pathName |
1708+
pathName = tree.getPath().getText() and
1709+
if pathName = "self" then name = item.getName() else name = pathName
1710+
)
16771711
or
16781712
exists(Rename rename | rename = tree.getRename() |
16791713
name = rename.getName().getText()

rust/ql/test/library-tests/dataflow/sources/CONSISTENCY/PathResolutionConsistency.expected

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ multipleCallTargets
1111
| test.rs:179:30:179:68 | ...::_print(...) |
1212
| test.rs:188:26:188:105 | ...::_print(...) |
1313
| test.rs:229:22:229:72 | ... .read_to_string(...) |
14+
| test.rs:664:22:664:43 | file.read(...) |
15+
| test.rs:673:22:673:41 | f1.read(...) |
1416
| test.rs:697:18:697:38 | ...::_print(...) |
1517
| test.rs:702:18:702:45 | ...::_print(...) |
1618
| test.rs:720:38:720:42 | ...::_print(...) |

0 commit comments

Comments
 (0)