Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rustdoc: avoid cleaning modules with duplicate names #101631

Merged
merged 5 commits into from
Sep 10, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 14 additions & 5 deletions src/librustdoc/clean/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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));
}
}
Expand Down
12 changes: 12 additions & 0 deletions src/librustdoc/visit_ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
20 changes: 20 additions & 0 deletions src/test/rustdoc/glob-shadowing-const.rs
Original file line number Diff line number Diff line change
@@ -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); }
86 changes: 86 additions & 0 deletions src/test/rustdoc/glob-shadowing.rs
Original file line number Diff line number Diff line change
@@ -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 {}
Original file line number Diff line number Diff line change
@@ -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 {}
Original file line number Diff line number Diff line change
@@ -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::*;