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.rs | 42 |
1 files changed, 42 insertions, 0 deletions
diff --git a/crates/hir-def/src/visibility.rs b/crates/hir-def/src/visibility.rs index 3aeb88047a..4edb683592 100644 --- a/crates/hir-def/src/visibility.rs +++ b/crates/hir-def/src/visibility.rs @@ -191,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 = @@ -210,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 |