Apply `doc(cfg)` from parent items while collecting trait impls

Because trait impls bypass the standard `clean` hierarchy they do not
participate in the `propagate_doc_cfg` pass, so instead we need to
pre-collect all possible `doc(cfg)` attributes that will apply to them
when cleaning.
This commit is contained in:
Wim Looman 2020-11-23 13:22:56 +01:00
parent 3d11e96569
commit d93f1d6c04
No known key found for this signature in database
GPG Key ID: C6F5748C6DD1607B
4 changed files with 75 additions and 7 deletions

View File

@ -339,9 +339,6 @@ crate fn build_impl(
return;
}
let attrs = merge_attrs(cx, parent_module.into(), load_attrs(cx, did), attrs);
debug!("merged_attrs={:?}", attrs);
let tcx = cx.tcx;
let associated_trait = tcx.impl_trait_ref(did);
@ -435,7 +432,7 @@ crate fn build_impl(
debug!("build_impl: impl {:?} for {:?}", trait_.def_id(), for_.def_id());
ret.push(clean::Item::from_def_id_and_parts(
let mut item = clean::Item::from_def_id_and_parts(
did,
None,
clean::ImplItem(clean::Impl {
@ -450,7 +447,10 @@ crate fn build_impl(
blanket_impl: None,
}),
cx,
));
);
item.attrs = merge_attrs(cx, parent_module.into(), load_attrs(cx, did), attrs);
debug!("merged_attrs={:?}", item.attrs);
ret.push(item);
}
fn build_module(cx: &DocContext<'_>, did: DefId, visited: &mut FxHashSet<DefId>) -> clean::Module {

View File

@ -5,6 +5,7 @@ use crate::fold::DocFolder;
use rustc_data_structures::fx::FxHashSet;
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
use rustc_middle::ty::DefIdTree;
use rustc_span::symbol::sym;
crate const COLLECT_TRAIT_IMPLS: Pass = Pass {
@ -90,7 +91,32 @@ crate fn collect_trait_impls(krate: Crate, cx: &DocContext<'_>) -> Crate {
for &impl_node in cx.tcx.hir().trait_impls(trait_did) {
let impl_did = cx.tcx.hir().local_def_id(impl_node);
cx.tcx.sess.time("build_local_trait_impl", || {
inline::build_impl(cx, None, impl_did.to_def_id(), None, &mut new_items);
let mut extra_attrs = Vec::new();
let mut parent = cx.tcx.parent(impl_did.to_def_id());
while let Some(did) = parent {
extra_attrs.extend(
cx.tcx
.get_attrs(did)
.iter()
.filter(|attr| attr.has_name(sym::doc))
.filter(|attr| {
if let Some([attr]) = attr.meta_item_list().as_deref() {
attr.has_name(sym::cfg)
} else {
false
}
})
.cloned(),
);
parent = cx.tcx.parent(did);
}
inline::build_impl(
cx,
None,
impl_did.to_def_id(),
Some(&extra_attrs),
&mut new_items,
);
});
}
}

View File

@ -25,12 +25,13 @@ pub mod unix_only {
// @has doc_cfg/unix_only/trait.ArmOnly.html \
// '//*[@id="main"]/*[@class="stability"]/*[@class="stab portability"]' \
// 'This is supported on Unix and ARM only.'
// @count - '//*[@class="stab portability"]' 2
// @count - '//*[@class="stab portability"]' 1
#[doc(cfg(target_arch = "arm"))]
pub trait ArmOnly {
fn unix_and_arm_only_function();
}
#[doc(cfg(target_arch = "arm"))]
impl ArmOnly for super::Portable {
fn unix_and_arm_only_function() {}
}

View File

@ -0,0 +1,41 @@
#![feature(doc_cfg)]
// @has 'issue_79201/trait.Foo.html'
// @count - '//*[@class="stab portability"]' 6
// @matches - '//*[@class="stab portability"]' 'crate feature foo-root'
// @matches - '//*[@class="stab portability"]' 'crate feature foo-public-mod'
// @matches - '//*[@class="stab portability"]' 'crate feature foo-private-mod'
// @matches - '//*[@class="stab portability"]' 'crate feature foo-fn'
// @matches - '//*[@class="stab portability"]' 'crate feature foo-method'
pub trait Foo {}
#[doc(cfg(feature = "foo-root"))]
impl crate::Foo for usize {}
#[doc(cfg(feature = "foo-public-mod"))]
pub mod public {
impl crate::Foo for u8 {}
}
#[doc(cfg(feature = "foo-private-mod"))]
mod private {
impl crate::Foo for u16 {}
}
#[doc(cfg(feature = "foo-const"))]
const _: () = {
impl crate::Foo for u32 {}
};
#[doc(cfg(feature = "foo-fn"))]
fn __() {
impl crate::Foo for u64 {}
}
#[doc(cfg(feature = "foo-method"))]
impl dyn Foo {
fn __() {
impl crate::Foo for u128 {}
}
}