Skip to content

Commit 6fe7786

Browse files
committed
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.
1 parent acce384 commit 6fe7786

File tree

6 files changed

+244
-69
lines changed

6 files changed

+244
-69
lines changed

src/librustdoc/html/render.rs

+17-35
Original file line numberDiff line numberDiff line change
@@ -257,8 +257,6 @@ pub struct Cache {
257257
parent_stack: Vec<DefId>,
258258
parent_is_trait_impl: bool,
259259
search_index: Vec<IndexItem>,
260-
seen_modules: FxHashSet<DefId>,
261-
seen_mod: bool,
262260
stripped_mod: bool,
263261
deref_trait_did: Option<DefId>,
264262
deref_mut_trait_did: Option<DefId>,
@@ -520,8 +518,6 @@ pub fn run(mut krate: clean::Crate,
520518
parent_is_trait_impl: false,
521519
extern_locations: FxHashMap(),
522520
primitive_locations: FxHashMap(),
523-
seen_modules: FxHashSet(),
524-
seen_mod: false,
525521
stripped_mod: false,
526522
access_levels: krate.access_levels.clone(),
527523
orphan_impl_items: Vec::new(),
@@ -977,37 +973,26 @@ impl DocFolder for Cache {
977973
_ => self.stripped_mod,
978974
};
979975

980-
// Inlining can cause us to visit the same item multiple times.
981-
// (i.e. relevant for gathering impls and implementors)
982-
let orig_seen_mod = if item.is_mod() {
983-
let seen_this = self.seen_mod || !self.seen_modules.insert(item.def_id);
984-
mem::replace(&mut self.seen_mod, seen_this)
985-
} else {
986-
self.seen_mod
987-
};
988-
989976
// Register any generics to their corresponding string. This is used
990977
// when pretty-printing types
991978
if let Some(generics) = item.inner.generics() {
992979
self.generics(generics);
993980
}
994981

995-
if !self.seen_mod {
996-
// Propagate a trait methods' documentation to all implementors of the
997-
// trait
998-
if let clean::TraitItem(ref t) = item.inner {
999-
self.traits.insert(item.def_id, t.clone());
1000-
}
982+
// Propagate a trait methods' documentation to all implementors of the
983+
// trait
984+
if let clean::TraitItem(ref t) = item.inner {
985+
self.traits.entry(item.def_id).or_insert_with(|| t.clone());
986+
}
1001987

1002-
// Collect all the implementors of traits.
1003-
if let clean::ImplItem(ref i) = item.inner {
1004-
if let Some(did) = i.trait_.def_id() {
1005-
self.implementors.entry(did).or_insert(vec![]).push(Implementor {
1006-
def_id: item.def_id,
1007-
stability: item.stability.clone(),
1008-
impl_: i.clone(),
1009-
});
1010-
}
988+
// Collect all the implementors of traits.
989+
if let clean::ImplItem(ref i) = item.inner {
990+
if let Some(did) = i.trait_.def_id() {
991+
self.implementors.entry(did).or_insert(vec![]).push(Implementor {
992+
def_id: item.def_id,
993+
stability: item.stability.clone(),
994+
impl_: i.clone(),
995+
});
1011996
}
1012997
}
1013998

@@ -1186,12 +1171,10 @@ impl DocFolder for Cache {
11861171
} else {
11871172
unreachable!()
11881173
};
1189-
if !self.seen_mod {
1190-
if let Some(did) = did {
1191-
self.impls.entry(did).or_insert(vec![]).push(Impl {
1192-
impl_item: item,
1193-
});
1194-
}
1174+
if let Some(did) = did {
1175+
self.impls.entry(did).or_insert(vec![]).push(Impl {
1176+
impl_item: item,
1177+
});
11951178
}
11961179
None
11971180
} else {
@@ -1201,7 +1184,6 @@ impl DocFolder for Cache {
12011184

12021185
if pushed { self.stack.pop().unwrap(); }
12031186
if parent_pushed { self.parent_stack.pop().unwrap(); }
1204-
self.seen_mod = orig_seen_mod;
12051187
self.stripped_mod = orig_stripped_mod;
12061188
self.parent_is_trait_impl = orig_parent_is_trait_impl;
12071189
ret

src/librustdoc/visit_ast.rs

+54-34
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,9 @@ pub struct RustdocVisitor<'a, 'tcx: 'a> {
4444
pub attrs: hir::HirVec<ast::Attribute>,
4545
pub cx: &'a core::DocContext<'a, 'tcx>,
4646
view_item_stack: FxHashSet<ast::NodeId>,
47-
inlining_from_glob: bool,
47+
inlining: bool,
48+
/// Is the current module and all of its parents public?
49+
inside_public_path: bool,
4850
}
4951

5052
impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
@@ -57,7 +59,8 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
5759
attrs: hir::HirVec::new(),
5860
cx: cx,
5961
view_item_stack: stack,
60-
inlining_from_glob: false,
62+
inlining: false,
63+
inside_public_path: true,
6164
}
6265
}
6366

@@ -189,10 +192,14 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
189192
om.stab = self.stability(id);
190193
om.depr = self.deprecation(id);
191194
om.id = id;
195+
// Keep track of if there were any private modules in the path.
196+
let orig_inside_public_path = self.inside_public_path;
197+
self.inside_public_path &= vis == hir::Public;
192198
for i in &m.item_ids {
193199
let item = self.cx.map.expect_item(i.id);
194200
self.visit_item(item, None, &mut om);
195201
}
202+
self.inside_public_path = orig_inside_public_path;
196203
if let Some(exports) = self.cx.export_map.get(&id) {
197204
for export in exports {
198205
if let Def::Macro(def_id) = export.def {
@@ -336,8 +343,8 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
336343

337344
let ret = match tcx.map.get(def_node_id) {
338345
hir_map::NodeItem(it) => {
346+
let prev = mem::replace(&mut self.inlining, true);
339347
if glob {
340-
let prev = mem::replace(&mut self.inlining_from_glob, true);
341348
match it.node {
342349
hir::ItemMod(ref m) => {
343350
for i in &m.item_ids {
@@ -348,10 +355,10 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
348355
hir::ItemEnum(..) => {}
349356
_ => { panic!("glob not mapped to a module or enum"); }
350357
}
351-
self.inlining_from_glob = prev;
352358
} else {
353359
self.visit_item(it, renamed, om);
354360
}
361+
self.inlining = prev;
355362
true
356363
}
357364
_ => false,
@@ -365,6 +372,19 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
365372
debug!("Visiting item {:?}", item);
366373
let name = renamed.unwrap_or(item.name);
367374
match item.node {
375+
hir::ItemForeignMod(ref fm) => {
376+
// If inlining we only want to include public functions.
377+
om.foreigns.push(if self.inlining {
378+
hir::ForeignMod {
379+
abi: fm.abi,
380+
items: fm.items.iter().filter(|i| i.vis == hir::Public).cloned().collect(),
381+
}
382+
} else {
383+
fm.clone()
384+
});
385+
}
386+
// If we're inlining, skip private items.
387+
_ if self.inlining && item.vis != hir::Public => {}
368388
hir::ItemExternCrate(ref p) => {
369389
let cstore = &self.cx.sess().cstore;
370390
om.extern_crates.push(ExternCrate {
@@ -379,7 +399,9 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
379399
}
380400
hir::ItemUse(ref vpath) => {
381401
let node = vpath.node.clone();
382-
let node = if item.vis == hir::Public {
402+
// If there was a private module in the current path then don't bother inlining
403+
// anything as it will probably be stripped anyway.
404+
let node = if item.vis == hir::Public && self.inside_public_path {
383405
let please_inline = item.attrs.iter().any(|item| {
384406
match item.meta_item_list() {
385407
Some(list) if item.check_name("doc") => {
@@ -479,43 +501,41 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
479501
};
480502
om.traits.push(t);
481503
},
504+
482505
hir::ItemImpl(unsafety, polarity, ref gen, ref tr, ref ty, ref items) => {
483-
let i = Impl {
484-
unsafety: unsafety,
485-
polarity: polarity,
486-
generics: gen.clone(),
487-
trait_: tr.clone(),
488-
for_: ty.clone(),
489-
items: items.clone(),
490-
attrs: item.attrs.clone(),
491-
id: item.id,
492-
whence: item.span,
493-
vis: item.vis.clone(),
494-
stab: self.stability(item.id),
495-
depr: self.deprecation(item.id),
496-
};
497-
// Don't duplicate impls when inlining glob imports, we'll pick
498-
// them up regardless of where they're located.
499-
if !self.inlining_from_glob {
506+
// Don't duplicate impls when inlining, we'll pick them up
507+
// regardless of where they're located.
508+
if !self.inlining {
509+
let i = Impl {
510+
unsafety: unsafety,
511+
polarity: polarity,
512+
generics: gen.clone(),
513+
trait_: tr.clone(),
514+
for_: ty.clone(),
515+
items: items.clone(),
516+
attrs: item.attrs.clone(),
517+
id: item.id,
518+
whence: item.span,
519+
vis: item.vis.clone(),
520+
stab: self.stability(item.id),
521+
depr: self.deprecation(item.id),
522+
};
500523
om.impls.push(i);
501524
}
502525
},
503526
hir::ItemDefaultImpl(unsafety, ref trait_ref) => {
504-
let i = DefaultImpl {
505-
unsafety: unsafety,
506-
trait_: trait_ref.clone(),
507-
id: item.id,
508-
attrs: item.attrs.clone(),
509-
whence: item.span,
510-
};
511-
// see comment above about ItemImpl
512-
if !self.inlining_from_glob {
527+
// See comment above about ItemImpl.
528+
if !self.inlining {
529+
let i = DefaultImpl {
530+
unsafety: unsafety,
531+
trait_: trait_ref.clone(),
532+
id: item.id,
533+
attrs: item.attrs.clone(),
534+
whence: item.span,
535+
};
513536
om.def_traits.push(i);
514537
}
515538
}
516-
hir::ItemForeignMod(ref fm) => {
517-
om.foreigns.push(fm.clone());
518-
}
519539
}
520540
}
521541

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// Copyright 2016 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+
// compile-flags: --no-defaults
12+
13+
#![crate_name = "foo"]
14+
15+
mod mod1 {
16+
extern {
17+
pub fn public_fn();
18+
fn private_fn();
19+
}
20+
}
21+
22+
pub use mod1::*;
23+
24+
// @has foo/index.html
25+
// @has - "mod1"
26+
// @has - "public_fn"
27+
// @!has - "private_fn"
28+
// @has foo/fn.public_fn.html
29+
// @!has foo/fn.private_fn.html
30+
31+
// @has foo/mod1/index.html
32+
// @has - "public_fn"
33+
// @has - "private_fn"
34+
// @has foo/mod1/fn.public_fn.html
35+
// @has foo/mod1/fn.private_fn.html
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// Copyright 2016 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+
#![crate_name = "foo"]
12+
13+
mod mod1 {
14+
extern {
15+
pub fn public_fn();
16+
fn private_fn();
17+
}
18+
}
19+
20+
pub use mod1::*;
21+
22+
// @has foo/index.html
23+
// @!has - "mod1"
24+
// @has - "public_fn"
25+
// @!has - "private_fn"
26+
// @has foo/fn.public_fn.html
27+
// @!has foo/fn.private_fn.html
28+
29+
// @!has foo/mod1/index.html
30+
// @has foo/mod1/fn.public_fn.html
31+
// @!has foo/mod1/fn.private_fn.html
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
// Copyright 2016 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+
// compile-flags: --no-defaults
12+
13+
#![crate_name = "foo"]
14+
15+
mod mod1 {
16+
mod mod2 {
17+
pub struct Mod2Public;
18+
struct Mod2Private;
19+
}
20+
pub use self::mod2::*;
21+
22+
pub struct Mod1Public;
23+
struct Mod1Private;
24+
}
25+
pub use mod1::*;
26+
27+
// @has foo/index.html
28+
// @has - "mod1"
29+
// @has - "Mod1Public"
30+
// @!has - "Mod1Private"
31+
// @!has - "mod2"
32+
// @has - "Mod2Public"
33+
// @!has - "Mod2Private"
34+
// @has foo/struct.Mod1Public.html
35+
// @!has foo/struct.Mod1Private.html
36+
// @has foo/struct.Mod2Public.html
37+
// @!has foo/struct.Mod2Private.html
38+
39+
// @has foo/mod1/index.html
40+
// @has - "mod2"
41+
// @has - "Mod1Public"
42+
// @has - "Mod1Private"
43+
// @!has - "Mod2Public"
44+
// @!has - "Mod2Private"
45+
// @has foo/mod1/struct.Mod1Public.html
46+
// @has foo/mod1/struct.Mod1Private.html
47+
// @!has foo/mod1/struct.Mod2Public.html
48+
// @!has foo/mod1/struct.Mod2Private.html
49+
50+
// @has foo/mod1/mod2/index.html
51+
// @has - "Mod2Public"
52+
// @has - "Mod2Private"
53+
// @has foo/mod1/mod2/struct.Mod2Public.html
54+
// @has foo/mod1/mod2/struct.Mod2Private.html
55+
56+
// @!has foo/mod2/index.html
57+
// @!has foo/mod2/struct.Mod2Public.html
58+
// @!has foo/mod2/struct.Mod2Private.html

0 commit comments

Comments
 (0)