Auto merge of #133345 - GuillaumeGomez:stop-cloning-context, r=notriddle,aDotInTheVoid

Stop cloning `Context` so much

This is a first step for https://github.com/rust-lang/rust/issues/82381.

It's already big enough so I'll continue in a follow-up once this PR is merged. Next step will be to get rid of `SharedContext` by inlining it directly into `Context`.

cc `@camelid`
r? `@notriddle`
This commit is contained in:
bors 2024-12-01 22:32:36 +00:00
commit a522d78598
9 changed files with 354 additions and 284 deletions

View File

@ -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)];
run_format_inner(&mut format_renderer, krate.module, prof)?;
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))?;
}
}
prof.verbose_generic_activity_with_arg("renderer_after_krate", T::descr())
.run(|| format_renderer.after_krate())
}

View File

@ -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<FxHashMap<Cow<'static, str>, 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<FxHashSet<&'static str>> = OnceLock::new();
fn init_id_map() -> FxHashMap<Cow<'static, str>, 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<S: AsRef<str> + 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;
}
}

View File

@ -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<String>,
pub(super) deref_id_map: RefCell<DefIdMap<String>>,
/// The map used to ensure all generated 'id=' attributes are unique.
pub(super) id_map: IdMap,
pub(super) id_map: RefCell<IdMap>,
/// Shared mutable state.
///
/// Issue for improving the situation: [#82381][]
///
/// [#82381]: https://github.com/rust-lang/rust/issues/82381
pub(crate) shared: Rc<SharedContext<'tcx>>,
pub(crate) shared: SharedContext<'tcx>,
/// Collection of all types with notable traits referenced in the current module.
pub(crate) types_with_notable_traits: RefCell<FxIndexSet<clean::Type>>,
/// 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<clean::Type>,
/// 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<S: AsRef<str> + ToString>(&mut self, id: S) -> String {
self.id_map.derive(id)
pub(super) fn derive_id<S: AsRef<str> + 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 !)

View File

@ -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<RenderedLink>,
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<ShortItemInfo> {
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("</summary>");
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<String> {
pub(crate) fn notable_traits_button(ty: &clean::Type, cx: &Context<'_>) -> Option<String> {
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!(
" <a href=\"#\" class=\"tooltip\" data-notable-ty=\"{ty}\">ⓘ</a>",
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 = <Vec<&str>>::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(
"<div class=\"item-info\">\
<div class=\"stab empty-impl\">This impl block contains no items.</div>\
@ -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<T> Trait for &T`.
pub(crate) fn get_filtered_impls_for_reference<'a>(
shared: &'a Rc<SharedContext<'_>>,
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<W: fmt::Write>(mut w: W, cx: &mut Context<'_>, item: &clean::Item) {
fn render_call_locations<W: fmt::Write>(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,
"<div class=\"docblock scraped-example-list\">\

View File

@ -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#"<script type="text/json" id="notable-traits-data">{}</script>"#,
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::<Vec<_>>();
@ -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<Symbol, (DefId, bool)> = 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("</div>");
@ -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<String> {
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<VariantIdx, clean::Item>,
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<VariantIdx, clean::Item>,
enum_def_id: DefId,
@ -1743,7 +1739,7 @@ fn item_variants(
write!(w, "</div>");
}
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<CtorKind>,
@ -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<hir::Safety>,
@ -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,

View File

@ -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<LinkBlock<'_>> = 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<LinkBlock<'a>>,
deref_id_map: &'a DefIdMap<String>,
) {
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<LinkBlock<'a>>,
deref_id_map: &'a DefIdMap<String>,
) {
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<LinkBlock<'a>>) {
fn sidebar_primitive<'a>(
cx: &'a Context<'_>,
it: &'a clean::Item,
items: &mut Vec<LinkBlock<'a>>,
deref_id_map: &'a DefIdMap<String>,
) {
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<LinkBlock<'a>>,
deref_id_map: &'a DefIdMap<String>,
) {
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<LinkBlock<'a>>,
deref_id_map: &'a DefIdMap<String>,
) {
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<LinkBlock<'a>>,
deref_id_map: &'a DefIdMap<String>,
) {
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<String>,
deref_id_map: &'a DefIdMap<String>,
) {
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<LinkBlock<'a>>,
deref_id_map: &'a DefIdMap<String>,
) {
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<LinkBlock<'a>>,
deref_id_map: &'a DefIdMap<String>,
) {
sidebar_assoc_items(cx, it, items);
sidebar_assoc_items(cx, it, items, deref_id_map);
}
/// Renders the trait implementations for this type

View File

@ -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<PartsAndLocations<Self>, 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<PartsAndLocations<Self>, 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<DefId, AliasedType<'cache, 'item>>,
visited_aliases: FxHashSet<DefId>,
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) {

View File

@ -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 },

View File

@ -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