Skip to content

Commit 6afbe3e

Browse files
authored
Rollup merge of #101631 - rust-lang:notriddle/duplicate-module, r=GuillaumeGomez
rustdoc: avoid cleaning modules with duplicate names Fixes #83375
2 parents f1412a6 + d92d642 commit 6afbe3e

6 files changed

+164
-5
lines changed

src/librustdoc/clean/mod.rs

+14-5
Original file line numberDiff line numberDiff line change
@@ -50,14 +50,23 @@ pub(crate) fn clean_doc_module<'tcx>(doc: &DocModule<'tcx>, cx: &mut DocContext<
5050
let mut inserted = FxHashSet::default();
5151
items.extend(doc.foreigns.iter().map(|(item, renamed)| {
5252
let item = clean_maybe_renamed_foreign_item(cx, item, *renamed);
53-
if let Some(name) = item.name {
53+
if let Some(name) = item.name && !item.attrs.lists(sym::doc).has_word(sym::hidden) {
5454
inserted.insert((item.type_(), name));
5555
}
5656
item
5757
}));
58-
items.extend(doc.mods.iter().map(|x| {
59-
inserted.insert((ItemType::Module, x.name));
60-
clean_doc_module(x, cx)
58+
items.extend(doc.mods.iter().filter_map(|x| {
59+
if !inserted.insert((ItemType::Module, x.name)) {
60+
return None;
61+
}
62+
let item = clean_doc_module(x, cx);
63+
if item.attrs.lists(sym::doc).has_word(sym::hidden) {
64+
// Hidden modules are stripped at a later stage.
65+
// If a hidden module has the same name as a visible one, we want
66+
// to keep both of them around.
67+
inserted.remove(&(ItemType::Module, x.name));
68+
}
69+
Some(item)
6170
}));
6271

6372
// Split up imports from all other items.
@@ -72,7 +81,7 @@ pub(crate) fn clean_doc_module<'tcx>(doc: &DocModule<'tcx>, cx: &mut DocContext<
7281
}
7382
let v = clean_maybe_renamed_item(cx, item, *renamed);
7483
for item in &v {
75-
if let Some(name) = item.name {
84+
if let Some(name) = item.name && !item.attrs.lists(sym::doc).has_word(sym::hidden) {
7685
inserted.insert((item.type_(), name));
7786
}
7887
}

src/librustdoc/visit_ast.rs

+12
Original file line numberDiff line numberDiff line change
@@ -164,8 +164,20 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
164164
self.inside_public_path &= self.cx.tcx.visibility(def_id).is_public();
165165
for &i in m.item_ids {
166166
let item = self.cx.tcx.hir().item(i);
167+
if matches!(item.kind, hir::ItemKind::Use(_, hir::UseKind::Glob)) {
168+
continue;
169+
}
167170
self.visit_item(item, None, &mut om);
168171
}
172+
for &i in m.item_ids {
173+
let item = self.cx.tcx.hir().item(i);
174+
// To match the way import precedence works, visit glob imports last.
175+
// Later passes in rustdoc will de-duplicate by name and kind, so if glob-
176+
// imported items appear last, then they'll be the ones that get discarded.
177+
if matches!(item.kind, hir::ItemKind::Use(_, hir::UseKind::Glob)) {
178+
self.visit_item(item, None, &mut om);
179+
}
180+
}
169181
self.inside_public_path = orig_inside_public_path;
170182
om
171183
}
+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// https://github.com/rust-lang/rust/pull/83872#issuecomment-820101008
2+
#![crate_name="foo"]
3+
4+
mod sub4 {
5+
/// 0
6+
pub const X: usize = 0;
7+
pub mod inner {
8+
pub use super::*;
9+
/// 1
10+
pub const X: usize = 1;
11+
}
12+
}
13+
14+
#[doc(inline)]
15+
pub use sub4::inner::*;
16+
17+
// @has 'foo/index.html'
18+
// @has - '//div[@class="item-right docblock-short"]' '1'
19+
// @!has - '//div[@class="item-right docblock-short"]' '0'
20+
fn main() { assert_eq!(X, 1); }

src/test/rustdoc/glob-shadowing.rs

+86
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
// @has 'glob_shadowing/index.html'
2+
// @count - '//div[@class="item-left module-item"]' 6
3+
// @!has - '//div[@class="item-right docblock-short"]' 'sub1::describe'
4+
// @has - '//div[@class="item-right docblock-short"]' 'sub2::describe'
5+
6+
// @!has - '//div[@class="item-right docblock-short"]' 'sub1::describe2'
7+
8+
// @!has - '//div[@class="item-right docblock-short"]' 'sub1::prelude'
9+
// @has - '//div[@class="item-right docblock-short"]' 'mod::prelude'
10+
11+
// @has - '//div[@class="item-right docblock-short"]' 'sub1::Foo (struct)'
12+
// @has - '//div[@class="item-right docblock-short"]' 'mod::Foo (function)'
13+
14+
// @has - '//div[@class="item-right docblock-short"]' 'sub4::inner::X'
15+
16+
// @has 'glob_shadowing/fn.describe.html'
17+
// @has - '//div[@class="docblock"]' 'sub2::describe'
18+
19+
mod sub1 {
20+
// this should be shadowed by sub2::describe
21+
/// sub1::describe
22+
pub fn describe() -> &'static str {
23+
"sub1::describe"
24+
}
25+
26+
// this should be shadowed by mod::prelude
27+
/// sub1::prelude
28+
pub mod prelude {
29+
}
30+
31+
// this should *not* be shadowed, because sub1::Foo and mod::Foo are in different namespaces
32+
/// sub1::Foo (struct)
33+
pub struct Foo;
34+
35+
// this should be shadowed,
36+
// because both sub1::describe2 and sub3::describe2 are from glob reexport
37+
/// sub1::describe2
38+
pub fn describe2() -> &'static str {
39+
"sub1::describe2"
40+
}
41+
}
42+
43+
mod sub2 {
44+
/// sub2::describe
45+
pub fn describe() -> &'static str {
46+
"sub2::describe"
47+
}
48+
}
49+
50+
mod sub3 {
51+
// this should be shadowed
52+
// because both sub1::describe2 and sub3::describe2 are from glob reexport
53+
/// sub3::describe2
54+
pub fn describe2() -> &'static str {
55+
"sub3::describe2"
56+
}
57+
}
58+
59+
mod sub4 {
60+
// this should be shadowed by sub4::inner::X
61+
/// sub4::X
62+
pub const X: usize = 0;
63+
pub mod inner {
64+
pub use super::*;
65+
/// sub4::inner::X
66+
pub const X: usize = 1;
67+
}
68+
}
69+
70+
/// mod::Foo (function)
71+
pub fn Foo() {}
72+
73+
#[doc(inline)]
74+
pub use sub2::describe;
75+
76+
#[doc(inline)]
77+
pub use sub1::*;
78+
79+
#[doc(inline)]
80+
pub use sub3::*;
81+
82+
#[doc(inline)]
83+
pub use sub4::inner::*;
84+
85+
/// mod::prelude
86+
pub mod prelude {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#![crate_name = "foo"]
2+
3+
pub mod sub {
4+
pub struct Item;
5+
6+
pub mod prelude {
7+
pub use super::Item;
8+
}
9+
}
10+
11+
#[doc(inline)]
12+
pub use sub::*;
13+
14+
// @count foo/index.html '//a[@class="mod"][@title="foo::prelude mod"]' 1
15+
// @count foo/prelude/index.html '//div[@class="item-row"]' 0
16+
pub mod prelude {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#![crate_name = "foo"]
2+
3+
pub mod sub {
4+
pub struct Item;
5+
6+
pub mod prelude {
7+
pub use super::Item;
8+
}
9+
}
10+
11+
// @count foo/index.html '//a[@class="mod"][@title="foo::prelude mod"]' 1
12+
// @count foo/prelude/index.html '//div[@class="item-row"]' 0
13+
pub mod prelude {}
14+
15+
#[doc(inline)]
16+
pub use sub::*;

0 commit comments

Comments
 (0)