diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 9259b3b5d3abb..8463fbfbd200b 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -24,6 +24,8 @@ use crate::clean::{ use super::Clean; +type Attrs<'hir> = rustc::ty::Attributes<'hir>; + /// Attempt to inline a definition into this AST. /// /// This function will fetch the definition specified, and if it is @@ -40,6 +42,7 @@ pub fn try_inline( cx: &DocContext<'_>, res: Res, name: ast::Name, + attrs: Option>, visited: &mut FxHashSet ) -> Option> { let did = if let Some(did) = res.opt_def_id() { @@ -49,10 +52,13 @@ pub fn try_inline( }; if did.is_local() { return None } let mut ret = Vec::new(); + + let attrs_clone = attrs.clone(); + let inner = match res { Res::Def(DefKind::Trait, did) => { record_extern_fqn(cx, did, clean::TypeKind::Trait); - ret.extend(build_impls(cx, did)); + ret.extend(build_impls(cx, did, attrs)); clean::TraitItem(build_external_trait(cx, did)) } Res::Def(DefKind::Fn, did) => { @@ -61,27 +67,27 @@ pub fn try_inline( } Res::Def(DefKind::Struct, did) => { record_extern_fqn(cx, did, clean::TypeKind::Struct); - ret.extend(build_impls(cx, did)); + ret.extend(build_impls(cx, did, attrs)); clean::StructItem(build_struct(cx, did)) } Res::Def(DefKind::Union, did) => { record_extern_fqn(cx, did, clean::TypeKind::Union); - ret.extend(build_impls(cx, did)); + ret.extend(build_impls(cx, did, attrs)); clean::UnionItem(build_union(cx, did)) } Res::Def(DefKind::TyAlias, did) => { record_extern_fqn(cx, did, clean::TypeKind::Typedef); - ret.extend(build_impls(cx, did)); + ret.extend(build_impls(cx, did, attrs)); clean::TypedefItem(build_type_alias(cx, did), false) } Res::Def(DefKind::Enum, did) => { record_extern_fqn(cx, did, clean::TypeKind::Enum); - ret.extend(build_impls(cx, did)); + ret.extend(build_impls(cx, did, attrs)); clean::EnumItem(build_enum(cx, did)) } Res::Def(DefKind::ForeignTy, did) => { record_extern_fqn(cx, did, clean::TypeKind::Foreign); - ret.extend(build_impls(cx, did)); + ret.extend(build_impls(cx, did, attrs)); clean::ForeignTypeItem } // Never inline enum variants but leave them shown as re-exports. @@ -113,11 +119,15 @@ pub fn try_inline( } _ => return None, }; + + let target_attrs = load_attrs(cx, did); + let attrs = merge_attrs(cx, target_attrs, attrs_clone); + cx.renderinfo.borrow_mut().inlined.insert(did); ret.push(clean::Item { source: cx.tcx.def_span(did).clean(cx), name: Some(name.clean(cx)), - attrs: load_attrs(cx, did), + attrs, inner, visibility: Some(clean::Public), stability: cx.tcx.lookup_stability(did).clean(cx), @@ -144,8 +154,8 @@ pub fn try_inline_glob(cx: &DocContext<'_>, res: Res, visited: &mut FxHashSet, did: DefId) -> clean::Attributes { - cx.tcx.get_attrs(did).clean(cx) +pub fn load_attrs<'hir>(cx: &DocContext<'hir>, did: DefId) -> Attrs<'hir> { + cx.tcx.get_attrs(did) } /// Record an external fully qualified name in the external_paths cache. @@ -187,7 +197,7 @@ pub fn build_external_trait(cx: &DocContext<'_>, did: DefId) -> clean::Trait { let generics = (cx.tcx.generics_of(did), &predicates).clean(cx); let generics = filter_non_trait_generics(did, generics); let (generics, supertrait_bounds) = separate_supertrait_bounds(generics); - let is_spotlight = load_attrs(cx, did).has_doc_flag(sym::spotlight); + let is_spotlight = load_attrs(cx, did).clean(cx).has_doc_flag(sym::spotlight); let is_auto = cx.tcx.trait_is_auto(did); clean::Trait { auto: auto_trait, @@ -274,23 +284,41 @@ fn build_type_alias(cx: &DocContext<'_>, did: DefId) -> clean::Typedef { } } -pub fn build_impls(cx: &DocContext<'_>, did: DefId) -> Vec { +pub fn build_impls(cx: &DocContext<'_>, did: DefId, attrs: Option>) -> Vec { let tcx = cx.tcx; let mut impls = Vec::new(); for &did in tcx.inherent_impls(did).iter() { - build_impl(cx, did, &mut impls); + build_impl(cx, did, attrs.clone(), &mut impls); } impls } -pub fn build_impl(cx: &DocContext<'_>, did: DefId, ret: &mut Vec) { +fn merge_attrs(cx: &DocContext<'_>, attrs: Attrs<'_>, other_attrs: Option> +) -> clean::Attributes { + let mut merged_attrs: Vec = Vec::with_capacity(attrs.len()); + // If we have additional attributes (from a re-export), + // always insert them first. This ensure that re-export + // doc comments show up before the original doc comments + // when we render them. + if let Some(a) = other_attrs { + merged_attrs.extend(a.iter().cloned()); + } + merged_attrs.extend(attrs.to_vec()); + merged_attrs.clean(cx) +} + +pub fn build_impl(cx: &DocContext<'_>, did: DefId, attrs: Option>, + ret: &mut Vec +) { if !cx.renderinfo.borrow_mut().inlined.insert(did) { return } - let attrs = load_attrs(cx, did); + let attrs = merge_attrs(cx, load_attrs(cx, did), attrs); + + let tcx = cx.tcx; let associated_trait = tcx.impl_trait_ref(did); @@ -416,7 +444,7 @@ fn build_module( let def_id = item.res.def_id(); if item.vis == ty::Visibility::Public { if did == def_id || !visited.insert(def_id) { continue } - if let Some(i) = try_inline(cx, item.res, item.ident.name, visited) { + if let Some(i) = try_inline(cx, item.res, item.ident.name, None, visited) { items.extend(i) } } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index a41b12e29b055..a7fb18c3f2c95 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2429,7 +2429,7 @@ impl Clean for ty::AssocItem { stability: get_stability(cx, self.def_id), deprecation: get_deprecation(cx, self.def_id), def_id: self.def_id, - attrs: inline::load_attrs(cx, self.def_id), + attrs: inline::load_attrs(cx, self.def_id).clean(cx), source: cx.tcx.def_span(self.def_id).clean(cx), inner, } @@ -3372,7 +3372,7 @@ impl Clean for ty::VariantDef { }; Item { name: Some(self.ident.clean(cx)), - attrs: inline::load_attrs(cx, self.def_id), + attrs: inline::load_attrs(cx, self.def_id).clean(cx), source: cx.tcx.def_span(self.def_id).clean(cx), visibility: Some(Inherited), def_id: self.def_id, @@ -3856,7 +3856,7 @@ fn build_deref_target_impls(cx: &DocContext<'_>, let primitive = match *target { ResolvedPath { did, .. } if did.is_local() => continue, ResolvedPath { did, .. } => { - ret.extend(inline::build_impls(cx, did)); + ret.extend(inline::build_impls(cx, did, None)); continue } _ => match target.primitive_type() { @@ -3894,7 +3894,7 @@ fn build_deref_target_impls(cx: &DocContext<'_>, }; if let Some(did) = did { if !did.is_local() { - inline::build_impl(cx, did, ret); + inline::build_impl(cx, did, None, ret); } } } @@ -3921,7 +3921,11 @@ impl Clean> for doctree::ExternCrate<'_> { }, ); - if let Some(items) = inline::try_inline(cx, res, self.name, &mut visited) { + if let Some(items) = inline::try_inline( + cx, res, self.name, + Some(rustc::ty::Attributes::Borrowed(self.attrs)), + &mut visited + ) { return items; } } @@ -3981,7 +3985,11 @@ impl Clean> for doctree::Import<'_> { } if !denied { let mut visited = FxHashSet::default(); - if let Some(items) = inline::try_inline(cx, path.res, name, &mut visited) { + if let Some(items) = inline::try_inline( + cx, path.res, name, + Some(rustc::ty::Attributes::Borrowed(self.attrs)), + &mut visited + ) { return items; } } diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs index a2a6b1efe820c..cd488b9df78d2 100644 --- a/src/librustdoc/passes/collect_trait_impls.rs +++ b/src/librustdoc/passes/collect_trait_impls.rs @@ -30,7 +30,7 @@ pub fn collect_trait_impls(krate: Crate, cx: &DocContext<'_>) -> Crate { for &cnum in cx.tcx.crates().iter() { for &did in cx.tcx.all_trait_implementations(cnum).iter() { - inline::build_impl(cx, did, &mut new_items); + inline::build_impl(cx, did, None, &mut new_items); } } @@ -66,7 +66,7 @@ pub fn collect_trait_impls(krate: Crate, cx: &DocContext<'_>) -> Crate { for def_id in primitive_impls.iter().filter_map(|&def_id| def_id) { if !def_id.is_local() { - inline::build_impl(cx, def_id, &mut new_items); + inline::build_impl(cx, def_id, None, &mut new_items); // FIXME(eddyb) is this `doc(hidden)` check needed? if !cx.tcx.get_attrs(def_id).lists(sym::doc).has_word(sym::hidden) { @@ -119,7 +119,7 @@ pub fn collect_trait_impls(krate: Crate, cx: &DocContext<'_>) -> Crate { for &trait_did in cx.all_traits.iter() { for &impl_node in cx.tcx.hir().trait_impls(trait_did) { let impl_did = cx.tcx.hir().local_def_id(impl_node); - inline::build_impl(cx, impl_did, &mut new_items); + inline::build_impl(cx, impl_did, None, &mut new_items); } } diff --git a/src/test/rustdoc/inline_cross/add-docs.rs b/src/test/rustdoc/inline_cross/add-docs.rs new file mode 100644 index 0000000000000..1af5e8f03b44e --- /dev/null +++ b/src/test/rustdoc/inline_cross/add-docs.rs @@ -0,0 +1,9 @@ +// aux-build:add-docs.rs + +extern crate inner; + + +// @has add_docs/struct.MyStruct.html +// @has add_docs/struct.MyStruct.html "Doc comment from 'pub use', Doc comment from definition" +/// Doc comment from 'pub use', +pub use inner::MyStruct; diff --git a/src/test/rustdoc/inline_cross/auxiliary/add-docs.rs b/src/test/rustdoc/inline_cross/auxiliary/add-docs.rs new file mode 100644 index 0000000000000..85efa508f30b5 --- /dev/null +++ b/src/test/rustdoc/inline_cross/auxiliary/add-docs.rs @@ -0,0 +1,4 @@ +#![crate_name = "inner"] + +/// Doc comment from definition +pub struct MyStruct;