3 use crate::core
::DocContext
;
4 use crate::fold
::DocFolder
;
6 use rustc_data_structures
::fx
::FxHashSet
;
7 use rustc_hir
::def_id
::{DefId, LOCAL_CRATE}
;
8 use rustc_middle
::ty
::DefIdTree
;
9 use rustc_span
::symbol
::sym
;
11 crate const COLLECT_TRAIT_IMPLS
: Pass
= Pass
{
12 name
: "collect-trait-impls",
13 run
: collect_trait_impls
,
14 description
: "retrieves trait impls for items in the crate",
17 crate fn collect_trait_impls(krate
: Crate
, cx
: &DocContext
<'_
>) -> Crate
{
18 let mut synth
= SyntheticImplCollector
::new(cx
);
19 let mut krate
= cx
.sess().time("collect_synthetic_impls", || synth
.fold_crate(krate
));
21 let prims
: FxHashSet
<PrimitiveType
> = krate
.primitives
.iter().map(|p
| p
.1).collect();
24 let mut coll
= ItemCollector
::new();
25 krate
= cx
.sess().time("collect_items_for_trait_impls", || coll
.fold_crate(krate
));
29 let mut new_items
= Vec
::new();
31 for &cnum
in cx
.tcx
.crates().iter() {
32 for &(did
, _
) in cx
.tcx
.all_trait_implementations(cnum
).iter() {
33 cx
.tcx
.sess
.time("build_extern_trait_impl", || {
34 inline
::build_impl(cx
, None
, did
, None
, &mut new_items
);
39 // Also try to inline primitive impls from other crates.
40 for &def_id
in PrimitiveType
::all_impls(cx
.tcx
).values().flatten() {
41 if !def_id
.is_local() {
42 cx
.sess().time("build_primitive_trait_impl", || {
43 inline
::build_impl(cx
, None
, def_id
, None
, &mut new_items
);
45 // FIXME(eddyb) is this `doc(hidden)` check needed?
46 if !cx
.tcx
.get_attrs(def_id
).lists(sym
::doc
).has_word(sym
::hidden
) {
47 let self_ty
= cx
.tcx
.type_of(def_id
);
48 let impls
= get_auto_trait_and_blanket_impls(cx
, self_ty
, def_id
);
49 let mut renderinfo
= cx
.renderinfo
.borrow_mut();
51 new_items
.extend(impls
.filter(|i
| renderinfo
.inlined
.insert(i
.def_id
)));
57 let mut cleaner
= BadImplStripper { prims, items: crate_items }
;
59 // scan through included items ahead of time to splice in Deref targets to the "valid" sets
60 for it
in &new_items
{
61 if let ImplItem(Impl { ref for_, ref trait_, ref items, .. }
) = it
.kind
{
62 if cleaner
.keep_item(for_
) && trait_
.def_id() == cx
.tcx
.lang_items().deref_trait() {
65 .find_map(|item
| match item
.kind
{
66 TypedefItem(ref t
, true) => Some(&t
.type_
),
69 .expect("Deref impl without Target type");
71 if let Some(prim
) = target
.primitive_type() {
72 cleaner
.prims
.insert(prim
);
73 } else if let Some(did
) = target
.def_id() {
74 cleaner
.items
.insert(did
);
80 new_items
.retain(|it
| {
81 if let ImplItem(Impl { ref for_, ref trait_, ref blanket_impl, .. }
) = it
.kind
{
82 cleaner
.keep_item(for_
)
83 || trait_
.as_ref().map_or(false, |t
| cleaner
.keep_item(t
))
84 || blanket_impl
.is_some()
90 // `tcx.crates()` doesn't include the local crate, and `tcx.all_trait_implementations`
91 // doesn't work with it anyway, so pull them from the HIR map instead
92 for &trait_did
in cx
.tcx
.all_traits(LOCAL_CRATE
).iter() {
93 for &impl_node
in cx
.tcx
.hir().trait_impls(trait_did
) {
94 let impl_did
= cx
.tcx
.hir().local_def_id(impl_node
);
95 cx
.tcx
.sess
.time("build_local_trait_impl", || {
96 let mut extra_attrs
= Vec
::new();
97 let mut parent
= cx
.tcx
.parent(impl_did
.to_def_id());
98 while let Some(did
) = parent
{
103 .filter(|attr
| attr
.has_name(sym
::doc
))
105 if let Some([attr
]) = attr
.meta_item_list().as_deref() {
106 attr
.has_name(sym
::cfg
)
113 parent
= cx
.tcx
.parent(did
);
118 impl_did
.to_def_id(),
126 if let Some(ref mut it
) = krate
.module
{
127 if let ModuleItem(Module { ref mut items, .. }
) = it
.kind
{
128 items
.extend(synth
.impls
);
129 items
.extend(new_items
);
131 panic
!("collect-trait-impls can't run");
134 panic
!("collect-trait-impls can't run");
140 struct SyntheticImplCollector
<'a
, 'tcx
> {
141 cx
: &'a DocContext
<'tcx
>,
145 impl<'a
, 'tcx
> SyntheticImplCollector
<'a
, 'tcx
> {
146 fn new(cx
: &'a DocContext
<'tcx
>) -> Self {
147 SyntheticImplCollector { cx, impls: Vec::new() }
151 impl<'a
, 'tcx
> DocFolder
for SyntheticImplCollector
<'a
, 'tcx
> {
152 fn fold_item(&mut self, i
: Item
) -> Option
<Item
> {
153 if i
.is_struct() || i
.is_enum() || i
.is_union() {
154 // FIXME(eddyb) is this `doc(hidden)` check needed?
155 if !self.cx
.tcx
.get_attrs(i
.def_id
).lists(sym
::doc
).has_word(sym
::hidden
) {
156 self.cx
.sess().time("get_auto_trait_and_blanket_synthetic_impls", || {
157 self.impls
.extend(get_auto_trait_and_blanket_impls(
159 self.cx
.tcx
.type_of(i
.def_id
),
166 Some(self.fold_item_recur(i
))
171 struct ItemCollector
{
172 items
: FxHashSet
<DefId
>,
181 impl DocFolder
for ItemCollector
{
182 fn fold_item(&mut self, i
: Item
) -> Option
<Item
> {
183 self.items
.insert(i
.def_id
);
185 Some(self.fold_item_recur(i
))
189 struct BadImplStripper
{
190 prims
: FxHashSet
<PrimitiveType
>,
191 items
: FxHashSet
<DefId
>,
194 impl BadImplStripper
{
195 fn keep_item(&self, ty
: &Type
) -> bool
{
196 if let Generic(_
) = ty
{
197 // keep impls made on generics
199 } else if let Some(prim
) = ty
.primitive_type() {
200 self.prims
.contains(&prim
)
201 } else if let Some(did
) = ty
.def_id() {
202 self.items
.contains(&did
)