diff options
| author | QuietMisdreavus <grey@quietmisdreavus.net> | 2018-08-07 10:10:05 -0500 |
|---|---|---|
| committer | QuietMisdreavus <grey@quietmisdreavus.net> | 2018-09-20 05:42:20 -0500 |
| commit | 02bea3c581bf7127a5ec77d1d3d7a5a513fcf6c5 (patch) | |
| tree | 6b1c899db0ea604db26cea4da42be4627db22c1f /src | |
| parent | 992d1e4d3de364c895963167b70934599574d9a7 (diff) | |
| download | rust-02bea3c581bf7127a5ec77d1d3d7a5a513fcf6c5.tar.gz rust-02bea3c581bf7127a5ec77d1d3d7a5a513fcf6c5.zip | |
rustdoc: collect trait impls as an early pass
Diffstat (limited to 'src')
| -rw-r--r-- | src/librustdoc/clean/inline.rs | 86 | ||||
| -rw-r--r-- | src/librustdoc/core.rs | 4 | ||||
| -rw-r--r-- | src/librustdoc/passes/collect_trait_impls.rs | 99 | ||||
| -rw-r--r-- | src/librustdoc/passes/mod.rs | 6 | ||||
| -rw-r--r-- | src/librustdoc/visit_ast.rs | 6 | ||||
| -rw-r--r-- | src/test/rustdoc/traits-in-bodies.rs | 18 |
6 files changed, 137 insertions, 82 deletions
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 507461f2ea1..684063beac3 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -291,78 +291,12 @@ pub fn build_impls(cx: &DocContext, did: DefId, auto_traits: bool) -> Vec<clean: impls.extend(get_blanket_impls_with_def_id(cx, did)); } - // If this is the first time we've inlined something from another crate, then - // we inline *all* impls from all the crates into this crate. Note that there's - // currently no way for us to filter this based on type, and we likely need - // many impls for a variety of reasons. - // - // Primarily, the impls will be used to populate the documentation for this - // type being inlined, but impls can also be used when generating - // documentation for primitives (no way to find those specifically). - if cx.populated_all_crate_impls.get() { - return impls; - } - - cx.populated_all_crate_impls.set(true); - - for &cnum in tcx.crates().iter() { - for did in tcx.all_trait_implementations(cnum).iter() { - build_impl(cx, *did, &mut impls); - } - } - - // Also try to inline primitive impls from other crates. - let lang_items = tcx.lang_items(); - let primitive_impls = [ - lang_items.isize_impl(), - lang_items.i8_impl(), - lang_items.i16_impl(), - lang_items.i32_impl(), - lang_items.i64_impl(), - lang_items.i128_impl(), - lang_items.usize_impl(), - lang_items.u8_impl(), - lang_items.u16_impl(), - lang_items.u32_impl(), - lang_items.u64_impl(), - lang_items.u128_impl(), - lang_items.f32_impl(), - lang_items.f64_impl(), - lang_items.f32_runtime_impl(), - lang_items.f64_runtime_impl(), - lang_items.char_impl(), - lang_items.str_impl(), - lang_items.slice_impl(), - lang_items.slice_u8_impl(), - lang_items.str_alloc_impl(), - lang_items.slice_alloc_impl(), - lang_items.slice_u8_alloc_impl(), - lang_items.const_ptr_impl(), - lang_items.mut_ptr_impl(), - ]; - - for def_id in primitive_impls.iter().filter_map(|&def_id| def_id) { - if !def_id.is_local() { - build_impl(cx, def_id, &mut impls); - - let auto_impls = get_auto_traits_with_def_id(cx, def_id); - let blanket_impls = get_blanket_impls_with_def_id(cx, def_id); - let mut renderinfo = cx.renderinfo.borrow_mut(); - - let new_impls: Vec<clean::Item> = auto_impls.into_iter() - .chain(blanket_impls.into_iter()) - .filter(|i| renderinfo.inlined.insert(i.def_id)) - .collect(); - - impls.extend(new_impls); - } - } - impls } pub fn build_impl(cx: &DocContext, did: DefId, ret: &mut Vec<clean::Item>) { if !cx.renderinfo.borrow_mut().inlined.insert(did) { + debug!("already inlined, bailing: {:?}", did); return } @@ -372,9 +306,12 @@ pub fn build_impl(cx: &DocContext, did: DefId, ret: &mut Vec<clean::Item>) { // Only inline impl if the implemented trait is // reachable in rustdoc generated documentation - if let Some(traitref) = associated_trait { - if !cx.access_levels.borrow().is_doc_reachable(traitref.def_id) { - return + if !did.is_local() { + if let Some(traitref) = associated_trait { + if !cx.access_levels.borrow().is_doc_reachable(traitref.def_id) { + debug!("trait {:?} not reachable, bailing: {:?}", traitref.def_id, did); + return + } } } @@ -382,9 +319,12 @@ pub fn build_impl(cx: &DocContext, did: DefId, ret: &mut Vec<clean::Item>) { // Only inline impl if the implementing type is // reachable in rustdoc generated documentation - if let Some(did) = for_.def_id() { - if !cx.access_levels.borrow().is_doc_reachable(did) { - return + if !did.is_local() { + if let Some(did) = for_.def_id() { + if !cx.access_levels.borrow().is_doc_reachable(did) { + debug!("impl type {:?} not accessible, bailing", did); + return + } } } diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 2feeecb388f..d7e087fd624 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -37,7 +37,7 @@ use syntax_pos::DUMMY_SP; use errors; use errors::emitter::{Emitter, EmitterWriter}; -use std::cell::{RefCell, Cell}; +use std::cell::RefCell; use std::mem; use rustc_data_structures::sync::{self, Lrc}; use std::rc::Rc; @@ -60,7 +60,6 @@ pub struct DocContext<'a, 'tcx: 'a, 'rcx: 'a, 'cstore: 'rcx> { /// The stack of module NodeIds up till this point pub crate_name: Option<String>, pub cstore: Rc<CStore>, - pub populated_all_crate_impls: Cell<bool>, // Note that external items for which `doc(hidden)` applies to are shown as // non-reachable while local items aren't. This is because we're reusing // the access levels from crateanalysis. @@ -514,7 +513,6 @@ pub fn run_core(search_paths: SearchPaths, resolver: &resolver, crate_name, cstore: cstore.clone(), - populated_all_crate_impls: Cell::new(false), access_levels: RefCell::new(access_levels), external_traits: Default::default(), active_extern_traits: Default::default(), diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs new file mode 100644 index 00000000000..0be5ab07dea --- /dev/null +++ b/src/librustdoc/passes/collect_trait_impls.rs @@ -0,0 +1,99 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use clean::*; + +use super::Pass; +use core::DocContext; + +pub const COLLECT_TRAIT_IMPLS: Pass = + Pass::early("collect-trait-impls", collect_trait_impls, + "retrieves trait impls for items in the crate"); + +pub fn collect_trait_impls(mut krate: Crate, cx: &DocContext) -> Crate { + if let Some(ref mut it) = krate.module { + if let ModuleItem(Module { ref mut items, .. }) = it.inner { + for &cnum in cx.tcx.crates().iter() { + for &did in cx.tcx.all_trait_implementations(cnum).iter() { + inline::build_impl(cx, did, items); + } + } + + // `tcx.crates()` doesn't include the local crate, and `tcx.all_trait_implementations` + // doesn't work with it anyway, so pull them from the HIR map instead + for &trait_did in cx.all_traits.iter() { + for &impl_node in cx.tcx.hir.trait_impls(trait_did) { + let impl_did = cx.tcx.hir.local_def_id(impl_node); + inline::build_impl(cx, impl_did, items); + } + } + + // Also try to inline primitive impls from other crates. + let lang_items = cx.tcx.lang_items(); + let primitive_impls = [ + lang_items.isize_impl(), + lang_items.i8_impl(), + lang_items.i16_impl(), + lang_items.i32_impl(), + lang_items.i64_impl(), + lang_items.i128_impl(), + lang_items.usize_impl(), + lang_items.u8_impl(), + lang_items.u16_impl(), + lang_items.u32_impl(), + lang_items.u64_impl(), + lang_items.u128_impl(), + lang_items.f32_impl(), + lang_items.f64_impl(), + lang_items.f32_runtime_impl(), + lang_items.f64_runtime_impl(), + lang_items.char_impl(), + lang_items.str_impl(), + lang_items.slice_impl(), + lang_items.slice_u8_impl(), + lang_items.str_alloc_impl(), + lang_items.slice_alloc_impl(), + lang_items.slice_u8_alloc_impl(), + lang_items.const_ptr_impl(), + lang_items.mut_ptr_impl(), + ]; + + for def_id in primitive_impls.iter().filter_map(|&def_id| def_id) { + if !def_id.is_local() { + inline::build_impl(cx, def_id, items); + + let auto_impls = get_auto_traits_with_def_id(cx, def_id); + let blanket_impls = get_blanket_impls_with_def_id(cx, def_id); + let mut renderinfo = cx.renderinfo.borrow_mut(); + + let new_impls: Vec<Item> = auto_impls.into_iter() + .chain(blanket_impls.into_iter()) + .filter(|i| renderinfo.inlined.insert(i.def_id)) + .collect(); + + items.extend(new_impls); + } + } + } else { + panic!("collect-trait-impls can't run"); + } + } else { + panic!("collect-trait-impls can't run"); + } + + // pulling in the impls puts their trait info into the DocContext, but that's already been + // drained by now, so stuff that info into the Crate so the rendering can pick it up + let mut external_traits = cx.external_traits.borrow_mut(); + for (did, trait_) in external_traits.drain() { + krate.external_traits.entry(did).or_insert(trait_); + } + + krate +} diff --git a/src/librustdoc/passes/mod.rs b/src/librustdoc/passes/mod.rs index 16251877bb1..09281aa7cfa 100644 --- a/src/librustdoc/passes/mod.rs +++ b/src/librustdoc/passes/mod.rs @@ -43,6 +43,9 @@ pub use self::propagate_doc_cfg::PROPAGATE_DOC_CFG; mod collect_intra_doc_links; pub use self::collect_intra_doc_links::COLLECT_INTRA_DOC_LINKS; +mod collect_trait_impls; +pub use self::collect_trait_impls::COLLECT_TRAIT_IMPLS; + /// Represents a single pass. #[derive(Copy, Clone)] pub enum Pass { @@ -132,10 +135,12 @@ pub const PASSES: &'static [Pass] = &[ STRIP_PRIV_IMPORTS, PROPAGATE_DOC_CFG, COLLECT_INTRA_DOC_LINKS, + COLLECT_TRAIT_IMPLS, ]; /// The list of passes run by default. pub const DEFAULT_PASSES: &'static [&'static str] = &[ + "collect-trait-impls", "strip-hidden", "strip-private", "collect-intra-doc-links", @@ -146,6 +151,7 @@ pub const DEFAULT_PASSES: &'static [&'static str] = &[ /// The list of default passes run with `--document-private-items` is passed to rustdoc. pub const DEFAULT_PRIVATE_PASSES: &'static [&'static str] = &[ + "collect-trait-impls", "strip-priv-imports", "collect-intra-doc-links", "collapse-docs", diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 0aaf2d526f9..a1942a966b1 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -510,9 +510,9 @@ impl<'a, 'tcx, 'rcx, 'cstore> RustdocVisitor<'a, 'tcx, 'rcx, 'cstore> { ref tr, ref ty, ref item_ids) => { - // Don't duplicate impls when inlining, we'll pick them up - // regardless of where they're located. - if !self.inlining { + // Don't duplicate impls when inlining or if it's implementing a trait, we'll pick + // them up regardless of where they're located. + if !self.inlining && tr.is_none() { let items = item_ids.iter() .map(|ii| self.cx.tcx.hir.impl_item(ii.id).clone()) .collect(); diff --git a/src/test/rustdoc/traits-in-bodies.rs b/src/test/rustdoc/traits-in-bodies.rs index 3acf4af5fd2..26ed5444122 100644 --- a/src/test/rustdoc/traits-in-bodies.rs +++ b/src/test/rustdoc/traits-in-bodies.rs @@ -11,11 +11,10 @@ //prior to fixing `everybody_loops` to preserve items, rustdoc would crash on this file, as it //didn't see that `SomeStruct` implemented `Clone` -//FIXME(misdreavus): whenever rustdoc shows traits impl'd inside bodies, make sure this test -//reflects that - pub struct Bounded<T: Clone>(T); +// @has traits_in_bodies/struct.SomeStruct.html +// @has - '//code' 'impl Clone for SomeStruct' pub struct SomeStruct; fn asdf() -> Bounded<SomeStruct> { @@ -27,3 +26,16 @@ fn asdf() -> Bounded<SomeStruct> { Bounded(SomeStruct) } + +// @has traits_in_bodies/struct.Point.html +// @has - '//code' 'impl Copy for Point' +#[derive(Clone)] +pub struct Point { + x: i32, + y: i32, +} + +const _FOO: () = { + impl Copy for Point {} + () +}; |
