]> git.lizzy.rs Git - rust.git/blobdiff - crates/hir_def/src/visibility.rs
parameters.split_last()
[rust.git] / crates / hir_def / src / visibility.rs
index 0e39519100f8b7c725a822c6c9c3b36145337448..80009010c52187ddf6f4a533708b8cbacf468024 100644 (file)
@@ -1,13 +1,17 @@
 //! 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.
@@ -21,7 +25,7 @@ pub enum RawVisibility {
 }
 
 impl RawVisibility {
-    pub(crate) const fn private() -> RawVisibility {
+    pub(crate) fn private() -> RawVisibility {
         RawVisibility::Module(ModPath::from_kind(PathKind::Super(0)))
     }
 
@@ -29,17 +33,19 @@ pub(crate) fn from_ast(
         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,
@@ -50,7 +56,7 @@ pub(crate) fn from_ast_with_hygiene_and_default(
         };
         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,
@@ -119,11 +125,34 @@ pub(crate) fn is_visible_from_def_map(
         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;
@@ -158,9 +187,8 @@ pub(crate) fn is_visible_from_def_map(
     /// 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;
@@ -190,3 +218,29 @@ pub(crate) fn max(self, other: Visibility, def_map: &DefMap) -> Option<Visibilit
         }
     }
 }
+
+/// 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)
+}