Skip to content

Commit b83ad87

Browse files
committed
introduce glob shadowing rules to rustdoc
Signed-off-by: longfangsong <longfangsong@icloud.com>
1 parent 015d2bc commit b83ad87

File tree

4 files changed

+122
-11
lines changed

4 files changed

+122
-11
lines changed

src/librustdoc/clean/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1934,11 +1934,11 @@ impl Clean<BareFunctionDecl> for hir::BareFnTy<'_> {
19341934
}
19351935
}
19361936

1937-
impl Clean<Vec<Item>> for (&hir::Item<'_>, Option<Symbol>) {
1937+
impl Clean<Vec<Item>> for doctree::Item<'_> {
19381938
fn clean(&self, cx: &mut DocContext<'_>) -> Vec<Item> {
19391939
use hir::ItemKind;
19401940

1941-
let (item, renamed) = self;
1941+
let (item, renamed) = (self.hir_item, self.renamed_name);
19421942
let def_id = item.def_id.to_def_id();
19431943
let mut name = renamed.unwrap_or_else(|| cx.tcx.hir().name(item.hir_id()));
19441944
cx.with_param_env(def_id, |cx| {

src/librustdoc/doctree.rs

+63-1
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,48 @@ use rustc_span::{self, Span, Symbol};
44

55
use rustc_hir as hir;
66

7+
/// A warp around an hir::Item
8+
#[derive(Debug)]
9+
pub(crate) struct Item<'hir> {
10+
/// the wrapped item
11+
pub(crate) hir_item: &'hir hir::Item<'hir>,
12+
/// the explicit renamed name
13+
pub(crate) renamed_name: Option<Symbol>,
14+
/// whether the item is from a glob import
15+
/// if `from_glob` is true and we see another item with same name,
16+
/// then this item can be replaced with that one
17+
pub(crate) from_glob: bool,
18+
}
19+
20+
impl<'hir> Item<'hir> {
21+
pub(crate) fn new(
22+
hir_item: &'hir hir::Item<'hir>,
23+
renamed_name: Option<Symbol>,
24+
from_glob: bool,
25+
) -> Self {
26+
Self { hir_item, renamed_name, from_glob }
27+
}
28+
29+
fn name(&'hir self) -> &'hir Symbol {
30+
self.renamed_name.as_ref().unwrap_or(&self.hir_item.ident.name)
31+
}
32+
}
33+
734
crate struct Module<'hir> {
835
crate name: Symbol,
936
crate where_outer: Span,
1037
crate where_inner: Span,
1138
crate mods: Vec<Module<'hir>>,
1239
crate id: hir::HirId,
40+
crate items: Vec<Item<'hir>>,
1341
// (item, renamed)
14-
crate items: Vec<(&'hir hir::Item<'hir>, Option<Symbol>)>,
1542
crate foreigns: Vec<(&'hir hir::ForeignItem<'hir>, Option<Symbol>)>,
1643
crate macros: Vec<(&'hir hir::MacroDef<'hir>, Option<Symbol>)>,
1744
crate is_crate: bool,
45+
/// whether the module is from a glob import
46+
/// if `from_glob` is true and we see another module with same name,
47+
/// then this item can be replaced with that one
48+
pub(crate) from_glob: bool,
1849
}
1950

2051
impl Module<'hir> {
@@ -29,6 +60,37 @@ impl Module<'hir> {
2960
foreigns: Vec::new(),
3061
macros: Vec::new(),
3162
is_crate: false,
63+
from_glob: false,
64+
}
65+
}
66+
67+
pub(crate) fn push_item(&mut self, new_item: Item<'hir>) {
68+
for item_iter in self.items.iter_mut() {
69+
if item_iter.name() == new_item.name() {
70+
if item_iter.from_glob {
71+
debug!("push_item: {:?} shadowed by {:?}", *item_iter, new_item);
72+
*item_iter = new_item;
73+
return;
74+
} else if new_item.from_glob {
75+
return;
76+
}
77+
}
78+
}
79+
self.items.push(new_item);
80+
}
81+
82+
pub(crate) fn push_mod(&mut self, new_item: Module<'hir>) {
83+
for item_iter in self.mods.iter_mut() {
84+
if item_iter.name == new_item.name {
85+
if item_iter.from_glob {
86+
debug!("push_mod: {:?} shadowed by {:?}", item_iter.name, new_item.name);
87+
*item_iter = new_item;
88+
return;
89+
} else if new_item.from_glob {
90+
return;
91+
}
92+
}
3293
}
94+
self.mods.push(new_item);
3395
}
3496
}

src/librustdoc/visit_ast.rs

