Skip to content

Commit dc45ff1

Browse files
committed
rustdoc: split build_impl into build_{local,external}_impl
1 parent f16d1fc commit dc45ff1

File tree

2 files changed

+139
-96
lines changed

2 files changed

+139
-96
lines changed

src/librustdoc/clean/inline.rs

Lines changed: 131 additions & 93 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,82 +562,57 @@ 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
}
574-
575616
if !document_hidden {
576617
// Return if the trait itself or any types of the generic parameters are doc(hidden).
577618
let mut stack: Vec<&Type> = vec![&for_];
@@ -597,16 +638,13 @@ pub(crate) fn build_impl(
597638
}
598639
}
599640
}
600-
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)