]>
Commit | Line | Data |
---|---|---|
60c5eb7d | 1 | use super::Pass; |
9fa01778 XL |
2 | use crate::clean::*; |
3 | use crate::core::DocContext; | |
4 | use crate::fold::DocFolder; | |
0bf4aa26 | 5 | |
cdc7bbd5 | 6 | use rustc_data_structures::fx::FxHashSet; |
fc512014 | 7 | use rustc_middle::ty::DefIdTree; |
dfeec247 | 8 | use rustc_span::symbol::sym; |
0bf4aa26 | 9 | |
fc512014 | 10 | crate const COLLECT_TRAIT_IMPLS: Pass = Pass { |
532ac7d7 | 11 | name: "collect-trait-impls", |
60c5eb7d | 12 | run: collect_trait_impls, |
532ac7d7 XL |
13 | description: "retrieves trait impls for items in the crate", |
14 | }; | |
0bf4aa26 | 15 | |
6a06907d XL |
16 | crate fn collect_trait_impls(krate: Crate, cx: &mut DocContext<'_>) -> Crate { |
17 | let (mut krate, synth_impls) = cx.sess().time("collect_synthetic_impls", || { | |
18 | let mut synth = SyntheticImplCollector { cx, impls: Vec::new() }; | |
19 | (synth.fold_crate(krate), synth.impls) | |
20 | }); | |
0bf4aa26 | 21 | |
60c5eb7d | 22 | let prims: FxHashSet<PrimitiveType> = krate.primitives.iter().map(|p| p.1).collect(); |
0bf4aa26 XL |
23 | |
24 | let crate_items = { | |
25 | let mut coll = ItemCollector::new(); | |
fc512014 | 26 | krate = cx.sess().time("collect_items_for_trait_impls", || coll.fold_crate(krate)); |
0bf4aa26 XL |
27 | coll.items |
28 | }; | |
29 | ||
30 | let mut new_items = Vec::new(); | |
31 | ||
136023e0 | 32 | for &cnum in cx.tcx.crates(()).iter() { |
3dfed10e | 33 | for &(did, _) in cx.tcx.all_trait_implementations(cnum).iter() { |
5869c6ff | 34 | cx.tcx.sess.prof.generic_activity("build_extern_trait_impl").run(|| { |
29967ef6 | 35 | inline::build_impl(cx, None, did, None, &mut new_items); |
3dfed10e | 36 | }); |
0bf4aa26 XL |
37 | } |
38 | } | |
39 | ||
40 | // Also try to inline primitive impls from other crates. | |
3dfed10e | 41 | for &def_id in PrimitiveType::all_impls(cx.tcx).values().flatten() { |
0bf4aa26 | 42 | if !def_id.is_local() { |
5869c6ff | 43 | cx.tcx.sess.prof.generic_activity("build_primitive_trait_impls").run(|| { |
fc512014 | 44 | inline::build_impl(cx, None, def_id, None, &mut new_items); |
0bf4aa26 | 45 | |
fc512014 XL |
46 | // FIXME(eddyb) is this `doc(hidden)` check needed? |
47 | if !cx.tcx.get_attrs(def_id).lists(sym::doc).has_word(sym::hidden) { | |
17df50a5 | 48 | let impls = get_auto_trait_and_blanket_impls(cx, def_id.into()); |
6a06907d | 49 | new_items.extend(impls.filter(|i| cx.inlined.insert(i.def_id))); |
fc512014 | 50 | } |
6a06907d | 51 | }); |
0bf4aa26 XL |
52 | } |
53 | } | |
54 | ||
36d6ef2b XL |
55 | let mut cleaner = BadImplStripper { prims, items: crate_items }; |
56 | ||
57 | // scan through included items ahead of time to splice in Deref targets to the "valid" sets | |
58 | for it in &new_items { | |
59 | if let ImplItem(Impl { ref for_, ref trait_, ref items, .. }) = *it.kind { | |
60 | if cleaner.keep_impl(for_) && trait_.def_id() == cx.tcx.lang_items().deref_trait() { | |
61 | let target = items | |
62 | .iter() | |
63 | .find_map(|item| match *item.kind { | |
64 | TypedefItem(ref t, true) => Some(&t.type_), | |
65 | _ => None, | |
66 | }) | |
67 | .expect("Deref impl without Target type"); | |
68 | ||
69 | if let Some(prim) = target.primitive_type() { | |
70 | cleaner.prims.insert(prim); | |
71 | } else if let Some(did) = target.def_id() { | |
17df50a5 | 72 | cleaner.items.insert(did.into()); |
36d6ef2b XL |
73 | } |
74 | } | |
75 | } | |
76 | } | |
77 | ||
78 | new_items.retain(|it| { | |
79 | if let ImplItem(Impl { ref for_, ref trait_, ref blanket_impl, .. }) = *it.kind { | |
80 | cleaner.keep_impl(for_) | |
81 | || trait_.as_ref().map_or(false, |t| cleaner.keep_impl(t)) | |
82 | || blanket_impl.is_some() | |
83 | } else { | |
84 | true | |
85 | } | |
86 | }); | |
87 | ||
136023e0 | 88 | // `tcx.crates(())` doesn't include the local crate, and `tcx.all_trait_implementations` |
0bf4aa26 | 89 | // doesn't work with it anyway, so pull them from the HIR map instead |
5869c6ff | 90 | let mut extra_attrs = Vec::new(); |
17df50a5 | 91 | for &trait_did in cx.tcx.all_traits(()).iter() { |
6a06907d XL |
92 | for &impl_did in cx.tcx.hir().trait_impls(trait_did) { |
93 | let impl_did = impl_did.to_def_id(); | |
5869c6ff XL |
94 | cx.tcx.sess.prof.generic_activity("build_local_trait_impl").run(|| { |
95 | let mut parent = cx.tcx.parent(impl_did); | |
fc512014 XL |
96 | while let Some(did) = parent { |
97 | extra_attrs.extend( | |
98 | cx.tcx | |
99 | .get_attrs(did) | |
100 | .iter() | |
101 | .filter(|attr| attr.has_name(sym::doc)) | |
102 | .filter(|attr| { | |
103 | if let Some([attr]) = attr.meta_item_list().as_deref() { | |
104 | attr.has_name(sym::cfg) | |
105 | } else { | |
106 | false | |
107 | } | |
108 | }) | |
109 | .cloned(), | |
110 | ); | |
111 | parent = cx.tcx.parent(did); | |
112 | } | |
5869c6ff XL |
113 | inline::build_impl(cx, None, impl_did, Some(&extra_attrs), &mut new_items); |
114 | extra_attrs.clear(); | |
3dfed10e | 115 | }); |
0bf4aa26 XL |
116 | } |
117 | } | |
118 | ||
cdc7bbd5 XL |
119 | let items = if let ModuleItem(Module { ref mut items, .. }) = *krate.module.kind { |
120 | items | |
0bf4aa26 XL |
121 | } else { |
122 | panic!("collect-trait-impls can't run"); | |
5869c6ff XL |
123 | }; |
124 | ||
6a06907d | 125 | items.extend(synth_impls); |
36d6ef2b | 126 | items.extend(new_items); |
0bf4aa26 XL |
127 | krate |
128 | } | |
129 | ||
532ac7d7 | 130 | struct SyntheticImplCollector<'a, 'tcx> { |
6a06907d | 131 | cx: &'a mut DocContext<'tcx>, |
0bf4aa26 XL |
132 | impls: Vec<Item>, |
133 | } | |
134 | ||
532ac7d7 | 135 | impl<'a, 'tcx> DocFolder for SyntheticImplCollector<'a, 'tcx> { |
0bf4aa26 XL |
136 | fn fold_item(&mut self, i: Item) -> Option<Item> { |
137 | if i.is_struct() || i.is_enum() || i.is_union() { | |
48663c56 | 138 | // FIXME(eddyb) is this `doc(hidden)` check needed? |
136023e0 XL |
139 | if !self |
140 | .cx | |
141 | .tcx | |
142 | .get_attrs(i.def_id.expect_def_id()) | |
143 | .lists(sym::doc) | |
144 | .has_word(sym::hidden) | |
17df50a5 XL |
145 | { |
146 | self.impls | |
136023e0 | 147 | .extend(get_auto_trait_and_blanket_impls(self.cx, i.def_id.expect_def_id())); |
0bf4aa26 XL |
148 | } |
149 | } | |
150 | ||
fc512014 | 151 | Some(self.fold_item_recur(i)) |
0bf4aa26 XL |
152 | } |
153 | } | |
154 | ||
155 | #[derive(Default)] | |
156 | struct ItemCollector { | |
136023e0 | 157 | items: FxHashSet<ItemId>, |
0bf4aa26 XL |
158 | } |
159 | ||
160 | impl ItemCollector { | |
161 | fn new() -> Self { | |
162 | Self::default() | |
163 | } | |
164 | } | |
165 | ||
166 | impl DocFolder for ItemCollector { | |
167 | fn fold_item(&mut self, i: Item) -> Option<Item> { | |
168 | self.items.insert(i.def_id); | |
169 | ||
fc512014 | 170 | Some(self.fold_item_recur(i)) |
0bf4aa26 XL |
171 | } |
172 | } | |
173 | ||
174 | struct BadImplStripper { | |
175 | prims: FxHashSet<PrimitiveType>, | |
136023e0 | 176 | items: FxHashSet<ItemId>, |
0bf4aa26 XL |
177 | } |
178 | ||
179 | impl BadImplStripper { | |
5869c6ff | 180 | fn keep_impl(&self, ty: &Type) -> bool { |
0bf4aa26 XL |
181 | if let Generic(_) = ty { |
182 | // keep impls made on generics | |
183 | true | |
184 | } else if let Some(prim) = ty.primitive_type() { | |
185 | self.prims.contains(&prim) | |
186 | } else if let Some(did) = ty.def_id() { | |
17df50a5 | 187 | self.keep_impl_with_def_id(did.into()) |
0bf4aa26 XL |
188 | } else { |
189 | false | |
190 | } | |
191 | } | |
17df50a5 | 192 | |
136023e0 | 193 | fn keep_impl_with_def_id(&self, did: ItemId) -> bool { |
17df50a5 XL |
194 | self.items.contains(&did) |
195 | } | |
0bf4aa26 | 196 | } |