Skip to content

Commit 02bea3c

Browse files
rustdoc: collect trait impls as an early pass
1 parent 992d1e4 commit 02bea3c

File tree

6 files changed

+137
-82
lines changed

6 files changed

+137
-82
lines changed

src/librustdoc/clean/inline.rs

Lines changed: 13 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -291,78 +291,12 @@ pub fn build_impls(cx: &DocContext, did: DefId, auto_traits: bool) -> Vec<clean:
291291
impls.extend(get_blanket_impls_with_def_id(cx, did));
292292
}
293293

294-
// If this is the first time we've inlined something from another crate, then
295-
// we inline *all* impls from all the crates into this crate. Note that there's
296-
// currently no way for us to filter this based on type, and we likely need
297-
// many impls for a variety of reasons.
298-
//
299-
// Primarily, the impls will be used to populate the documentation for this
300-
// type being inlined, but impls can also be used when generating
301-
// documentation for primitives (no way to find those specifically).
302-
if cx.populated_all_crate_impls.get() {
303-
return impls;
304-
}
305-
306-
cx.populated_all_crate_impls.set(true);
307-
308-
for &cnum in tcx.crates().iter() {
309-
for did in tcx.all_trait_implementations(cnum).iter() {
310-
build_impl(cx, *did, &mut impls);
311-
}
312-
}
313-
314-
// Also try to inline primitive impls from other crates.
315-
let lang_items = tcx.lang_items();
316-
let primitive_impls = [
317-
lang_items.isize_impl(),
318-
lang_items.i8_impl(),
319-
lang_items.i16_impl(),
320-
lang_items.i32_impl(),
321-
lang_items.i64_impl(),
322-
lang_items.i128_impl(),
323-
lang_items.usize_impl(),
324-
lang_items.u8_impl(),
325-
lang_items.u16_impl(),
326-
lang_items.u32_impl(),
327-
lang_items.u64_impl(),
328-
lang_items.u128_impl(),
329-
lang_items.f32_impl(),
330-
lang_items.f64_impl(),
331-
lang_items.f32_runtime_impl(),
332-
lang_items.f64_runtime_impl(),
333-
lang_items.char_impl(),
334-
lang_items.str_impl(),
335-
lang_items.slice_impl(),
336-
lang_items.slice_u8_impl(),
337-
lang_items.str_alloc_impl(),
338-
lang_items.slice_alloc_impl(),
339-
lang_items.slice_u8_alloc_impl(),
340-
lang_items.const_ptr_impl(),
341-
lang_items.mut_ptr_impl(),
342-
];
343-
344-
for def_id in primitive_impls.iter().filter_map(|&def_id| def_id) {
345-
if !def_id.is_local() {
346-
build_impl(cx, def_id, &mut impls);
347-
348-
let auto_impls = get_auto_traits_with_def_id(cx, def_id);
349-
let blanket_impls = get_blanket_impls_with_def_id(cx, def_id);
350-
let mut renderinfo = cx.renderinfo.borrow_mut();
351-
352-
let new_impls: Vec<clean::Item> = auto_impls.into_iter()
353-
.chain(blanket_impls.into_iter())
354-
.filter(|i| renderinfo.inlined.insert(i.def_id))
355-
.collect();
356-
357-
impls.extend(new_impls);
358-
}
359-
}
360-
361294
impls
362295
}
363296

