diff --git a/src/librustdoc/formats/renderer.rs b/src/librustdoc/formats/renderer.rs index edd7d56b17983..582ef7d2c4828 100644 --- a/src/librustdoc/formats/renderer.rs +++ b/src/librustdoc/formats/renderer.rs @@ -1,5 +1,5 @@ +use rustc_data_structures::profiling::SelfProfilerRef; use rustc_middle::ty::TyCtxt; -use tracing::debug; use crate::clean; use crate::config::RenderOptions; @@ -17,6 +17,18 @@ pub(crate) trait FormatRenderer<'tcx>: Sized { /// /// This is true for html, and false for json. See #80664 const RUN_ON_MODULE: bool; + /// This associated type is the type where the current module information is stored. + /// + /// For each module, we go through their items by calling for each item: + /// + /// 1. save_module_data + /// 2. item + /// 3. set_back_info + /// + /// However,the `item` method might update information in `self` (for example if the child is + /// a module). To prevent it to impact the other children of the current module, we need to + /// reset the information between each call to `item` by using `set_back_info`. + type ModuleData; /// Sets up any state required for the renderer. When this is called the cache has already been /// populated. @@ -27,8 +39,20 @@ pub(crate) trait FormatRenderer<'tcx>: Sized { tcx: TyCtxt<'tcx>, ) -> Result<(Self, clean::Crate), Error>; - /// Make a new renderer to render a child of the item currently being rendered. - fn make_child_renderer(&self) -> Self; + /// This method is called right before call [`Self::item`]. This method returns a type + /// containing information that needs to be reset after the [`Self::item`] method has been + /// called with the [`Self::set_back_info`] method. + /// + /// In short it goes like this: + /// + /// ```ignore (not valid code) + /// let reset_data = type.save_module_data(); + /// type.item(item)?; + /// type.set_back_info(reset_data); + /// ``` + fn save_module_data(&mut self) -> Self::ModuleData; + /// Used to reset current module's information. + fn set_back_info(&mut self, info: Self::ModuleData); /// Renders a single non-module item. This means no recursive sub-item rendering is required. fn item(&mut self, item: clean::Item) -> Result<(), Error>; @@ -47,6 +71,40 @@ pub(crate) trait FormatRenderer<'tcx>: Sized { fn cache(&self) -> &Cache; } +fn run_format_inner<'tcx, T: FormatRenderer<'tcx>>( + cx: &mut T, + item: clean::Item, + prof: &SelfProfilerRef, +) -> Result<(), Error> { + if item.is_mod() && T::RUN_ON_MODULE { + // modules are special because they add a namespace. We also need to + // recurse into the items of the module as well. + let _timer = + prof.generic_activity_with_arg("render_mod_item", item.name.unwrap().to_string()); + + cx.mod_item_in(&item)?; + let (clean::StrippedItem(box clean::ModuleItem(module)) | clean::ModuleItem(module)) = + item.inner.kind + else { + unreachable!() + }; + for it in module.items { + let info = cx.save_module_data(); + run_format_inner(cx, it, prof)?; + cx.set_back_info(info); + } + + cx.mod_item_out()?; + // FIXME: checking `item.name.is_some()` is very implicit and leads to lots of special + // cases. Use an explicit match instead. + } else if let Some(item_name) = item.name + && !item.is_extern_crate() + { + prof.generic_activity_with_arg("render_item", item_name.as_str()).run(|| cx.item(item))?; + } + Ok(()) +} + /// Main method for rendering a crate. pub(crate) fn run_format<'tcx, T: FormatRenderer<'tcx>>( krate: clean::Crate, @@ -66,36 +124,8 @@ pub(crate) fn run_format<'tcx, T: FormatRenderer<'tcx>>( } // Render the crate documentation - let mut work = vec![(format_renderer.make_child_renderer(), krate.module)]; - - while let Some((mut cx, item)) = work.pop() { - if item.is_mod() && T::RUN_ON_MODULE { - // modules are special because they add a namespace. We also need to - // recurse into the items of the module as well. - let _timer = - prof.generic_activity_with_arg("render_mod_item", item.name.unwrap().to_string()); - - cx.mod_item_in(&item)?; - let (clean::StrippedItem(box clean::ModuleItem(module)) | clean::ModuleItem(module)) = - item.inner.kind - else { - unreachable!() - }; - for it in module.items { - debug!("Adding {:?} to worklist", it.name); - work.push((cx.make_child_renderer(), it)); - } - - cx.mod_item_out()?; - // FIXME: checking `item.name.is_some()` is very implicit and leads to lots of special - // cases. Use an explicit match instead. - } else if let Some(item_name) = item.name - && !item.is_extern_crate() - { - prof.generic_activity_with_arg("render_item", item_name.as_str()) - .run(|| cx.item(item))?; - } - } + run_format_inner(&mut format_renderer, krate.module, prof)?; + prof.verbose_generic_activity_with_arg("renderer_after_krate", T::descr()) .run(|| format_renderer.after_krate()) } diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index b6829d5457ba7..d18673c8140da 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -37,7 +37,7 @@ use std::sync::OnceLock; use pulldown_cmark::{ BrokenLink, CodeBlockKind, CowStr, Event, LinkType, Options, Parser, Tag, TagEnd, html, }; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::{Diag, DiagMessage}; use rustc_hir::def_id::LocalDefId; use rustc_middle::ty::TyCtxt; @@ -1886,71 +1886,81 @@ pub struct IdMap { existing_footnotes: usize, } -// The map is pre-initialized and cloned each time to avoid reinitializing it repeatedly. -static DEFAULT_ID_MAP: OnceLock, usize>> = OnceLock::new(); +// The map is pre-initialized and then can be used as is to prevent cloning it for each item +// (in the sidebar rendering). +static DEFAULT_ID_MAP: OnceLock> = OnceLock::new(); -fn init_id_map() -> FxHashMap, usize> { - let mut map = FxHashMap::default(); +fn init_id_map() -> FxHashSet<&'static str> { + let mut map = FxHashSet::default(); // This is the list of IDs used in JavaScript. - map.insert("help".into(), 1); - map.insert("settings".into(), 1); - map.insert("not-displayed".into(), 1); - map.insert("alternative-display".into(), 1); - map.insert("search".into(), 1); - map.insert("crate-search".into(), 1); - map.insert("crate-search-div".into(), 1); + map.insert("help"); + map.insert("settings"); + map.insert("not-displayed"); + map.insert("alternative-display"); + map.insert("search"); + map.insert("crate-search"); + map.insert("crate-search-div"); // This is the list of IDs used in HTML generated in Rust (including the ones // used in tera template files). - map.insert("themeStyle".into(), 1); - map.insert("settings-menu".into(), 1); - map.insert("help-button".into(), 1); - map.insert("sidebar-button".into(), 1); - map.insert("main-content".into(), 1); - map.insert("toggle-all-docs".into(), 1); - map.insert("all-types".into(), 1); - map.insert("default-settings".into(), 1); - map.insert("sidebar-vars".into(), 1); - map.insert("copy-path".into(), 1); - map.insert("rustdoc-toc".into(), 1); - map.insert("rustdoc-modnav".into(), 1); + map.insert("themeStyle"); + map.insert("settings-menu"); + map.insert("help-button"); + map.insert("sidebar-button"); + map.insert("main-content"); + map.insert("toggle-all-docs"); + map.insert("all-types"); + map.insert("default-settings"); + map.insert("sidebar-vars"); + map.insert("copy-path"); + map.insert("rustdoc-toc"); + map.insert("rustdoc-modnav"); // This is the list of IDs used by rustdoc sections (but still generated by // rustdoc). - map.insert("fields".into(), 1); - map.insert("variants".into(), 1); - map.insert("implementors-list".into(), 1); - map.insert("synthetic-implementors-list".into(), 1); - map.insert("foreign-impls".into(), 1); - map.insert("implementations".into(), 1); - map.insert("trait-implementations".into(), 1); - map.insert("synthetic-implementations".into(), 1); - map.insert("blanket-implementations".into(), 1); - map.insert("required-associated-types".into(), 1); - map.insert("provided-associated-types".into(), 1); - map.insert("provided-associated-consts".into(), 1); - map.insert("required-associated-consts".into(), 1); - map.insert("required-methods".into(), 1); - map.insert("provided-methods".into(), 1); - map.insert("dyn-compatibility".into(), 1); - map.insert("implementors".into(), 1); - map.insert("synthetic-implementors".into(), 1); - map.insert("implementations-list".into(), 1); - map.insert("trait-implementations-list".into(), 1); - map.insert("synthetic-implementations-list".into(), 1); - map.insert("blanket-implementations-list".into(), 1); - map.insert("deref-methods".into(), 1); - map.insert("layout".into(), 1); - map.insert("aliased-type".into(), 1); + map.insert("fields"); + map.insert("variants"); + map.insert("implementors-list"); + map.insert("synthetic-implementors-list"); + map.insert("foreign-impls"); + map.insert("implementations"); + map.insert("trait-implementations"); + map.insert("synthetic-implementations"); + map.insert("blanket-implementations"); + map.insert("required-associated-types"); + map.insert("provided-associated-types"); + map.insert("provided-associated-consts"); + map.insert("required-associated-consts"); + map.insert("required-methods"); + map.insert("provided-methods"); + map.insert("dyn-compatibility"); + map.insert("implementors"); + map.insert("synthetic-implementors"); + map.insert("implementations-list"); + map.insert("trait-implementations-list"); + map.insert("synthetic-implementations-list"); + map.insert("blanket-implementations-list"); + map.insert("deref-methods"); + map.insert("layout"); + map.insert("aliased-type"); map } impl IdMap { pub fn new() -> Self { - IdMap { map: DEFAULT_ID_MAP.get_or_init(init_id_map).clone(), existing_footnotes: 0 } + IdMap { map: FxHashMap::default(), existing_footnotes: 0 } } pub(crate) fn derive + ToString>(&mut self, candidate: S) -> String { let id = match self.map.get_mut(candidate.as_ref()) { - None => candidate.to_string(), + None => { + let candidate = candidate.to_string(); + if DEFAULT_ID_MAP.get_or_init(init_id_map).contains(candidate.as_str()) { + let id = format!("{}-{}", candidate, 1); + self.map.insert(candidate.into(), 2); + id + } else { + candidate + } + } Some(a) => { let id = format!("{}-{}", candidate.as_ref(), *a); *a += 1; @@ -1970,4 +1980,9 @@ impl IdMap { closure(self, &mut existing_footnotes); self.existing_footnotes = existing_footnotes; } + + pub(crate) fn clear(&mut self) { + self.map.clear(); + self.existing_footnotes = 0; + } } diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs index 3a8144621747c..40468aef4db33 100644 --- a/src/librustdoc/html/render/context.rs +++ b/src/librustdoc/html/render/context.rs @@ -2,7 +2,6 @@ use std::cell::RefCell; use std::collections::BTreeMap; use std::io; use std::path::{Path, PathBuf}; -use std::rc::Rc; use std::sync::mpsc::{Receiver, channel}; use rinja::Template; @@ -49,36 +48,49 @@ pub(crate) struct Context<'tcx> { /// The current destination folder of where HTML artifacts should be placed. /// This changes as the context descends into the module hierarchy. pub(crate) dst: PathBuf, - /// A flag, which when `true`, will render pages which redirect to the - /// real location of an item. This is used to allow external links to - /// publicly reused items to redirect to the right location. - pub(super) render_redirect_pages: bool, /// Tracks section IDs for `Deref` targets so they match in both the main /// body and the sidebar. - pub(super) deref_id_map: DefIdMap, + pub(super) deref_id_map: RefCell>, /// The map used to ensure all generated 'id=' attributes are unique. - pub(super) id_map: IdMap, + pub(super) id_map: RefCell, /// Shared mutable state. /// /// Issue for improving the situation: [#82381][] /// /// [#82381]: https://github.com/rust-lang/rust/issues/82381 - pub(crate) shared: Rc>, + pub(crate) shared: SharedContext<'tcx>, + /// Collection of all types with notable traits referenced in the current module. + pub(crate) types_with_notable_traits: RefCell>, + /// Contains information that needs to be saved and reset after rendering an item which is + /// not a module. + pub(crate) info: ContextInfo, +} + +/// This struct contains the information that needs to be reset between each +/// [`FormatRenderer::item`] call. +/// +/// When we enter a new module, we set these values for the whole module but they might be updated +/// in each child item (especially if it's a module). So to prevent these changes to impact other +/// items rendering in the same module, we need to reset them to the module's set values. +#[derive(Clone, Copy)] +pub(crate) struct ContextInfo { + /// A flag, which when `true`, will render pages which redirect to the + /// real location of an item. This is used to allow external links to + /// publicly reused items to redirect to the right location. + pub(super) render_redirect_pages: bool, /// This flag indicates whether source links should be generated or not. If /// the source files are present in the html rendering, then this will be /// `true`. pub(crate) include_sources: bool, - /// Collection of all types with notable traits referenced in the current module. - pub(crate) types_with_notable_traits: FxIndexSet, /// 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. -#[cfg(all(not(windows), target_pointer_width = "64"))] -rustc_data_structures::static_assert_size!(Context<'_>, 192); -#[cfg(all(windows, target_pointer_width = "64"))] -rustc_data_structures::static_assert_size!(Context<'_>, 200); +impl ContextInfo { + fn new(include_sources: bool) -> Self { + Self { render_redirect_pages: false, include_sources, is_inside_inlined_module: false } + } +} /// Shared mutable state used in [`Context`] and elsewhere. pub(crate) struct SharedContext<'tcx> { @@ -163,8 +175,8 @@ impl<'tcx> Context<'tcx> { self.shared.tcx.sess } - pub(super) fn derive_id + ToString>(&mut self, id: S) -> String { - self.id_map.derive(id) + pub(super) fn derive_id + ToString>(&self, id: S) -> String { + self.id_map.borrow_mut().derive(id) } /// String representation of how to get back to the root path of the 'doc/' @@ -174,14 +186,16 @@ 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; + let mut render_redirect_pages = self.info.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) { + if self.info.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; @@ -221,24 +235,23 @@ impl<'tcx> Context<'tcx> { }; if !render_redirect_pages { - let clone_shared = Rc::clone(&self.shared); + let mut page_buffer = Buffer::html(); + print_item(self, it, &mut page_buffer); let page = layout::Page { css_class: tyname_s, root_path: &self.root_path(), - static_root_path: clone_shared.static_root_path.as_deref(), + static_root_path: self.shared.static_root_path.as_deref(), title: &title, description: &desc, - resource_suffix: &clone_shared.resource_suffix, + resource_suffix: &self.shared.resource_suffix, rust_logo: has_doc_flag(self.tcx(), LOCAL_CRATE.as_def_id(), sym::rust_logo), }; - let mut page_buffer = Buffer::html(); - print_item(self, it, &mut page_buffer); layout::render( - &clone_shared.layout, + &self.shared.layout, &page, |buf: &mut _| print_sidebar(self, it, buf), move |buf: &mut Buffer| buf.push_buffer(page_buffer), - &clone_shared.style_files, + &self.shared.style_files, ) } else { if let Some(&(ref names, ty)) = self.cache().paths.get(&it.item_id.expect_def_id()) { @@ -441,6 +454,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { } const RUN_ON_MODULE: bool = true; + type ModuleData = ContextInfo; fn init( krate: clean::Crate, @@ -562,13 +576,11 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { let mut cx = Context { current: Vec::new(), dst, - render_redirect_pages: false, - id_map, + id_map: RefCell::new(id_map), deref_id_map: Default::default(), - shared: Rc::new(scx), - include_sources, - types_with_notable_traits: FxIndexSet::default(), - is_inside_inlined_module: false, + shared: scx, + types_with_notable_traits: RefCell::new(FxIndexSet::default()), + info: ContextInfo::new(include_sources), }; if emit_crate { @@ -582,18 +594,15 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { Ok((cx, krate)) } - fn make_child_renderer(&self) -> Self { - Self { - current: self.current.clone(), - dst: self.dst.clone(), - render_redirect_pages: self.render_redirect_pages, - deref_id_map: Default::default(), - id_map: IdMap::new(), - shared: Rc::clone(&self.shared), - include_sources: self.include_sources, - types_with_notable_traits: FxIndexSet::default(), - is_inside_inlined_module: self.is_inside_inlined_module, - } + fn save_module_data(&mut self) -> Self::ModuleData { + self.deref_id_map.borrow_mut().clear(); + self.id_map.borrow_mut().clear(); + self.types_with_notable_traits.borrow_mut().clear(); + self.info + } + + fn set_back_info(&mut self, info: Self::ModuleData) { + self.info = info; } fn after_krate(&mut self) -> Result<(), Error> { @@ -607,7 +616,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { if !root_path.ends_with('/') { root_path.push('/'); } - let shared = Rc::clone(&self.shared); + let shared = &self.shared; let mut page = layout::Page { title: "List of all items in this crate", css_class: "mod sys", @@ -754,11 +763,8 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { shared.fs.write(redirect_map_path, paths)?; } - // No need for it anymore. - drop(shared); - // Flush pending errors. - Rc::get_mut(&mut self.shared).unwrap().fs.close(); + self.shared.fs.close(); let nb_errors = self.shared.errors.iter().map(|err| self.tcx().dcx().err(err)).count(); if nb_errors > 0 { Err(Error::new(io::Error::new(io::ErrorKind::Other, "I/O error"), "")) @@ -775,8 +781,8 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { // External crates will provide links to these structures, so // these modules are recursed into, but not rendered normally // (a flag on the context). - if !self.render_redirect_pages { - self.render_redirect_pages = item.is_stripped(); + if !self.info.render_redirect_pages { + self.info.render_redirect_pages = item.is_stripped(); } let item_name = item.name.unwrap(); self.dst.push(item_name.as_str()); @@ -793,19 +799,19 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { self.shared.fs.write(joint_dst, buf)?; } } - if !self.is_inside_inlined_module { + if !self.info.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; + self.info.is_inside_inlined_module = true; } } else if !self.cache().document_hidden && 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; + self.info.is_inside_inlined_module = false; } // Render sidebar-items.js used throughout this module. - if !self.render_redirect_pages { + if !self.info.render_redirect_pages { let (clean::StrippedItem(box clean::ModuleItem(ref module)) | clean::ModuleItem(ref module)) = item.kind else { @@ -836,8 +842,8 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { // External crates will provide links to these structures, so // these modules are recursed into, but not rendered normally // (a flag on the context). - if !self.render_redirect_pages { - self.render_redirect_pages = item.is_stripped(); + if !self.info.render_redirect_pages { + self.info.render_redirect_pages = item.is_stripped(); } let buf = self.render_item(&item, false); @@ -850,7 +856,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { let joint_dst = self.dst.join(file_name); self.shared.fs.write(joint_dst, buf)?; - if !self.render_redirect_pages { + if !self.info.render_redirect_pages { self.shared.all.borrow_mut().append(full_path(self, &item), &item_type); } // If the item is a macro, redirect from the old macro URL (with !) diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 7c5048cd164b7..f436725757232 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -41,7 +41,6 @@ use std::collections::VecDeque; use std::fmt::{self, Write}; use std::iter::Peekable; use std::path::PathBuf; -use std::rc::Rc; use std::{fs, str}; use rinja::Template; @@ -504,7 +503,7 @@ fn scrape_examples_help(shared: &SharedContext<'_>) -> String { } fn document<'a, 'cx: 'a>( - cx: &'a mut Context<'cx>, + cx: &'a Context<'cx>, item: &'a clean::Item, parent: Option<&'a clean::Item>, heading_offset: HeadingOffset, @@ -525,7 +524,7 @@ fn document<'a, 'cx: 'a>( /// Render md_text as markdown. fn render_markdown<'a, 'cx: 'a>( - cx: &'a mut Context<'cx>, + cx: &'a Context<'cx>, md_text: &'a str, links: Vec, heading_offset: HeadingOffset, @@ -537,7 +536,7 @@ fn render_markdown<'a, 'cx: 'a>( Markdown { content: md_text, links: &links, - ids: &mut cx.id_map, + ids: &mut cx.id_map.borrow_mut(), error_codes: cx.shared.codes, edition: cx.shared.edition(), playground: &cx.shared.playground, @@ -552,7 +551,7 @@ fn render_markdown<'a, 'cx: 'a>( /// docs are longer, a "Read more" link is appended to the end. fn document_short<'a, 'cx: 'a>( item: &'a clean::Item, - cx: &'a mut Context<'cx>, + cx: &'a Context<'cx>, link: AssocItemLink<'a>, parent: &'a clean::Item, show_def_docs: bool, @@ -585,7 +584,7 @@ fn document_short<'a, 'cx: 'a>( fn document_full_collapsible<'a, 'cx: 'a>( item: &'a clean::Item, - cx: &'a mut Context<'cx>, + cx: &'a Context<'cx>, heading_offset: HeadingOffset, ) -> impl fmt::Display + 'a + Captures<'cx> { document_full_inner(item, cx, true, heading_offset) @@ -593,7 +592,7 @@ fn document_full_collapsible<'a, 'cx: 'a>( fn document_full<'a, 'cx: 'a>( item: &'a clean::Item, - cx: &'a mut Context<'cx>, + cx: &'a Context<'cx>, heading_offset: HeadingOffset, ) -> impl fmt::Display + 'a + Captures<'cx> { document_full_inner(item, cx, false, heading_offset) @@ -601,7 +600,7 @@ fn document_full<'a, 'cx: 'a>( fn document_full_inner<'a, 'cx: 'a>( item: &'a clean::Item, - cx: &'a mut Context<'cx>, + cx: &'a Context<'cx>, is_collapsible: bool, heading_offset: HeadingOffset, ) -> impl fmt::Display + 'a + Captures<'cx> { @@ -644,7 +643,7 @@ struct ItemInfo { /// * Deprecated /// * Required features (through the `doc_cfg` feature) fn document_item_info( - cx: &mut Context<'_>, + cx: &Context<'_>, item: &clean::Item, parent: Option<&clean::Item>, ) -> ItemInfo { @@ -690,7 +689,7 @@ enum ShortItemInfo { /// the item's documentation. fn short_item_info( item: &clean::Item, - cx: &mut Context<'_>, + cx: &Context<'_>, parent: Option<&clean::Item>, ) -> Vec { let mut extra_info = vec![]; @@ -715,7 +714,8 @@ fn short_item_info( if let Some(note) = note { let note = note.as_str(); - let html = MarkdownItemInfo(note, &mut cx.id_map); + let mut id_map = cx.id_map.borrow_mut(); + let html = MarkdownItemInfo(note, &mut id_map); message.push_str(": "); message.push_str(&html.into_string()); } @@ -749,18 +749,17 @@ fn short_item_info( // Render the list of items inside one of the sections "Trait Implementations", // "Auto Trait Implementations," "Blanket Trait Implementations" (on struct/enum pages). pub(crate) fn render_impls( - cx: &mut Context<'_>, + cx: &Context<'_>, mut w: impl Write, impls: &[&Impl], containing_item: &clean::Item, toggle_open_by_default: bool, ) { - let tcx = cx.tcx(); let mut rendered_impls = impls .iter() .map(|i| { let did = i.trait_did().unwrap(); - let provided_trait_methods = i.inner_impl().provided_trait_methods(tcx); + let provided_trait_methods = i.inner_impl().provided_trait_methods(cx.tcx()); let assoc_link = AssocItemLink::GotoSource(did.into(), &provided_trait_methods); let mut buffer = Buffer::new(); render_impl( @@ -906,7 +905,7 @@ fn assoc_method( d: &clean::FnDecl, link: AssocItemLink<'_>, parent: ItemType, - cx: &mut Context<'_>, + cx: &Context<'_>, render_mode: RenderMode, ) { let tcx = cx.tcx(); @@ -1071,7 +1070,7 @@ fn render_assoc_item( item: &clean::Item, link: AssocItemLink<'_>, parent: ItemType, - cx: &mut Context<'_>, + cx: &Context<'_>, render_mode: RenderMode, ) { match &item.kind { @@ -1191,7 +1190,7 @@ fn write_impl_section_heading(w: &mut impl fmt::Write, title: &str, id: &str) { pub(crate) fn render_all_impls( mut w: impl Write, - cx: &mut Context<'_>, + cx: &Context<'_>, containing_item: &clean::Item, concrete: &[&Impl], synthetic: &[&Impl], @@ -1225,7 +1224,7 @@ pub(crate) fn render_all_impls( } fn render_assoc_items<'a, 'cx: 'a>( - cx: &'a mut Context<'cx>, + cx: &'a Context<'cx>, containing_item: &'a clean::Item, it: DefId, what: AssocItemRender<'a>, @@ -1240,15 +1239,14 @@ fn render_assoc_items<'a, 'cx: 'a>( fn render_assoc_items_inner( mut w: &mut dyn fmt::Write, - cx: &mut Context<'_>, + cx: &Context<'_>, containing_item: &clean::Item, it: DefId, what: AssocItemRender<'_>, derefs: &mut DefIdSet, ) { info!("Documenting associated items of {:?}", containing_item.name); - let shared = Rc::clone(&cx.shared); - let cache = &shared.cache; + let cache = &cx.shared.cache; let Some(v) = cache.impls.get(&it) else { return }; let (non_trait, traits): (Vec<_>, _) = v.iter().partition(|i| i.inner_impl().trait_.is_none()); if !non_trait.is_empty() { @@ -1276,7 +1274,7 @@ fn render_assoc_items_inner( ); tmp_buf.write_str(""); if let Some(def_id) = type_.def_id(cx.cache()) { - cx.deref_id_map.insert(def_id, id); + cx.deref_id_map.borrow_mut().insert(def_id, id); } (RenderMode::ForDeref { mut_: deref_mut_ }, derived_id, r#" class="impl-items""#) } @@ -1340,7 +1338,7 @@ fn render_assoc_items_inner( fn render_deref_methods( mut w: impl Write, - cx: &mut Context<'_>, + cx: &Context<'_>, impl_: &Impl, container_item: &clean::Item, deref_mut: bool, @@ -1407,7 +1405,7 @@ fn should_render_item(item: &clean::Item, deref_mut_: bool, tcx: TyCtxt<'_>) -> } } -pub(crate) fn notable_traits_button(ty: &clean::Type, cx: &mut Context<'_>) -> Option { +pub(crate) fn notable_traits_button(ty: &clean::Type, cx: &Context<'_>) -> Option { let mut has_notable_trait = false; if ty.is_unit() { @@ -1450,7 +1448,7 @@ pub(crate) fn notable_traits_button(ty: &clean::Type, cx: &mut Context<'_>) -> O } if has_notable_trait { - cx.types_with_notable_traits.insert(ty.clone()); + cx.types_with_notable_traits.borrow_mut().insert(ty.clone()); Some(format!( " ", ty = Escape(&format!("{:#}", ty.print(cx))), @@ -1554,7 +1552,7 @@ struct ImplRenderingParameters { fn render_impl( w: &mut Buffer, - cx: &mut Context<'_>, + cx: &Context<'_>, i: &Impl, parent: &clean::Item, link: AssocItemLink<'_>, @@ -1563,8 +1561,7 @@ fn render_impl( aliases: &[String], rendering_params: ImplRenderingParameters, ) { - let shared = Rc::clone(&cx.shared); - let cache = &shared.cache; + let cache = &cx.shared.cache; let traits = &cache.traits; let trait_ = i.trait_did().map(|did| &traits[&did]); let mut close_tags = >::with_capacity(2); @@ -1577,7 +1574,7 @@ fn render_impl( fn doc_impl_item( boring: &mut Buffer, interesting: &mut Buffer, - cx: &mut Context<'_>, + cx: &Context<'_>, item: &clean::Item, parent: &clean::Item, link: AssocItemLink<'_>, @@ -1867,7 +1864,7 @@ fn render_impl( fn render_default_items( boring: &mut Buffer, interesting: &mut Buffer, - cx: &mut Context<'_>, + cx: &Context<'_>, t: &clean::Trait, i: &clean::Impl, parent: &clean::Item, @@ -1907,6 +1904,7 @@ fn render_impl( } } + let trait_is_none = trait_.is_none(); // If we've implemented a trait, then also emit documentation for all // default items which weren't overridden in the implementation block. // We don't emit documentation for default items if they appear in the @@ -1952,7 +1950,7 @@ fn render_impl( } if let Some(ref dox) = i.impl_item.opt_doc_value() { - if trait_.is_none() && impl_.items.is_empty() { + if trait_is_none && impl_.items.is_empty() { w.write_str( "
\
This impl block contains no items.
\ @@ -1965,7 +1963,7 @@ fn render_impl( Markdown { content: dox, links: &i.impl_item.links(cx), - ids: &mut cx.id_map, + ids: &mut cx.id_map.borrow_mut(), error_codes: cx.shared.codes, edition: cx.shared.edition(), playground: &cx.shared.playground, @@ -2025,7 +2023,7 @@ fn render_rightside(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, render pub(crate) fn render_impl_summary( w: &mut Buffer, - cx: &mut Context<'_>, + cx: &Context<'_>, i: &Impl, parent: &clean::Item, show_def_docs: bool, @@ -2186,7 +2184,7 @@ fn extract_for_impl_name(item: &clean::Item, cx: &Context<'_>) -> Option<(String /// implementations that are on concrete or partially generic types, only keeping implementations /// of the form `impl Trait for &T`. pub(crate) fn get_filtered_impls_for_reference<'a>( - shared: &'a Rc>, + shared: &'a SharedContext<'_>, it: &clean::Item, ) -> (Vec<&'a Impl>, Vec<&'a Impl>, Vec<&'a Impl>) { let def_id = it.item_id.expect_def_id(); @@ -2423,14 +2421,14 @@ const MAX_FULL_EXAMPLES: usize = 5; const NUM_VISIBLE_LINES: usize = 10; /// Generates the HTML for example call locations generated via the --scrape-examples flag. -fn render_call_locations(mut w: W, cx: &mut Context<'_>, item: &clean::Item) { +fn render_call_locations(mut w: W, cx: &Context<'_>, item: &clean::Item) { let tcx = cx.tcx(); let def_id = item.item_id.expect_def_id(); let key = tcx.def_path_hash(def_id); let Some(call_locations) = cx.shared.call_locations.get(&key) else { return }; // Generate a unique ID so users can link to this section for a given method - let id = cx.id_map.derive("scraped-examples"); + let id = cx.derive_id("scraped-examples"); write!( &mut w, "
\ diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index dc205252507c5..4c8d704e65bc1 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -1,7 +1,5 @@ -use std::cell::{RefCell, RefMut}; use std::cmp::Ordering; use std::fmt; -use std::rc::Rc; use itertools::Itertools; use rinja::Template; @@ -61,7 +59,7 @@ macro_rules! item_template { ( $(#[$meta:meta])* struct $name:ident<'a, 'cx> { - cx: RefCell<&'a mut Context<'cx>>, + cx: &'a Context<'cx>, it: &'a clean::Item, $($field_name:ident: $field_ty:ty),*, }, @@ -70,14 +68,14 @@ macro_rules! item_template { #[derive(Template)] $(#[$meta])* struct $name<'a, 'cx> { - cx: RefCell<&'a mut Context<'cx>>, + cx: &'a Context<'cx>, it: &'a clean::Item, $($field_name: $field_ty),* } impl<'a, 'cx: 'a> ItemTemplate<'a, 'cx> for $name<'a, 'cx> { - fn item_and_mut_cx(&self) -> (&'a clean::Item, RefMut<'_, &'a mut Context<'cx>>) { - (&self.it, self.cx.borrow_mut()) + fn item_and_cx(&self) -> (&'a clean::Item, &'a Context<'cx>) { + (&self.it, &self.cx) } } @@ -95,8 +93,8 @@ macro_rules! item_template_methods { (document $($rest:tt)*) => { fn document<'b>(&'b self) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> { display_fn(move |f| { - let (item, mut cx) = self.item_and_mut_cx(); - let v = document(*cx, item, None, HeadingOffset::H2); + let (item, cx) = self.item_and_cx(); + let v = document(cx, item, None, HeadingOffset::H2); write!(f, "{v}") }) } @@ -105,9 +103,9 @@ macro_rules! item_template_methods { (document_type_layout $($rest:tt)*) => { fn document_type_layout<'b>(&'b self) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> { display_fn(move |f| { - let (item, cx) = self.item_and_mut_cx(); + let (item, cx) = self.item_and_cx(); let def_id = item.item_id.expect_def_id(); - let v = document_type_layout(*cx, def_id); + let v = document_type_layout(cx, def_id); write!(f, "{v}") }) } @@ -116,8 +114,8 @@ macro_rules! item_template_methods { (render_attributes_in_pre $($rest:tt)*) => { fn render_attributes_in_pre<'b>(&'b self) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> { display_fn(move |f| { - let (item, cx) = self.item_and_mut_cx(); - let v = render_attributes_in_pre(item, "", &cx); + let (item, cx) = self.item_and_cx(); + let v = render_attributes_in_pre(item, "", cx); write!(f, "{v}") }) } @@ -126,9 +124,9 @@ macro_rules! item_template_methods { (render_assoc_items $($rest:tt)*) => { fn render_assoc_items<'b>(&'b self) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> { display_fn(move |f| { - let (item, mut cx) = self.item_and_mut_cx(); + let (item, cx) = self.item_and_cx(); let def_id = item.item_id.expect_def_id(); - let v = render_assoc_items(*cx, item, def_id, AssocItemRender::All); + let v = render_assoc_items(cx, item, def_id, AssocItemRender::All); write!(f, "{v}") }) } @@ -175,7 +173,7 @@ fn print_where_clause_and_check<'a, 'tcx: 'a>( len_before != buffer.len() } -pub(super) fn print_item(cx: &mut Context<'_>, item: &clean::Item, buf: &mut Buffer) { +pub(super) fn print_item(cx: &Context<'_>, item: &clean::Item, buf: &mut Buffer) { debug_assert!(!item.is_stripped()); let typ = match item.kind { clean::ModuleItem(_) => { @@ -223,7 +221,7 @@ pub(super) fn print_item(cx: &mut Context<'_>, item: &clean::Item, buf: &mut Buf // this page, and this link will be auto-clicked. The `id` attribute is // used to find the link to auto-click. let src_href = - if cx.include_sources && !item.is_primitive() { cx.src_href(item) } else { None }; + if cx.info.include_sources && !item.is_primitive() { cx.src_href(item) } else { None }; let path_components = if item.is_primitive() || item.is_keyword() { vec![] @@ -277,13 +275,14 @@ pub(super) fn print_item(cx: &mut Context<'_>, item: &clean::Item, buf: &mut Buf } // Render notable-traits.js used for all methods in this module. - if !cx.types_with_notable_traits.is_empty() { + let mut types_with_notable_traits = cx.types_with_notable_traits.borrow_mut(); + if !types_with_notable_traits.is_empty() { write!( buf, r#""#, - notable_traits_json(cx.types_with_notable_traits.iter(), cx) + notable_traits_json(types_with_notable_traits.iter(), cx) ); - cx.types_with_notable_traits.clear(); + types_with_notable_traits.clear(); } } @@ -308,10 +307,10 @@ fn toggle_close(mut w: impl fmt::Write) { } trait ItemTemplate<'a, 'cx: 'a>: rinja::Template + fmt::Display { - fn item_and_mut_cx(&self) -> (&'a clean::Item, RefMut<'_, &'a mut Context<'cx>>); + fn item_and_cx(&self) -> (&'a clean::Item, &'a Context<'cx>); } -fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items: &[clean::Item]) { +fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[clean::Item]) { write!(w, "{}", document(cx, item, None, HeadingOffset::H2)); let mut not_stripped_items = @@ -594,7 +593,7 @@ fn extra_info_tags<'a, 'tcx: 'a>( }) } -fn item_function(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, f: &clean::Function) { +fn item_function(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, f: &clean::Function) { let tcx = cx.tcx(); let header = it.fn_header(tcx).expect("printing a function which isn't a function"); debug!( @@ -649,7 +648,7 @@ fn item_function(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, f: &cle write!(w, "{}", document(cx, it, None, HeadingOffset::H2)); } -fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean::Trait) { +fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Trait) { let tcx = cx.tcx(); let bounds = bounds(&t.bounds, false, cx); let required_types = t.items.iter().filter(|m| m.is_ty_associated_type()).collect::>(); @@ -801,7 +800,7 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: // Trait documentation write!(w, "{}", document(cx, it, None, HeadingOffset::H2)); - fn trait_item(w: &mut Buffer, cx: &mut Context<'_>, m: &clean::Item, t: &clean::Item) { + fn trait_item(w: &mut Buffer, cx: &Context<'_>, m: &clean::Item, t: &clean::Item) { let name = m.name.unwrap(); info!("Documenting {name} on {ty_name:?}", ty_name = t.name); let item_type = m.type_(); @@ -929,8 +928,6 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: // If there are methods directly on this trait object, render them here. write!(w, "{}", render_assoc_items(cx, it, it.item_id.expect_def_id(), AssocItemRender::All)); - let cloned_shared = Rc::clone(&cx.shared); - let cache = &cloned_shared.cache; let mut extern_crates = FxIndexSet::default(); if !t.is_dyn_compatible(cx.tcx()) { @@ -950,12 +947,13 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: ); } - if let Some(implementors) = cache.implementors.get(&it.item_id.expect_def_id()) { + if let Some(implementors) = cx.shared.cache.implementors.get(&it.item_id.expect_def_id()) { // The DefId is for the first Type found with that name. The bool is // if any Types with the same name but different DefId have been found. let mut implementor_dups: FxHashMap = FxHashMap::default(); for implementor in implementors { - if let Some(did) = implementor.inner_impl().for_.without_borrowed_ref().def_id(cache) + if let Some(did) = + implementor.inner_impl().for_.without_borrowed_ref().def_id(&cx.shared.cache) && !did.is_local() { extern_crates.insert(did.krate); @@ -1036,7 +1034,10 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: it, w, &implementor_dups, - &collect_paths_for_type(implementor.inner_impl().for_.clone(), cache), + &collect_paths_for_type( + implementor.inner_impl().for_.clone(), + &cx.shared.cache, + ), ); } w.write_str("
"); @@ -1139,8 +1140,8 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: .chain(std::iter::once("trait.impl")) .collect(); if let Some(did) = it.item_id.as_def_id() - && let get_extern = { || cache.external_paths.get(&did).map(|s| &s.0) } - && let Some(fqp) = cache.exact_paths.get(&did).or_else(get_extern) + && let get_extern = { || cx.shared.cache.external_paths.get(&did).map(|s| &s.0) } + && let Some(fqp) = cx.shared.cache.exact_paths.get(&did).or_else(get_extern) { js_src_path.extend(fqp[..fqp.len() - 1].iter().copied()); js_src_path.push_fmt(format_args!("{}.{}.js", it.type_(), fqp.last().unwrap())); @@ -1164,7 +1165,7 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: fn item_trait_alias( w: &mut impl fmt::Write, - cx: &mut Context<'_>, + cx: &Context<'_>, it: &clean::Item, t: &clean::TraitAlias, ) { @@ -1190,7 +1191,7 @@ fn item_trait_alias( .unwrap(); } -fn item_type_alias(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean::TypeAlias) { +fn item_type_alias(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::TypeAlias) { wrap_item(w, |w| { write!( w, @@ -1355,8 +1356,7 @@ fn item_type_alias(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &c // // [JSONP]: https://en.wikipedia.org/wiki/JSONP // [^115718]: https://github.com/rust-lang/rust/issues/115718 - let cloned_shared = Rc::clone(&cx.shared); - let cache = &cloned_shared.cache; + let cache = &cx.shared.cache; if let Some(target_did) = t.type_.def_id(cache) && let get_extern = { || cache.external_paths.get(&target_did) } && let Some(&(ref target_fqp, target_type)) = cache.paths.get(&target_did).or_else(get_extern) && @@ -1380,11 +1380,11 @@ fn item_type_alias(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &c } } -fn item_union(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean::Union) { +fn item_union(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::Union) { item_template!( #[template(path = "item_union.html")] struct ItemUnion<'a, 'cx> { - cx: RefCell<&'a mut Context<'cx>>, + cx: &'a Context<'cx>, it: &'a clean::Item, s: &'a clean::Union, }, @@ -1394,8 +1394,7 @@ fn item_union(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean: impl<'a, 'cx: 'a> ItemUnion<'a, 'cx> { fn render_union<'b>(&'b self) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> { display_fn(move |f| { - let cx = self.cx.borrow_mut(); - let v = render_union(self.it, Some(&self.s.generics), &self.s.fields, *cx); + let v = render_union(self.it, Some(&self.s.generics), &self.s.fields, self.cx); write!(f, "{v}") }) } @@ -1405,15 +1404,13 @@ fn item_union(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean: field: &'a clean::Item, ) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> { display_fn(move |f| { - let mut cx = self.cx.borrow_mut(); - let v = document(*cx, field, Some(self.it), HeadingOffset::H3); + let v = document(self.cx, field, Some(self.it), HeadingOffset::H3); write!(f, "{v}") }) } fn stability_field(&self, field: &clean::Item) -> Option { - let cx = self.cx.borrow(); - field.stability_class(cx.tcx()) + field.stability_class(self.cx.tcx()) } fn print_ty<'b>( @@ -1421,8 +1418,7 @@ fn item_union(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean: ty: &'a clean::Type, ) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> { display_fn(move |f| { - let cx = self.cx.borrow(); - let v = ty.print(*cx); + let v = ty.print(&self.cx); write!(f, "{v}") }) } @@ -1441,7 +1437,7 @@ fn item_union(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean: } } - ItemUnion { cx: RefCell::new(cx), it, s }.render_into(w).unwrap(); + ItemUnion { cx, it, s }.render_into(w).unwrap(); } fn print_tuple_struct_fields<'a, 'cx: 'a>( @@ -1471,7 +1467,7 @@ fn print_tuple_struct_fields<'a, 'cx: 'a>( }) } -fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean::Enum) { +fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum) { let count_variants = e.variants().count(); wrap_item(w, |w| { render_attributes_in_code(w, it, cx); @@ -1532,7 +1528,7 @@ fn should_show_enum_discriminant( fn display_c_like_variant( w: &mut Buffer, - cx: &mut Context<'_>, + cx: &Context<'_>, item: &clean::Item, variant: &clean::Variant, index: VariantIdx, @@ -1557,7 +1553,7 @@ fn display_c_like_variant( fn render_enum_fields( mut w: &mut Buffer, - cx: &mut Context<'_>, + cx: &Context<'_>, g: Option<&clean::Generics>, variants: &IndexVec, count_variants: usize, @@ -1621,7 +1617,7 @@ fn render_enum_fields( fn item_variants( w: &mut Buffer, - cx: &mut Context<'_>, + cx: &Context<'_>, it: &clean::Item, variants: &IndexVec, enum_def_id: DefId, @@ -1743,7 +1739,7 @@ fn item_variants( write!(w, "
"); } -fn item_macro(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean::Macro) { +fn item_macro(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Macro) { wrap_item(w, |w| { // FIXME: Also print `#[doc(hidden)]` for `macro_rules!` if it `is_doc_hidden`. if !t.macro_rules { @@ -1756,7 +1752,7 @@ fn item_macro(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: fn item_proc_macro( w: &mut impl fmt::Write, - cx: &mut Context<'_>, + cx: &Context<'_>, it: &clean::Item, m: &clean::ProcMacro, ) { @@ -1790,7 +1786,7 @@ fn item_proc_macro( write!(w, "{}", document(cx, it, None, HeadingOffset::H2)).unwrap(); } -fn item_primitive(w: &mut impl fmt::Write, cx: &mut Context<'_>, it: &clean::Item) { +fn item_primitive(w: &mut impl fmt::Write, cx: &Context<'_>, it: &clean::Item) { let def_id = it.item_id.expect_def_id(); write!(w, "{}", document(cx, it, None, HeadingOffset::H2)).unwrap(); if it.name.map(|n| n.as_str() != "reference").unwrap_or(false) { @@ -1798,8 +1794,7 @@ fn item_primitive(w: &mut impl fmt::Write, cx: &mut Context<'_>, it: &clean::Ite } else { // We handle the "reference" primitive type on its own because we only want to list // implementations on generic types. - let shared = Rc::clone(&cx.shared); - let (concrete, synthetic, blanket_impl) = get_filtered_impls_for_reference(&shared, it); + let (concrete, synthetic, blanket_impl) = get_filtered_impls_for_reference(&cx.shared, it); render_all_impls(w, cx, it, &concrete, &synthetic, &blanket_impl); } @@ -1807,7 +1802,7 @@ fn item_primitive(w: &mut impl fmt::Write, cx: &mut Context<'_>, it: &clean::Ite fn item_constant( w: &mut Buffer, - cx: &mut Context<'_>, + cx: &Context<'_>, it: &clean::Item, generics: &clean::Generics, ty: &clean::Type, @@ -1862,7 +1857,7 @@ fn item_constant( write!(w, "{}", document(cx, it, None, HeadingOffset::H2)) } -fn item_struct(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean::Struct) { +fn item_struct(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::Struct) { wrap_item(w, |w| { render_attributes_in_code(w, it, cx); render_struct(w, it, Some(&s.generics), s.ctor_kind, &s.fields, "", true, cx); @@ -1879,7 +1874,7 @@ fn item_struct(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean fn item_fields( w: &mut Buffer, - cx: &mut Context<'_>, + cx: &Context<'_>, it: &clean::Item, fields: &[clean::Item], ctor_kind: Option, @@ -1920,7 +1915,7 @@ fn item_fields( fn item_static( w: &mut impl fmt::Write, - cx: &mut Context<'_>, + cx: &Context<'_>, it: &clean::Item, s: &clean::Static, safety: Option, @@ -1944,7 +1939,7 @@ fn item_static( write!(w, "{}", document(cx, it, None, HeadingOffset::H2)).unwrap(); } -fn item_foreign_type(w: &mut impl fmt::Write, cx: &mut Context<'_>, it: &clean::Item) { +fn item_foreign_type(w: &mut impl fmt::Write, cx: &Context<'_>, it: &clean::Item) { wrap_item(w, |buffer| { buffer.write_str("extern {\n").unwrap(); render_attributes_in_code(buffer, it, cx); @@ -1962,7 +1957,7 @@ fn item_foreign_type(w: &mut impl fmt::Write, cx: &mut Context<'_>, it: &clean:: .unwrap(); } -fn item_keyword(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item) { +fn item_keyword(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item) { write!(w, "{}", document(cx, it, None, HeadingOffset::H2)) } @@ -2134,7 +2129,7 @@ impl Ord for ImplString { } fn render_implementor( - cx: &mut Context<'_>, + cx: &Context<'_>, implementor: &Impl, trait_: &clean::Item, w: &mut Buffer, diff --git a/src/librustdoc/html/render/sidebar.rs b/src/librustdoc/html/render/sidebar.rs index 76de8d872311e..e99e2f04b2c5e 100644 --- a/src/librustdoc/html/render/sidebar.rs +++ b/src/librustdoc/html/render/sidebar.rs @@ -1,10 +1,9 @@ use std::borrow::Cow; -use std::rc::Rc; use rinja::Template; use rustc_data_structures::fx::FxHashSet; use rustc_hir::def::CtorKind; -use rustc_hir::def_id::DefIdSet; +use rustc_hir::def_id::{DefIdMap, DefIdSet}; use rustc_middle::ty::{self, TyCtxt}; use tracing::debug; @@ -119,17 +118,18 @@ pub(crate) mod filters { pub(super) fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buffer) { let mut ids = IdMap::new(); let mut blocks: Vec> = docblock_toc(cx, it, &mut ids).into_iter().collect(); + let deref_id_map = cx.deref_id_map.borrow(); match it.kind { - clean::StructItem(ref s) => sidebar_struct(cx, it, s, &mut blocks), - clean::TraitItem(ref t) => sidebar_trait(cx, it, t, &mut blocks), - clean::PrimitiveItem(_) => sidebar_primitive(cx, it, &mut blocks), - clean::UnionItem(ref u) => sidebar_union(cx, it, u, &mut blocks), - clean::EnumItem(ref e) => sidebar_enum(cx, it, e, &mut blocks), - clean::TypeAliasItem(ref t) => sidebar_type_alias(cx, it, t, &mut blocks), + clean::StructItem(ref s) => sidebar_struct(cx, it, s, &mut blocks, &deref_id_map), + clean::TraitItem(ref t) => sidebar_trait(cx, it, t, &mut blocks, &deref_id_map), + clean::PrimitiveItem(_) => sidebar_primitive(cx, it, &mut blocks, &deref_id_map), + clean::UnionItem(ref u) => sidebar_union(cx, it, u, &mut blocks, &deref_id_map), + clean::EnumItem(ref e) => sidebar_enum(cx, it, e, &mut blocks, &deref_id_map), + clean::TypeAliasItem(ref t) => sidebar_type_alias(cx, it, t, &mut blocks, &deref_id_map), clean::ModuleItem(ref m) => { blocks.push(sidebar_module(&m.items, &mut ids, ModuleLike::from(it))) } - clean::ForeignTypeItem => sidebar_foreign_type(cx, it, &mut blocks), + clean::ForeignTypeItem => sidebar_foreign_type(cx, it, &mut blocks, &deref_id_map), _ => {} } // The sidebar is designed to display sibling functions, modules and @@ -245,6 +245,7 @@ fn sidebar_struct<'a>( it: &'a clean::Item, s: &'a clean::Struct, items: &mut Vec>, + deref_id_map: &'a DefIdMap, ) { let fields = get_struct_fields_name(&s.fields); let field_name = match s.ctor_kind { @@ -255,7 +256,7 @@ fn sidebar_struct<'a>( if let Some(name) = field_name { items.push(LinkBlock::new(Link::new("fields", name), "structfield", fields)); } - sidebar_assoc_items(cx, it, items); + sidebar_assoc_items(cx, it, items, deref_id_map); } fn sidebar_trait<'a>( @@ -263,6 +264,7 @@ fn sidebar_trait<'a>( it: &'a clean::Item, t: &'a clean::Trait, blocks: &mut Vec>, + deref_id_map: &'a DefIdMap, ) { fn filter_items<'a>( items: &'a [clean::Item], @@ -313,7 +315,7 @@ fn sidebar_trait<'a>( .into_iter() .map(|(id, title, items)| LinkBlock::new(Link::new(id, title), "", items)), ); - sidebar_assoc_items(cx, it, blocks); + sidebar_assoc_items(cx, it, blocks, deref_id_map); if !t.is_dyn_compatible(cx.tcx()) { blocks.push(LinkBlock::forced( @@ -331,13 +333,17 @@ fn sidebar_trait<'a>( } } -fn sidebar_primitive<'a>(cx: &'a Context<'_>, it: &'a clean::Item, items: &mut Vec>) { +fn sidebar_primitive<'a>( + cx: &'a Context<'_>, + it: &'a clean::Item, + items: &mut Vec>, + deref_id_map: &'a DefIdMap, +) { if it.name.map(|n| n.as_str() != "reference").unwrap_or(false) { - sidebar_assoc_items(cx, it, items); + sidebar_assoc_items(cx, it, items, deref_id_map); } else { - let shared = Rc::clone(&cx.shared); let (concrete, synthetic, blanket_impl) = - super::get_filtered_impls_for_reference(&shared, it); + super::get_filtered_impls_for_reference(&cx.shared, it); sidebar_render_assoc_items(cx, &mut IdMap::new(), concrete, synthetic, blanket_impl, items); } @@ -348,6 +354,7 @@ fn sidebar_type_alias<'a>( it: &'a clean::Item, t: &'a clean::TypeAlias, items: &mut Vec>, + deref_id_map: &'a DefIdMap, ) { if let Some(inner_type) = &t.inner_type { items.push(LinkBlock::forced(Link::new("aliased-type", "Aliased type"), "type")); @@ -370,7 +377,7 @@ fn sidebar_type_alias<'a>( } } } - sidebar_assoc_items(cx, it, items); + sidebar_assoc_items(cx, it, items, deref_id_map); } fn sidebar_union<'a>( @@ -378,10 +385,11 @@ fn sidebar_union<'a>( it: &'a clean::Item, u: &'a clean::Union, items: &mut Vec>, + deref_id_map: &'a DefIdMap, ) { let fields = get_struct_fields_name(&u.fields); items.push(LinkBlock::new(Link::new("fields", "Fields"), "structfield", fields)); - sidebar_assoc_items(cx, it, items); + sidebar_assoc_items(cx, it, items, deref_id_map); } /// Adds trait implementations into the blocks of links @@ -389,6 +397,7 @@ fn sidebar_assoc_items<'a>( cx: &'a Context<'_>, it: &'a clean::Item, links: &mut Vec>, + deref_id_map: &'a DefIdMap, ) { let did = it.item_id.expect_def_id(); let cache = cx.cache(); @@ -433,7 +442,15 @@ fn sidebar_assoc_items<'a>( { let mut derefs = DefIdSet::default(); derefs.insert(did); - sidebar_deref_methods(cx, &mut blocks, impl_, v, &mut derefs, &mut used_links); + sidebar_deref_methods( + cx, + &mut blocks, + impl_, + v, + &mut derefs, + &mut used_links, + deref_id_map, + ); } let (synthetic, concrete): (Vec<&Impl>, Vec<&Impl>) = @@ -462,6 +479,7 @@ fn sidebar_deref_methods<'a>( v: &[Impl], derefs: &mut DefIdSet, used_links: &mut FxHashSet, + deref_id_map: &'a DefIdMap, ) { let c = cx.cache(); @@ -501,7 +519,7 @@ fn sidebar_deref_methods<'a>( if !ret.is_empty() { let id = if let Some(target_def_id) = real_target.def_id(c) { Cow::Borrowed( - cx.deref_id_map + deref_id_map .get(&target_def_id) .expect("Deref section without derived id") .as_str(), @@ -531,7 +549,15 @@ fn sidebar_deref_methods<'a>( .unwrap_or(false) }) { - sidebar_deref_methods(cx, out, target_deref_impl, target_impls, derefs, used_links); + sidebar_deref_methods( + cx, + out, + target_deref_impl, + target_impls, + derefs, + used_links, + deref_id_map, + ); } } } @@ -541,6 +567,7 @@ fn sidebar_enum<'a>( it: &'a clean::Item, e: &'a clean::Enum, items: &mut Vec>, + deref_id_map: &'a DefIdMap, ) { let mut variants = e .variants() @@ -550,7 +577,7 @@ fn sidebar_enum<'a>( variants.sort_unstable(); items.push(LinkBlock::new(Link::new("variants", "Variants"), "variant", variants)); - sidebar_assoc_items(cx, it, items); + sidebar_assoc_items(cx, it, items, deref_id_map); } pub(crate) fn sidebar_module_like( @@ -607,8 +634,9 @@ fn sidebar_foreign_type<'a>( cx: &'a Context<'_>, it: &'a clean::Item, items: &mut Vec>, + deref_id_map: &'a DefIdMap, ) { - sidebar_assoc_items(cx, it, items); + sidebar_assoc_items(cx, it, items, deref_id_map); } /// Renders the trait implementations for this type diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs index 7c676469597dc..ce10e5ecc2441 100644 --- a/src/librustdoc/html/render/write_shared.rs +++ b/src/librustdoc/html/render/write_shared.rs @@ -43,7 +43,6 @@ use crate::config::{EmitType, PathToParts, RenderOptions, ShouldMerge}; use crate::docfs::PathError; use crate::error::Error; use crate::formats::Impl; -use crate::formats::cache::Cache; use crate::formats::item_type::ItemType; use crate::html::format::Buffer; use crate::html::layout; @@ -62,13 +61,12 @@ pub(crate) fn write_shared( tcx: TyCtxt<'_>, ) -> Result<(), Error> { // NOTE(EtomicBomb): I don't think we need sync here because no read-after-write? - Rc::get_mut(&mut cx.shared).unwrap().fs.set_sync_only(true); + cx.shared.fs.set_sync_only(true); let lock_file = cx.dst.join(".lock"); // Write shared runs within a flock; disable thread dispatching of IO temporarily. let _lock = try_err!(flock::Lock::new(&lock_file, true, true, true), &lock_file); - let SerializedSearchIndex { index, desc } = - build_index(krate, &mut Rc::get_mut(&mut cx.shared).unwrap().cache, tcx); + let SerializedSearchIndex { index, desc } = build_index(krate, &mut cx.shared.cache, tcx); write_search_desc(cx, krate, &desc)?; // does not need to be merged let crate_name = krate.name(cx.tcx()); @@ -104,7 +102,7 @@ pub(crate) fn write_shared( &cx.shared.style_files, cx.shared.layout.css_file_extension.as_deref(), &cx.shared.resource_suffix, - cx.include_sources, + cx.info.include_sources, )?; match &opt.index_page { Some(index_page) if opt.enable_index_page => { @@ -128,7 +126,7 @@ pub(crate) fn write_shared( } } - Rc::get_mut(&mut cx.shared).unwrap().fs.set_sync_only(false); + cx.shared.fs.set_sync_only(false); Ok(()) } @@ -597,13 +595,11 @@ impl TypeAliasPart { krate: &Crate, crate_name_json: &OrderedJson, ) -> Result, Error> { - let cache = &Rc::clone(&cx.shared).cache; let mut path_parts = PartsAndLocations::default(); let mut type_impl_collector = TypeImplCollector { aliased_types: IndexMap::default(), visited_aliases: FxHashSet::default(), - cache, cx, }; DocVisitor::visit_crate(&mut type_impl_collector, krate); @@ -625,14 +621,14 @@ impl TypeAliasPart { // each type alias, and if it gives a different result, split the impl for &(type_alias_fqp, type_alias_item) in type_aliases { let mut buf = Buffer::html(); - cx.id_map = Default::default(); - cx.deref_id_map = Default::default(); + cx.id_map.borrow_mut().clear(); + cx.deref_id_map.borrow_mut().clear(); let target_did = impl_ .inner_impl() .trait_ .as_ref() .map(|trait_| trait_.def_id()) - .or_else(|| impl_.inner_impl().for_.def_id(cache)); + .or_else(|| impl_.inner_impl().for_.def_id(&cx.shared.cache)); let provided_methods; let assoc_link = if let Some(target_did) = target_did { provided_methods = impl_.inner_impl().provided_trait_methods(cx.tcx()); @@ -720,7 +716,7 @@ impl TraitAliasPart { } fn get( - cx: &mut Context<'_>, + cx: &Context<'_>, crate_name_json: &OrderedJson, ) -> Result, Error> { let cache = &cx.shared.cache; @@ -828,8 +824,7 @@ struct TypeImplCollector<'cx, 'cache, 'item> { /// Map from DefId-of-aliased-type to its data. aliased_types: IndexMap>, visited_aliases: FxHashSet, - cache: &'cache Cache, - cx: &'cache mut Context<'cx>, + cx: &'cache Context<'cx>, } /// Data for an aliased type. @@ -868,7 +863,7 @@ struct AliasedTypeImpl<'cache, 'item> { impl<'item> DocVisitor<'item> for TypeImplCollector<'_, '_, 'item> { fn visit_item(&mut self, it: &'item Item) { self.visit_item_recur(it); - let cache = self.cache; + let cache = &self.cx.shared.cache; let ItemKind::TypeAliasItem(ref t) = it.kind else { return }; let Some(self_did) = it.item_id.as_def_id() else { return }; if !self.visited_aliases.insert(self_did) { diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs index 2fe9364c259c3..c37506e358836 100644 --- a/src/librustdoc/html/sources.rs +++ b/src/librustdoc/html/sources.rs @@ -2,7 +2,6 @@ use std::cell::RefCell; use std::ffi::OsStr; use std::ops::RangeInclusive; use std::path::{Component, Path, PathBuf}; -use std::rc::Rc; use std::{fmt, fs}; use rinja::Template; @@ -124,7 +123,7 @@ struct SourceCollector<'a, 'tcx> { impl DocVisitor<'_> for SourceCollector<'_, '_> { fn visit_item(&mut self, item: &clean::Item) { - if !self.cx.include_sources { + if !self.cx.info.include_sources { return; } @@ -146,7 +145,7 @@ impl DocVisitor<'_> for SourceCollector<'_, '_> { // something like that), so just don't include sources for the // entire crate. The other option is maintaining this mapping on a // per-file basis, but that's probably not worth it... - self.cx.include_sources = match self.emit_source(&filename, file_span) { + self.cx.info.include_sources = match self.emit_source(&filename, file_span) { Ok(()) => true, Err(e) => { self.cx.shared.tcx.dcx().span_err( @@ -197,7 +196,7 @@ impl SourceCollector<'_, '_> { // Remove the utf-8 BOM if any let contents = contents.strip_prefix('\u{feff}').unwrap_or(&contents); - let shared = Rc::clone(&self.cx.shared); + let shared = &self.cx.shared; // Create the intermediate directories let cur = RefCell::new(PathBuf::new()); let root_path = RefCell::new(PathBuf::new()); @@ -250,12 +249,11 @@ impl SourceCollector<'_, '_> { &page, "", |buf: &mut _| { - let cx = &mut self.cx; print_src( buf, contents, file_span, - cx, + self.cx, &root_path, highlight::DecorationInfo::default(), SourceContext::Standalone { file_path }, diff --git a/src/librustdoc/json/mod.rs b/src/librustdoc/json/mod.rs index 560ed872ef3af..9efcf6b4983b3 100644 --- a/src/librustdoc/json/mod.rs +++ b/src/librustdoc/json/mod.rs @@ -137,6 +137,7 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> { } const RUN_ON_MODULE: bool = false; + type ModuleData = (); fn init( krate: clean::Crate, @@ -161,8 +162,12 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> { )) } - fn make_child_renderer(&self) -> Self { - self.clone() + fn save_module_data(&mut self) -> Self::ModuleData { + unreachable!("RUN_ON_MODULE = false should never call save_module_data") + } + + fn set_back_info(&mut self, _info: Self::ModuleData) { + unreachable!("RUN_ON_MODULE = false should never call set_back_info") } /// Inserts an item into the index. This should be used rather than directly calling insert on