Skip to content

Commit 752b9a8

Browse files
authored
Rollup merge of #100323 - GuillaumeGomez:impl-blocks-only-private, r=notriddle
[rustdoc] Don't render impl blocks with doc comment if they only contain private items by default Fixes #100001. cc `@jhpratt` r? `@notriddle`
2 parents a431ef4 + c634852 commit 752b9a8

File tree

5 files changed

+138
-17
lines changed

5 files changed

+138
-17
lines changed

Diff for: src/librustdoc/passes/strip_hidden.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ pub(crate) const STRIP_HIDDEN: Pass = Pass {
1717
/// Strip items marked `#[doc(hidden)]`
1818
pub(crate) fn strip_hidden(krate: clean::Crate, cx: &mut DocContext<'_>) -> clean::Crate {
1919
let mut retained = ItemIdSet::default();
20+
let is_json_output = cx.output_format.is_json() && !cx.show_coverage;
2021

2122
// strip all #[doc(hidden)] items
2223
let krate = {
@@ -25,7 +26,12 @@ pub(crate) fn strip_hidden(krate: clean::Crate, cx: &mut DocContext<'_>) -> clea
2526
};
2627

2728
// strip all impls referencing stripped items
28-
let mut stripper = ImplStripper { retained: &retained, cache: &cx.cache };
29+
let mut stripper = ImplStripper {
30+
retained: &retained,
31+
cache: &cx.cache,
32+
is_json_output,
33+
document_private: cx.render_options.document_private,
34+
};
2935
stripper.fold_crate(krate)
3036
}
3137

Diff for: src/librustdoc/passes/strip_private.rs

+8-2
Original file line numberDiff line numberDiff line change
@@ -17,19 +17,25 @@ pub(crate) const STRIP_PRIVATE: Pass = Pass {
1717
pub(crate) fn strip_private(mut krate: clean::Crate, cx: &mut DocContext<'_>) -> clean::Crate {
1818
// This stripper collects all *retained* nodes.
1919
let mut retained = ItemIdSet::default();
20+
let is_json_output = cx.output_format.is_json() && !cx.show_coverage;
2021

2122
// strip all private items
2223
{
2324
let mut stripper = Stripper {
2425
retained: &mut retained,
2526
access_levels: &cx.cache.access_levels,
2627
update_retained: true,
27-
is_json_output: cx.output_format.is_json() && !cx.show_coverage,
28+
is_json_output,
2829
};
2930
krate = ImportStripper.fold_crate(stripper.fold_crate(krate));
3031
}
3132

3233
// strip all impls referencing private items
33-
let mut stripper = ImplStripper { retained: &retained, cache: &cx.cache };
34+
let mut stripper = ImplStripper {
35+
retained: &retained,
36+
cache: &cx.cache,
37+
is_json_output,
38+
document_private: cx.render_options.document_private,
39+
};
3440
stripper.fold_crate(krate)
3541
}

Diff for: src/librustdoc/passes/stripper.rs

+39-14
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,19 @@ pub(crate) struct Stripper<'a> {
1414
pub(crate) is_json_output: bool,
1515
}
1616

17-
impl<'a> Stripper<'a> {
18-
// We need to handle this differently for the JSON output because some non exported items could
19-
// be used in public API. And so, we need these items as well. `is_exported` only checks if they
20-
// are in the public API, which is not enough.
21-
#[inline]
22-
fn is_item_reachable(&self, item_id: ItemId) -> bool {
23-
if self.is_json_output {
24-
self.access_levels.is_reachable(item_id.expect_def_id())
25-
} else {
26-
self.access_levels.is_exported(item_id.expect_def_id())
27-
}
17+
// We need to handle this differently for the JSON output because some non exported items could
18+
// be used in public API. And so, we need these items as well. `is_exported` only checks if they
19+
// are in the public API, which is not enough.
20+
#[inline]
21+
fn is_item_reachable(
22+
is_json_output: bool,
23+
access_levels: &AccessLevels<DefId>,
24+
item_id: ItemId,
25+
) -> bool {
26+
if is_json_output {
27+
access_levels.is_reachable(item_id.expect_def_id())
28+
} else {
29+
access_levels.is_exported(item_id.expect_def_id())
2830
}
2931
}
3032

@@ -61,7 +63,9 @@ impl<'a> DocFolder for Stripper<'a> {
6163
| clean::MacroItem(..)
6264
| clean::ForeignTypeItem => {
6365
let item_id = i.item_id;
64-
if item_id.is_local() && !self.is_item_reachable(item_id) {
66+
if item_id.is_local()
67+
&& !is_item_reachable(self.is_json_output, self.access_levels, item_id)
68+
{
6569
debug!("Stripper: stripping {:?} {:?}", i.type_(), i.name);
6670
return None;
6771
}
@@ -133,15 +137,36 @@ impl<'a> DocFolder for Stripper<'a> {
133137
pub(crate) struct ImplStripper<'a> {
134138
pub(crate) retained: &'a ItemIdSet,
135139
pub(crate) cache: &'a Cache,
140+
pub(crate) is_json_output: bool,
141+
pub(crate) document_private: bool,
136142
}
137143

138144
impl<'a> DocFolder for ImplStripper<'a> {
139145
fn fold_item(&mut self, i: Item) -> Option<Item> {
140146
if let clean::ImplItem(ref imp) = *i.kind {
141147
// Impl blocks can be skipped if they are: empty; not a trait impl; and have no
142148
// documentation.
143-
if imp.trait_.is_none() && imp.items.is_empty() && i.doc_value().is_none() {
144-
return None;
149+
//
150+
// There is one special case: if the impl block contains only private items.
151+
if imp.trait_.is_none() {
152+
// If the only items present are private ones and we're not rendering private items,
153+
// we don't document it.
154+
if !imp.items.is_empty()
155+
&& !self.document_private
156+
&& imp.items.iter().all(|i| {
157+
let item_id = i.item_id;
158+
item_id.is_local()
159+
&& !is_item_reachable(
160+
self.is_json_output,
161+
&self.cache.access_levels,
162+
item_id,
163+
)
164+
})
165+
{
166+
return None;
167+
} else if imp.items.is_empty() && i.doc_value().is_none() {
168+
return None;
169+
}
145170
}
146171
if let Some(did) = imp.for_.def_id(self.cache) {
147172
if did.is_local() && !imp.for_.is_assoc_ty() && !self.retained.contains(&did.into())
+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// compile-flags: --document-private-items
2+
3+
#![feature(inherent_associated_types)]
4+
#![allow(incomplete_features)]
5+
#![crate_name = "foo"]
6+
7+
// @has 'foo/struct.Foo.html'
8+
pub struct Foo;
9+
10+
// There are 3 impl blocks with public item and one that should not be displayed
11+
// by default because it only contains private items (but not in this case because
12+
// we used `--document-private-items`).
13+
// @count - '//*[@class="impl has-srclink"]' 'impl Foo' 4
14+
15+
// Impl block only containing private items should not be displayed unless the
16+
// `--document-private-items` flag is used.
17+
/// Private
18+
impl Foo {
19+
const BAR: u32 = 0;
20+
type FOO = i32;
21+
fn hello() {}
22+
}
23+
24+
// But if any element of the impl block is public, it should be displayed.
25+
/// Not private
26+
impl Foo {
27+
pub const BAR: u32 = 0;
28+
type FOO = i32;
29+
fn hello() {}
30+
}
31+
32+
/// Not private
33+
impl Foo {
34+
const BAR: u32 = 0;
35+
pub type FOO = i32;
36+
fn hello() {}
37+
}
38+
39+
/// Not private
40+
impl Foo {
41+
const BAR: u32 = 0;
42+
type FOO = i32;
43+
pub fn hello() {}
44+
}

Diff for: src/test/rustdoc/empty-impl-block-private.rs

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
#![feature(inherent_associated_types)]
2+
#![allow(incomplete_features)]
3+
#![crate_name = "foo"]
4+
5+
// @has 'foo/struct.Foo.html'
6+
pub struct Foo;
7+
8+
// There are 3 impl blocks with public item and one that should not be displayed
9+
// because it only contains private items.
10+
// @count - '//*[@class="impl has-srclink"]' 'impl Foo' 3
11+
12+
// Impl block only containing private items should not be displayed.
13+
/// Private
14+
impl Foo {
15+
const BAR: u32 = 0;
16+
type FOO = i32;
17+
fn hello() {}
18+
}
19+
20+
// But if any element of the impl block is public, it should be displayed.
21+
/// Not private
22+
impl Foo {
23+
pub const BAR: u32 = 0;
24+
type FOO = i32;
25+
fn hello() {}
26+
}
27+
28+
/// Not private
29+
impl Foo {
30+
const BAR: u32 = 0;
31+
pub type FOO = i32;
32+
fn hello() {}
33+
}
34+
35+
/// Not private
36+
impl Foo {
37+
const BAR: u32 = 0;
38+
type FOO = i32;
39+
pub fn hello() {}
40+
}

0 commit comments

Comments
 (0)