Skip to content

Commit 755c02d

Browse files
filter collected trait impls against items in the crate
1 parent 354507e commit 755c02d

File tree

1 file changed

+104
-15
lines changed

1 file changed

+104
-15
lines changed

src/librustdoc/passes/collect_trait_impls.rs

Lines changed: 104 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010

1111
use clean::*;
1212

13+
use rustc::util::nodemap::FxHashSet;
14+
use rustc::hir::def_id::DefId;
15+
1316
use super::Pass;
1417
use core::DocContext;
1518
use fold::DocFolder;
@@ -22,22 +25,20 @@ pub fn collect_trait_impls(krate: Crate, cx: &DocContext) -> Crate {
2225
let mut synth = SyntheticImplCollector::new(cx);
2326
let mut krate = synth.fold_crate(krate);
2427

25-
if let Some(ref mut it) = krate.module {
26-
if let ModuleItem(Module { ref mut items, .. }) = it.inner {
27-
items.extend(synth.impls);
28+
let prims: FxHashSet<PrimitiveType> =
29+
krate.primitives.iter().map(|p| p.1).collect();
30+
31+
let crate_items = {
32+
let mut coll = ItemCollector::new();
33+
krate = coll.fold_crate(krate);
34+
coll.items
35+
};
36+
37+
let mut new_items = Vec::new();
2838

2939
for &cnum in cx.tcx.crates().iter() {
3040
for &did in cx.tcx.all_trait_implementations(cnum).iter() {
31-
inline::build_impl(cx, did, items);
32-
}
33-
}
34-
35-
// `tcx.crates()` doesn't include the local crate, and `tcx.all_trait_implementations`
36-
// doesn't work with it anyway, so pull them from the HIR map instead
37-
for &trait_did in cx.all_traits.iter() {
38-
for &impl_node in cx.tcx.hir.trait_impls(trait_did) {
39-
let impl_did = cx.tcx.hir.local_def_id(impl_node);
40-
inline::build_impl(cx, impl_did, items);
41+
inline::build_impl(cx, did, &mut new_items);
4142
}
4243
}
4344

@@ -73,7 +74,7 @@ pub fn collect_trait_impls(krate: Crate, cx: &DocContext) -> Crate {
7374

7475
for def_id in primitive_impls.iter().filter_map(|&def_id| def_id) {
7576
if !def_id.is_local() {
76-
inline::build_impl(cx, def_id, items);
77+
inline::build_impl(cx, def_id, &mut new_items);
7778

7879
let auto_impls = get_auto_traits_with_def_id(cx, def_id);
7980
let blanket_impls = get_blanket_impls_with_def_id(cx, def_id);
@@ -84,9 +85,58 @@ pub fn collect_trait_impls(krate: Crate, cx: &DocContext) -> Crate {
8485
.filter(|i| renderinfo.inlined.insert(i.def_id))
8586
.collect();
8687

87-
items.extend(new_impls);
88+
new_items.extend(new_impls);
8889
}
8990
}
91+
92+
let mut cleaner = BadImplStripper {
93+
prims,
94+
items: crate_items,
95+
};
96+
97+
// scan through included items ahead of time to splice in Deref targets to the "valid" sets
98+
for it in &new_items {
99+
if let ImplItem(Impl { ref for_, ref trait_, ref items, .. }) = it.inner {
100+
if cleaner.keep_item(for_) && trait_.def_id() == cx.tcx.lang_items().deref_trait() {
101+
let target = items.iter().filter_map(|item| {
102+
match item.inner {
103+
TypedefItem(ref t, true) => Some(&t.type_),
104+
_ => None,
105+
}
106+
}).next().expect("Deref impl without Target type");
107+
108+
if let Some(prim) = target.primitive_type() {
109+
cleaner.prims.insert(prim);
110+
} else if let Some(did) = target.def_id() {
111+
cleaner.items.insert(did);
112+
}
113+
}
114+
}
115+
}
116+
117+
new_items.retain(|it| {
118+
if let ImplItem(Impl { ref for_, ref trait_, ref blanket_impl, .. }) = it.inner {
119+
cleaner.keep_item(for_) ||
120+
trait_.as_ref().map_or(false, |t| cleaner.keep_item(t)) ||
121+
blanket_impl.is_some()
122+
} else {
123+
true
124+
}
125+
});
126+
127+
// `tcx.crates()` doesn't include the local crate, and `tcx.all_trait_implementations`
128+
// doesn't work with it anyway, so pull them from the HIR map instead
129+
for &trait_did in cx.all_traits.iter() {
130+
for &impl_node in cx.tcx.hir.trait_impls(trait_did) {
131+
let impl_did = cx.tcx.hir.local_def_id(impl_node);
132+
inline::build_impl(cx, impl_did, &mut new_items);
133+
}
134+
}
135+
136+
if let Some(ref mut it) = krate.module {
137+
if let ModuleItem(Module { ref mut items, .. }) = it.inner {
138+
items.extend(synth.impls);
139+
items.extend(new_items);
90140
} else {
91141
panic!("collect-trait-impls can't run");
92142
}
@@ -128,3 +178,42 @@ impl<'a, 'tcx, 'rcx, 'cstore> DocFolder for SyntheticImplCollector<'a, 'tcx, 'rc
128178
self.fold_item_recur(i)
129179
}
130180
}
181+
182+
#[derive(Default)]
183+
struct ItemCollector {
184+
items: FxHashSet<DefId>,
185+
}
186+
187+
impl ItemCollector {
188+
fn new() -> Self {
189+
Self::default()
190+
}
191+
}
192+
193+
impl DocFolder for ItemCollector {
194+
fn fold_item(&mut self, i: Item) -> Option<Item> {
195+
self.items.insert(i.def_id);
196+
197+
self.fold_item_recur(i)
198+
}
199+
}
200+
201+
struct BadImplStripper {
202+
prims: FxHashSet<PrimitiveType>,
203+
items: FxHashSet<DefId>,
204+
}
205+
206+
impl BadImplStripper {
207+
fn keep_item(&self, ty: &Type) -> bool {
208+
if let Generic(_) = ty {
209+
// keep impls made on generics
210+
true
211+
} else if let Some(prim) = ty.primitive_type() {
212+
self.prims.contains(&prim)
213+
} else if let Some(did) = ty.def_id() {
214+
self.items.contains(&did)
215+
} else {
216+
false
217+
}
218+
}
219+
}

0 commit comments

Comments
 (0)