1
Fork 0

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:
bors 2016-11-16 01:17:53 -08:00 committed by GitHub
commit d88d06448e
6 changed files with 244 additions and 69 deletions

View file

@ -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

View file

@ -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());
}
}
}

View 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

View 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

View 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

View 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