3 use crate::core
::DocContext
;
4 use crate::fold
::DocFolder
;
6 use rustc_data_structures
::fx
::{FxHashMap, 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 // `tcx.crates()` doesn't include the local crate, and `tcx.all_trait_implementations`
57 // doesn't work with it anyway, so pull them from the HIR map instead
58 let mut extra_attrs
= Vec
::new();
59 for &trait_did
in cx
.tcx
.all_traits(LOCAL_CRATE
).iter() {
60 for &impl_did
in cx
.tcx
.hir().trait_impls(trait_did
) {
61 let impl_did
= impl_did
.to_def_id();
62 cx
.tcx
.sess
.prof
.generic_activity("build_local_trait_impl").run(|| {
63 let mut parent
= cx
.tcx
.parent(impl_did
);
64 while let Some(did
) = parent
{
69 .filter(|attr
| attr
.has_name(sym
::doc
))
71 if let Some([attr
]) = attr
.meta_item_list().as_deref() {
72 attr
.has_name(sym
::cfg
)
79 parent
= cx
.tcx
.parent(did
);
81 inline
::build_impl(cx
, None
, impl_did
, Some(&extra_attrs
), &mut new_items
);
87 let mut cleaner
= BadImplStripper { prims, items: crate_items }
;
89 let mut type_did_to_deref_target
: FxHashMap
<DefId
, &Type
> = FxHashMap
::default();
90 // Gather all type to `Deref` target edges.
91 for it
in &new_items
{
92 if let ImplItem(Impl { ref for_, ref trait_, ref items, .. }
) = *it
.kind
{
93 if trait_
.def_id() == cx
.tcx
.lang_items().deref_trait() {
94 let target
= items
.iter().find_map(|item
| match *item
.kind
{
95 TypedefItem(ref t
, true) => Some(&t
.type_
),
98 if let (Some(for_did
), Some(target
)) = (for_
.def_id(), target
) {
99 type_did_to_deref_target
.insert(for_did
, target
);
104 // Follow all `Deref` targets of included items and recursively add them as valid
106 map
: &FxHashMap
<DefId
, &Type
>,
107 cleaner
: &mut BadImplStripper
,
110 if let Some(target
) = map
.get(type_did
) {
111 debug
!("add_deref_target: type {:?}, target {:?}", type_did
, target
);
112 if let Some(target_prim
) = target
.primitive_type() {
113 cleaner
.prims
.insert(target_prim
);
114 } else if let Some(target_did
) = target
.def_id() {
115 // `impl Deref<Target = S> for S`
116 if target_did
== *type_did
{
117 // Avoid infinite cycles
120 cleaner
.items
.insert(target_did
);
121 add_deref_target(map
, cleaner
, &target_did
);
125 for type_did
in type_did_to_deref_target
.keys() {
126 // Since only the `DefId` portion of the `Type` instances is known to be same for both the
127 // `Deref` target type and the impl for type positions, this map of types is keyed by
128 // `DefId` and for convenience uses a special cleaner that accepts `DefId`s directly.
129 if cleaner
.keep_impl_with_def_id(type_did
) {
130 add_deref_target(&type_did_to_deref_target
, &mut cleaner
, type_did
);
134 let items
= if let Some(ref mut it
) = krate
.module
{
135 if let ModuleItem(Module { ref mut items, .. }
) = *it
.kind
{
138 panic
!("collect-trait-impls can't run");
141 panic
!("collect-trait-impls can't run");
144 items
.extend(synth_impls
);
145 for it
in new_items
.drain(..) {
146 if let ImplItem(Impl { ref for_, ref trait_, ref blanket_impl, .. }
) = *it
.kind
{
147 if !(cleaner
.keep_impl(for_
)
148 || trait_
.as_ref().map_or(false, |t
| cleaner
.keep_impl(t
))
149 || blanket_impl
.is_some())
161 struct SyntheticImplCollector
<'a
, 'tcx
> {
162 cx
: &'a
mut DocContext
<'tcx
>,
166 impl<'a
, 'tcx
> DocFolder
for SyntheticImplCollector
<'a
, 'tcx
> {
167 fn fold_item(&mut self, i
: Item
) -> Option
<Item
> {
168 if i
.is_struct() || i
.is_enum() || i
.is_union() {
169 // FIXME(eddyb) is this `doc(hidden)` check needed?
170 if !self.cx
.tcx
.get_attrs(i
.def_id
).lists(sym
::doc
).has_word(sym
::hidden
) {
171 self.impls
.extend(get_auto_trait_and_blanket_impls(self.cx
, i
.def_id
));
175 Some(self.fold_item_recur(i
))
180 struct ItemCollector
{
181 items
: FxHashSet
<DefId
>,
190 impl DocFolder
for ItemCollector
{
191 fn fold_item(&mut self, i
: Item
) -> Option
<Item
> {
192 self.items
.insert(i
.def_id
);
194 Some(self.fold_item_recur(i
))
198 struct BadImplStripper
{
199 prims
: FxHashSet
<PrimitiveType
>,
200 items
: FxHashSet
<DefId
>,
203 impl BadImplStripper
{
204 fn keep_impl(&self, ty
: &Type
) -> bool
{
205 if let Generic(_
) = ty
{
206 // keep impls made on generics
208 } else if let Some(prim
) = ty
.primitive_type() {
209 self.prims
.contains(&prim
)
210 } else if let Some(did
) = ty
.def_id() {
211 self.keep_impl_with_def_id(&did
)
217 fn keep_impl_with_def_id(&self, did
: &DefId
) -> bool
{
218 self.items
.contains(did
)