364297
pub fn build_impl(cx: &DocContext, did: DefId, ret: &mut Vec<clean::Item>) {
365298
if !cx.renderinfo.borrow_mut().inlined.insert(did) {
299+
debug!("already inlined, bailing: {:?}", did);
366300
return
367301
}
368302

@@ -372,19 +306,25 @@ pub fn build_impl(cx: &DocContext, did: DefId, ret: &mut Vec<clean::Item>) {
372306

373307
// Only inline impl if the implemented trait is
374308
// reachable in rustdoc generated documentation
375-
if let Some(traitref) = associated_trait {
376-
if !cx.access_levels.borrow().is_doc_reachable(traitref.def_id) {
377-
return
309+
if !did.is_local() {
310+
if let Some(traitref) = associated_trait {
311+
if !cx.access_levels.borrow().is_doc_reachable(traitref.def_id) {
312+
debug!("trait {:?} not reachable, bailing: {:?}", traitref.def_id, did);
313+
return
314+
}
378315
}
379316
}
380317

381318
let for_ = tcx.type_of(did).clean(cx);
382319

383320
// Only inline impl if the implementing type is
384321
// reachable in rustdoc generated documentation
385-
if let Some(did) = for_.def_id() {
386-
if !cx.access_levels.borrow().is_doc_reachable(did) {
387-
return
322+
if !did.is_local() {
323+
if let Some(did) = for_.def_id() {
324+
if !cx.access_levels.borrow().is_doc_reachable(did) {
325+
debug!("impl type {:?} not accessible, bailing", did);
326+
return
327+
}
388328
}
389329
}
390330

src/librustdoc/core.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ use syntax_pos::DUMMY_SP;
3737
use errors;
3838
use errors::emitter::{Emitter, EmitterWriter};
3939

40-
use std::cell::{RefCell, Cell};
40+
use std::cell::RefCell;
4141
use std::mem;
4242
use rustc_data_structures::sync::{self, Lrc};
4343
use std::rc::Rc;
@@ -60,7 +60,6 @@ pub struct DocContext<'a, 'tcx: 'a, 'rcx: 'a, 'cstore: 'rcx> {
6060
/// The stack of module NodeIds up till this point
6161
pub crate_name: Option<String>,
6262
pub cstore: Rc<CStore>,
63-
pub populated_all_crate_impls: Cell<bool>,
6463
// Note that external items for which `doc(hidden)` applies to are shown as
6564
// non-reachable while local items aren't. This is because we're reusing
6665
// the access levels from crateanalysis.
@@ -514,7 +513,6 @@ pub fn run_core(search_paths: SearchPaths,
514513
resolver: &resolver,
515514
crate_name,
516515
cstore: cstore.clone(),
517-
populated_all_crate_impls: Cell::new(false),
518516
access_levels: RefCell::new(access_levels),
519517
external_traits: Default::default(),
520518
active_extern_traits: Default::default(),
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
use clean::*;
12+
13+
use super::Pass;
14+
use core::DocContext;
15+
16+
pub const COLLECT_TRAIT_IMPLS: Pass =
17+
Pass::early("collect-trait-impls", collect_trait_impls,
18+
"retrieves trait impls for items in the crate");
19+
20+
pub fn collect_trait_impls(mut krate: Crate, cx: &DocContext) -> Crate {
21+
if let Some(ref mut it) = krate.module {
22+
if let ModuleItem(Module { ref mut items, .. }) = it.inner {
23+
for &cnum in cx.tcx.crates().iter() {
24+
for &did in cx.tcx.all_trait_implementations(cnum).iter() {
25+
inline::build_impl(cx, did, items);
26+
}
27+
}
28+
29+
// `tcx.crates()` doesn't include the local crate, and `tcx.all_trait_implementations`
30+
// doesn't work with it anyway, so pull them from the HIR map instead
31+
for &trait_did in cx.all_traits.iter() {
32+
for &impl_node in cx.tcx.hir.trait_impls(trait_did) {
33+
let impl_did = cx.tcx.hir.local_def_id(impl_node);
34+
inline::build_impl(cx, impl_did, items);
35+
}
36+
}
37+
38+
// Also try to inline primitive impls from other crates.
39+
let lang_items = cx.tcx.lang_items();
40+
let primitive_impls = [
41+
lang_items.isize_impl(),
42+
lang_items.i8_impl(),
43+
lang_items.i16_impl(),
44+
lang_items.i32_impl(),
45+
lang_items.i64_impl(),
46+
lang_items.i128_impl(),
47+
lang_items.usize_impl(),
48+
lang_items.u8_impl(),
49+
lang_items.u16_impl(),
50+
lang_items.u32_impl(),
51+
lang_items.u64_impl(),
52+
lang_items.u128_impl(),
53+
lang_items.f32_impl(),
54+
lang_items.f64_impl(),
55+
lang_items.f32_runtime_impl(),
56+
lang_items.f64_runtime_impl(),
57+
lang_items.char_impl(),
58+
lang_items.str_impl(),
59+
lang_items.slice_impl(),
60+
lang_items.slice_u8_impl(),
61+
lang_items.str_alloc_impl(),
62+
lang_items.slice_alloc_impl(),
63+
lang_items.slice_u8_alloc_impl(),
64+
lang_items.const_ptr_impl(),
65+
lang_items.mut_ptr_impl(),
66+
];
67+
68+
for def_id in primitive_impls.iter().filter_map(|&def_id| def_id) {
69+
if !def_id.is_local() {
70+
inline::build_impl(cx, def_id, items);
71+
72+
let auto_impls = get_auto_traits_with_def_id(cx, def_id);
73+
let blanket_impls = get_blanket_impls_with_def_id(cx, def_id);
74+
let mut renderinfo = cx.renderinfo.borrow_mut();
75+
76+
let new_impls: Vec<Item> = auto_impls.into_iter()
77+
.chain(blanket_impls.into_iter())
78+
.filter(|i| renderinfo.inlined.insert(i.def_id))
79+
.collect();
80+
81+
items.extend(new_impls);
82+
}
83+
}
84+
} else {
85+
panic!("collect-trait-impls can't run");
86+
}
87+
} else {
88+
panic!("collect-trait-impls can't run");
89+
}
90+
91+
// pulling in the impls puts their trait info into the DocContext, but that's already been
92+
// drained by now, so stuff that info into the Crate so the rendering can pick it up
93+
let mut external_traits = cx.external_traits.borrow_mut();
94+
for (did, trait_) in external_traits.drain() {
95+
krate.external_traits.entry(did).or_insert(trait_);
96+
}
97+
98+
krate
99+
}

src/librustdoc/passes/mod.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ pub use self::propagate_doc_cfg::PROPAGATE_DOC_CFG;
4343
mod collect_intra_doc_links;
4444
pub use self::collect_intra_doc_links::COLLECT_INTRA_DOC_LINKS;
4545

46+
mod collect_trait_impls;
47+
pub use self::collect_trait_impls::COLLECT_TRAIT_IMPLS;
48+
4649
/// Represents a single pass.
4750
#[derive(Copy, Clone)]
4851
pub enum Pass {
@@ -132,10 +135,12 @@ pub const PASSES: &'static [Pass] = &[
132135
STRIP_PRIV_IMPORTS,
133136
PROPAGATE_DOC_CFG,
134137
COLLECT_INTRA_DOC_LINKS,
138+
COLLECT_TRAIT_IMPLS,
135139
];
136140

137141
/// The list of passes run by default.
138142
pub const DEFAULT_PASSES: &'static [&'static str] = &[
143+
"collect-trait-impls",
139144
"strip-hidden",
140145
"strip-private",
141146
"collect-intra-doc-links",
@@ -146,6 +151,7 @@ pub const DEFAULT_PASSES: &'static [&'static str] = &[
146151

147152
/// The list of default passes run with `--document-private-items` is passed to rustdoc.
148153
pub const DEFAULT_PRIVATE_PASSES: &'static [&'static str] = &[
154+
"collect-trait-impls",
149155
"strip-priv-imports",
150156
"collect-intra-doc-links",
151157
"collapse-docs",

src/librustdoc/visit_ast.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -510,9 +510,9 @@ impl<'a, 'tcx, 'rcx, 'cstore> RustdocVisitor<'a, 'tcx, 'rcx, 'cstore> {
510510
ref tr,
511511
ref ty,
512512
ref item_ids) => {
513-
// Don't duplicate impls when inlining, we'll pick them up
514-
// regardless of where they're located.
515-
if !self.inlining {
513+
// Don't duplicate impls when inlining or if it's implementing a trait, we'll pick
514+
// them up regardless of where they're located.
515+
if !self.inlining && tr.is_none() {
516516
let items = item_ids.iter()
517517
.map(|ii| self.cx.tcx.hir.impl_item(ii.id).clone())
518518
.collect();

src/test/rustdoc/traits-in-bodies.rs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,10 @@
1111
//prior to fixing `everybody_loops` to preserve items, rustdoc would crash on this file, as it
1212
//didn't see that `SomeStruct` implemented `Clone`
1313

14-
//FIXME(misdreavus): whenever rustdoc shows traits impl'd inside bodies, make sure this test
15-
//reflects that
16-
1714
pub struct Bounded<T: Clone>(T);
1815

16+
// @has traits_in_bodies/struct.SomeStruct.html
17+
// @has - '//code' 'impl Clone for SomeStruct'
1918
pub struct SomeStruct;
2019

2120
fn asdf() -> Bounded<SomeStruct> {
@@ -27,3 +26,16 @@ fn asdf() -> Bounded<SomeStruct> {
2726

2827
Bounded(SomeStruct)
2928
}
29+
30+
// @has traits_in_bodies/struct.Point.html
31+
// @has - '//code' 'impl Copy for Point'
32+
#[derive(Clone)]
33+
pub struct Point {
34+
x: i32,
35+
y: i32,
36+
}
37+
38+
const _FOO: () = {
39+
impl Copy for Point {}
40+
()
41+
};

0 commit comments

Comments
 (0)