Skip to content

Commit beebaf1

Browse files
committed
rustdoc: Fix a few stripping issues
We need to recurse into stripped modules to strip things like impl methods but when doing so we must not add any items to the `retained` set.
1 parent 126af08 commit beebaf1

File tree

3 files changed

+106
-18
lines changed

3 files changed

+106
-18
lines changed

src/librustdoc/passes.rs

+40-18
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use rustc::hir::def_id::DefId;
1212
use rustc::middle::privacy::AccessLevels;
1313
use rustc::util::nodemap::DefIdSet;
1414
use std::cmp;
15+
use std::mem;
1516
use std::string::String;
1617
use std::usize;
1718

@@ -29,7 +30,8 @@ pub fn strip_hidden(krate: clean::Crate) -> plugins::PluginResult {
2930
// strip all #[doc(hidden)] items
3031
let krate = {
3132
struct Stripper<'a> {
32-
retained: &'a mut DefIdSet
33+
retained: &'a mut DefIdSet,
34+
update_retained: bool,
3335
}
3436
impl<'a> fold::DocFolder for Stripper<'a> {
3537
fn fold_item(&mut self, i: Item) -> Option<Item> {
@@ -38,17 +40,25 @@ pub fn strip_hidden(krate: clean::Crate) -> plugins::PluginResult {
3840
// use a dedicated hidden item for given item type if any
3941
match i.inner {
4042
clean::StructFieldItem(..) | clean::ModuleItem(..) => {
41-
return Strip(i).fold()
43+
// We need to recurse into stripped modules to
44+
// strip things like impl methods but when doing so
45+
// we must not add any items to the `retained` set.
46+
let old = mem::replace(&mut self.update_retained, false);
47+
let ret = Strip(self.fold_item_recur(i).unwrap()).fold();
48+
self.update_retained = old;
49+
return ret;
4250
}
4351
_ => return None,
4452
}
4553
} else {
46-
self.retained.insert(i.def_id);
54+
if self.update_retained {
55+
self.retained.insert(i.def_id);
56+
}
4757
}
4858
self.fold_item_recur(i)
4959
}
5060
}
51-
let mut stripper = Stripper{ retained: &mut retained };
61+
let mut stripper = Stripper{ retained: &mut retained, update_retained: true };
5262
stripper.fold_crate(krate)
5363
};
5464

@@ -69,6 +79,7 @@ pub fn strip_private(mut krate: clean::Crate) -> plugins::PluginResult {
6979
let mut stripper = Stripper {
7080
retained: &mut retained,
7181
access_levels: &access_levels,
82+
update_retained: true,
7283
};
7384
krate = ImportStripper.fold_crate(stripper.fold_crate(krate));
7485
}
@@ -81,12 +92,21 @@ pub fn strip_private(mut krate: clean::Crate) -> plugins::PluginResult {
8192
struct Stripper<'a> {
8293
retained: &'a mut DefIdSet,
8394
access_levels: &'a AccessLevels<DefId>,
95+
update_retained: bool,
8496
}
8597

