From 1ce809d0fa59ade71b13c200870b1fd5f74ceff4 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Tue, 24 Dec 2019 21:23:22 +0100 Subject: Add logic for resolving and checking visibility --- crates/ra_hir_def/src/resolver.rs | 21 +++++++++++++++++++ crates/ra_hir_def/src/visibility.rs | 40 ++++++++++++++++++++++++++++++++++++- 2 files changed, 60 insertions(+), 1 deletion(-) (limited to 'crates') diff --git a/crates/ra_hir_def/src/resolver.rs b/crates/ra_hir_def/src/resolver.rs index cf3c33d78..d509dc3dd 100644 --- a/crates/ra_hir_def/src/resolver.rs +++ b/crates/ra_hir_def/src/resolver.rs @@ -19,6 +19,7 @@ use crate::{ nameres::CrateDefMap, path::{ModPath, PathKind}, per_ns::PerNs, + visibility::{ResolvedVisibility, Visibility}, AdtId, AssocContainerId, ConstId, ContainerId, DefWithBodyId, EnumId, EnumVariantId, FunctionId, GenericDefId, HasModule, ImplId, LocalModuleId, Lookup, ModuleDefId, ModuleId, StaticId, StructId, TraitId, TypeAliasId, TypeParamId, VariantId, @@ -231,6 +232,26 @@ impl Resolver { Some(res) } + pub fn resolve_visibility( + &self, + db: &impl DefDatabase, + visibility: &Visibility, + ) -> Option { + 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( &self, db: &impl DefDatabase, diff --git a/crates/ra_hir_def/src/visibility.rs b/crates/ra_hir_def/src/visibility.rs index 7d881911d..901bc7191 100644 --- a/crates/ra_hir_def/src/visibility.rs +++ b/crates/ra_hir_def/src/visibility.rs @@ -9,7 +9,7 @@ use crate::{ db::DefDatabase, path::{ModPath, PathKind}, src::{HasChildSource, HasSource}, - AdtId, Lookup, VisibilityDefId, + AdtId, Lookup, ModuleId, VisibilityDefId, }; /// Visibility of an item, not yet resolved. @@ -89,6 +89,44 @@ impl Visibility { 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(node: T, db: &impl DefDatabase) -> Visibility -- cgit v1.2.3