diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 7a5cf8031375d..9e4c2a4e1974a 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -38,7 +38,7 @@ use rustc_target::spec::abi::Abi; use crate::clean::cfg::Cfg; use crate::clean::external_path; use crate::clean::inline::{self, print_inlined_const}; -use crate::clean::utils::{is_literal_expr, print_evaluated_const}; +use crate::clean::utils::{inherits_doc_hidden, is_literal_expr, print_evaluated_const}; use crate::core::DocContext; use crate::formats::cache::Cache; use crate::formats::item_type::ItemType; @@ -2489,6 +2489,15 @@ impl Import { pub(crate) fn imported_item_is_doc_hidden(&self, tcx: TyCtxt<'_>) -> bool { self.source.did.is_some_and(|did| tcx.is_doc_hidden(did)) } + + pub(crate) fn inherits_doc_hidden(&self, tcx: TyCtxt<'_>) -> bool { + self.imported_item_is_doc_hidden(tcx) + || self + .source + .did + .and_then(|did| did.as_local()) + .map_or(false, |did| inherits_doc_hidden(tcx, did, None)) + } } #[derive(Clone, Debug)] @@ -2499,6 +2508,12 @@ pub(crate) enum ImportKind { Glob, } +impl ImportKind { + pub fn is_glob(&self) -> bool { + matches!(self, Self::Glob) + } +} + #[derive(Clone, Debug)] pub(crate) struct ImportSource { pub(crate) path: Path, diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index 61376ab31dd28..8690fa0fdc44a 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -17,7 +17,7 @@ use rustc_target::spec::abi::Abi as RustcAbi; use rustdoc_json_types::*; -use crate::clean::{self, ItemId}; +use crate::clean::{self, ImportKind, ItemId}; use crate::formats::item_type::ItemType; use crate::formats::FormatRenderer; use crate::json::JsonRenderer; @@ -761,20 +761,22 @@ impl FromWithTcx for Discriminant { impl FromWithTcx for Import { fn from_tcx(import: clean::Import, tcx: TyCtxt<'_>) -> Self { - use clean::ImportKind::*; - let (name, glob) = match import.kind { - Simple(s) => (s.to_string(), false), - Glob => ( + let (name, glob, id) = match import.kind { + ImportKind::Simple(s) => { + let id = if import.inherits_doc_hidden(tcx) { + None + } else { + import.source.did.map(ItemId::from).map(|i| id_from_item_default(i, tcx)) + }; + (s.to_string(), false, id) + } + ImportKind::Glob => ( import.source.path.last_opt().unwrap_or_else(|| Symbol::intern("*")).to_string(), true, + import.source.did.map(ItemId::from).map(|i| id_from_item_default(i, tcx)), ), }; - Import { - source: import.source.path.whole_name(), - name, - id: import.source.did.map(ItemId::from).map(|i| id_from_item_default(i, tcx)), - glob, - } + Import { source: import.source.path.whole_name(), name, id, glob } } } diff --git a/src/librustdoc/passes/stripper.rs b/src/librustdoc/passes/stripper.rs index df955421ba487..5f40bcb2ba80e 100644 --- a/src/librustdoc/passes/stripper.rs +++ b/src/librustdoc/passes/stripper.rs @@ -245,7 +245,7 @@ pub(crate) struct ImportStripper<'tcx> { impl<'tcx> ImportStripper<'tcx> { fn import_should_be_hidden(&self, i: &Item, imp: &clean::Import) -> bool { - if self.is_json_output { + if self.is_json_output && imp.kind.is_glob() { // FIXME: This should be handled the same way as for HTML output. imp.imported_item_is_doc_hidden(self.tcx) } else { diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs index 5d979521885ad..32fa74943b5b0 100644 --- a/src/rustdoc-json-types/lib.rs +++ b/src/rustdoc-json-types/lib.rs @@ -669,10 +669,25 @@ pub struct Import { /// May be different from the last segment of `source` when renaming imports: /// `use source as name;` pub name: String, - /// The ID of the item being imported. Will be `None` in case of re-exports of primitives: - /// ```rust + /// The ID of the item being imported. Will be `None` in case of re-exports of primitives or + /// if the reexported item is `#[doc(hidden)]` or inherits it from one of its parents. + /// + /// Example of reexported primitive type: + /// + /// ``` /// pub use i32 as my_i32; /// ``` + /// + /// Example of reexported item which inherits `doc(hidden)`: + /// + /// ``` + /// #[doc(hidden)] + /// pub mod foo { + /// pub struct Bar; + /// } + /// + /// pub use foo::Bar; + /// ``` pub id: Option, /// Whether this import uses a glob: `use source::*;` pub glob: bool, diff --git a/tests/rustdoc-json/doc_hidden_reexports.rs b/tests/rustdoc-json/doc_hidden_reexports.rs new file mode 100644 index 0000000000000..daac4939d7f41 --- /dev/null +++ b/tests/rustdoc-json/doc_hidden_reexports.rs @@ -0,0 +1,19 @@ +// Regression test for . +// Ensures that the various "doc(hidden)" reexport cases are correctly handled. + +pub mod submodule { + #[doc(hidden)] + pub struct Hidden {} +} + +#[doc(hidden)] +mod x { + pub struct Y {} +} + +// @has "$.index[*].inner[?(@.import.name=='UsedHidden')].import.source" '"submodule::Hidden"' +// @has "$.index[*].inner[?(@.import.name=='UsedHidden')].import.id" "null" +pub use submodule::Hidden as UsedHidden; +// @has "$.index[*].inner[?(@.import.name=='Z')].import.source" '"x::Y"' +// @has "$.index[*].inner[?(@.import.name=='Z')].import.id" 'null' +pub use x::Y as Z; diff --git a/tests/rustdoc-json/reexport/pub_use_doc_hidden.rs b/tests/rustdoc-json/reexport/pub_use_doc_hidden.rs index 15d194ef5d925..09303cbd74e6a 100644 --- a/tests/rustdoc-json/reexport/pub_use_doc_hidden.rs +++ b/tests/rustdoc-json/reexport/pub_use_doc_hidden.rs @@ -6,8 +6,9 @@ mod repeat_n { pub struct RepeatN {} } -/// not here +/// is here pub use repeat_n::RepeatN; // @count "$.index[*][?(@.name=='pub_use_doc_hidden')].inner.items[*]" 0 +// @has "$.index[*][?(@.docs == 'is here')]" // @!has "$.index[*][?(@.docs == 'not here')]"