diff --git a/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs b/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs index f5e03e5281e..a615abd1bbe 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs @@ -1025,7 +1025,7 @@ fn same_crate_reexport() { check_found_path( r#" mod bar { - mod foo { pub(super) struct S; } + mod foo { pub(crate) struct S; } pub(crate) use foo::*; } $0 @@ -1047,7 +1047,7 @@ fn same_crate_reexport_rename() { check_found_path( r#" mod bar { - mod foo { pub(super) struct S; } + mod foo { pub(crate) struct S; } pub(crate) use foo::S as U; } $0 diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs index 22b9c2b4e37..b9aec936903 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs @@ -985,12 +985,8 @@ fn update_recursive( for (name, res) in resolutions { match name { Some(name) => { - changed |= self.push_res_and_update_glob_vis( - module_id, - name, - res.with_visibility(vis), - import, - ); + changed |= + self.push_res_and_update_glob_vis(module_id, name, *res, vis, import); } None => { let tr = match res.take_types() { @@ -1043,10 +1039,11 @@ fn update_recursive( .collect::>(); for (glob_importing_module, glob_import_vis, use_) in glob_imports { + let vis = glob_import_vis.min(vis, &self.def_map).unwrap_or(glob_import_vis); self.update_recursive( glob_importing_module, resolutions, - glob_import_vis, + vis, Some(ImportType::Glob(use_)), depth + 1, ); @@ -1058,8 +1055,19 @@ fn push_res_and_update_glob_vis( module_id: LocalModuleId, name: &Name, mut defs: PerNs, + vis: Visibility, def_import_type: Option, ) -> bool { + if let Some((_, v, _)) = defs.types.as_mut() { + *v = v.min(vis, &self.def_map).unwrap_or(vis); + } + if let Some((_, v, _)) = defs.values.as_mut() { + *v = v.min(vis, &self.def_map).unwrap_or(vis); + } + if let Some((_, v, _)) = defs.macros.as_mut() { + *v = v.min(vis, &self.def_map).unwrap_or(vis); + } + let mut changed = false; if let Some(ImportType::Glob(_)) = def_import_type { diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/globs.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/globs.rs index a2696055ca1..543ab41cd59 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/globs.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/globs.rs @@ -412,3 +412,42 @@ pub fn function() {} "#]], ); } + +#[test] +fn regression_18308() { + check( + r#" +use outer::*; + +mod outer { + mod inner_superglob { + pub use super::*; + } + + // The importing order matters! + pub use inner_superglob::*; + use super::glob_target::*; +} + +mod glob_target { + pub struct ShouldBePrivate; +} +"#, + expect![[r#" + crate + glob_target: t + outer: t + + crate::glob_target + ShouldBePrivate: t v + + crate::outer + ShouldBePrivate: t v + inner_superglob: t + + crate::outer::inner_superglob + ShouldBePrivate: t v + inner_superglob: t + "#]], + ); +} diff --git a/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs b/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs index 3aeb88047a0..4edb6835922 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs @@ -191,6 +191,11 @@ pub(crate) fn max(self, other: Visibility, def_map: &DefMap) -> Option Option Option { + match (self, other) { + (vis, Visibility::Public) | (Visibility::Public, vis) => Some(vis), + (Visibility::Module(mod_a, expl_a), Visibility::Module(mod_b, expl_b)) => { + if mod_a.krate != mod_b.krate { + return None; + } + + let def_block = def_map.block_id(); + if (mod_a.containing_block(), mod_b.containing_block()) != (def_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_b)); + } + + if b_ancestors.any(|m| m == mod_a.local_id) { + // A is above B + return Some(Visibility::Module(mod_b, expl_a)); + } + + None + } + } + } } /// Whether the item was imported through an explicit `pub(crate) use` or just a `use` without