From 1f8d552d6dfd4bb534c98b79150f21a122ed0b4c Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Fri, 9 Sep 2022 12:58:42 -0700 Subject: [PATCH 1/5] rustdoc: avoid cleaning modules with duplicate names --- src/librustdoc/clean/mod.rs | 8 +++++--- ...-83375-multiple-mods-w-same-name-doc-inline.rs | 15 +++++++++++++++ 2 files changed, 20 insertions(+), 3 deletions(-) create mode 100644 src/test/rustdoc/issue-83375-multiple-mods-w-same-name-doc-inline.rs diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 08b696e65eb3b..ecbfc63631430 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -55,9 +55,11 @@ pub(crate) fn clean_doc_module<'tcx>(doc: &DocModule<'tcx>, cx: &mut DocContext< } item })); - items.extend(doc.mods.iter().map(|x| { - inserted.insert((ItemType::Module, x.name)); - clean_doc_module(x, cx) + items.extend(doc.mods.iter().filter_map(|x| { + if !inserted.insert((ItemType::Module, x.name)) { + return None; + } + Some(clean_doc_module(x, cx)) })); // Split up imports from all other items. diff --git a/src/test/rustdoc/issue-83375-multiple-mods-w-same-name-doc-inline.rs b/src/test/rustdoc/issue-83375-multiple-mods-w-same-name-doc-inline.rs new file mode 100644 index 0000000000000..f9a2c0954a7be --- /dev/null +++ b/src/test/rustdoc/issue-83375-multiple-mods-w-same-name-doc-inline.rs @@ -0,0 +1,15 @@ +#![crate_name = "foo"] + +pub mod sub { + pub struct Item; + + pub mod prelude { + pub use super::Item; + } +} + +// @count foo/index.html '//a[@class="mod"][@title="foo::prelude mod"]' 1 +pub mod prelude {} + +#[doc(inline)] +pub use sub::*; From 624f972358b2d1a33ce50bc27d33074be24981e0 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Fri, 9 Sep 2022 15:02:28 -0700 Subject: [PATCH 2/5] rustdoc: when removing duplicate names, ignore `#[doc(hidden)]` items --- src/librustdoc/clean/mod.rs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index ecbfc63631430..bca3f4db4a854 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -50,7 +50,7 @@ pub(crate) fn clean_doc_module<'tcx>(doc: &DocModule<'tcx>, cx: &mut DocContext< let mut inserted = FxHashSet::default(); items.extend(doc.foreigns.iter().map(|(item, renamed)| { let item = clean_maybe_renamed_foreign_item(cx, item, *renamed); - if let Some(name) = item.name { + if let Some(name) = item.name && !item.attrs.lists(sym::doc).has_word(sym::hidden) { inserted.insert((item.type_(), name)); } item @@ -59,7 +59,14 @@ pub(crate) fn clean_doc_module<'tcx>(doc: &DocModule<'tcx>, cx: &mut DocContext< if !inserted.insert((ItemType::Module, x.name)) { return None; } - Some(clean_doc_module(x, cx)) + let item = clean_doc_module(x, cx); + if item.attrs.lists(sym::doc).has_word(sym::hidden) { + // Hidden modules are stripped at a later stage. + // If a hidden module has the same name as a visible one, we want + // to keep both of them around. + inserted.remove(&(ItemType::Module, x.name)); + } + Some(item) })); // Split up imports from all other items. @@ -74,7 +81,7 @@ pub(crate) fn clean_doc_module<'tcx>(doc: &DocModule<'tcx>, cx: &mut DocContext< } let v = clean_maybe_renamed_item(cx, item, *renamed); for item in &v { - if let Some(name) = item.name { + if let Some(name) = item.name && !item.attrs.lists(sym::doc).has_word(sym::hidden) { inserted.insert((item.type_(), name)); } } From 56e9ec547a8b4b39c0da7ea66d1575b9f78da1a8 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Fri, 9 Sep 2022 18:04:27 -0700 Subject: [PATCH 3/5] rustdoc: implement glob shadowing when doing local inlining --- src/librustdoc/visit_ast.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index ca7a20bf3688a..c27ac0ac40e1d 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -164,8 +164,20 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { self.inside_public_path &= self.cx.tcx.visibility(def_id).is_public(); for &i in m.item_ids { let item = self.cx.tcx.hir().item(i); + if matches!(item.kind, hir::ItemKind::Use(_, hir::UseKind::Glob)) { + continue; + } self.visit_item(item, None, &mut om); } + for &i in m.item_ids { + let item = self.cx.tcx.hir().item(i); + // To match the way import precedence works, visit glob imports last. + // Later passes in rustdoc will de-duplicate by name and kind, so if glob- + // imported items appear last, then they'll be the ones that get discarded. + if matches!(item.kind, hir::ItemKind::Use(_, hir::UseKind::Glob)) { + self.visit_item(item, None, &mut om); + } + } self.inside_public_path = orig_inside_public_path; om } From c1aea94ee78bbdf7acaf383959ac33e42e4e8931 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Fri, 9 Sep 2022 18:04:47 -0700 Subject: [PATCH 4/5] rustdoc: test cases for glob shadowing --- src/test/rustdoc/glob-shadowing.rs | 86 +++++++++++++++++++ ...e-mods-w-same-name-doc-inline-last-item.rs | 16 ++++ ...75-multiple-mods-w-same-name-doc-inline.rs | 1 + 3 files changed, 103 insertions(+) create mode 100644 src/test/rustdoc/glob-shadowing.rs create mode 100644 src/test/rustdoc/issue-83375-multiple-mods-w-same-name-doc-inline-last-item.rs diff --git a/src/test/rustdoc/glob-shadowing.rs b/src/test/rustdoc/glob-shadowing.rs new file mode 100644 index 0000000000000..66a31c42bcfc7 --- /dev/null +++ b/src/test/rustdoc/glob-shadowing.rs @@ -0,0 +1,86 @@ +// @has 'glob_shadowing/index.html' +// @count - '//div[@class="item-left module-item"]' 6 +// @!has - '//div[@class="item-right docblock-short"]' 'sub1::describe' +// @has - '//div[@class="item-right docblock-short"]' 'sub2::describe' + +// @!has - '//div[@class="item-right docblock-short"]' 'sub1::describe2' + +// @!has - '//div[@class="item-right docblock-short"]' 'sub1::prelude' +// @has - '//div[@class="item-right docblock-short"]' 'mod::prelude' + +// @has - '//div[@class="item-right docblock-short"]' 'sub1::Foo (struct)' +// @has - '//div[@class="item-right docblock-short"]' 'mod::Foo (function)' + +// @has - '//div[@class="item-right docblock-short"]' 'sub4::inner::X' + +// @has 'glob_shadowing/fn.describe.html' +// @has - '//div[@class="docblock"]' 'sub2::describe' + +mod sub1 { + // this should be shadowed by sub2::describe + /// sub1::describe + pub fn describe() -> &'static str { + "sub1::describe" + } + + // this should be shadowed by mod::prelude + /// sub1::prelude + pub mod prelude { + } + + // this should *not* be shadowed, because sub1::Foo and mod::Foo are in different namespaces + /// sub1::Foo (struct) + pub struct Foo; + + // this should be shadowed, + // because both sub1::describe2 and sub3::describe2 are from glob reexport + /// sub1::describe2 + pub fn describe2() -> &'static str { + "sub1::describe2" + } +} + +mod sub2 { + /// sub2::describe + pub fn describe() -> &'static str { + "sub2::describe" + } +} + +mod sub3 { + // this should be shadowed + // because both sub1::describe2 and sub3::describe2 are from glob reexport + /// sub3::describe2 + pub fn describe2() -> &'static str { + "sub3::describe2" + } +} + +mod sub4 { + // this should be shadowed by sub4::inner::X + /// sub4::X + pub const X: usize = 0; + pub mod inner { + pub use super::*; + /// sub4::inner::X + pub const X: usize = 1; + } +} + +/// mod::Foo (function) +pub fn Foo() {} + +#[doc(inline)] +pub use sub2::describe; + +#[doc(inline)] +pub use sub1::*; + +#[doc(inline)] +pub use sub3::*; + +#[doc(inline)] +pub use sub4::inner::*; + +/// mod::prelude +pub mod prelude {} diff --git a/src/test/rustdoc/issue-83375-multiple-mods-w-same-name-doc-inline-last-item.rs b/src/test/rustdoc/issue-83375-multiple-mods-w-same-name-doc-inline-last-item.rs new file mode 100644 index 0000000000000..d3a7a870b580a --- /dev/null +++ b/src/test/rustdoc/issue-83375-multiple-mods-w-same-name-doc-inline-last-item.rs @@ -0,0 +1,16 @@ +#![crate_name = "foo"] + +pub mod sub { + pub struct Item; + + pub mod prelude { + pub use super::Item; + } +} + +#[doc(inline)] +pub use sub::*; + +// @count foo/index.html '//a[@class="mod"][@title="foo::prelude mod"]' 1 +// @count foo/prelude/index.html '//div[@class="item-row"]' 0 +pub mod prelude {} diff --git a/src/test/rustdoc/issue-83375-multiple-mods-w-same-name-doc-inline.rs b/src/test/rustdoc/issue-83375-multiple-mods-w-same-name-doc-inline.rs index f9a2c0954a7be..b836925099364 100644 --- a/src/test/rustdoc/issue-83375-multiple-mods-w-same-name-doc-inline.rs +++ b/src/test/rustdoc/issue-83375-multiple-mods-w-same-name-doc-inline.rs @@ -9,6 +9,7 @@ pub mod sub { } // @count foo/index.html '//a[@class="mod"][@title="foo::prelude mod"]' 1 +// @count foo/prelude/index.html '//div[@class="item-row"]' 0 pub mod prelude {} #[doc(inline)] From d92d642707c845b88a0618135ad993723a30c7e2 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Fri, 9 Sep 2022 18:13:31 -0700 Subject: [PATCH 5/5] rustdoc: add another test case for glob shadowing --- src/test/rustdoc/glob-shadowing-const.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 src/test/rustdoc/glob-shadowing-const.rs diff --git a/src/test/rustdoc/glob-shadowing-const.rs b/src/test/rustdoc/glob-shadowing-const.rs new file mode 100644 index 0000000000000..5b786cf53f298 --- /dev/null +++ b/src/test/rustdoc/glob-shadowing-const.rs @@ -0,0 +1,20 @@ +// https://github.com/rust-lang/rust/pull/83872#issuecomment-820101008 +#![crate_name="foo"] + +mod sub4 { + /// 0 + pub const X: usize = 0; + pub mod inner { + pub use super::*; + /// 1 + pub const X: usize = 1; + } +} + +#[doc(inline)] +pub use sub4::inner::*; + +// @has 'foo/index.html' +// @has - '//div[@class="item-right docblock-short"]' '1' +// @!has - '//div[@class="item-right docblock-short"]' '0' +fn main() { assert_eq!(X, 1); }