Auto merge of #37773 - ollie27:rustdoc_inline_glob, r=brson
rustdoc: Fix some local inlining issues * Only inline public items when inlining glob imports. * Never inline while in a private module or a child of a private module. * Never inline impls. This allowed the removal of a workaround in the rendering code.
This commit is contained in:
commit
d88d06448e
6 changed files with 244 additions and 69 deletions
|
@ -257,8 +257,6 @@ pub struct Cache {
|
|||
parent_stack: Vec<DefId>,
|
||||
parent_is_trait_impl: bool,
|
||||
search_index: Vec<IndexItem>,
|
||||
seen_modules: FxHashSet<DefId>,
|
||||
seen_mod: bool,
|
||||
stripped_mod: bool,
|
||||
deref_trait_did: Option<DefId>,
|
||||
deref_mut_trait_did: Option<DefId>,
|
||||
|
@ -520,8 +518,6 @@ pub fn run(mut krate: clean::Crate,
|
|||
parent_is_trait_impl: false,
|
||||
extern_locations: FxHashMap(),
|
||||
primitive_locations: FxHashMap(),
|
||||
seen_modules: FxHashSet(),
|
||||
seen_mod: false,
|
||||
stripped_mod: false,
|
||||
access_levels: krate.access_levels.clone(),
|
||||
orphan_impl_items: Vec::new(),
|
||||
|
@ -977,26 +973,16 @@ impl DocFolder for Cache {
|
|||
_ => self.stripped_mod,
|
||||
};
|
||||
|
||||
// Inlining can cause us to visit the same item multiple times.
|
||||
// (i.e. relevant for gathering impls and implementors)
|
||||
let orig_seen_mod = if item.is_mod() {
|
||||
let seen_this = self.seen_mod || !self.seen_modules.insert(item.def_id);
|
||||
mem::replace(&mut self.seen_mod, seen_this)
|
||||
} else {
|
||||
self.seen_mod
|
||||
};
|
||||
|
||||
// Register any generics to their corresponding string. This is used
|
||||
// when pretty-printing types
|
||||
if let Some(generics) = item.inner.generics() {
|
||||
self.generics(generics);
|
||||
}
|
||||
|
||||
if !self.seen_mod {
|
||||
// Propagate a trait methods' documentation to all implementors of the
|
||||
// trait
|
||||
if let clean::TraitItem(ref t) = item.inner {
|
||||
self.traits.insert(item.def_id, t.clone());
|
||||
self.traits.entry(item.def_id).or_insert_with(|| t.clone());
|
||||
}
|
||||
|
||||
// Collect all the implementors of traits.
|
||||
|
@ -1009,7 +995,6 @@ impl DocFolder for Cache {
|
|||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Index this method for searching later on
|
||||
if let Some(ref s) = item.name {
|
||||
|
@ -1186,13 +1171,11 @@ impl DocFolder for Cache {
|
|||
} else {
|
||||
unreachable!()
|
||||
};
|
||||
if !self.seen_mod {
|
||||
if let Some(did) = did {
|
||||
self.impls.entry(did).or_insert(vec![]).push(Impl {
|
||||
impl_item: item,
|
||||
});
|
||||
}
|
||||
}
|
||||
None
|
||||
} else {
|
||||
Some(item)
|
||||
|
@ -1201,7 +1184,6 @@ impl DocFolder for Cache {
|
|||
|
||||
if pushed { self.stack.pop().unwrap(); }
|
||||
if parent_pushed { self.parent_stack.pop().unwrap(); }
|
||||
self.seen_mod = orig_seen_mod;
|
||||
self.stripped_mod = orig_stripped_mod;
|
||||
self.parent_is_trait_impl = orig_parent_is_trait_impl;
|
||||
ret
|
||||
|
|
|
@ -44,7 +44,9 @@ pub struct RustdocVisitor<'a, 'tcx: 'a> {
|
|||
pub attrs: hir::HirVec<ast::Attribute>,
|
||||
pub cx: &'a core::DocContext<'a, 'tcx>,
|
||||
view_item_stack: FxHashSet<ast::NodeId>,
|
||||
inlining_from_glob: bool,
|
||||
inlining: bool,
|
||||
/// Is the current module and all of its parents public?
|
||||
inside_public_path: bool,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
|
||||
|
@ -57,7 +59,8 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
|
|||
attrs: hir::HirVec::new(),
|
||||
cx: cx,
|
||||
view_item_stack: stack,
|
||||
inlining_from_glob: false,
|
||||
inlining: false,
|
||||
inside_public_path: true,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -189,10 +192,14 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
|
|||
om.stab = self.stability(id);
|
||||
om.depr = self.deprecation(id);
|
||||
om.id = id;
|
||||
// Keep track of if there were any private modules in the path.
|
||||
let orig_inside_public_path = self.inside_public_path;
|
||||
self.inside_public_path &= vis == hir::Public;
|
||||
for i in &m.item_ids {
|
||||
let item = self.cx.map.expect_item(i.id);
|
||||
self.visit_item(item, None, &mut om);
|
||||
}
|
||||
self.inside_public_path = orig_inside_public_path;
|
||||
if let Some(exports) = self.cx.export_map.get(&id) {
|
||||
for export in exports {
|
||||
if let Def::Macro(def_id) = export.def {
|
||||
|
@ -336,8 +343,8 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
|
|||
|
||||
let ret = match tcx.map.get(def_node_id) {
|
||||
hir_map::NodeItem(it) => {
|
||||
let prev = mem::replace(&mut self.inlining, true);
|
||||
if glob {
|
||||
let prev = mem::replace(&mut self.inlining_from_glob, true);
|
||||
match it.node {
|
||||
hir::ItemMod(ref m) => {
|
||||
for i in &m.item_ids {
|
||||
|
@ -348,10 +355,10 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
|
|||
hir::ItemEnum(..) => {}
|
||||
_ => { panic!("glob not mapped to a module or enum"); }
|
||||
}
|
||||
self.inlining_from_glob = prev;
|
||||
} else {
|
||||
self.visit_item(it, renamed, om);
|
||||
}
|
||||
self.inlining = prev;
|
||||
true
|
||||
}
|
||||
_ => false,
|
||||
|
@ -365,6 +372,19 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
|
|||
debug!("Visiting item {:?}", item);
|
||||
let name = renamed.unwrap_or(item.name);
|
||||
match item.node {
|
||||
hir::ItemForeignMod(ref fm) => {
|
||||
// If inlining we only want to include public functions.
|
||||
om.foreigns.push(if self.inlining {
|
||||
hir::ForeignMod {
|
||||
abi: fm.abi,
|
||||
items: fm.items.iter().filter(|i| i.vis == hir::Public).cloned().collect(),
|
||||
}
|
||||
} else {
|
||||
fm.clone()
|
||||
});
|
||||
}
|
||||
// If we're inlining, skip private items.
|
||||
_ if self.inlining && item.vis != hir::Public => {}
|
||||
hir::ItemExternCrate(ref p) => {
|
||||
let cstore = &self.cx.sess().cstore;
|
||||
om.extern_crates.push(ExternCrate {
|
||||
|
@ -379,7 +399,9 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
|
|||
}
|
||||
hir::ItemUse(ref vpath) => {
|
||||
let node = vpath.node.clone();
|
||||
let node = if item.vis == hir::Public {
|
||||
// If there was a private module in the current path then don't bother inlining
|
||||
// anything as it will probably be stripped anyway.
|
||||
let node = if item.vis == hir::Public && self.inside_public_path {
|
||||
let please_inline = item.attrs.iter().any(|item| {
|
||||
match item.meta_item_list() {
|
||||
Some(list) if item.check_name("doc") => {
|
||||
|
@ -479,7 +501,11 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
|
|||
};
|
||||
om.traits.push(t);
|
||||
},
|
||||
|
||||
hir::ItemImpl(unsafety, polarity, ref gen, ref tr, ref ty, ref items) => {
|
||||
// Don't duplicate impls when inlining, we'll pick them up
|
||||
// regardless of where they're located.
|
||||
if !self.inlining {
|
||||
let i = Impl {
|
||||
unsafety: unsafety,
|
||||
polarity: polarity,
|
||||
|
@ -494,13 +520,12 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
|
|||
stab: self.stability(item.id),
|
||||
depr: self.deprecation(item.id),
|
||||
};
|
||||
// Don't duplicate impls when inlining glob imports, we'll pick
|
||||
// them up regardless of where they're located.
|
||||
if !self.inlining_from_glob {
|
||||
om.impls.push(i);
|
||||
}
|
||||
},
|
||||
hir::ItemDefaultImpl(unsafety, ref trait_ref) => {
|
||||
// See comment above about ItemImpl.
|
||||
if !self.inlining {
|
||||
let i = DefaultImpl {
|
||||
unsafety: unsafety,
|
||||
trait_: trait_ref.clone(),
|
||||
|
@ -508,14 +533,9 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
|
|||
attrs: item.attrs.clone(),
|
||||
whence: item.span,
|
||||
};
|
||||
// see comment above about ItemImpl
|
||||
if !self.inlining_from_glob {
|
||||
om.def_traits.push(i);
|
||||
}
|
||||
}
|
||||
hir::ItemForeignMod(ref fm) => {
|
||||
om.foreigns.push(fm.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
35
src/test/rustdoc/inline_local/glob-extern-no-defaults.rs
Normal file
35
src/test/rustdoc/inline_local/glob-extern-no-defaults.rs
Normal file
|
@ -0,0 +1,35 @@
|
|||
// Copyright 2016 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.
|
||||
|
||||
// compile-flags: --no-defaults
|
||||
|
||||
#![crate_name = "foo"]
|
||||
|
||||
mod mod1 {
|
||||
extern {
|
||||
pub fn public_fn();
|
||||
fn private_fn();
|
||||
}
|
||||
}
|
||||
|
||||
pub use mod1::*;
|
||||
|
||||
// @has foo/index.html
|
||||
// @has - "mod1"
|
||||
// @has - "public_fn"
|
||||
// @!has - "private_fn"
|
||||
// @has foo/fn.public_fn.html
|
||||
// @!has foo/fn.private_fn.html
|
||||
|
||||
// @has foo/mod1/index.html
|
||||
// @has - "public_fn"
|
||||
// @has - "private_fn"
|
||||
// @has foo/mod1/fn.public_fn.html
|
||||
// @has foo/mod1/fn.private_fn.html
|
31
src/test/rustdoc/inline_local/glob-extern.rs
Normal file
31
src/test/rustdoc/inline_local/glob-extern.rs
Normal file
|
@ -0,0 +1,31 @@
|
|||
// Copyright 2016 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.
|
||||
|
||||
#![crate_name = "foo"]
|
||||
|
||||
mod mod1 {
|
||||
extern {
|
||||
pub fn public_fn();
|
||||
fn private_fn();
|
||||
}
|
||||
}
|
||||
|
||||
pub use mod1::*;
|
||||
|
||||
// @has foo/index.html
|
||||
// @!has - "mod1"
|
||||
// @has - "public_fn"
|
||||
// @!has - "private_fn"
|
||||
// @has foo/fn.public_fn.html
|
||||
// @!has foo/fn.private_fn.html
|
||||
|
||||
// @!has foo/mod1/index.html
|
||||
// @has foo/mod1/fn.public_fn.html
|
||||
// @!has foo/mod1/fn.private_fn.html
|
58
src/test/rustdoc/inline_local/glob-private-no-defaults.rs
Normal file
58
src/test/rustdoc/inline_local/glob-private-no-defaults.rs
Normal file
|
@ -0,0 +1,58 @@
|
|||
// Copyright 2016 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.
|
||||
|
||||
// compile-flags: --no-defaults
|
||||
|
||||
#![crate_name = "foo"]
|
||||
|
||||
mod mod1 {
|
||||
mod mod2 {
|
||||
pub struct Mod2Public;
|
||||
struct Mod2Private;
|
||||
}
|
||||
pub use self::mod2::*;
|
||||
|
||||
pub struct Mod1Public;
|
||||
struct Mod1Private;
|
||||
}
|
||||
pub use mod1::*;
|
||||
|
||||
// @has foo/index.html
|
||||
// @has - "mod1"
|
||||
// @has - "Mod1Public"
|
||||
// @!has - "Mod1Private"
|
||||
// @!has - "mod2"
|
||||
// @has - "Mod2Public"
|
||||
// @!has - "Mod2Private"
|
||||
// @has foo/struct.Mod1Public.html
|
||||
// @!has foo/struct.Mod1Private.html
|
||||
// @has foo/struct.Mod2Public.html
|
||||
// @!has foo/struct.Mod2Private.html
|
||||
|
||||
// @has foo/mod1/index.html
|
||||
// @has - "mod2"
|
||||
// @has - "Mod1Public"
|
||||
// @has - "Mod1Private"
|
||||
// @!has - "Mod2Public"
|
||||
// @!has - "Mod2Private"
|
||||
// @has foo/mod1/struct.Mod1Public.html
|
||||
// @has foo/mod1/struct.Mod1Private.html
|
||||
// @!has foo/mod1/struct.Mod2Public.html
|
||||
// @!has foo/mod1/struct.Mod2Private.html
|
||||
|
||||
// @has foo/mod1/mod2/index.html
|
||||
// @has - "Mod2Public"
|
||||
// @has - "Mod2Private"
|
||||
// @has foo/mod1/mod2/struct.Mod2Public.html
|
||||
// @has foo/mod1/mod2/struct.Mod2Private.html
|
||||
|
||||
// @!has foo/mod2/index.html
|
||||
// @!has foo/mod2/struct.Mod2Public.html
|
||||
// @!has foo/mod2/struct.Mod2Private.html
|
49
src/test/rustdoc/inline_local/glob-private.rs
Normal file
49
src/test/rustdoc/inline_local/glob-private.rs
Normal file
|
@ -0,0 +1,49 @@
|
|||
// Copyright 2016 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.
|
||||
|
||||
#![crate_name = "foo"]
|
||||
|
||||
mod mod1 {
|
||||
mod mod2 {
|
||||
pub struct Mod2Public;
|
||||
struct Mod2Private;
|
||||
}
|
||||
pub use self::mod2::*;
|
||||
|
||||
pub struct Mod1Public;
|
||||
struct Mod1Private;
|
||||
}
|
||||
pub use mod1::*;
|
||||
|
||||
// @has foo/index.html
|
||||
// @!has - "mod1"
|
||||
// @has - "Mod1Public"
|
||||
// @!has - "Mod1Private"
|
||||
// @!has - "mod2"
|
||||
// @has - "Mod2Public"
|
||||
// @!has - "Mod2Private"
|
||||
// @has foo/struct.Mod1Public.html
|
||||
// @!has foo/struct.Mod1Private.html
|
||||
// @has foo/struct.Mod2Public.html
|
||||
// @!has foo/struct.Mod2Private.html
|
||||
|
||||
// @!has foo/mod1/index.html
|
||||
// @has foo/mod1/struct.Mod1Public.html
|
||||
// @!has foo/mod1/struct.Mod1Private.html
|
||||
// @!has foo/mod1/struct.Mod2Public.html
|
||||
// @!has foo/mod1/struct.Mod2Private.html
|
||||
|
||||
// @!has foo/mod1/mod2/index.html
|
||||
// @has foo/mod1/mod2/struct.Mod2Public.html
|
||||
// @!has foo/mod1/mod2/struct.Mod2Private.html
|
||||
|
||||
// @!has foo/mod2/index.html
|
||||
// @!has foo/mod2/struct.Mod2Public.html
|
||||
// @!has foo/mod2/struct.Mod2Private.html
|
Loading…
Add table
Add a link
Reference in a new issue