From b83ad87a281e819bfb5a04cb472804978b51d7fa Mon Sep 17 00:00:00 2001 From: longfangsong Date: Mon, 5 Apr 2021 15:39:17 +0800 Subject: [PATCH 01/16] introduce glob shadowing rules to rustdoc Signed-off-by: longfangsong --- src/librustdoc/clean/mod.rs | 4 +- src/librustdoc/doctree.rs | 64 +++++++++++++++++++++++++++++- src/librustdoc/visit_ast.rs | 27 +++++++++---- src/test/rustdoc/glob-shadowing.rs | 38 ++++++++++++++++++ 4 files changed, 122 insertions(+), 11 deletions(-) create mode 100644 src/test/rustdoc/glob-shadowing.rs diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 217e899001ef9..1b13022c8e161 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1934,11 +1934,11 @@ impl Clean for hir::BareFnTy<'_> { } } -impl Clean> for (&hir::Item<'_>, Option) { +impl Clean> for doctree::Item<'_> { fn clean(&self, cx: &mut DocContext<'_>) -> Vec { use hir::ItemKind; - let (item, renamed) = self; + let (item, renamed) = (self.hir_item, self.renamed_name); let def_id = item.def_id.to_def_id(); let mut name = renamed.unwrap_or_else(|| cx.tcx.hir().name(item.hir_id())); cx.with_param_env(def_id, |cx| { diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs index 189624c0d809c..bdc9dca1f39bb 100644 --- a/src/librustdoc/doctree.rs +++ b/src/librustdoc/doctree.rs @@ -4,17 +4,48 @@ use rustc_span::{self, Span, Symbol}; use rustc_hir as hir; +/// A warp around an hir::Item +#[derive(Debug)] +pub(crate) struct Item<'hir> { + /// the wrapped item + pub(crate) hir_item: &'hir hir::Item<'hir>, + /// the explicit renamed name + pub(crate) renamed_name: Option, + /// whether the item is from a glob import + /// if `from_glob` is true and we see another item with same name, + /// then this item can be replaced with that one + pub(crate) from_glob: bool, +} + +impl<'hir> Item<'hir> { + pub(crate) fn new( + hir_item: &'hir hir::Item<'hir>, + renamed_name: Option, + from_glob: bool, + ) -> Self { + Self { hir_item, renamed_name, from_glob } + } + + fn name(&'hir self) -> &'hir Symbol { + self.renamed_name.as_ref().unwrap_or(&self.hir_item.ident.name) + } +} + crate struct Module<'hir> { crate name: Symbol, crate where_outer: Span, crate where_inner: Span, crate mods: Vec>, crate id: hir::HirId, + crate items: Vec>, // (item, renamed) - crate items: Vec<(&'hir hir::Item<'hir>, Option)>, crate foreigns: Vec<(&'hir hir::ForeignItem<'hir>, Option)>, crate macros: Vec<(&'hir hir::MacroDef<'hir>, Option)>, crate is_crate: bool, + /// whether the module is from a glob import + /// if `from_glob` is true and we see another module with same name, + /// then this item can be replaced with that one + pub(crate) from_glob: bool, } impl Module<'hir> { @@ -29,6 +60,37 @@ impl Module<'hir> { foreigns: Vec::new(), macros: Vec::new(), is_crate: false, + from_glob: false, + } + } + + pub(crate) fn push_item(&mut self, new_item: Item<'hir>) { + for item_iter in self.items.iter_mut() { + if item_iter.name() == new_item.name() { + if item_iter.from_glob { + debug!("push_item: {:?} shadowed by {:?}", *item_iter, new_item); + *item_iter = new_item; + return; + } else if new_item.from_glob { + return; + } + } + } + self.items.push(new_item); + } + + pub(crate) fn push_mod(&mut self, new_item: Module<'hir>) { + for item_iter in self.mods.iter_mut() { + if item_iter.name == new_item.name { + if item_iter.from_glob { + debug!("push_mod: {:?} shadowed by {:?}", item_iter.name, new_item.name); + *item_iter = new_item; + return; + } else if new_item.from_glob { + return; + } + } } + self.mods.push(new_item); } } diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index ca30d8f0d4623..63468df73efad 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -77,6 +77,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { hir::CRATE_HIR_ID, &krate.item, self.cx.tcx.crate_name, + false, ); top_level_module.is_crate = true; // Attach the crate's exported macros to the top-level module. @@ -134,17 +135,19 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { id: hir::HirId, m: &'tcx hir::Mod<'tcx>, name: Symbol, + from_glob: bool, ) -> Module<'tcx> { let mut om = Module::new(name); om.where_outer = span; om.where_inner = m.inner; om.id = id; + om.from_glob = from_glob; // Keep track of if there were any private modules in the path. let orig_inside_public_path = self.inside_public_path; self.inside_public_path &= vis.node.is_pub(); for &i in m.item_ids { let item = self.cx.tcx.hir().item(i); - self.visit_item(item, None, &mut om); + self.visit_item(item, None, &mut om, from_glob); } self.inside_public_path = orig_inside_public_path; om @@ -225,14 +228,14 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { let prev = mem::replace(&mut self.inlining, true); for &i in m.item_ids { let i = self.cx.tcx.hir().item(i); - self.visit_item(i, None, om); + self.visit_item(i, None, om, glob); } self.inlining = prev; true } Node::Item(it) if !glob => { let prev = mem::replace(&mut self.inlining, true); - self.visit_item(it, renamed, om); + self.visit_item(it, renamed, om, glob); self.inlining = prev; true } @@ -257,6 +260,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { item: &'tcx hir::Item<'_>, renamed: Option, om: &mut Module<'tcx>, + from_glob: bool, ) { debug!("visiting item {:?}", item); let name = renamed.unwrap_or(item.ident.name); @@ -309,10 +313,17 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { } } - om.items.push((item, renamed)) + om.push_item(Item::new(item, renamed, is_glob)) } hir::ItemKind::Mod(ref m) => { - om.mods.push(self.visit_mod_contents(item.span, &item.vis, item.hir_id(), m, name)); + om.push_mod(self.visit_mod_contents( + item.span, + &item.vis, + item.hir_id(), + m, + name, + from_glob, + )); } hir::ItemKind::Fn(..) | hir::ItemKind::ExternCrate(..) @@ -323,19 +334,19 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { | hir::ItemKind::OpaqueTy(..) | hir::ItemKind::Static(..) | hir::ItemKind::Trait(..) - | hir::ItemKind::TraitAlias(..) => om.items.push((item, renamed)), + | hir::ItemKind::TraitAlias(..) => om.push_item(Item::new(item, renamed, from_glob)), hir::ItemKind::Const(..) => { // Underscore constants do not correspond to a nameable item and // so are never useful in documentation. if name != kw::Underscore { - om.items.push((item, renamed)); + om.push_item(Item::new(item, renamed, from_glob)); } } hir::ItemKind::Impl(ref impl_) => { // Don't duplicate impls when inlining or if it's implementing a trait, we'll pick // them up regardless of where they're located. if !self.inlining && impl_.of_trait.is_none() { - om.items.push((item, None)); + om.push_item(Item::new(item, None, from_glob)); } } } diff --git a/src/test/rustdoc/glob-shadowing.rs b/src/test/rustdoc/glob-shadowing.rs new file mode 100644 index 0000000000000..c118e0f5a78cb --- /dev/null +++ b/src/test/rustdoc/glob-shadowing.rs @@ -0,0 +1,38 @@ +// @has 'glob_shadowing/index.html' +// @count - '//tr[@class="module-item"]' 2 +// @has - '//tr[@class="module-item"]' 'mod::prelude' +// @has - '//tr[@class="module-item"]' 'sub2::describe' + +mod sub1 { + /// sub1::describe + pub fn describe() -> &'static str { + "sub1::describe" + } + + /// sub1::prelude + pub mod prelude { + pub use super::describe; + } +} + +mod sub2 { + /// sub2::describe + pub fn describe() -> &'static str { + "sub2::describe" + } +} + +/// mod::prelude +pub mod prelude { + /// mod::prelude::describe + pub fn describe() -> &'static str { + "mod::describe" + } +} + +#[doc(inline)] +pub use sub2::describe; + +#[doc(inline)] +pub use sub1::*; + From 17b908efbee6a75f11caa56dc4c1ca3b9f39882d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BE=99=E6=96=B9=E6=B7=9E?= Date: Mon, 5 Apr 2021 16:08:56 +0800 Subject: [PATCH 02/16] Update src/librustdoc/doctree.rs Co-authored-by: Joshua Nelson --- src/librustdoc/doctree.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs index bdc9dca1f39bb..151e8bc934634 100644 --- a/src/librustdoc/doctree.rs +++ b/src/librustdoc/doctree.rs @@ -4,7 +4,7 @@ use rustc_span::{self, Span, Symbol}; use rustc_hir as hir; -/// A warp around an hir::Item +/// A wrapper around a [`hir::Item`]. #[derive(Debug)] pub(crate) struct Item<'hir> { /// the wrapped item From 791c3713bbc083211f9f3ed99e18a2441e84ffee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BE=99=E6=96=B9=E6=B7=9E?= Date: Mon, 5 Apr 2021 16:09:03 +0800 Subject: [PATCH 03/16] Update src/librustdoc/doctree.rs Co-authored-by: Joshua Nelson --- src/librustdoc/doctree.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs index 151e8bc934634..747082088cb9f 100644 --- a/src/librustdoc/doctree.rs +++ b/src/librustdoc/doctree.rs @@ -6,15 +6,15 @@ use rustc_hir as hir; /// A wrapper around a [`hir::Item`]. #[derive(Debug)] -pub(crate) struct Item<'hir> { +crate struct Item<'hir> { /// the wrapped item - pub(crate) hir_item: &'hir hir::Item<'hir>, + crate hir_item: &'hir hir::Item<'hir>, /// the explicit renamed name - pub(crate) renamed_name: Option, + crate renamed_name: Option, /// whether the item is from a glob import /// if `from_glob` is true and we see another item with same name, /// then this item can be replaced with that one - pub(crate) from_glob: bool, + crate from_glob: bool, } impl<'hir> Item<'hir> { From 29ebc1eba45e374372b03cbf4f36de7e39451877 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BE=99=E6=96=B9=E6=B7=9E?= Date: Mon, 5 Apr 2021 16:09:09 +0800 Subject: [PATCH 04/16] Update src/librustdoc/doctree.rs Co-authored-by: Joshua Nelson --- src/librustdoc/doctree.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs index 747082088cb9f..7cf14f12c3747 100644 --- a/src/librustdoc/doctree.rs +++ b/src/librustdoc/doctree.rs @@ -38,7 +38,6 @@ crate struct Module<'hir> { crate mods: Vec>, crate id: hir::HirId, crate items: Vec>, - // (item, renamed) crate foreigns: Vec<(&'hir hir::ForeignItem<'hir>, Option)>, crate macros: Vec<(&'hir hir::MacroDef<'hir>, Option)>, crate is_crate: bool, From 8c031caa12d176a30e887585525ccaaeb2027a68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BE=99=E6=96=B9=E6=B7=9E?= Date: Mon, 5 Apr 2021 16:37:36 +0800 Subject: [PATCH 05/16] Update src/librustdoc/doctree.rs Co-authored-by: Joshua Nelson --- src/librustdoc/doctree.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs index 7cf14f12c3747..ba926bbba9984 100644 --- a/src/librustdoc/doctree.rs +++ b/src/librustdoc/doctree.rs @@ -79,8 +79,7 @@ impl Module<'hir> { } pub(crate) fn push_mod(&mut self, new_item: Module<'hir>) { - for item_iter in self.mods.iter_mut() { - if item_iter.name == new_item.name { + if let Some(shadowed_mod) = self.mods.iter_mut().find(|mod_| mod_.name == new_item.name) { if item_iter.from_glob { debug!("push_mod: {:?} shadowed by {:?}", item_iter.name, new_item.name); *item_iter = new_item; From 58bb79919be010e5ba46346c75e7ea2654205572 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BE=99=E6=96=B9=E6=B7=9E?= Date: Mon, 5 Apr 2021 16:38:37 +0800 Subject: [PATCH 06/16] Update src/test/rustdoc/glob-shadowing.rs Co-authored-by: Joshua Nelson --- src/test/rustdoc/glob-shadowing.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/test/rustdoc/glob-shadowing.rs b/src/test/rustdoc/glob-shadowing.rs index c118e0f5a78cb..c1f36b2e59928 100644 --- a/src/test/rustdoc/glob-shadowing.rs +++ b/src/test/rustdoc/glob-shadowing.rs @@ -35,4 +35,3 @@ pub use sub2::describe; #[doc(inline)] pub use sub1::*; - From 0005dc33e32e70db96ea743b181dce7cb69dcc04 Mon Sep 17 00:00:00 2001 From: longfangsong Date: Mon, 5 Apr 2021 16:39:08 +0800 Subject: [PATCH 07/16] use `Item::name()` in `clean` Signed-off-by: longfangsong --- src/librustdoc/clean/mod.rs | 5 +++-- src/librustdoc/doctree.rs | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 1b13022c8e161..c362dcd7da76c 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1938,9 +1938,10 @@ impl Clean> for doctree::Item<'_> { fn clean(&self, cx: &mut DocContext<'_>) -> Vec { use hir::ItemKind; - let (item, renamed) = (self.hir_item, self.renamed_name); + let item = self.hir_item; + let mut name = self.name().clone(); let def_id = item.def_id.to_def_id(); - let mut name = renamed.unwrap_or_else(|| cx.tcx.hir().name(item.hir_id())); + cx.with_param_env(def_id, |cx| { let kind = match item.kind { ItemKind::Static(ty, mutability, body_id) => { diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs index ba926bbba9984..f2aefc85cdb54 100644 --- a/src/librustdoc/doctree.rs +++ b/src/librustdoc/doctree.rs @@ -26,7 +26,7 @@ impl<'hir> Item<'hir> { Self { hir_item, renamed_name, from_glob } } - fn name(&'hir self) -> &'hir Symbol { + pub(crate) fn name(&'hir self) -> &'hir Symbol { self.renamed_name.as_ref().unwrap_or(&self.hir_item.ident.name) } } From 09cb2851aa172e778fb571427c492e5b158662a5 Mon Sep 17 00:00:00 2001 From: longfangsong Date: Mon, 5 Apr 2021 17:37:39 +0800 Subject: [PATCH 08/16] apply some suggestions from code review Signed-off-by: longfangsong --- src/librustdoc/doctree.rs | 33 ++++++++++++++++-------------- src/test/rustdoc/glob-shadowing.rs | 10 ++++----- 2 files changed, 22 insertions(+), 21 deletions(-) diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs index f2aefc85cdb54..9945656ae7974 100644 --- a/src/librustdoc/doctree.rs +++ b/src/librustdoc/doctree.rs @@ -64,31 +64,34 @@ impl Module<'hir> { } pub(crate) fn push_item(&mut self, new_item: Item<'hir>) { - for item_iter in self.items.iter_mut() { - if item_iter.name() == new_item.name() { - if item_iter.from_glob { - debug!("push_item: {:?} shadowed by {:?}", *item_iter, new_item); - *item_iter = new_item; + if let Some(existed_item) = + self.items.iter_mut().find(|item| item.name() == new_item.name()) + { + if existed_item.name() == new_item.name() { + if existed_item.from_glob { + debug!("push_item: {:?} shadowed by {:?}", *existed_item, new_item); + *existed_item = new_item; return; } else if new_item.from_glob { return; } } + } else { + self.items.push(new_item); } - self.items.push(new_item); } pub(crate) fn push_mod(&mut self, new_item: Module<'hir>) { - if let Some(shadowed_mod) = self.mods.iter_mut().find(|mod_| mod_.name == new_item.name) { - if item_iter.from_glob { - debug!("push_mod: {:?} shadowed by {:?}", item_iter.name, new_item.name); - *item_iter = new_item; - return; - } else if new_item.from_glob { - return; - } + if let Some(existed_mod) = self.mods.iter_mut().find(|mod_| mod_.name == new_item.name) { + if existed_mod.from_glob { + debug!("push_mod: {:?} shadowed by {:?}", existed_mod.name, new_item.name); + *existed_mod = new_item; + return; + } else if new_item.from_glob { + return; } + } else { + self.mods.push(new_item); } - self.mods.push(new_item); } } diff --git a/src/test/rustdoc/glob-shadowing.rs b/src/test/rustdoc/glob-shadowing.rs index c1f36b2e59928..f04851391e159 100644 --- a/src/test/rustdoc/glob-shadowing.rs +++ b/src/test/rustdoc/glob-shadowing.rs @@ -3,6 +3,9 @@ // @has - '//tr[@class="module-item"]' 'mod::prelude' // @has - '//tr[@class="module-item"]' 'sub2::describe' +// @has 'glob_shadowing/fn.describe.html' +// @has - '//div[@class='docblock']' 'sub2::describe' + mod sub1 { /// sub1::describe pub fn describe() -> &'static str { @@ -23,12 +26,7 @@ mod sub2 { } /// mod::prelude -pub mod prelude { - /// mod::prelude::describe - pub fn describe() -> &'static str { - "mod::describe" - } -} +pub mod prelude {} #[doc(inline)] pub use sub2::describe; From 4b934bb2229cc0afd877ad66f2b99e38ec8399b7 Mon Sep 17 00:00:00 2001 From: longfangsong Date: Mon, 5 Apr 2021 18:49:19 +0800 Subject: [PATCH 09/16] apply some suggestions from code review Signed-off-by: longfangsong --- src/librustdoc/clean/mod.rs | 2 +- src/librustdoc/doctree.rs | 36 +++++++++++++----------------- src/test/rustdoc/glob-shadowing.rs | 3 ++- 3 files changed, 19 insertions(+), 22 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index c362dcd7da76c..ace89e456072e 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1939,7 +1939,7 @@ impl Clean> for doctree::Item<'_> { use hir::ItemKind; let item = self.hir_item; - let mut name = self.name().clone(); + let mut name = self.name(); let def_id = item.def_id.to_def_id(); cx.with_param_env(def_id, |cx| { diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs index 9945656ae7974..5e38023d8a368 100644 --- a/src/librustdoc/doctree.rs +++ b/src/librustdoc/doctree.rs @@ -26,8 +26,8 @@ impl<'hir> Item<'hir> { Self { hir_item, renamed_name, from_glob } } - pub(crate) fn name(&'hir self) -> &'hir Symbol { - self.renamed_name.as_ref().unwrap_or(&self.hir_item.ident.name) + pub(crate) fn name(&self) -> Symbol { + self.renamed_name.unwrap_or(self.hir_item.ident.name) } } @@ -44,7 +44,7 @@ crate struct Module<'hir> { /// whether the module is from a glob import /// if `from_glob` is true and we see another module with same name, /// then this item can be replaced with that one - pub(crate) from_glob: bool, + crate from_glob: bool, } impl Module<'hir> { @@ -64,34 +64,30 @@ impl Module<'hir> { } pub(crate) fn push_item(&mut self, new_item: Item<'hir>) { - if let Some(existed_item) = + if let Some(existing_item) = self.items.iter_mut().find(|item| item.name() == new_item.name()) { - if existed_item.name() == new_item.name() { - if existed_item.from_glob { - debug!("push_item: {:?} shadowed by {:?}", *existed_item, new_item); - *existed_item = new_item; - return; - } else if new_item.from_glob { - return; - } + if existing_item.from_glob { + debug!("push_item: {:?} shadowed by {:?}", *existing_item, new_item); + *existing_item = new_item; + return; + } else if new_item.from_glob { + return; } - } else { - self.items.push(new_item); } + self.items.push(new_item); } pub(crate) fn push_mod(&mut self, new_item: Module<'hir>) { - if let Some(existed_mod) = self.mods.iter_mut().find(|mod_| mod_.name == new_item.name) { - if existed_mod.from_glob { - debug!("push_mod: {:?} shadowed by {:?}", existed_mod.name, new_item.name); - *existed_mod = new_item; + if let Some(existing_mod) = self.mods.iter_mut().find(|mod_| mod_.name == new_item.name) { + if existing_mod.from_glob { + debug!("push_mod: {:?} shadowed by {:?}", existing_mod.name, new_item.name); + *existing_mod = new_item; return; } else if new_item.from_glob { return; } - } else { - self.mods.push(new_item); } + self.mods.push(new_item); } } diff --git a/src/test/rustdoc/glob-shadowing.rs b/src/test/rustdoc/glob-shadowing.rs index f04851391e159..c32cb60277ab9 100644 --- a/src/test/rustdoc/glob-shadowing.rs +++ b/src/test/rustdoc/glob-shadowing.rs @@ -1,10 +1,11 @@ // @has 'glob_shadowing/index.html' // @count - '//tr[@class="module-item"]' 2 // @has - '//tr[@class="module-item"]' 'mod::prelude' +// @!has - '//tr[@class="module-item"]' 'sub1::describe' // @has - '//tr[@class="module-item"]' 'sub2::describe' // @has 'glob_shadowing/fn.describe.html' -// @has - '//div[@class='docblock']' 'sub2::describe' +// @has - '//div[@class="docblock"]' 'sub2::describe' mod sub1 { /// sub1::describe From 6ad7e7e5c74bf2911c8efd669ecb2bbaa6debd2a Mon Sep 17 00:00:00 2001 From: longfangsong Date: Wed, 7 Apr 2021 01:46:51 +0800 Subject: [PATCH 10/16] apply some suggestions from code reviewing Signed-off-by: longfangsong --- src/librustdoc/doctree.rs | 57 ++++++++++++++++++++---------- src/librustdoc/visit_ast.rs | 2 +- src/test/rustdoc/glob-shadowing.rs | 8 ++++- 3 files changed, 47 insertions(+), 20 deletions(-) diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs index 5e38023d8a368..2a1ac5ef92106 100644 --- a/src/librustdoc/doctree.rs +++ b/src/librustdoc/doctree.rs @@ -64,30 +64,51 @@ impl Module<'hir> { } pub(crate) fn push_item(&mut self, new_item: Item<'hir>) { - if let Some(existing_item) = - self.items.iter_mut().find(|item| item.name() == new_item.name()) - { - if existing_item.from_glob { - debug!("push_item: {:?} shadowed by {:?}", *existing_item, new_item); - *existing_item = new_item; - return; - } else if new_item.from_glob { - return; + if !new_item.name().is_empty() { + // todo: also check namespace + if let Some(existing_item) = + self.items.iter_mut().find(|item| item.name() == new_item.name()) + { + match (existing_item.from_glob, new_item.from_glob) { + (true, _) => { + // `existing_item` is from glob, no matter whether `new_item` is from glob + // `new_item` should always shadow `existing_item` + debug!("push_item: {:?} shadowed by {:?}", existing_item, new_item); + *existing_item = new_item; + return; + } + (false, true) => { + // `existing_item` is not from glob but `new_item` is + // just keep `existing_item` and return at once + return; + } + (false, false) => unreachable!() // todo: how to handle this? + } } } + // no item with same name and namespace exists, just collect `new_item` self.items.push(new_item); } - pub(crate) fn push_mod(&mut self, new_item: Module<'hir>) { - if let Some(existing_mod) = self.mods.iter_mut().find(|mod_| mod_.name == new_item.name) { - if existing_mod.from_glob { - debug!("push_mod: {:?} shadowed by {:?}", existing_mod.name, new_item.name); - *existing_mod = new_item; - return; - } else if new_item.from_glob { - return; + pub(crate) fn push_mod(&mut self, new_mod: Module<'hir>) { + if let Some(existing_mod) = self.mods.iter_mut().find(|mod_| mod_.name == new_mod.name) { + match (existing_mod.from_glob, new_mod.from_glob) { + (true, _) => { + // `existing_mod` is from glob, no matter whether `new_mod` is from glob + // `new_mod` should always shadow `existing_mod` + debug!("push_mod: {:?} shadowed by {:?}", existing_mod.name, new_mod.name); + *existing_mod = new_mod; + return; + }, + (false, true) => { + // `existing_mod` is not from glob but `new_mod` is + // just keep `existing_mod` and return at once + return; + }, + (false, false) => unreachable!(), } } - self.mods.push(new_item); + // no mod with same name exists, just collect `new_mod` + self.mods.push(new_mod); } } diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 63468df73efad..b00ba7e917bdb 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -313,7 +313,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { } } - om.push_item(Item::new(item, renamed, is_glob)) + om.push_item(Item::new(item, renamed, from_glob)) } hir::ItemKind::Mod(ref m) => { om.push_mod(self.visit_mod_contents( diff --git a/src/test/rustdoc/glob-shadowing.rs b/src/test/rustdoc/glob-shadowing.rs index c32cb60277ab9..dd60bb672e19c 100644 --- a/src/test/rustdoc/glob-shadowing.rs +++ b/src/test/rustdoc/glob-shadowing.rs @@ -1,5 +1,5 @@ // @has 'glob_shadowing/index.html' -// @count - '//tr[@class="module-item"]' 2 +// @count - '//tr[@class="module-item"]' 4 // @has - '//tr[@class="module-item"]' 'mod::prelude' // @!has - '//tr[@class="module-item"]' 'sub1::describe' // @has - '//tr[@class="module-item"]' 'sub2::describe' @@ -17,6 +17,9 @@ mod sub1 { pub mod prelude { pub use super::describe; } + + /// sub1::Foo (struct) + pub struct Foo; } mod sub2 { @@ -29,6 +32,9 @@ mod sub2 { /// mod::prelude pub mod prelude {} +/// mod::Foo (function) +pub fn Foo() {} + #[doc(inline)] pub use sub2::describe; From 81008846e02745055a9168a1e3522a1671bd644c Mon Sep 17 00:00:00 2001 From: longfangsong Date: Wed, 7 Apr 2021 13:11:41 +0800 Subject: [PATCH 11/16] take namespace into consideration when doing shadowing Signed-off-by: longfangsong --- src/librustdoc/doctree.rs | 40 +++++++++++++++++++----------- src/librustdoc/visit_ast.rs | 28 ++++++++++++++++++--- src/test/rustdoc/glob-shadowing.rs | 2 ++ 3 files changed, 51 insertions(+), 19 deletions(-) diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs index 2a1ac5ef92106..2c702fec217b2 100644 --- a/src/librustdoc/doctree.rs +++ b/src/librustdoc/doctree.rs @@ -11,8 +11,10 @@ crate struct Item<'hir> { crate hir_item: &'hir hir::Item<'hir>, /// the explicit renamed name crate renamed_name: Option, + /// the [`Namespace`] this Item belongs to + crate namespace: Option, /// whether the item is from a glob import - /// if `from_glob` is true and we see another item with same name, + /// if `from_glob` is true and we see another item with same name and namespace, /// then this item can be replaced with that one crate from_glob: bool, } @@ -21,9 +23,10 @@ impl<'hir> Item<'hir> { pub(crate) fn new( hir_item: &'hir hir::Item<'hir>, renamed_name: Option, + namespace: Option, from_glob: bool, ) -> Self { - Self { hir_item, renamed_name, from_glob } + Self { hir_item, renamed_name, namespace, from_glob } } pub(crate) fn name(&self) -> Symbol { @@ -43,7 +46,7 @@ crate struct Module<'hir> { crate is_crate: bool, /// whether the module is from a glob import /// if `from_glob` is true and we see another module with same name, - /// then this item can be replaced with that one + /// then this module can be replaced with that one crate from_glob: bool, } @@ -64,25 +67,29 @@ impl Module<'hir> { } pub(crate) fn push_item(&mut self, new_item: Item<'hir>) { - if !new_item.name().is_empty() { - // todo: also check namespace - if let Some(existing_item) = - self.items.iter_mut().find(|item| item.name() == new_item.name()) + if !new_item.name().is_empty() && new_item.namespace.is_some() { + if let Some(existing_item) = self + .items + .iter_mut() + .find(|item| item.name() == new_item.name() && item.namespace == new_item.namespace) { match (existing_item.from_glob, new_item.from_glob) { (true, _) => { - // `existing_item` is from glob, no matter whether `new_item` is from glob + // `existing_item` is from glob, no matter whether `new_item` is from glob, // `new_item` should always shadow `existing_item` debug!("push_item: {:?} shadowed by {:?}", existing_item, new_item); *existing_item = new_item; return; } (false, true) => { - // `existing_item` is not from glob but `new_item` is + // `existing_item` is not from glob but `new_item` is, // just keep `existing_item` and return at once return; } - (false, false) => unreachable!() // todo: how to handle this? + (false, false) => { + // should report "defined multiple time" error before reach this + unreachable!() + } } } } @@ -94,18 +101,21 @@ impl Module<'hir> { if let Some(existing_mod) = self.mods.iter_mut().find(|mod_| mod_.name == new_mod.name) { match (existing_mod.from_glob, new_mod.from_glob) { (true, _) => { - // `existing_mod` is from glob, no matter whether `new_mod` is from glob + // `existing_mod` is from glob, no matter whether `new_mod` is from glob, // `new_mod` should always shadow `existing_mod` debug!("push_mod: {:?} shadowed by {:?}", existing_mod.name, new_mod.name); *existing_mod = new_mod; return; - }, + } (false, true) => { - // `existing_mod` is not from glob but `new_mod` is + // `existing_mod` is not from glob but `new_mod` is, // just keep `existing_mod` and return at once return; - }, - (false, false) => unreachable!(), + } + (false, false) => { + // should report "defined multiple time" error before reach this + unreachable!() + } } } // no mod with same name exists, just collect `new_mod` diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index b00ba7e917bdb..ccaecf22c910d 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -313,7 +313,12 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { } } - om.push_item(Item::new(item, renamed, from_glob)) + om.push_item(Item::new( + item, + renamed, + self.cx.tcx.def_kind(item.def_id).ns(), + from_glob, + )) } hir::ItemKind::Mod(ref m) => { om.push_mod(self.visit_mod_contents( @@ -334,19 +339,34 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { | hir::ItemKind::OpaqueTy(..) | hir::ItemKind::Static(..) | hir::ItemKind::Trait(..) - | hir::ItemKind::TraitAlias(..) => om.push_item(Item::new(item, renamed, from_glob)), + | hir::ItemKind::TraitAlias(..) => om.push_item(Item::new( + item, + renamed, + self.cx.tcx.def_kind(item.def_id).ns(), + from_glob, + )), hir::ItemKind::Const(..) => { // Underscore constants do not correspond to a nameable item and // so are never useful in documentation. if name != kw::Underscore { - om.push_item(Item::new(item, renamed, from_glob)); + om.push_item(Item::new( + item, + renamed, + self.cx.tcx.def_kind(item.def_id).ns(), + from_glob, + )); } } hir::ItemKind::Impl(ref impl_) => { // Don't duplicate impls when inlining or if it's implementing a trait, we'll pick // them up regardless of where they're located. if !self.inlining && impl_.of_trait.is_none() { - om.push_item(Item::new(item, None, from_glob)); + om.push_item(Item::new( + item, + None, + self.cx.tcx.def_kind(item.def_id).ns(), + from_glob, + )); } } } diff --git a/src/test/rustdoc/glob-shadowing.rs b/src/test/rustdoc/glob-shadowing.rs index dd60bb672e19c..6040894b93197 100644 --- a/src/test/rustdoc/glob-shadowing.rs +++ b/src/test/rustdoc/glob-shadowing.rs @@ -40,3 +40,5 @@ pub use sub2::describe; #[doc(inline)] pub use sub1::*; + +pub fn describe() {} From 981f38eb23fcba495d8fd451e9ee9539d93c480d Mon Sep 17 00:00:00 2001 From: longfangsong Date: Wed, 7 Apr 2021 13:19:55 +0800 Subject: [PATCH 12/16] update test Signed-off-by: longfangsong --- src/test/rustdoc/glob-shadowing.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/test/rustdoc/glob-shadowing.rs b/src/test/rustdoc/glob-shadowing.rs index 6040894b93197..21fdbe2aafd12 100644 --- a/src/test/rustdoc/glob-shadowing.rs +++ b/src/test/rustdoc/glob-shadowing.rs @@ -1,8 +1,10 @@ // @has 'glob_shadowing/index.html' // @count - '//tr[@class="module-item"]' 4 -// @has - '//tr[@class="module-item"]' 'mod::prelude' // @!has - '//tr[@class="module-item"]' 'sub1::describe' +// @has - '//tr[@class="module-item"]' 'mod::prelude' // @has - '//tr[@class="module-item"]' 'sub2::describe' +// @has - '//tr[@class="module-item"]' 'sub1::Foo (struct)' +// @has - '//tr[@class="module-item"]' 'mod::Foo (function)' // @has 'glob_shadowing/fn.describe.html' // @has - '//div[@class="docblock"]' 'sub2::describe' @@ -40,5 +42,3 @@ pub use sub2::describe; #[doc(inline)] pub use sub1::*; - -pub fn describe() {} From 7ee35c6b51653f97feff2d7d33620de4ae9cab73 Mon Sep 17 00:00:00 2001 From: longfangsong Date: Wed, 7 Apr 2021 23:51:39 +0800 Subject: [PATCH 13/16] Pass tcx when push_item instead of store namespace Signed-off-by: longfangsong --- src/librustdoc/doctree.rs | 23 ++++++++++------------- src/librustdoc/visit_ast.rs | 30 ++++++------------------------ 2 files changed, 16 insertions(+), 37 deletions(-) diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs index 2c702fec217b2..e0193773c6ab9 100644 --- a/src/librustdoc/doctree.rs +++ b/src/librustdoc/doctree.rs @@ -1,8 +1,8 @@ //! This module is used to store stuff from Rust's AST in a more convenient //! manner (and with prettier names) before cleaning. -use rustc_span::{self, Span, Symbol}; - +use crate::core::DocContext; use rustc_hir as hir; +use rustc_span::{self, Span, Symbol}; /// A wrapper around a [`hir::Item`]. #[derive(Debug)] @@ -11,8 +11,6 @@ crate struct Item<'hir> { crate hir_item: &'hir hir::Item<'hir>, /// the explicit renamed name crate renamed_name: Option, - /// the [`Namespace`] this Item belongs to - crate namespace: Option, /// whether the item is from a glob import /// if `from_glob` is true and we see another item with same name and namespace, /// then this item can be replaced with that one @@ -23,10 +21,9 @@ impl<'hir> Item<'hir> { pub(crate) fn new( hir_item: &'hir hir::Item<'hir>, renamed_name: Option, - namespace: Option, from_glob: bool, ) -> Self { - Self { hir_item, renamed_name, namespace, from_glob } + Self { hir_item, renamed_name, from_glob } } pub(crate) fn name(&self) -> Symbol { @@ -66,13 +63,13 @@ impl Module<'hir> { } } - pub(crate) fn push_item(&mut self, new_item: Item<'hir>) { - if !new_item.name().is_empty() && new_item.namespace.is_some() { - if let Some(existing_item) = self - .items - .iter_mut() - .find(|item| item.name() == new_item.name() && item.namespace == new_item.namespace) - { + pub(crate) fn push_item(&mut self, ctx: &DocContext<'_>, new_item: Item<'hir>) { + let new_item_ns = ctx.tcx.def_kind(new_item.hir_item.def_id).ns(); + if !new_item.name().is_empty() && new_item_ns.is_some() { + if let Some(existing_item) = self.items.iter_mut().find(|item| { + item.name() == new_item.name() + && ctx.tcx.def_kind(item.hir_item.def_id).ns() == new_item_ns + }) { match (existing_item.from_glob, new_item.from_glob) { (true, _) => { // `existing_item` is from glob, no matter whether `new_item` is from glob, diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index ccaecf22c910d..786ef232d8541 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -313,12 +313,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { } } - om.push_item(Item::new( - item, - renamed, - self.cx.tcx.def_kind(item.def_id).ns(), - from_glob, - )) + om.push_item(self.cx, Item::new(item, renamed, from_glob)) } hir::ItemKind::Mod(ref m) => { om.push_mod(self.visit_mod_contents( @@ -339,34 +334,21 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { | hir::ItemKind::OpaqueTy(..) | hir::ItemKind::Static(..) | hir::ItemKind::Trait(..) - | hir::ItemKind::TraitAlias(..) => om.push_item(Item::new( - item, - renamed, - self.cx.tcx.def_kind(item.def_id).ns(), - from_glob, - )), + | hir::ItemKind::TraitAlias(..) => { + om.push_item(self.cx, Item::new(item, renamed, from_glob)) + } hir::ItemKind::Const(..) => { // Underscore constants do not correspond to a nameable item and // so are never useful in documentation. if name != kw::Underscore { - om.push_item(Item::new( - item, - renamed, - self.cx.tcx.def_kind(item.def_id).ns(), - from_glob, - )); + om.push_item(self.cx, Item::new(item, renamed, from_glob)); } } hir::ItemKind::Impl(ref impl_) => { // Don't duplicate impls when inlining or if it's implementing a trait, we'll pick // them up regardless of where they're located. if !self.inlining && impl_.of_trait.is_none() { - om.push_item(Item::new( - item, - None, - self.cx.tcx.def_kind(item.def_id).ns(), - from_glob, - )); + om.push_item(self.cx, Item::new(item, None, from_glob)); } } } From f9df01a8daf061b52408f47f7b20be371363c495 Mon Sep 17 00:00:00 2001 From: longfangsong Date: Thu, 8 Apr 2021 01:11:16 +0800 Subject: [PATCH 14/16] Add some discription to the test file --- src/test/rustdoc/glob-shadowing.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/test/rustdoc/glob-shadowing.rs b/src/test/rustdoc/glob-shadowing.rs index 21fdbe2aafd12..c3fea97342f23 100644 --- a/src/test/rustdoc/glob-shadowing.rs +++ b/src/test/rustdoc/glob-shadowing.rs @@ -10,16 +10,19 @@ // @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 { pub use super::describe; } + // this should not be shadowed, because sub1::Foo and mod::Foo are in different namespace /// sub1::Foo (struct) pub struct Foo; } From 06b02732748e3944d5f15c0f46436d2e60f8bdb6 Mon Sep 17 00:00:00 2001 From: longfangsong Date: Fri, 9 Apr 2021 14:01:03 +0800 Subject: [PATCH 15/16] Handle two different glob re-exports Signed-off-by: longfangsong --- src/librustdoc/doctree.rs | 54 +++++++++++++++++++++++++----- src/test/rustdoc/glob-shadowing.rs | 23 +++++++++++-- 2 files changed, 66 insertions(+), 11 deletions(-) diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs index e0193773c6ab9..155843b8ca02e 100644 --- a/src/librustdoc/doctree.rs +++ b/src/librustdoc/doctree.rs @@ -65,15 +65,18 @@ impl Module<'hir> { pub(crate) fn push_item(&mut self, ctx: &DocContext<'_>, new_item: Item<'hir>) { let new_item_ns = ctx.tcx.def_kind(new_item.hir_item.def_id).ns(); + let mut to_remove = None; if !new_item.name().is_empty() && new_item_ns.is_some() { - if let Some(existing_item) = self.items.iter_mut().find(|item| { - item.name() == new_item.name() - && ctx.tcx.def_kind(item.hir_item.def_id).ns() == new_item_ns - }) { + if let Some((index, existing_item)) = + self.items.iter_mut().enumerate().find(|(_, item)| { + item.name() == new_item.name() + && ctx.tcx.def_kind(item.hir_item.def_id).ns() == new_item_ns + }) + { match (existing_item.from_glob, new_item.from_glob) { - (true, _) => { - // `existing_item` is from glob, no matter whether `new_item` is from glob, - // `new_item` should always shadow `existing_item` + (true, false) => { + // `existing_item` is from glob, `new_item` is not, + // `new_item` should shadow `existing_item` debug!("push_item: {:?} shadowed by {:?}", existing_item, new_item); *existing_item = new_item; return; @@ -83,6 +86,17 @@ impl Module<'hir> { // just keep `existing_item` and return at once return; } + (true, true) => { + // both `existing_item` and `new_item` are from glob + if existing_item.hir_item.def_id == new_item.hir_item.def_id { + // they actually point to same object, it is ok to just keep one of them + return; + } else { + // a "glob import vs glob import in the same module" will raise when actually use these item + // we should accept neither of these two items + to_remove = Some(index); + } + } (false, false) => { // should report "defined multiple time" error before reach this unreachable!() @@ -90,20 +104,38 @@ impl Module<'hir> { } } } + if let Some(index) = to_remove { + self.items.swap_remove(index); + return; + } // no item with same name and namespace exists, just collect `new_item` self.items.push(new_item); } pub(crate) fn push_mod(&mut self, new_mod: Module<'hir>) { - if let Some(existing_mod) = self.mods.iter_mut().find(|mod_| mod_.name == new_mod.name) { + let mut to_remove = None; + if let Some((index, existing_mod)) = + self.mods.iter_mut().enumerate().find(|(_, mod_)| mod_.name == new_mod.name) + { match (existing_mod.from_glob, new_mod.from_glob) { - (true, _) => { + (true, false) => { // `existing_mod` is from glob, no matter whether `new_mod` is from glob, // `new_mod` should always shadow `existing_mod` debug!("push_mod: {:?} shadowed by {:?}", existing_mod.name, new_mod.name); *existing_mod = new_mod; return; } + (true, true) => { + // both `existing_item` and `new_item` are from glob + if existing_mod.id == new_mod.id { + // they actually point to same object, it is ok to just keep one of them + return; + } else { + // a "glob import vs glob import in the same module" will raise when actually use these item + // we should accept neither of these two items + to_remove = Some(index); + } + } (false, true) => { // `existing_mod` is not from glob but `new_mod` is, // just keep `existing_mod` and return at once @@ -115,6 +147,10 @@ impl Module<'hir> { } } } + if let Some(index) = to_remove { + self.mods.swap_remove(index); + return; + } // no mod with same name exists, just collect `new_mod` self.mods.push(new_mod); } diff --git a/src/test/rustdoc/glob-shadowing.rs b/src/test/rustdoc/glob-shadowing.rs index c3fea97342f23..6101587915837 100644 --- a/src/test/rustdoc/glob-shadowing.rs +++ b/src/test/rustdoc/glob-shadowing.rs @@ -1,11 +1,11 @@ // @has 'glob_shadowing/index.html' // @count - '//tr[@class="module-item"]' 4 // @!has - '//tr[@class="module-item"]' 'sub1::describe' +// @!has - '//tr[@class="module-item"]' 'sub1::describe2' // @has - '//tr[@class="module-item"]' 'mod::prelude' // @has - '//tr[@class="module-item"]' 'sub2::describe' // @has - '//tr[@class="module-item"]' 'sub1::Foo (struct)' // @has - '//tr[@class="module-item"]' 'mod::Foo (function)' - // @has 'glob_shadowing/fn.describe.html' // @has - '//div[@class="docblock"]' 'sub2::describe' @@ -22,9 +22,16 @@ mod sub1 { pub use super::describe; } - // this should not be shadowed, because sub1::Foo and mod::Foo are in different namespace + // this should *not* be shadowed, because sub1::Foo and mod::Foo are in different namespace /// 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 { @@ -34,6 +41,15 @@ mod sub2 { } } +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::prelude pub mod prelude {} @@ -45,3 +61,6 @@ pub use sub2::describe; #[doc(inline)] pub use sub1::*; + +#[doc(inline)] +pub use sub3::*; From 18f031f53e858d5a19d299772f2f3f30da773280 Mon Sep 17 00:00:00 2001 From: longfangsong Date: Thu, 15 Apr 2021 17:58:35 +0800 Subject: [PATCH 16/16] Fix wrongly pushing down from_glob when visiting_mod_contents Signed-off-by: longfangsong --- src/librustdoc/doctree.rs | 2 ++ src/librustdoc/visit_ast.rs | 12 ++++------- src/test/rustdoc/glob-shadowing.rs | 32 ++++++++++++++++++++++++------ 3 files changed, 32 insertions(+), 14 deletions(-) diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs index 155843b8ca02e..363a0e7c303a2 100644 --- a/src/librustdoc/doctree.rs +++ b/src/librustdoc/doctree.rs @@ -98,6 +98,7 @@ impl Module<'hir> { } } (false, false) => { + error!("push_item: {:?} conflict with {:?}", existing_item, new_item); // should report "defined multiple time" error before reach this unreachable!() } @@ -142,6 +143,7 @@ impl Module<'hir> { return; } (false, false) => { + error!("push_mod: {:?} conflict with {:?}", existing_mod.name, new_mod.name); // should report "defined multiple time" error before reach this unreachable!() } diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 786ef232d8541..caca8b5259adc 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -316,14 +316,10 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { om.push_item(self.cx, Item::new(item, renamed, from_glob)) } hir::ItemKind::Mod(ref m) => { - om.push_mod(self.visit_mod_contents( - item.span, - &item.vis, - item.hir_id(), - m, - name, - from_glob, - )); + let mut mod_ = + self.visit_mod_contents(item.span, &item.vis, item.hir_id(), m, name, false); + mod_.from_glob = from_glob; + om.push_mod(mod_); } hir::ItemKind::Fn(..) | hir::ItemKind::ExternCrate(..) diff --git a/src/test/rustdoc/glob-shadowing.rs b/src/test/rustdoc/glob-shadowing.rs index 6101587915837..d05c0b98d7e70 100644 --- a/src/test/rustdoc/glob-shadowing.rs +++ b/src/test/rustdoc/glob-shadowing.rs @@ -1,11 +1,18 @@ // @has 'glob_shadowing/index.html' -// @count - '//tr[@class="module-item"]' 4 +// @count - '//tr[@class="module-item"]' 5 // @!has - '//tr[@class="module-item"]' 'sub1::describe' +// @has - '//tr[@class="module-item"]' 'sub2::describe' + // @!has - '//tr[@class="module-item"]' 'sub1::describe2' + +// @!has - '//tr[@class="module-item"]' 'sub1::prelude' // @has - '//tr[@class="module-item"]' 'mod::prelude' -// @has - '//tr[@class="module-item"]' 'sub2::describe' + // @has - '//tr[@class="module-item"]' 'sub1::Foo (struct)' // @has - '//tr[@class="module-item"]' 'mod::Foo (function)' + +// @has - '//tr[@class="module-item"]' 'sub4::inner::X' + // @has 'glob_shadowing/fn.describe.html' // @has - '//div[@class="docblock"]' 'sub2::describe' @@ -19,10 +26,9 @@ mod sub1 { // this should be shadowed by mod::prelude /// sub1::prelude pub mod prelude { - pub use super::describe; } - // this should *not* be shadowed, because sub1::Foo and mod::Foo are in different namespace + // this should *not* be shadowed, because sub1::Foo and mod::Foo are in different namespaces /// sub1::Foo (struct) pub struct Foo; @@ -50,8 +56,16 @@ mod sub3 { } } -/// mod::prelude -pub mod prelude {} +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() {} @@ -64,3 +78,9 @@ pub use sub1::*; #[doc(inline)] pub use sub3::*; + +#[doc(inline)] +pub use sub4::inner::*; + +/// mod::prelude +pub mod prelude {} \ No newline at end of file