Skip to content

Commit

Permalink
rustdoc: do not mark the contents of a skipped module as inlined
Browse files Browse the repository at this point in the history
  • Loading branch information
notriddle authored and Mark-Simulacrum committed Aug 8, 2022
1 parent 0281ea4 commit e597688
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 21 deletions.
37 changes: 32 additions & 5 deletions src/librustdoc/clean/inline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ pub(crate) fn try_inline_glob(
cx: &mut DocContext<'_>,
res: Res,
visited: &mut FxHashSet<DefId>,
inlined_names: &mut FxHashSet<(ItemType, Symbol)>,
) -> Option<Vec<clean::Item>> {
let did = res.opt_def_id()?;
if did.is_local() {
Expand All @@ -153,8 +154,17 @@ pub(crate) fn try_inline_glob(

match res {
Res::Def(DefKind::Mod, did) => {
let m = build_module(cx, did, visited);
Some(m.items)
let mut items = build_module_items(cx, did, visited, inlined_names);
items.drain_filter(|item| {
if let Some(name) = item.name {
// If an item with the same type and name already exists,
// it takes priority over the inlined stuff.
!inlined_names.insert((item.type_(), name))
} else {
false
}
});
Some(items)
}
// glob imports on things like enums aren't inlined even for local exports, so just bail
_ => None,
Expand Down Expand Up @@ -517,6 +527,18 @@ fn build_module(
did: DefId,
visited: &mut FxHashSet<DefId>,
) -> clean::Module {
let items = build_module_items(cx, did, visited, &mut FxHashSet::default());

let span = clean::Span::new(cx.tcx.def_span(did));
clean::Module { items, span }
}

fn build_module_items(
cx: &mut DocContext<'_>,
did: DefId,
visited: &mut FxHashSet<DefId>,
inlined_names: &mut FxHashSet<(ItemType, Symbol)>,
) -> Vec<clean::Item> {
let mut items = Vec::new();

// If we're re-exporting a re-export it may actually re-export something in
Expand All @@ -526,7 +548,13 @@ fn build_module(
if item.vis.is_public() {
let res = item.res.expect_non_local();
if let Some(def_id) = res.mod_def_id() {
if did == def_id || !visited.insert(def_id) {
// If we're inlining a glob import, it's possible to have
// two distinct modules with the same name. We don't want to
// inline it, or mark any of its contents as visited.
if did == def_id
|| inlined_names.contains(&(ItemType::Module, item.ident.name))
|| !visited.insert(def_id)
{
continue;
}
}
Expand Down Expand Up @@ -563,8 +591,7 @@ fn build_module(
}
}

let span = clean::Span::new(cx.tcx.def_span(did));
clean::Module { items, span }
items
}

pub(crate) fn print_inlined_const(tcx: TyCtxt<'_>, did: DefId) -> String {
Expand Down
27 changes: 11 additions & 16 deletions src/librustdoc/clean/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ impl<'tcx> Clean<'tcx, Item> for DocModule<'tcx> {
// priority to the not-imported one, so we should, too.
items.extend(self.items.iter().flat_map(|(item, renamed)| {
// First, lower everything other than imports.
if matches!(item.kind, hir::ItemKind::Use(..)) {
if matches!(item.kind, hir::ItemKind::Use(_, hir::UseKind::Glob)) {
return Vec::new();
}
let v = clean_maybe_renamed_item(cx, item, *renamed);
Expand All @@ -84,20 +84,13 @@ impl<'tcx> Clean<'tcx, Item> for DocModule<'tcx> {
}));
items.extend(self.items.iter().flat_map(|(item, renamed)| {
// Now we actually lower the imports, skipping everything else.
if !matches!(item.kind, hir::ItemKind::Use(..)) {
return Vec::new();
if let hir::ItemKind::Use(path, hir::UseKind::Glob) = item.kind {
let name = renamed.unwrap_or_else(|| cx.tcx.hir().name(item.hir_id()));
clean_use_statement(item, name, path, hir::UseKind::Glob, cx, &mut inserted)
} else {
// skip everything else
Vec::new()
}
let mut v = clean_maybe_renamed_item(cx, item, *renamed);
v.drain_filter(|item| {
if let Some(name) = item.name {
// If an item with the same type and name already exists,
// it takes priority over the inlined stuff.
!inserted.insert((item.type_(), name))
} else {
false
}
});
v
}));

// determine if we should display the inner contents or
Expand Down Expand Up @@ -1967,7 +1960,7 @@ fn clean_maybe_renamed_item<'tcx>(
return clean_extern_crate(item, name, orig_name, cx);
}
ItemKind::Use(path, kind) => {
return clean_use_statement(item, name, path, kind, cx);
return clean_use_statement(item, name, path, kind, cx, &mut FxHashSet::default());
}
_ => unreachable!("not yet converted"),
};
Expand Down Expand Up @@ -2088,6 +2081,7 @@ fn clean_use_statement<'tcx>(
path: &hir::Path<'tcx>,
kind: hir::UseKind,
cx: &mut DocContext<'tcx>,
inlined_names: &mut FxHashSet<(ItemType, Symbol)>,
) -> Vec<Item> {
// We need this comparison because some imports (for std types for example)
// are "inserted" as well but directly by the compiler and they should not be
Expand Down Expand Up @@ -2153,7 +2147,8 @@ fn clean_use_statement<'tcx>(
let inner = if kind == hir::UseKind::Glob {
if !denied {
let mut visited = FxHashSet::default();
if let Some(items) = inline::try_inline_glob(cx, path.res, &mut visited) {
if let Some(items) = inline::try_inline_glob(cx, path.res, &mut visited, inlined_names)
{
return items;
}
}
Expand Down
13 changes: 13 additions & 0 deletions src/test/rustdoc/auxiliary/issue-100204-aux.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#![crate_name="first"]

pub mod prelude {
pub use crate::Bot;
}

pub struct Bot;

impl Bot {
pub fn new() -> Bot {
Bot
}
}
14 changes: 14 additions & 0 deletions src/test/rustdoc/issue-100204-inline-impl-through-glob-import.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// aux-build:issue-100204-aux.rs
// build-aux-docs
// ignore-cross-compile

#![crate_name="second"]

extern crate first;

pub mod prelude {}

// @has first/struct.Bot.html '//h4[@class="code-header"]' 'pub fn new() -> Bot'
// @has second/struct.Bot.html '//h4[@class="code-header"]' 'pub fn new() -> Bot'
#[doc(inline)]
pub use first::*;

0 comments on commit e597688

Please sign in to comment.