about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorDylan DPC <99973273+Dylan-DPC@users.noreply.github.com>2022-09-10 18:56:09 +0530
committerGitHub <noreply@github.com>2022-09-10 18:56:09 +0530
commit6afbe3eca92da175a197cdd3d75cf9c623bf53eb (patch)
treeeaf4c9d7abde9b9787aad0b782ced4697d03a2c8 /src
parentf1412a665f6c3f04fba0f192d9de4c12d823f9f3 (diff)
parentd92d642707c845b88a0618135ad993723a30c7e2 (diff)
downloadrust-6afbe3eca92da175a197cdd3d75cf9c623bf53eb.tar.gz
rust-6afbe3eca92da175a197cdd3d75cf9c623bf53eb.zip
Rollup merge of #101631 - rust-lang:notriddle/duplicate-module, r=GuillaumeGomez
rustdoc: avoid cleaning modules with duplicate names

Fixes #83375
Diffstat (limited to 'src')
-rw-r--r--src/librustdoc/clean/mod.rs19
-rw-r--r--src/librustdoc/visit_ast.rs12
-rw-r--r--src/test/rustdoc/glob-shadowing-const.rs20
-rw-r--r--src/test/rustdoc/glob-shadowing.rs86
-rw-r--r--src/test/rustdoc/issue-83375-multiple-mods-w-same-name-doc-inline-last-item.rs16
-rw-r--r--src/test/rustdoc/issue-83375-multiple-mods-w-same-name-doc-inline.rs16
6 files changed, 164 insertions, 5 deletions
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 08b696e65eb..bca3f4db4a8 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -50,14 +50,23 @@ 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
     }));
-    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;
+        }
+        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.
@@ -72,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));
             }
         }
diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs
index ca7a20bf368..c27ac0ac40e 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
     }
diff --git a/src/test/rustdoc/glob-shadowing-const.rs b/src/test/rustdoc/glob-shadowing-const.rs
new file mode 100644
index 00000000000..5b786cf53f2
--- /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); }
diff --git a/src/test/rustdoc/glob-shadowing.rs b/src/test/rustdoc/glob-shadowing.rs
new file mode 100644
index 00000000000..66a31c42bcf
--- /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 00000000000..d3a7a870b58
--- /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
new file mode 100644
index 00000000000..b8369250993
--- /dev/null
+++ b/src/test/rustdoc/issue-83375-multiple-mods-w-same-name-doc-inline.rs
@@ -0,0 +1,16 @@
+#![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
+// @count foo/prelude/index.html '//div[@class="item-row"]' 0
+pub mod prelude {}
+
+#[doc(inline)]
+pub use sub::*;