Skip to content

Commit c00bc1f

Browse files
Auto merge of #145907 - lolbinarycat:rustdoc-optimize-2, r=<try>
rustdoc: split build_impl into build_{local,external}_impl
2 parents 91ee6a4 + dc45ff1 commit c00bc1f

File tree

3 files changed

+163
-115
lines changed

3 files changed

+163
-115
lines changed

compiler/rustc_resolve/src/rustdoc.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -207,8 +207,10 @@ pub fn attrs_to_doc_fragments<'a, A: AttributeExt + Clone + 'a>(
207207
attrs: impl Iterator<Item = (&'a A, Option<DefId>)>,
208208
doc_only: bool,
209209
) -> (Vec<DocFragment>, ThinVec<A>) {
210-
let mut doc_fragments = Vec::new();
211-
let mut other_attrs = ThinVec::<A>::new();
210+
let (min_size, max_size) = attrs.size_hint();
211+
let size_hint = max_size.unwrap_or(min_size);
212+
let mut doc_fragments = Vec::with_capacity(size_hint);
213+
let mut other_attrs = ThinVec::<A>::with_capacity(if doc_only { 0 } else { size_hint });
212214
for (attr, item_id) in attrs {
213215
if let Some((doc_str, comment_kind)) = attr.doc_str_and_comment_kind() {
214216
let doc = beautify_doc_string(doc_str, comment_kind);
@@ -230,6 +232,9 @@ pub fn attrs_to_doc_fragments<'a, A: AttributeExt + Clone + 'a>(
230232
}
231233
}
232234

235+
doc_fragments.shrink_to_fit();
236+
other_attrs.shrink_to_fit();
237+
233238
unindent_doc_fragments(&mut doc_fragments);
234239

235240
(doc_fragments, other_attrs)

src/librustdoc/clean/inline.rs

Lines changed: 148 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -433,19 +433,97 @@ pub(crate) fn merge_attrs(
433433
}
434434
}
435435

436+
/// Inline an `impl`, inherent or of a trait. The `did` must be for an `impl` defined in the current crate.
437+
pub(crate) fn build_local_impl(
438+
cx: &mut DocContext<'_>,
439+
did: DefId,
440+
attrs: Option<(&[hir::Attribute], Option<LocalDefId>)>,
441+
ret: &mut Vec<clean::Item>,
442+
) {
443+
if !cx.inlined.insert(did.into()) {
444+
return;
445+
}
446+
debug_assert!(did.is_local(), "build_local_impl called on external impl");
447+
let tcx = cx.tcx;
448+
let _prof_timer = tcx.sess.prof.generic_activity("build_local_impl");
449+
450+
let associated_trait = tcx.impl_trait_ref(did).map(ty::EarlyBinder::skip_binder);
451+
452+
let impl_item = match did.as_local() {
453+
Some(did) => match &tcx.hir_expect_item(did).kind {
454+
hir::ItemKind::Impl(impl_) => impl_,
455+
_ => panic!("`DefID` passed to `build_impl` is not an `impl"),
456+
},
457+
None => unreachable!("build_local_impl called on external impl"),
458+
};
459+
460+
let for_ = clean_ty(impl_item.self_ty, cx);
461+
462+
let document_hidden = cx.render_options.document_hidden;
463+
let (trait_items, generics) = (
464+
impl_item
465+
.items
466+
.iter()
467+
.map(|&item| tcx.hir_impl_item(item))
468+
.filter(|item| {
469+
// Filter out impl items whose corresponding trait item has `doc(hidden)`
470+
// not to document such impl items.
471+
// For inherent impls, we don't do any filtering, because that's already done in strip_hidden.rs.
472+
473+
// When `--document-hidden-items` is passed, we don't
474+
// do any filtering, too.
475+
if document_hidden {
476+
return true;
477+
}
478+
if let Some(associated_trait) = associated_trait {
479+
let assoc_tag = match item.kind {
480+
hir::ImplItemKind::Const(..) => ty::AssocTag::Const,
481+
hir::ImplItemKind::Fn(..) => ty::AssocTag::Fn,
482+
hir::ImplItemKind::Type(..) => ty::AssocTag::Type,
483+
};
484+
let trait_item = tcx
485+
.associated_items(associated_trait.def_id)
486+
.find_by_ident_and_kind(tcx, item.ident, assoc_tag, associated_trait.def_id)
487+
.unwrap(); // SAFETY: For all impl items there exists trait item that has the same name.
488+
!tcx.is_doc_hidden(trait_item.def_id)
489+
} else {
490+
true
491+
}
492+
})
493+
.map(|item| clean_impl_item(item, cx))
494+
.collect::<Vec<_>>(),
495+
clean_generics(impl_item.generics, cx),
496+
);
497+
build_impl_finalize(cx, did, attrs, ret, associated_trait, for_, trait_items, generics)
498+
}
499+
436500
/// Inline an `impl`, inherent or of a trait. The `did` must be for an `impl`.
437501
pub(crate) fn build_impl(
438502
cx: &mut DocContext<'_>,
439503
did: DefId,
440504
attrs: Option<(&[hir::Attribute], Option<LocalDefId>)>,
441505
ret: &mut Vec<clean::Item>,
506+
) {
507+
if did.is_local() {
508+
build_local_impl(cx, did, attrs, ret);
509+
} else {
510+
build_external_impl(cx, did, attrs, ret);
511+
}
512+
}
513+
514+
/// Inline an `impl`, inherent or of a trait. The `did` must be for an `impl` defined in an external crate.
515+
pub(crate) fn build_external_impl(
516+
cx: &mut DocContext<'_>,
517+
did: DefId,
518+
attrs: Option<(&[hir::Attribute], Option<LocalDefId>)>,
519+
ret: &mut Vec<clean::Item>,
442520
) {
443521
if !cx.inlined.insert(did.into()) {
444522
return;
445523
}
446524

447525
let tcx = cx.tcx;
448-
let _prof_timer = tcx.sess.prof.generic_activity("build_impl");
526+
let _prof_timer = tcx.sess.prof.generic_activity("build_external_impl");
449527

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

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

463541
// Only inline impl if the implemented trait is
464542
// reachable in rustdoc generated documentation
465-
if !did.is_local()
466-
&& let Some(traitref) = associated_trait
543+
if let Some(traitref) = associated_trait
467544
&& !is_directly_public(cx, traitref.def_id)
468545
{
469546
return;
470547
}
471548

472-
let impl_item = match did.as_local() {
473-
Some(did) => match &tcx.hir_expect_item(did).kind {
474-
hir::ItemKind::Impl(impl_) => Some(impl_),
475-
_ => panic!("`DefID` passed to `build_impl` is not an `impl"),
476-
},
477-
None => None,
478-
};
479-
480-
let for_ = match &impl_item {
481-
Some(impl_) => clean_ty(impl_.self_ty, cx),
482-
None => clean_middle_ty(
483-
ty::Binder::dummy(tcx.type_of(did).instantiate_identity()),
484-
cx,
485-
Some(did),
486-
None,
487-
),
488-
};
549+
let for_ = clean_middle_ty(
550+
ty::Binder::dummy(tcx.type_of(did).instantiate_identity()),
551+
cx,
552+
Some(did),
553+
None,
554+
);
489555

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

565+
debug_assert!(!did.is_local(), "build_external_impl called on local impl");
566+
567+
let document_hidden = cx.render_options.document_hidden;
568+
let (trait_items, generics) = (
569+
tcx.associated_items(did)
570+
.in_definition_order()
571+
.filter(|item| !item.is_impl_trait_in_trait())
572+
.filter(|item| {
573+
// If this is a trait impl, filter out associated items whose corresponding item
574+
// in the associated trait is marked `doc(hidden)`.
575+
// If this is an inherent impl, filter out private associated items.
576+
if let Some(associated_trait) = associated_trait {
577+
let trait_item = tcx
578+
.associated_items(associated_trait.def_id)
579+
.find_by_ident_and_kind(
580+
tcx,
581+
item.ident(tcx),
582+
item.as_tag(),
583+
associated_trait.def_id,
584+
)
585+
.unwrap(); // corresponding associated item has to exist
586+
document_hidden || !tcx.is_doc_hidden(trait_item.def_id)
587+
} else {
588+
item.visibility(tcx).is_public()
589+
}
590+
})
591+
.map(|item| clean_middle_assoc_item(item, cx))
592+
.collect::<Vec<_>>(),
593+
clean::enter_impl_trait(cx, |cx| clean_ty_generics(cx, did)),
594+
);
595+
build_impl_finalize(cx, did, attrs, ret, associated_trait, for_, trait_items, generics)
596+
}
597+
598+
fn build_impl_finalize<'tcx>(
599+
cx: &mut DocContext<'tcx>,
600+
did: DefId,
601+
attrs: Option<(&[rustc_hir::Attribute], Option<LocalDefId>)>,
602+
ret: &mut Vec<Item>,
603+
associated_trait: Option<ty::TraitRef<'tcx>>,
604+
for_: Type,
605+
trait_items: Vec<Item>,
606+
generics: clean::Generics,
607+
) {
608+
let tcx = cx.tcx;
499609
let document_hidden = cx.render_options.document_hidden;
500-
let (trait_items, generics) = match impl_item {
501-
Some(impl_) => (
502-
impl_
503-
.items
504-
.iter()
505-
.map(|&item| tcx.hir_impl_item(item))
506-
.filter(|item| {
507-
// Filter out impl items whose corresponding trait item has `doc(hidden)`
508-
// not to document such impl items.
509-
// For inherent impls, we don't do any filtering, because that's already done in strip_hidden.rs.
510-
511-
// When `--document-hidden-items` is passed, we don't
512-
// do any filtering, too.
513-
if document_hidden {
514-
return true;
515-
}
516-
if let Some(associated_trait) = associated_trait {
517-
let assoc_tag = match item.kind {
518-
hir::ImplItemKind::Const(..) => ty::AssocTag::Const,
519-
hir::ImplItemKind::Fn(..) => ty::AssocTag::Fn,
520-
hir::ImplItemKind::Type(..) => ty::AssocTag::Type,
521-
};
522-
let trait_item = tcx
523-
.associated_items(associated_trait.def_id)
524-
.find_by_ident_and_kind(
525-
tcx,
526-
item.ident,
527-
assoc_tag,
528-
associated_trait.def_id,
529-
)
530-
.unwrap(); // SAFETY: For all impl items there exists trait item that has the same name.
531-
!tcx.is_doc_hidden(trait_item.def_id)
532-
} else {
533-
true
534-
}
535-
})
536-
.map(|item| clean_impl_item(item, cx))
537-
.collect::<Vec<_>>(),
538-
clean_generics(impl_.generics, cx),
539-
),
540-
None => (
541-
tcx.associated_items(did)
542-
.in_definition_order()
543-
.filter(|item| !item.is_impl_trait_in_trait())
544-
.filter(|item| {
545-
// If this is a trait impl, filter out associated items whose corresponding item
546-
// in the associated trait is marked `doc(hidden)`.
547-
// If this is an inherent impl, filter out private associated items.
548-
if let Some(associated_trait) = associated_trait {
549-
let trait_item = tcx
550-
.associated_items(associated_trait.def_id)
551-
.find_by_ident_and_kind(
552-
tcx,
553-
item.ident(tcx),
554-
item.as_tag(),
555-
associated_trait.def_id,
556-
)
557-
.unwrap(); // corresponding associated item has to exist
558-
document_hidden || !tcx.is_doc_hidden(trait_item.def_id)
559-
} else {
560-
item.visibility(tcx).is_public()
561-
}
562-
})
563-
.map(|item| clean_middle_assoc_item(item, cx))
564-
.collect::<Vec<_>>(),
565-
clean::enter_impl_trait(cx, |cx| clean_ty_generics(cx, did)),
566-
),
567-
};
568610
let polarity = tcx.impl_polarity(did);
569611
let trait_ = associated_trait
570612
.map(|t| clean_trait_ref_with_constraints(cx, ty::Binder::dummy(t), ThinVec::new()));
571613
if trait_.as_ref().map(|t| t.def_id()) == tcx.lang_items().deref_trait() {
572614
super::build_deref_target_impls(cx, &trait_items, ret);
573615
}
616+
if !document_hidden {
617+
// Return if the trait itself or any types of the generic parameters are doc(hidden).
618+
let mut stack: Vec<&Type> = vec![&for_];
574619

575-
// Return if the trait itself or any types of the generic parameters are doc(hidden).
576-
let mut stack: Vec<&Type> = vec![&for_];
577-
578-
if let Some(did) = trait_.as_ref().map(|t| t.def_id())
579-
&& !document_hidden
580-
&& tcx.is_doc_hidden(did)
581-
{
582-
return;
583-
}
584-
585-
if let Some(generics) = trait_.as_ref().and_then(|t| t.generics()) {
586-
stack.extend(generics);
587-
}
588-
589-
while let Some(ty) = stack.pop() {
590-
if let Some(did) = ty.def_id(&cx.cache)
591-
&& !document_hidden
620+
if let Some(did) = trait_.as_ref().map(|t| t.def_id())
592621
&& tcx.is_doc_hidden(did)
593622
{
594623
return;
595624
}
596-
if let Some(generics) = ty.generics() {
625+
626+
if let Some(generics) = trait_.as_ref().and_then(|t| t.generics()) {
597627
stack.extend(generics);
598628
}
599-
}
600629

630+
while let Some(ty) = stack.pop() {
631+
if let Some(did) = ty.def_id(&cx.cache)
632+
&& tcx.is_doc_hidden(did)
633+
{
634+
return;
635+
}
636+
if let Some(generics) = ty.generics() {
637+
stack.extend(generics);
638+
}
639+
}
640+
}
601641
if let Some(did) = trait_.as_ref().map(|t| t.def_id()) {
602642
cx.with_param_env(did, |cx| {
603643
record_extern_trait(cx, did);
604644
});
605645
}
606-
607646
let (merged_attrs, cfg) = merge_attrs(cx, load_attrs(cx, did), attrs);
608647
trace!("merged_attrs={merged_attrs:?}");
609-
610648
trace!(
611649
"build_impl: impl {:?} for {:?}",
612650
trait_.as_ref().map(|t| t.def_id()),
@@ -620,7 +658,7 @@ pub(crate) fn build_impl(
620658
generics,
621659
trait_,
622660
for_,
623-
items: trait_items,
661+
items: trait_items.to_vec(),
624662
polarity,
625663
kind: if utils::has_doc_flag(tcx, did, sym::fake_variadic) {
626664
ImplKind::FakeVariadic

src/librustdoc/passes/collect_trait_impls.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ pub(crate) fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) ->
5252
for &cnum in tcx.crates(()) {
5353
for &impl_def_id in tcx.trait_impls_in_crate(cnum) {
5454
cx.with_param_env(impl_def_id, |cx| {
55-
inline::build_impl(cx, impl_def_id, None, &mut new_items_external);
55+
inline::build_external_impl(cx, impl_def_id, None, &mut new_items_external);
5656
});
5757
}
5858
}
@@ -79,7 +79,12 @@ pub(crate) fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) ->
7979
parent = tcx.opt_parent(did);
8080
}
8181
cx.with_param_env(impl_def_id, |cx| {
82-
inline::build_impl(cx, impl_def_id, Some((&attr_buf, None)), &mut new_items_local);
82+
inline::build_local_impl(
83+
cx,
84+
impl_def_id,
85+
Some((&attr_buf, None)),
86+
&mut new_items_local,
87+
);
8388
});
8489
attr_buf.clear();
8590
}
@@ -90,7 +95,7 @@ pub(crate) fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) ->
9095
// Try to inline primitive impls from other crates.
9196
if !def_id.is_local() {
9297
cx.with_param_env(def_id, |cx| {
93-
inline::build_impl(cx, def_id, None, &mut new_items_external);
98+
inline::build_external_impl(cx, def_id, None, &mut new_items_external);
9499
});
95100
}
96101
}

0 commit comments

Comments
 (0)