Skip to content

Commit

Permalink
Merge pull request #18413 from ShoyuVanilla/extern-crate-reexport
Browse files Browse the repository at this point in the history
fix: Allow public re-export of `extern crate` import
  • Loading branch information
Veykril authored Oct 28, 2024
2 parents 9a7fd6f + 0abb563 commit b12859a
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 3 deletions.
5 changes: 5 additions & 0 deletions src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1166,6 +1166,11 @@ impl UseTree {
self.expand_impl(None, &mut cb)
}

/// The [`UseTreeKind`] of this `UseTree`.
pub fn kind(&self) -> &UseTreeKind {
&self.kind
}

fn expand_impl(
&self,
prefix: Option<ModPath>,
Expand Down
31 changes: 28 additions & 3 deletions src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ use crate::{
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::{
Expand Down Expand Up @@ -1058,8 +1058,33 @@ impl DefCollector<'_> {
vis: Visibility,
def_import_type: Option<ImportType>,
) -> 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);
Expand Down
46 changes: 46 additions & 0 deletions src/tools/rust-analyzer/crates/hir-def/src/nameres/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,52 @@ pub struct Arc;
);
}

#[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(
Expand Down

0 comments on commit b12859a

Please sign in to comment.