Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions compiler/rustc_resolve/src/rustdoc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -207,8 +207,10 @@ pub fn attrs_to_doc_fragments<'a, A: AttributeExt + Clone + 'a>(
attrs: impl Iterator<Item = (&'a A, Option<DefId>)>,
doc_only: bool,
) -> (Vec<DocFragment>, ThinVec<A>) {
let mut doc_fragments = Vec::new();
let mut other_attrs = ThinVec::<A>::new();
let (min_size, max_size) = attrs.size_hint();
let size_hint = max_size.unwrap_or(min_size);
let mut doc_fragments = Vec::with_capacity(size_hint);
let mut other_attrs = ThinVec::<A>::with_capacity(if doc_only { 0 } else { size_hint });
for (attr, item_id) in attrs {
if let Some((doc_str, comment_kind)) = attr.doc_str_and_comment_kind() {
let doc = beautify_doc_string(doc_str, comment_kind);
Expand All @@ -230,6 +232,9 @@ pub fn attrs_to_doc_fragments<'a, A: AttributeExt + Clone + 'a>(
}
}

doc_fragments.shrink_to_fit();
other_attrs.shrink_to_fit();

unindent_doc_fragments(&mut doc_fragments);

(doc_fragments, other_attrs)
Expand Down
258 changes: 148 additions & 110 deletions src/librustdoc/clean/inline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -433,19 +433,97 @@ pub(crate) fn merge_attrs(
}
}

/// Inline an `impl`, inherent or of a trait. The `did` must be for an `impl` defined in the current crate.
pub(crate) fn build_local_impl(
cx: &mut DocContext<'_>,
did: DefId,
attrs: Option<(&[hir::Attribute], Option<LocalDefId>)>,
ret: &mut Vec<clean::Item>,
) {
if !cx.inlined.insert(did.into()) {
return;
}
debug_assert!(did.is_local(), "build_local_impl called on external impl");
let tcx = cx.tcx;
let _prof_timer = tcx.sess.prof.generic_activity("build_local_impl");

let associated_trait = tcx.impl_trait_ref(did).map(ty::EarlyBinder::skip_binder);

let impl_item = match did.as_local() {
Some(did) => match &tcx.hir_expect_item(did).kind {
hir::ItemKind::Impl(impl_) => impl_,
_ => panic!("`DefID` passed to `build_impl` is not an `impl"),
},
None => unreachable!("build_local_impl called on external impl"),
};

let for_ = clean_ty(impl_item.self_ty, cx);

let document_hidden = cx.render_options.document_hidden;
let (trait_items, generics) = (
impl_item
.items
.iter()
.map(|&item| tcx.hir_impl_item(item))
.filter(|item| {
// Filter out impl items whose corresponding trait item has `doc(hidden)`
// not to document such impl items.
// For inherent impls, we don't do any filtering, because that's already done in strip_hidden.rs.

// When `--document-hidden-items` is passed, we don't
// do any filtering, too.
if document_hidden {
return true;
}
if let Some(associated_trait) = associated_trait {
let assoc_tag = match item.kind {
hir::ImplItemKind::Const(..) => ty::AssocTag::Const,
hir::ImplItemKind::Fn(..) => ty::AssocTag::Fn,
hir::ImplItemKind::Type(..) => ty::AssocTag::Type,
};
let trait_item = tcx
.associated_items(associated_trait.def_id)
.find_by_ident_and_kind(tcx, item.ident, assoc_tag, associated_trait.def_id)
.unwrap(); // SAFETY: For all impl items there exists trait item that has the same name.
!tcx.is_doc_hidden(trait_item.def_id)
} else {
true
}
})
.map(|item| clean_impl_item(item, cx))
.collect::<Vec<_>>(),
clean_generics(impl_item.generics, cx),
);
build_impl_finalize(cx, did, attrs, ret, associated_trait, for_, trait_items, generics)
}

/// Inline an `impl`, inherent or of a trait. The `did` must be for an `impl`.
pub(crate) fn build_impl(
cx: &mut DocContext<'_>,
did: DefId,
attrs: Option<(&[hir::Attribute], Option<LocalDefId>)>,
ret: &mut Vec<clean::Item>,
) {
if did.is_local() {
build_local_impl(cx, did, attrs, ret);
} else {
build_external_impl(cx, did, attrs, ret);
}
}

/// Inline an `impl`, inherent or of a trait. The `did` must be for an `impl` defined in an external crate.
pub(crate) fn build_external_impl(
cx: &mut DocContext<'_>,
did: DefId,
attrs: Option<(&[hir::Attribute], Option<LocalDefId>)>,
ret: &mut Vec<clean::Item>,
) {
if !cx.inlined.insert(did.into()) {
return;
}

let tcx = cx.tcx;
let _prof_timer = tcx.sess.prof.generic_activity("build_impl");
let _prof_timer = tcx.sess.prof.generic_activity("build_external_impl");

let associated_trait = tcx.impl_trait_ref(did).map(ty::EarlyBinder::skip_binder);

Expand All @@ -462,30 +540,18 @@ pub(crate) fn build_impl(

// Only inline impl if the implemented trait is
// reachable in rustdoc generated documentation
if !did.is_local()
&& let Some(traitref) = associated_trait
if let Some(traitref) = associated_trait
&& !is_directly_public(cx, traitref.def_id)
{
return;
}

let impl_item = match did.as_local() {
Some(did) => match &tcx.hir_expect_item(did).kind {
hir::ItemKind::Impl(impl_) => Some(impl_),
_ => panic!("`DefID` passed to `build_impl` is not an `impl"),
},
None => None,
};

let for_ = match &impl_item {
Some(impl_) => clean_ty(impl_.self_ty, cx),
None => clean_middle_ty(
ty::Binder::dummy(tcx.type_of(did).instantiate_identity()),
cx,
Some(did),
None,
),
};
let for_ = clean_middle_ty(
ty::Binder::dummy(tcx.type_of(did).instantiate_identity()),
cx,
Some(did),
None,
);

// Only inline impl if the implementing type is
// reachable in rustdoc generated documentation
Expand All @@ -496,117 +562,89 @@ pub(crate) fn build_impl(
return;
}

debug_assert!(!did.is_local(), "build_external_impl called on local impl");

let document_hidden = cx.render_options.document_hidden;
let (trait_items, generics) = (
tcx.associated_items(did)
.in_definition_order()
.filter(|item| !item.is_impl_trait_in_trait())
.filter(|item| {
// If this is a trait impl, filter out associated items whose corresponding item
// in the associated trait is marked `doc(hidden)`.
// If this is an inherent impl, filter out private associated items.
if let Some(associated_trait) = associated_trait {
let trait_item = tcx
.associated_items(associated_trait.def_id)
.find_by_ident_and_kind(
tcx,
item.ident(tcx),
item.as_tag(),
associated_trait.def_id,
)
.unwrap(); // corresponding associated item has to exist
document_hidden || !tcx.is_doc_hidden(trait_item.def_id)
} else {
item.visibility(tcx).is_public()
}
})
.map(|item| clean_middle_assoc_item(item, cx))
.collect::<Vec<_>>(),
clean::enter_impl_trait(cx, |cx| clean_ty_generics(cx, did)),
);
build_impl_finalize(cx, did, attrs, ret, associated_trait, for_, trait_items, generics)
}

fn build_impl_finalize<'tcx>(
cx: &mut DocContext<'tcx>,
did: DefId,
attrs: Option<(&[rustc_hir::Attribute], Option<LocalDefId>)>,
ret: &mut Vec<Item>,
associated_trait: Option<ty::TraitRef<'tcx>>,
for_: Type,
trait_items: Vec<Item>,
generics: clean::Generics,
) {
let tcx = cx.tcx;
let document_hidden = cx.render_options.document_hidden;
let (trait_items, generics) = match impl_item {
Some(impl_) => (
impl_
.items
.iter()
.map(|&item| tcx.hir_impl_item(item))
.filter(|item| {
// Filter out impl items whose corresponding trait item has `doc(hidden)`
// not to document such impl items.
// For inherent impls, we don't do any filtering, because that's already done in strip_hidden.rs.

// When `--document-hidden-items` is passed, we don't
// do any filtering, too.
if document_hidden {
return true;
}
if let Some(associated_trait) = associated_trait {
let assoc_tag = match item.kind {
hir::ImplItemKind::Const(..) => ty::AssocTag::Const,
hir::ImplItemKind::Fn(..) => ty::AssocTag::Fn,
hir::ImplItemKind::Type(..) => ty::AssocTag::Type,
};
let trait_item = tcx
.associated_items(associated_trait.def_id)
.find_by_ident_and_kind(
tcx,
item.ident,
assoc_tag,
associated_trait.def_id,
)
.unwrap(); // SAFETY: For all impl items there exists trait item that has the same name.
!tcx.is_doc_hidden(trait_item.def_id)
} else {
true
}
})
.map(|item| clean_impl_item(item, cx))
.collect::<Vec<_>>(),
clean_generics(impl_.generics, cx),
),
None => (
tcx.associated_items(did)
.in_definition_order()
.filter(|item| !item.is_impl_trait_in_trait())
.filter(|item| {
// If this is a trait impl, filter out associated items whose corresponding item
// in the associated trait is marked `doc(hidden)`.
// If this is an inherent impl, filter out private associated items.
if let Some(associated_trait) = associated_trait {
let trait_item = tcx
.associated_items(associated_trait.def_id)
.find_by_ident_and_kind(
tcx,
item.ident(tcx),
item.as_tag(),
associated_trait.def_id,
)
.unwrap(); // corresponding associated item has to exist
document_hidden || !tcx.is_doc_hidden(trait_item.def_id)
} else {
item.visibility(tcx).is_public()
}
})
.map(|item| clean_middle_assoc_item(item, cx))
.collect::<Vec<_>>(),
clean::enter_impl_trait(cx, |cx| clean_ty_generics(cx, did)),
),
};
let polarity = tcx.impl_polarity(did);
let trait_ = associated_trait
.map(|t| clean_trait_ref_with_constraints(cx, ty::Binder::dummy(t), ThinVec::new()));
if trait_.as_ref().map(|t| t.def_id()) == tcx.lang_items().deref_trait() {
super::build_deref_target_impls(cx, &trait_items, ret);
}
if !document_hidden {
// Return if the trait itself or any types of the generic parameters are doc(hidden).
let mut stack: Vec<&Type> = vec![&for_];

// Return if the trait itself or any types of the generic parameters are doc(hidden).
let mut stack: Vec<&Type> = vec![&for_];

if let Some(did) = trait_.as_ref().map(|t| t.def_id())
&& !document_hidden
&& tcx.is_doc_hidden(did)
{
return;
}

if let Some(generics) = trait_.as_ref().and_then(|t| t.generics()) {
stack.extend(generics);
}

while let Some(ty) = stack.pop() {
if let Some(did) = ty.def_id(&cx.cache)
&& !document_hidden
if let Some(did) = trait_.as_ref().map(|t| t.def_id())
&& tcx.is_doc_hidden(did)
{
return;
}
if let Some(generics) = ty.generics() {

if let Some(generics) = trait_.as_ref().and_then(|t| t.generics()) {
stack.extend(generics);
}
}

while let Some(ty) = stack.pop() {
if let Some(did) = ty.def_id(&cx.cache)
&& tcx.is_doc_hidden(did)
{
return;
}
if let Some(generics) = ty.generics() {
stack.extend(generics);
}
}
}
if let Some(did) = trait_.as_ref().map(|t| t.def_id()) {
cx.with_param_env(did, |cx| {
record_extern_trait(cx, did);
});
}

let (merged_attrs, cfg) = merge_attrs(cx, load_attrs(cx, did), attrs);
trace!("merged_attrs={merged_attrs:?}");

trace!(
"build_impl: impl {:?} for {:?}",
trait_.as_ref().map(|t| t.def_id()),
Expand All @@ -620,7 +658,7 @@ pub(crate) fn build_impl(
generics,
trait_,
for_,
items: trait_items,
items: trait_items.to_vec(),
polarity,
kind: if utils::has_doc_flag(tcx, did, sym::fake_variadic) {
ImplKind::FakeVariadic
Expand Down
11 changes: 8 additions & 3 deletions src/librustdoc/passes/collect_trait_impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ pub(crate) fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) ->
for &cnum in tcx.crates(()) {
for &impl_def_id in tcx.trait_impls_in_crate(cnum) {
cx.with_param_env(impl_def_id, |cx| {
inline::build_impl(cx, impl_def_id, None, &mut new_items_external);
inline::build_external_impl(cx, impl_def_id, None, &mut new_items_external);
});
}
}
Expand All @@ -79,7 +79,12 @@ pub(crate) fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) ->
parent = tcx.opt_parent(did);
}
cx.with_param_env(impl_def_id, |cx| {
inline::build_impl(cx, impl_def_id, Some((&attr_buf, None)), &mut new_items_local);
inline::build_local_impl(
cx,
impl_def_id,
Some((&attr_buf, None)),
&mut new_items_local,
);
});
attr_buf.clear();
}
Expand All @@ -90,7 +95,7 @@ pub(crate) fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) ->
// Try to inline primitive impls from other crates.
if !def_id.is_local() {
cx.with_param_env(def_id, |cx| {
inline::build_impl(cx, def_id, None, &mut new_items_external);
inline::build_external_impl(cx, def_id, None, &mut new_items_external);
});
}
}
Expand Down
Loading