8698
impl<'a> fold::DocFolder for Stripper<'a> {
8799
fn fold_item(&mut self, i: Item) -> Option<Item> {
88100
match i.inner {
89-
clean::StrippedItem(..) => return Some(i),
101+
clean::StrippedItem(..) => {
102+
// We need to recurse into stripped modules to strip things
103+
// like impl methods but when doing so we must not add any
104+
// items to the `retained` set.
105+
let old = mem::replace(&mut self.update_retained, false);
106+
let ret = self.fold_item_recur(i);
107+
self.update_retained = old;
108+
return ret;
109+
}
90110
// These items can all get re-exported
91111
clean::TypedefItem(..) | clean::StaticItem(..) |
92112
clean::StructItem(..) | clean::EnumItem(..) |
@@ -109,18 +129,13 @@ impl<'a> fold::DocFolder for Stripper<'a> {
109129

110130
clean::ModuleItem(..) => {
111131
if i.def_id.is_local() && i.visibility != Some(clean::Public) {
112-
return Strip(self.fold_item_recur(i).unwrap()).fold()
132+
let old = mem::replace(&mut self.update_retained, false);
133+
let ret = Strip(self.fold_item_recur(i).unwrap()).fold();
134+
self.update_retained = old;
135+
return ret;
113136
}
114137
}
115138

116-
// trait impls for private items should be stripped
117-
clean::ImplItem(clean::Impl{
118-
for_: clean::ResolvedPath{ did, is_generic, .. }, ..
119-
}) => {
120-
if did.is_local() && !is_generic && !self.access_levels.is_exported(did) {
121-
return None;
122-
}
123-
}
124139
// handled in the `strip-priv-imports` pass
125140
clean::ExternCrateItem(..) | clean::ImportItem(..) => {}
126141

@@ -152,21 +167,24 @@ impl<'a> fold::DocFolder for Stripper<'a> {
152167
};
153168

154169
let i = if fastreturn {
155-
self.retained.insert(i.def_id);
170+
if self.update_retained {
171+
self.retained.insert(i.def_id);
172+
}
156173
return Some(i);
157174
} else {
158175
self.fold_item_recur(i)
159176
};
160177

161178
i.and_then(|i| {
162179
match i.inner {
163-
// emptied modules/impls have no need to exist
180+
// emptied modules have no need to exist
164181
clean::ModuleItem(ref m)
165182
if m.items.is_empty() &&
166183
i.doc_value().is_none() => None,
167-
clean::ImplItem(ref i) if i.items.is_empty() => None,
168184
_ => {
169-
self.retained.insert(i.def_id);
185+
if self.update_retained {
186+
self.retained.insert(i.def_id);
187+
}
170188
Some(i)
171189
}
172190
}
@@ -182,6 +200,10 @@ struct ImplStripper<'a> {
182200
impl<'a> fold::DocFolder for ImplStripper<'a> {
183201
fn fold_item(&mut self, i: Item) -> Option<Item> {
184202
if let clean::ImplItem(ref imp) = i.inner {
203+
// emptied none trait impls can be stripped
204+
if imp.trait_.is_none() && imp.items.is_empty() {
205+
return None;
206+
}
185207
if let Some(did) = imp.for_.def_id() {
186208
if did.is_local() && !imp.for_.is_generic() &&
187209
!self.retained.contains(&did)

src/test/rustdoc/hidden-impls.rs

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
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 hidden {
14+
#[derive(Clone)]
15+
pub struct Foo;
16+
}
17+
18+
#[doc(hidden)]
19+
pub mod __hidden {
20+
pub use hidden::Foo;
21+
}
22+
23+
// @has foo/trait.Clone.html
24+
// @!has - 'Foo'
25+
// @has implementors/foo/trait.Clone.js
26+
// @!has - 'Foo'
27+
pub use std::clone::Clone;

src/test/rustdoc/hidden-methods.rs

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
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+
#[doc(hidden)]
14+
pub mod hidden {
15+
pub struct Foo;
16+
17+
impl Foo {
18+
#[doc(hidden)]
19+
pub fn this_should_be_hidden() {}
20+
}
21+
22+
pub struct Bar;
23+
24+
impl Bar {
25+
fn this_should_be_hidden() {}
26+
}
27+
}
28+
29+
// @has foo/struct.Foo.html
30+
// @!has - 'Methods'
31+
// @!has - 'impl Foo'
32+
// @!has - 'this_should_be_hidden'
33+
pub use hidden::Foo;
34+
35+
// @has foo/struct.Bar.html
36+
// @!has - 'Methods'
37+
// @!has - 'impl Bar'
38+
// @!has - 'this_should_be_hidden'
39+
pub use hidden::Bar;

0 commit comments

Comments
 (0)