Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-def/src/visibility.rs')
-rw-r--r--crates/hir-def/src/visibility.rs48
1 files changed, 44 insertions, 4 deletions
diff --git a/crates/hir-def/src/visibility.rs b/crates/hir-def/src/visibility.rs
index 11d91513f1..4edb683592 100644
--- a/crates/hir-def/src/visibility.rs
+++ b/crates/hir-def/src/visibility.rs
@@ -139,13 +139,11 @@ impl Visibility {
let def_map_block = def_map.block_id();
loop {
match (to_module.block, def_map_block) {
- // to_module is not a block, so there is no parent def map to use
+ // `to_module` is not a block, so there is no parent def map to use.
(None, _) => (),
+ // `to_module` is at `def_map`'s block, no need to move further.
(Some(a), Some(b)) if a == b => {
cov_mark::hit!(is_visible_from_same_block_def_map);
- if let Some(parent) = def_map.parent() {
- to_module = parent;
- }
}
_ => {
if let Some(parent) = to_module.def_map(db).parent() {
@@ -193,6 +191,11 @@ impl Visibility {
return None;
}
+ let def_block = def_map.block_id();
+ if (mod_a.containing_block(), mod_b.containing_block()) != (def_block, def_block) {
+ return None;
+ }
+
let mut a_ancestors =
iter::successors(Some(mod_a.local_id), |&m| def_map[m].parent);
let mut b_ancestors =
@@ -212,6 +215,43 @@ impl Visibility {
}
}
}
+
+ /// Returns the least permissive visibility of `self` and `other`.
+ ///
+ /// If there is no subset relation between `self` and `other`, returns `None` (ie. they're only
+ /// visible in unrelated modules).
+ pub(crate) fn min(self, other: Visibility, def_map: &DefMap) -> Option<Visibility> {
+ match (self, other) {
+ (vis, Visibility::Public) | (Visibility::Public, vis) => Some(vis),
+ (Visibility::Module(mod_a, expl_a), Visibility::Module(mod_b, expl_b)) => {
+ if mod_a.krate != mod_b.krate {
+ return None;
+ }
+
+ let def_block = def_map.block_id();
+ if (mod_a.containing_block(), mod_b.containing_block()) != (def_block, def_block) {
+ return None;
+ }
+
+ let mut a_ancestors =
+ iter::successors(Some(mod_a.local_id), |&m| def_map[m].parent);
+ let mut b_ancestors =
+ iter::successors(Some(mod_b.local_id), |&m| def_map[m].parent);
+
+ if a_ancestors.any(|m| m == mod_b.local_id) {
+ // B is above A
+ return Some(Visibility::Module(mod_a, expl_b));
+ }
+
+ if b_ancestors.any(|m| m == mod_a.local_id) {
+ // A is above B
+ return Some(Visibility::Module(mod_b, expl_a));
+ }
+
+ None
+ }
+ }
+ }
}
/// Whether the item was imported through an explicit `pub(crate) use` or just a `use` without