//! Defines hir-level representation of visibility (e.g. `pub` and `pub(crate)`).
+use std::sync::Arc;
+
use hir_expand::{hygiene::Hygiene, InFile};
+use la_arena::ArenaMap;
use syntax::ast;
use crate::{
db::DefDatabase,
nameres::DefMap,
path::{ModPath, PathKind},
- ModuleId,
+ resolver::HasResolver,
+ FunctionId, HasModule, LocalFieldId, ModuleId, VariantId,
};
/// Visibility of an item, not yet resolved.
}
impl RawVisibility {
- pub(crate) const fn private() -> RawVisibility {
+ pub(crate) fn private() -> RawVisibility {
RawVisibility::Module(ModPath::from_kind(PathKind::Super(0)))
}
db: &dyn DefDatabase,
node: InFile<Option<ast::Visibility>>,
) -> RawVisibility {
- Self::from_ast_with_hygiene(node.value, &Hygiene::new(db.upcast(), node.file_id))
+ Self::from_ast_with_hygiene(db, node.value, &Hygiene::new(db.upcast(), node.file_id))
}
pub(crate) fn from_ast_with_hygiene(
+ db: &dyn DefDatabase,
node: Option<ast::Visibility>,
hygiene: &Hygiene,
) -> RawVisibility {
- Self::from_ast_with_hygiene_and_default(node, RawVisibility::private(), hygiene)
+ Self::from_ast_with_hygiene_and_default(db, node, RawVisibility::private(), hygiene)
}
pub(crate) fn from_ast_with_hygiene_and_default(
+ db: &dyn DefDatabase,
node: Option<ast::Visibility>,
default: RawVisibility,
hygiene: &Hygiene,
};
match node.kind() {
ast::VisibilityKind::In(path) => {
- let path = ModPath::from_src(path, hygiene);
+ let path = ModPath::from_src(db.upcast(), path, hygiene);
let path = match path {
None => return RawVisibility::private(),
Some(path) => path,
def_map: &DefMap,
mut from_module: crate::LocalModuleId,
) -> bool {
- let to_module = match self {
+ let mut to_module = match self {
Visibility::Module(m) => m,
Visibility::Public => return true,
};
+ // `to_module` might be the root module of a block expression. Those have the same
+ // visibility as the containing module (even though no items are directly nameable from
+ // there, getting this right is important for method resolution).
+ // In that case, we adjust the visibility of `to_module` to point to the containing module.
+ // Additional complication: `to_module` might be in `from_module`'s `DefMap`, which we're
+ // currently computing, so we must not call the `def_map` query for it.
+ let arc;
+ let to_module_def_map =
+ if to_module.krate == def_map.krate() && to_module.block == def_map.block_id() {
+ cov_mark::hit!(is_visible_from_same_block_def_map);
+ def_map
+ } else {
+ arc = to_module.def_map(db);
+ &arc
+ };
+ let is_block_root = match to_module.block {
+ Some(_) => to_module_def_map[to_module.local_id].parent.is_none(),
+ None => false,
+ };
+ if is_block_root {
+ to_module = to_module_def_map.containing_module(to_module.local_id).unwrap();
+ }
+
// from_module needs to be a descendant of to_module
let mut def_map = def_map;
let mut parent_arc;
/// visible in unrelated modules).
pub(crate) fn max(self, other: Visibility, def_map: &DefMap) -> Option<Visibility> {
match (self, other) {
- (Visibility::Module(_), Visibility::Public)
- | (Visibility::Public, Visibility::Module(_))
- | (Visibility::Public, Visibility::Public) => Some(Visibility::Public),
+ (Visibility::Module(_) | Visibility::Public, Visibility::Public)
+ | (Visibility::Public, Visibility::Module(_)) => Some(Visibility::Public),
(Visibility::Module(mod_a), Visibility::Module(mod_b)) => {
if mod_a.krate != mod_b.krate {
return None;
}
}
}
+
+/// Resolve visibility of all specific fields of a struct or union variant.
+pub(crate) fn field_visibilities_query(
+ db: &dyn DefDatabase,
+ variant_id: VariantId,
+) -> Arc<ArenaMap<LocalFieldId, Visibility>> {
+ let var_data = match variant_id {
+ VariantId::StructId(it) => db.struct_data(it).variant_data.clone(),
+ VariantId::UnionId(it) => db.union_data(it).variant_data.clone(),
+ VariantId::EnumVariantId(it) => {
+ db.enum_data(it.parent).variants[it.local_id].variant_data.clone()
+ }
+ };
+ let resolver = variant_id.module(db).resolver(db);
+ let mut res = ArenaMap::default();
+ for (field_id, field_data) in var_data.fields().iter() {
+ res.insert(field_id, field_data.visibility.resolve(db, &resolver))
+ }
+ Arc::new(res)
+}
+
+/// Resolve visibility of a function.
+pub(crate) fn function_visibility_query(db: &dyn DefDatabase, def: FunctionId) -> Visibility {
+ let resolver = def.resolver(db);
+ db.function_data(def).visibility.resolve(db, &resolver)
+}