From db95734b9d41e00c17bb934b96ffd8cb660a2248 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 19 Jun 2023 21:17:57 +0200 Subject: [PATCH] Fix invalid creation of files in rustdoc --- src/librustdoc/formats/cache.rs | 5 ++++ src/librustdoc/html/render/context.rs | 41 ++++++++++++++++++++++----- src/librustdoc/visit_ast.rs | 7 +++-- 3 files changed, 44 insertions(+), 9 deletions(-) diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index 8aaad8bce1b..dac762e9ff9 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -121,6 +121,11 @@ pub(crate) struct Cache { pub(crate) intra_doc_links: FxHashMap>, /// Cfg that have been hidden via #![doc(cfg_hide(...))] pub(crate) hidden_cfg: FxHashSet, + + /// Contains the list of `DefId`s which have been inlined. It is used when generating files + /// to check if a stripped item should get its file generated or not: if it's inside a + /// `#[doc(hidden)]` item or a private one and not inlined, it shouldn't get a file. + pub(crate) inlined_items: DefIdSet, } /// This struct is used to wrap the `cache` and `tcx` in order to run `DocFolder`. diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs index 56af257fd5e..4c476263635 100644 --- a/src/librustdoc/html/render/context.rs +++ b/src/librustdoc/html/render/context.rs @@ -73,6 +73,8 @@ pub(crate) struct Context<'tcx> { pub(crate) include_sources: bool, /// Collection of all types with notable traits referenced in the current module. pub(crate) types_with_notable_traits: FxHashSet, + /// Field used during rendering, to know if we're inside an inlined item. + pub(crate) is_inside_inlined_module: bool, } // `Context` is cloned a lot, so we don't want the size to grow unexpectedly. @@ -171,6 +173,19 @@ impl<'tcx> Context<'tcx> { } fn render_item(&mut self, it: &clean::Item, is_module: bool) -> String { + let mut render_redirect_pages = self.render_redirect_pages; + // If the item is stripped but inlined, links won't point to the item so no need to generate + // a file for it. + if it.is_stripped() && + let Some(def_id) = it.def_id() && + def_id.is_local() + { + if self.is_inside_inlined_module || self.shared.cache.inlined_items.contains(&def_id) { + // For now we're forced to generate a redirect page for stripped items until + // `record_extern_fqn` correctly points to external items. + render_redirect_pages = true; + } + } let mut title = String::new(); if !is_module { title.push_str(it.name.unwrap().as_str()); @@ -205,7 +220,7 @@ impl<'tcx> Context<'tcx> { tyname.as_str() }; - if !self.render_redirect_pages { + if !render_redirect_pages { let clone_shared = Rc::clone(&self.shared); let page = layout::Page { css_class: tyname_s, @@ -545,6 +560,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { shared: Rc::new(scx), include_sources, types_with_notable_traits: FxHashSet::default(), + is_inside_inlined_module: false, }; if emit_crate { @@ -574,6 +590,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { shared: Rc::clone(&self.shared), include_sources: self.include_sources, types_with_notable_traits: FxHashSet::default(), + is_inside_inlined_module: self.is_inside_inlined_module, } } @@ -768,12 +785,22 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { info!("Recursing into {}", self.dst.display()); - let buf = self.render_item(item, true); - // buf will be empty if the module is stripped and there is no redirect for it - if !buf.is_empty() { - self.shared.ensure_dir(&self.dst)?; - let joint_dst = self.dst.join("index.html"); - self.shared.fs.write(joint_dst, buf)?; + if !item.is_stripped() { + let buf = self.render_item(item, true); + // buf will be empty if the module is stripped and there is no redirect for it + if !buf.is_empty() { + self.shared.ensure_dir(&self.dst)?; + let joint_dst = self.dst.join("index.html"); + self.shared.fs.write(joint_dst, buf)?; + } + } + if !self.is_inside_inlined_module { + if let Some(def_id) = item.def_id() && self.cache().inlined_items.contains(&def_id) { + self.is_inside_inlined_module = true; + } + } else if item.is_doc_hidden() { + // We're not inside an inlined module anymore since this one cannot be re-exported. + self.is_inside_inlined_module = false; } // Render sidebar-items.js used throughout this module. diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 22c8cc09243..fcf591a9328 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -313,7 +313,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { return false; } - let ret = match tcx.hir().get_by_def_id(res_did) { + let inlined = match tcx.hir().get_by_def_id(res_did) { // Bang macros are handled a bit on their because of how they are handled by the // compiler. If they have `#[doc(hidden)]` and the re-export doesn't have // `#[doc(inline)]`, then we don't inline it. @@ -344,7 +344,10 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { _ => false, }; self.view_item_stack.remove(&res_did); - ret + if inlined { + self.cx.cache.inlined_items.insert(res_did.to_def_id()); + } + inlined } /// Returns `true` if the item is visible, meaning it's not `#[doc(hidden)]` or private.