+19-8
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
7777
hir::CRATE_HIR_ID,
7878
&krate.item,
7979
self.cx.tcx.crate_name,
80+
false,
8081
);
8182
top_level_module.is_crate = true;
8283
// Attach the crate's exported macros to the top-level module.
@@ -134,17 +135,19 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
134135
id: hir::HirId,
135136
m: &'tcx hir::Mod<'tcx>,
136137
name: Symbol,
138+
from_glob: bool,
137139
) -> Module<'tcx> {
138140
let mut om = Module::new(name);
139141
om.where_outer = span;
140142
om.where_inner = m.inner;
141143
om.id = id;
144+
om.from_glob = from_glob;
142145
// Keep track of if there were any private modules in the path.
143146
let orig_inside_public_path = self.inside_public_path;
144147
self.inside_public_path &= vis.node.is_pub();
145148
for &i in m.item_ids {
146149
let item = self.cx.tcx.hir().item(i);
147-
self.visit_item(item, None, &mut om);
150+
self.visit_item(item, None, &mut om, from_glob);
148151
}
149152
self.inside_public_path = orig_inside_public_path;
150153
om
@@ -225,14 +228,14 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
225228
let prev = mem::replace(&mut self.inlining, true);
226229
for &i in m.item_ids {
227230
let i = self.cx.tcx.hir().item(i);
228-
self.visit_item(i, None, om);
231+
self.visit_item(i, None, om, glob);
229232
}
230233
self.inlining = prev;
231234
true
232235
}
233236
Node::Item(it) if !glob => {
234237
let prev = mem::replace(&mut self.inlining, true);
235-
self.visit_item(it, renamed, om);
238+
self.visit_item(it, renamed, om, glob);
236239
self.inlining = prev;
237240
true
238241
}
@@ -257,6 +260,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
257260
item: &'tcx hir::Item<'_>,
258261
renamed: Option<Symbol>,
259262
om: &mut Module<'tcx>,
263+
from_glob: bool,
260264
) {
261265
debug!("visiting item {:?}", item);
262266
let name = renamed.unwrap_or(item.ident.name);
@@ -309,10 +313,17 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
309313
}
310314
}
311315

312-
om.items.push((item, renamed))
316+
om.push_item(Item::new(item, renamed, is_glob))
313317
}
314318
hir::ItemKind::Mod(ref m) => {
315-
om.mods.push(self.visit_mod_contents(item.span, &item.vis, item.hir_id(), m, name));
319+
om.push_mod(self.visit_mod_contents(
320+
item.span,
321+
&item.vis,
322+
item.hir_id(),
323+
m,
324+
name,
325+
from_glob,
326+
));
316327
}
317328
hir::ItemKind::Fn(..)
318329
| hir::ItemKind::ExternCrate(..)
@@ -323,19 +334,19 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
323334
| hir::ItemKind::OpaqueTy(..)
324335
| hir::ItemKind::Static(..)
325336
| hir::ItemKind::Trait(..)
326-
| hir::ItemKind::TraitAlias(..) => om.items.push((item, renamed)),
337+
| hir::ItemKind::TraitAlias(..) => om.push_item(Item::new(item, renamed, from_glob)),
327338
hir::ItemKind::Const(..) => {
328339
// Underscore constants do not correspond to a nameable item and
329340
// so are never useful in documentation.
330341
if name != kw::Underscore {
331-
om.items.push((item, renamed));
342+
om.push_item(Item::new(item, renamed, from_glob));
332343
}
333344
}
334345
hir::ItemKind::Impl(ref impl_) => {
335346
// Don't duplicate impls when inlining or if it's implementing a trait, we'll pick
336347
// them up regardless of where they're located.
337348
if !self.inlining && impl_.of_trait.is_none() {
338-
om.items.push((item, None));
349+
om.push_item(Item::new(item, None, from_glob));
339350
}
340351
}
341352
}

src/test/rustdoc/glob-shadowing.rs

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// @has 'glob_shadowing/index.html'
2+
// @count - '//tr[@class="module-item"]' 2
3+
// @has - '//tr[@class="module-item"]' 'mod::prelude'
4+
// @has - '//tr[@class="module-item"]' 'sub2::describe'
5+
6+
mod sub1 {
7+
/// sub1::describe
8+
pub fn describe() -> &'static str {
9+
"sub1::describe"
10+
}
11+
12+
/// sub1::prelude
13+
pub mod prelude {
14+
pub use super::describe;
15+
}
16+
}
17+
18+
mod sub2 {
19+
/// sub2::describe
20+
pub fn describe() -> &'static str {
21+
"sub2::describe"
22+
}
23+
}
24+
25+
/// mod::prelude
26+
pub mod prelude {
27+
/// mod::prelude::describe
28+
pub fn describe() -> &'static str {
29+
"mod::describe"
30+
}
31+
}
32+
33+
#[doc(inline)]
34+
pub use sub2::describe;
35+
36+
#[doc(inline)]
37+
pub use sub1::*;
38+

0 commit comments

Comments
 (0)