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.rs90
1 files changed, 79 insertions, 11 deletions
diff --git a/crates/hir-def/src/visibility.rs b/crates/hir-def/src/visibility.rs
index aea2ac550e..2514e88864 100644
--- a/crates/hir-def/src/visibility.rs
+++ b/crates/hir-def/src/visibility.rs
@@ -2,6 +2,7 @@
use std::iter;
+use base_db::Crate;
use hir_expand::{InFile, Lookup};
use la_arena::ArenaMap;
use syntax::ast::{self, HasVisibility};
@@ -19,6 +20,8 @@ pub use crate::item_tree::{RawVisibility, VisibilityExplicitness};
pub enum Visibility {
/// Visibility is restricted to a certain module.
Module(ModuleId, VisibilityExplicitness),
+ /// Visibility is restricted to the crate.
+ PubCrate(Crate),
/// Visibility is unrestricted.
Public,
}
@@ -41,8 +44,13 @@ impl Visibility {
pub fn is_visible_from(self, db: &dyn DefDatabase, from_module: ModuleId) -> bool {
let to_module = match self {
Visibility::Module(m, _) => m,
+ Visibility::PubCrate(krate) => return from_module.krate == krate,
Visibility::Public => return true,
};
+ if from_module == to_module {
+ // if the modules are the same, visibility is trivially satisfied
+ return true;
+ }
// if they're not in the same crate, it can't be visible
if from_module.krate != to_module.krate {
return false;
@@ -59,12 +67,18 @@ impl Visibility {
) -> bool {
let to_module = match self {
Visibility::Module(m, _) => m,
+ Visibility::PubCrate(krate) => return def_map.krate() == krate,
Visibility::Public => return true,
};
// if they're not in the same crate, it can't be visible
if def_map.krate() != to_module.krate {
return false;
}
+
+ if from_module == to_module.local_id && def_map.block_id() == to_module.block {
+ // if the modules are the same, visibility is trivially satisfied
+ return true;
+ }
Self::is_visible_from_def_map_(db, def_map, to_module, from_module)
}
@@ -88,9 +102,7 @@ impl Visibility {
// `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);
- }
+ (Some(a), Some(b)) if a == b => {}
_ => {
if let Some(parent) = to_module.def_map(db).parent() {
to_module = parent;
@@ -132,26 +144,56 @@ impl Visibility {
pub(crate) fn max(self, other: Visibility, def_map: &DefMap) -> Option<Visibility> {
match (self, other) {
(_, Visibility::Public) | (Visibility::Public, _) => Some(Visibility::Public),
+ (Visibility::PubCrate(krate), Visibility::PubCrate(krateb)) => {
+ if krate == krateb {
+ Some(Visibility::PubCrate(krate))
+ } else {
+ None
+ }
+ }
+ (Visibility::Module(mod_, _), Visibility::PubCrate(krate))
+ | (Visibility::PubCrate(krate), Visibility::Module(mod_, _)) => {
+ if mod_.krate == krate {
+ Some(Visibility::PubCrate(krate))
+ } else {
+ None
+ }
+ }
(Visibility::Module(mod_a, expl_a), Visibility::Module(mod_b, expl_b)) => {
- if mod_a.krate != mod_b.krate {
+ if mod_a == mod_b {
+ // Most module visibilities are `pub(self)`, and assuming no errors
+ // this will be the common and thus fast path.
+ return Some(Visibility::Module(
+ mod_a,
+ match (expl_a, expl_b) {
+ (VisibilityExplicitness::Explicit, _)
+ | (_, VisibilityExplicitness::Explicit) => {
+ VisibilityExplicitness::Explicit
+ }
+ _ => VisibilityExplicitness::Implicit,
+ },
+ ));
+ }
+
+ if mod_a.krate() != def_map.krate() || mod_b.krate() != def_map.krate() {
return None;
}
let def_block = def_map.block_id();
- if (mod_a.containing_block(), mod_b.containing_block()) != (def_block, def_block) {
+ if mod_a.containing_block() != def_block || mod_b.containing_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_b, expl_b));
}
+ let mut b_ancestors =
+ iter::successors(Some(mod_b.local_id), |&m| def_map[m].parent);
if b_ancestors.any(|m| m == mod_a.local_id) {
// A is above B
return Some(Visibility::Module(mod_a, expl_a));
@@ -169,26 +211,52 @@ impl Visibility {
pub(crate) fn min(self, other: Visibility, def_map: &DefMap) -> Option<Visibility> {
match (self, other) {
(vis, Visibility::Public) | (Visibility::Public, vis) => Some(vis),
+ (Visibility::PubCrate(krate), Visibility::PubCrate(krateb)) => {
+ if krate == krateb {
+ Some(Visibility::PubCrate(krate))
+ } else {
+ None
+ }
+ }
+ (Visibility::Module(mod_, exp), Visibility::PubCrate(krate))
+ | (Visibility::PubCrate(krate), Visibility::Module(mod_, exp)) => {
+ if mod_.krate == krate { Some(Visibility::Module(mod_, exp)) } else { None }
+ }
(Visibility::Module(mod_a, expl_a), Visibility::Module(mod_b, expl_b)) => {
- if mod_a.krate != mod_b.krate {
+ if mod_a == mod_b {
+ // Most module visibilities are `pub(self)`, and assuming no errors
+ // this will be the common and thus fast path.
+ return Some(Visibility::Module(
+ mod_a,
+ match (expl_a, expl_b) {
+ (VisibilityExplicitness::Explicit, _)
+ | (_, VisibilityExplicitness::Explicit) => {
+ VisibilityExplicitness::Explicit
+ }
+ _ => VisibilityExplicitness::Implicit,
+ },
+ ));
+ }
+
+ if mod_a.krate() != def_map.krate() || mod_b.krate() != def_map.krate() {
return None;
}
let def_block = def_map.block_id();
- if (mod_a.containing_block(), mod_b.containing_block()) != (def_block, def_block) {
+ if mod_a.containing_block() != def_block || mod_b.containing_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_a));
}
+ let mut b_ancestors =
+ iter::successors(Some(mod_b.local_id), |&m| def_map[m].parent);
if b_ancestors.any(|m| m == mod_a.local_id) {
// A is above B
return Some(Visibility::Module(mod_b, expl_b));