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
: &mut DocContext
<'_
>) -> Crate
{
18 let (mut krate
, synth_impls
) = cx
.sess().time("collect_synthetic_impls", || {
19 let mut synth
= SyntheticImplCollector { cx, impls: Vec::new() }
;
20 (synth
.fold_crate(krate
), synth
.impls
)
23 let prims
: FxHashSet
<PrimitiveType
> = krate
.primitives
.iter().map(|p
| p
.1).collect();
26 let mut coll
= ItemCollector
::new();
27 krate
= cx
.sess().time("collect_items_for_trait_impls", || coll
.fold_crate(krate
));
31 let mut new_items
= Vec
::new();
33 for &cnum
in cx
.tcx
.crates().iter() {
34 for &(did
, _
) in cx
.tcx
.all_trait_implementations(cnum
).iter() {
35 cx
.tcx
.sess
.prof
.generic_activity("build_extern_trait_impl").run(|| {
36 inline
::build_impl(cx
, None
, did
, None
, &mut new_items
);
41 // Also try to inline primitive impls from other crates.
42 for &def_id
in PrimitiveType
::all_impls(cx
.tcx
).values().flatten() {
43 if !def_id
.is_local() {
44 cx
.tcx
.sess
.prof
.generic_activity("build_primitive_trait_impls").run(|| {
45 inline
::build_impl(cx
, None
, def_id
, None
, &mut new_items
);
47 // FIXME(eddyb) is this `doc(hidden)` check needed?
48 if !cx
.tcx
.get_attrs(def_id
).lists(sym
::doc
).has_word(sym
::hidden
) {
49 let impls
= get_auto_trait_and_blanket_impls(cx
, def_id
);
50 new_items
.extend(impls
.filter(|i
| cx
.inlined
.insert(i
.def_id
)));
56 let mut cleaner
= BadImplStripper { prims, items: crate_items }
;
58 // scan through included items ahead of time to splice in Deref targets to the "valid" sets
59 for it
in &new_items
{
60 if let ImplItem(Impl { ref for_, ref trait_, ref items, .. }
) = *it
.kind
{
61 if cleaner
.keep_impl(for_
) && trait_
.def_id() == cx
.tcx
.lang_items().deref_trait() {
64 .find_map(|item
| match *item
.kind
{
65 TypedefItem(ref t
, true) => Some(&t
.type_
),
68 .expect("Deref impl without Target type");
70 if let Some(prim
) = target
.primitive_type() {
71 cleaner
.prims
.insert(prim
);
72 } else if let Some(did
) = target
.def_id() {
73 cleaner
.items
.insert(did
);
79 new_items
.retain(|it
| {
80 if let ImplItem(Impl { ref for_, ref trait_, ref blanket_impl, .. }
) = *it
.kind
{
81 cleaner
.keep_impl(for_
)
82 || trait_
.as_ref().map_or(false, |t
| cleaner
.keep_impl(t
))
83 || blanket_impl
.is_some()
89 // `tcx.crates()` doesn't include the local crate, and `tcx.all_trait_implementations`
90 // doesn't work with it anyway, so pull them from the HIR map instead
91 let mut extra_attrs
= Vec
::new();
92 for &trait_did
in cx
.tcx
.all_traits(LOCAL_CRATE
).iter() {
93 for &impl_did
in cx
.tcx
.hir().trait_impls(trait_did
) {
94 let impl_did
= impl_did
.to_def_id();
95 cx
.tcx
.sess
.prof
.generic_activity("build_local_trait_impl").run(|| {
96 let mut parent
= cx
.tcx
.parent(impl_did
);
97 while let Some(did
) = parent
{
102 .filter(|attr
| attr
.has_name(sym
::doc
))
104 if let Some([attr
]) = attr
.meta_item_list().as_deref() {
105 attr
.has_name(sym
::cfg
)
112 parent
= cx
.tcx
.parent(did
);
114 inline
::build_impl(cx
, None
, impl_did
, Some(&extra_attrs
), &mut new_items
);
120 let items
= if let Some(ref mut it
) = krate
.module
{
121 if let ModuleItem(Module { ref mut items, .. }
) = *it
.kind
{
124 panic
!("collect-trait-impls can't run");
127 panic
!("collect-trait-impls can't run");
130 items
.extend(synth_impls
);
131 items
.extend(new_items
);
136 struct SyntheticImplCollector
<'a
, 'tcx
> {
137 cx
: &'a
mut DocContext
<'tcx
>,
141 impl<'a
, 'tcx
> DocFolder
for SyntheticImplCollector
<'a
, 'tcx
> {
142 fn fold_item(&mut self, i
: Item
) -> Option
<Item
> {
143 if i
.is_struct() || i
.is_enum() || i
.is_union() {
144 // FIXME(eddyb) is this `doc(hidden)` check needed?
145 if !self.cx
.tcx
.get_attrs(i
.def_id
).lists(sym
::doc
).has_word(sym
::hidden
) {
146 self.impls
.extend(get_auto_trait_and_blanket_impls(self.cx
, i
.def_id
));
150 Some(self.fold_item_recur(i
))
155 struct ItemCollector
{
156 items
: FxHashSet
<DefId
>,
165 impl DocFolder
for ItemCollector
{
166 fn fold_item(&mut self, i
: Item
) -> Option
<Item
> {
167 self.items
.insert(i
.def_id
);
169 Some(self.fold_item_recur(i
))
173 struct BadImplStripper
{
174 prims
: FxHashSet
<PrimitiveType
>,
175 items
: FxHashSet
<DefId
>,
178 impl BadImplStripper
{
179 fn keep_impl(&self, ty
: &Type
) -> bool
{
180 if let Generic(_
) = ty
{
181 // keep impls made on generics
183 } else if let Some(prim
) = ty
.primitive_type() {
184 self.prims
.contains(&prim
)
185 } else if let Some(did
) = ty
.def_id() {
186 self.items
.contains(&did
)