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_span
::symbol
::sym
;
10 pub const COLLECT_TRAIT_IMPLS
: Pass
= Pass
{
11 name
: "collect-trait-impls",
12 run
: collect_trait_impls
,
13 description
: "retrieves trait impls for items in the crate",
16 pub fn collect_trait_impls(krate
: Crate
, cx
: &DocContext
<'_
>) -> Crate
{
17 let mut synth
= SyntheticImplCollector
::new(cx
);
18 let mut krate
= synth
.fold_crate(krate
);
20 let prims
: FxHashSet
<PrimitiveType
> = krate
.primitives
.iter().map(|p
| p
.1).collect();
23 let mut coll
= ItemCollector
::new();
24 krate
= coll
.fold_crate(krate
);
28 let mut new_items
= Vec
::new();
30 for &cnum
in cx
.tcx
.crates().iter() {
31 for &did
in cx
.tcx
.all_trait_implementations(cnum
).iter() {
32 inline
::build_impl(cx
, did
, None
, &mut new_items
);
36 // Also try to inline primitive impls from other crates.
37 let lang_items
= cx
.tcx
.lang_items();
38 let primitive_impls
= [
39 lang_items
.isize_impl(),
41 lang_items
.i16_impl(),
42 lang_items
.i32_impl(),
43 lang_items
.i64_impl(),
44 lang_items
.i128_impl(),
45 lang_items
.usize_impl(),
47 lang_items
.u16_impl(),
48 lang_items
.u32_impl(),
49 lang_items
.u64_impl(),
50 lang_items
.u128_impl(),
51 lang_items
.f32_impl(),
52 lang_items
.f64_impl(),
53 lang_items
.f32_runtime_impl(),
54 lang_items
.f64_runtime_impl(),
55 lang_items
.bool_impl(),
56 lang_items
.char_impl(),
57 lang_items
.str_impl(),
58 lang_items
.slice_impl(),
59 lang_items
.slice_u8_impl(),
60 lang_items
.str_alloc_impl(),
61 lang_items
.slice_alloc_impl(),
62 lang_items
.slice_u8_alloc_impl(),
63 lang_items
.const_ptr_impl(),
64 lang_items
.mut_ptr_impl(),
65 lang_items
.const_slice_ptr_impl(),
66 lang_items
.mut_slice_ptr_impl(),
69 for def_id
in primitive_impls
.iter().filter_map(|&def_id
| def_id
) {
70 if !def_id
.is_local() {
71 inline
::build_impl(cx
, def_id
, None
, &mut new_items
);
73 // FIXME(eddyb) is this `doc(hidden)` check needed?
74 if !cx
.tcx
.get_attrs(def_id
).lists(sym
::doc
).has_word(sym
::hidden
) {
75 let self_ty
= cx
.tcx
.type_of(def_id
);
76 let impls
= get_auto_trait_and_blanket_impls(cx
, self_ty
, def_id
);
77 let mut renderinfo
= cx
.renderinfo
.borrow_mut();
79 new_items
.extend(impls
.filter(|i
| renderinfo
.inlined
.insert(i
.def_id
)));
84 let mut cleaner
= BadImplStripper { prims, items: crate_items }
;
86 // scan through included items ahead of time to splice in Deref targets to the "valid" sets
87 for it
in &new_items
{
88 if let ImplItem(Impl { ref for_, ref trait_, ref items, .. }
) = it
.inner
{
89 if cleaner
.keep_item(for_
) && trait_
.def_id() == cx
.tcx
.lang_items().deref_trait() {
92 .find_map(|item
| match item
.inner
{
93 TypedefItem(ref t
, true) => Some(&t
.type_
),
96 .expect("Deref impl without Target type");
98 if let Some(prim
) = target
.primitive_type() {
99 cleaner
.prims
.insert(prim
);
100 } else if let Some(did
) = target
.def_id() {
101 cleaner
.items
.insert(did
);
107 new_items
.retain(|it
| {
108 if let ImplItem(Impl { ref for_, ref trait_, ref blanket_impl, .. }
) = it
.inner
{
109 cleaner
.keep_item(for_
)
110 || trait_
.as_ref().map_or(false, |t
| cleaner
.keep_item(t
))
111 || blanket_impl
.is_some()
117 // `tcx.crates()` doesn't include the local crate, and `tcx.all_trait_implementations`
118 // doesn't work with it anyway, so pull them from the HIR map instead
119 for &trait_did
in cx
.tcx
.all_traits(LOCAL_CRATE
).iter() {
120 for &impl_node
in cx
.tcx
.hir().trait_impls(trait_did
) {
121 let impl_did
= cx
.tcx
.hir().local_def_id(impl_node
);
122 inline
::build_impl(cx
, impl_did
.to_def_id(), None
, &mut new_items
);
126 if let Some(ref mut it
) = krate
.module
{
127 if let ModuleItem(Module { ref mut items, .. }
) = it
.inner
{
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.impls
.extend(get_auto_trait_and_blanket_impls(
158 self.cx
.tcx
.type_of(i
.def_id
),
164 self.fold_item_recur(i
)
169 struct ItemCollector
{
170 items
: FxHashSet
<DefId
>,
179 impl DocFolder
for ItemCollector
{
180 fn fold_item(&mut self, i
: Item
) -> Option
<Item
> {
181 self.items
.insert(i
.def_id
);
183 self.fold_item_recur(i
)
187 struct BadImplStripper
{
188 prims
: FxHashSet
<PrimitiveType
>,
189 items
: FxHashSet
<DefId
>,
192 impl BadImplStripper
{
193 fn keep_item(&self, ty
: &Type
) -> bool
{
194 if let Generic(_
) = ty
{
195 // keep impls made on generics
197 } else if let Some(prim
) = ty
.primitive_type() {
198 self.prims
.contains(&prim
)
199 } else if let Some(did
) = ty
.def_id() {
200 self.items
.contains(&did
)