diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs index b39a3fece62..b5bf2feb82a 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs @@ -1166,6 +1166,11 @@ pub fn expand( self.expand_impl(None, &mut cb) } + /// The [`UseTreeKind`] of this `UseTree`. + pub fn kind(&self) -> &UseTreeKind { + &self.kind + } + fn expand_impl( &self, prefix: Option, 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 b9aec936903..a37e3c70e22 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 @@ -31,7 +31,7 @@ item_scope::{ImportId, ImportOrExternCrate, ImportType, PerNsGlobImports}, item_tree::{ self, AttrOwner, FieldsShape, FileItemTreeId, ImportKind, ItemTree, ItemTreeId, - ItemTreeNode, Macro2, MacroCall, MacroRules, Mod, ModItem, ModKind, TreeId, + ItemTreeNode, Macro2, MacroCall, MacroRules, Mod, ModItem, ModKind, TreeId, UseTreeKind, }, macro_call_as_call_id, macro_call_as_call_id_with_eager, nameres::{ @@ -1058,8 +1058,33 @@ fn push_res_and_update_glob_vis( 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); + // `extern crate crate_name` things can be re-exported as `pub use crate_name`. + // But they cannot be re-exported as `pub use self::crate_name`, `pub use crate::crate_name` + // or `pub use ::crate_name`. + // + // This has been historically allowed, but may be not allowed in future + // https://github.com/rust-lang/rust/issues/127909 + if let Some((_, v, it)) = defs.types.as_mut() { + let is_extern_crate_reimport_without_prefix = || { + let Some(ImportOrExternCrate::ExternCrate(_)) = it else { + return false; + }; + let Some(ImportType::Import(id)) = def_import_type else { + return false; + }; + let use_id = id.import.lookup(self.db).id; + let item_tree = use_id.item_tree(self.db); + let use_kind = item_tree[use_id.value].use_tree.kind(); + let UseTreeKind::Single { path, .. } = use_kind else { + return false; + }; + path.segments().len() < 2 + }; + if is_extern_crate_reimport_without_prefix() { + *v = vis; + } else { + *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); diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests.rs index 7b02a89e5de..e1e30e5cec9 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests.rs @@ -385,6 +385,52 @@ fn extern_crate_rename() { ); } +#[test] +fn extern_crate_reexport() { + check( + r#" +//- /main.rs crate:main deps:importer +use importer::*; +use importer::extern_crate1::exported::*; +use importer::allowed_reexport::*; +use importer::extern_crate2::*; +use importer::not_allowed_reexport1; +use importer::not_allowed_reexport2; + +//- /importer.rs crate:importer deps:extern_crate1,extern_crate2 +extern crate extern_crate1; +extern crate extern_crate2; + +pub use extern_crate1; +pub use extern_crate1 as allowed_reexport; + +pub use ::extern_crate; +pub use self::extern_crate as not_allowed_reexport1; +pub use crate::extern_crate as not_allowed_reexport2; + +//- /extern_crate1.rs crate:extern_crate1 +pub mod exported { + pub struct PublicItem; + struct PrivateItem; +} + +pub struct Exported; + +//- /extern_crate2.rs crate:extern_crate2 +pub struct NotExported; +"#, + expect![[r#" + crate + Exported: t v + PublicItem: t v + allowed_reexport: t + exported: t + not_allowed_reexport1: _ + not_allowed_reexport2: _ + "#]], + ); +} + #[test] fn extern_crate_rename_2015_edition() { check(