diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 00c6e38839f54..f0991306307a1 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -445,12 +445,21 @@ impl Item { cx: &mut DocContext<'_>, ) -> Item { let ast_attrs = cx.tcx.get_attrs(def_id); + let mut clean_attrs = box ast_attrs.clean(cx); + + if let Some(inlined_ids) = cx.cache.inlined_items.get(&def_id).cloned() { + tracing::debug!("extending docstrings of {:?} with {:?}", def_id, inlined_ids); + for &inlined_id in inlined_ids.iter() { + let other_attrs = cx.tcx.get_attrs(inlined_id).clean(cx); + clean_attrs.doc_strings.extend(other_attrs.doc_strings); + } + } Self::from_def_id_and_attrs_and_parts( def_id, name, kind, - box ast_attrs.clean(cx), + clean_attrs, cx, ast_attrs.cfg(cx.tcx, &cx.cache.hidden_cfg), ) diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index a8fef4a317802..182d484cb34ef 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -1,7 +1,7 @@ use std::mem; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX}; +use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, CRATE_DEF_INDEX}; use rustc_middle::middle::privacy::AccessLevels; use rustc_middle::ty::TyCtxt; use rustc_span::{sym, Symbol}; @@ -53,11 +53,16 @@ crate struct Cache { /// This map is used when writing out the special 'implementors' /// javascript file. By using the exact path that the type /// is declared with, we ensure that each path will be identical + /// /// to the path used if the corresponding type is inlined. By /// doing this, we can detect duplicate impls on a trait page, and only display /// the impl for the inlined type. crate exact_paths: FxHashMap>, + /// Associates every items with all of its public reexports. This is used to merge + /// every docstrings that are relevant to show. + crate inlined_items: FxHashMap>, + /// This map contains information about all known traits of this crate. /// Implementations of a crate should inherit the documentation of the /// parent trait if no extra documentation is specified, and default methods diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 90cb5d586c211..2f48100e5b328 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -4,7 +4,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::Node; use rustc_hir::CRATE_HIR_ID; use rustc_middle::middle::privacy::AccessLevel; @@ -68,6 +68,7 @@ crate struct RustdocVisitor<'a, 'tcx> { /// Are the current module and all of its parents public? inside_public_path: bool, exact_paths: FxHashMap>, + inlined_items: FxHashMap>, } impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { @@ -78,6 +79,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { RustdocVisitor { cx, view_item_stack: stack, + inlined_items: FxHashMap::default(), inlining: false, inside_public_path: true, exact_paths: FxHashMap::default(), @@ -144,6 +146,8 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { .collect(); self.cx.cache.exact_paths = self.exact_paths; + self.cx.cache.inlined_items = self.inlined_items; + top_level_module } @@ -194,6 +198,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { }; let use_attrs = tcx.hir().attrs(id); + // Don't inline `doc(hidden)` imports so they can be stripped at a later stage. let is_no_inline = use_attrs.lists(sym::doc).has_word(sym::no_inline) || use_attrs.lists(sym::doc).has_word(sym::hidden); @@ -320,6 +325,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { om, please_inline, ) { + self.inlined_items.entry(path.res.def_id()).or_default().push(item.def_id); return; } }