Add logic for resolving and checking visibility

This commit is contained in:
Florian Diebold 2019-12-24 21:23:22 +01:00
parent 069bf55cca
commit 1ce809d0fa
2 changed files with 60 additions and 1 deletions

View File

@ -19,6 +19,7 @@ use crate::{
nameres::CrateDefMap, nameres::CrateDefMap,
path::{ModPath, PathKind}, path::{ModPath, PathKind},
per_ns::PerNs, per_ns::PerNs,
visibility::{ResolvedVisibility, Visibility},
AdtId, AssocContainerId, ConstId, ContainerId, DefWithBodyId, EnumId, EnumVariantId, AdtId, AssocContainerId, ConstId, ContainerId, DefWithBodyId, EnumId, EnumVariantId,
FunctionId, GenericDefId, HasModule, ImplId, LocalModuleId, Lookup, ModuleDefId, ModuleId, FunctionId, GenericDefId, HasModule, ImplId, LocalModuleId, Lookup, ModuleDefId, ModuleId,
StaticId, StructId, TraitId, TypeAliasId, TypeParamId, VariantId, StaticId, StructId, TraitId, TypeAliasId, TypeParamId, VariantId,
@ -231,6 +232,26 @@ impl Resolver {
Some(res) Some(res)
} }
pub fn resolve_visibility(
&self,
db: &impl DefDatabase,
visibility: &Visibility,
) -> Option<ResolvedVisibility> {
match visibility {
Visibility::Module(mod_path) => {
let resolved = self.resolve_module_path_in_items(db, &mod_path).take_types()?;
match resolved {
ModuleDefId::ModuleId(m) => Some(ResolvedVisibility::Module(m)),
_ => {
// error: visibility needs to refer to module
None
}
}
}
Visibility::Public => Some(ResolvedVisibility::Public),
}
}
pub fn resolve_path_in_value_ns( pub fn resolve_path_in_value_ns(
&self, &self,
db: &impl DefDatabase, db: &impl DefDatabase,

View File

@ -9,7 +9,7 @@ use crate::{
db::DefDatabase, db::DefDatabase,
path::{ModPath, PathKind}, path::{ModPath, PathKind},
src::{HasChildSource, HasSource}, src::{HasChildSource, HasSource},
AdtId, Lookup, VisibilityDefId, AdtId, Lookup, ModuleId, VisibilityDefId,
}; };
/// Visibility of an item, not yet resolved. /// Visibility of an item, not yet resolved.
@ -89,6 +89,44 @@ impl Visibility {
ast::VisibilityKind::Pub => Visibility::Public, ast::VisibilityKind::Pub => Visibility::Public,
} }
} }
pub fn resolve(
&self,
db: &impl DefDatabase,
resolver: &crate::resolver::Resolver,
) -> ResolvedVisibility {
// we fall back to public visibility (i.e. fail open) if the path can't be resolved
resolver.resolve_visibility(db, self).unwrap_or(ResolvedVisibility::Public)
}
}
/// Visibility of an item, with the path resolved.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum ResolvedVisibility {
/// Visibility is restricted to a certain module.
Module(ModuleId),
/// Visibility is unrestricted.
Public,
}
impl ResolvedVisibility {
pub fn visible_from(self, db: &impl DefDatabase, from_module: ModuleId) -> bool {
let to_module = match self {
ResolvedVisibility::Module(m) => m,
ResolvedVisibility::Public => return true,
};
// if they're not in the same crate, it can't be visible
if from_module.krate != to_module.krate {
return false;
}
// from_module needs to be a descendant of to_module
let def_map = db.crate_def_map(from_module.krate);
let mut ancestors = std::iter::successors(Some(from_module), |m| {
let parent_id = def_map[m.local_id].parent?;
Some(ModuleId { local_id: parent_id, ..*m })
});
ancestors.any(|m| m == to_module)
}
} }
fn visibility_from_loc<T>(node: T, db: &impl DefDatabase) -> Visibility fn visibility_from_loc<T>(node: T, db: &impl DefDatabase) -> Visibility