diff options
| author | Michael Howell <michael@notriddle.com> | 2023-02-15 14:44:31 -0700 |
|---|---|---|
| committer | Michael Howell <michael@notriddle.com> | 2023-02-22 21:00:10 -0700 |
| commit | 49d995a4cf7c4355aa846fa039b7af656ffa287d (patch) | |
| tree | 5d1e3a819485cd244be1333d18cd6c3a3b5e7810 | |
| parent | 0978711950b77582e4f8f334f6e9848d48ab7790 (diff) | |
| download | rust-49d995a4cf7c4355aa846fa039b7af656ffa287d.tar.gz rust-49d995a4cf7c4355aa846fa039b7af656ffa287d.zip | |
rustdoc: reduce allocations when generating tooltips
An attempt to reduce the perf regression in https://github.com/rust-lang/rust/pull/108052#issuecomment-1430631861
| -rw-r--r-- | compiler/rustc_resolve/src/rustdoc.rs | 16 | ||||
| -rw-r--r-- | src/librustdoc/clean/types.rs | 8 | ||||
| -rw-r--r-- | src/librustdoc/html/format.rs | 19 | ||||
| -rw-r--r-- | src/librustdoc/html/markdown.rs | 8 | ||||
| -rw-r--r-- | src/librustdoc/json/conversions.rs | 2 | ||||
| -rw-r--r-- | src/librustdoc/passes/collect_intra_doc_links.rs | 14 | ||||
| -rw-r--r-- | src/librustdoc/passes/lint/html_tags.rs | 2 |
7 files changed, 40 insertions, 29 deletions
diff --git a/compiler/rustc_resolve/src/rustdoc.rs b/compiler/rustc_resolve/src/rustdoc.rs index 5e4b66018e4..b8853c1744c 100644 --- a/compiler/rustc_resolve/src/rustdoc.rs +++ b/compiler/rustc_resolve/src/rustdoc.rs @@ -265,9 +265,9 @@ fn strip_generics_from_path_segment(segment: Vec<char>) -> Result<String, Malfor } } -pub fn strip_generics_from_path(path_str: &str) -> Result<String, MalformedGenerics> { +pub fn strip_generics_from_path(path_str: &str) -> Result<Box<str>, MalformedGenerics> { if !path_str.contains(['<', '>']) { - return Ok(path_str.to_string()); + return Ok(path_str.into()); } let mut stripped_segments = vec![]; let mut path = path_str.chars().peekable(); @@ -322,7 +322,11 @@ pub fn strip_generics_from_path(path_str: &str) -> Result<String, MalformedGener let stripped_path = stripped_segments.join("::"); - if !stripped_path.is_empty() { Ok(stripped_path) } else { Err(MalformedGenerics::MissingType) } + if !stripped_path.is_empty() { + Ok(stripped_path.into()) + } else { + Err(MalformedGenerics::MissingType) + } } /// Returns whether the first doc-comment is an inner attribute. @@ -336,7 +340,7 @@ pub fn inner_docs(attrs: &[ast::Attribute]) -> bool { /// Simplified version of the corresponding function in rustdoc. /// If the rustdoc version returns a successful result, this function must return the same result. /// Otherwise this function may return anything. -fn preprocess_link(link: &str) -> String { +fn preprocess_link(link: &str) -> Box<str> { let link = link.replace('`', ""); let link = link.split('#').next().unwrap(); let link = link.trim(); @@ -345,7 +349,7 @@ fn preprocess_link(link: &str) -> String { let link = link.strip_suffix("{}").unwrap_or(link); let link = link.strip_suffix("[]").unwrap_or(link); let link = if link != "!" { link.strip_suffix('!').unwrap_or(link) } else { link }; - strip_generics_from_path(link).unwrap_or_else(|_| link.to_string()) + strip_generics_from_path(link).unwrap_or_else(|_| link.into()) } /// Keep inline and reference links `[]`, @@ -365,7 +369,7 @@ pub fn may_be_doc_link(link_type: LinkType) -> bool { /// Simplified version of `preprocessed_markdown_links` from rustdoc. /// Must return at least the same links as it, but may add some more links on top of that. -pub(crate) fn attrs_to_preprocessed_links(attrs: &[ast::Attribute]) -> Vec<String> { +pub(crate) fn attrs_to_preprocessed_links(attrs: &[ast::Attribute]) -> Vec<Box<str>> { let (doc_fragments, _) = attrs_to_doc_fragments(attrs.iter().map(|attr| (attr, None)), true); let doc = prepare_to_doc_link_resolution(&doc_fragments).into_values().next().unwrap(); diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index fc1396e86f6..27d18aad7a3 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -1017,12 +1017,12 @@ pub(crate) fn collapse_doc_fragments(doc_strings: &[DocFragment]) -> String { #[derive(Clone, Debug, PartialEq, Eq)] pub(crate) struct ItemLink { /// The original link written in the markdown - pub(crate) link: String, + pub(crate) link: Box<str>, /// The link text displayed in the HTML. /// /// This may not be the same as `link` if there was a disambiguator /// in an intra-doc link (e.g. \[`fn@f`\]) - pub(crate) link_text: String, + pub(crate) link_text: Box<str>, /// The `DefId` of the Item whose **HTML Page** contains the item being /// linked to. This will be different to `item_id` on item's that don't /// have their own page, such as struct fields and enum variants. @@ -1035,9 +1035,9 @@ pub struct RenderedLink { /// The text the link was original written as. /// /// This could potentially include disambiguators and backticks. - pub(crate) original_text: String, + pub(crate) original_text: Box<str>, /// The text to display in the HTML - pub(crate) new_text: String, + pub(crate) new_text: Box<str>, /// The URL to put in the `href` pub(crate) href: String, /// The tooltip. diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 6bdd9db9bfa..0e4c5ed6836 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -772,14 +772,21 @@ pub(crate) fn link_tooltip(did: DefId, fragment: &Option<UrlFragment>, cx: &Cont let Some((fqp, shortty)) = cache.paths.get(&did) .or_else(|| cache.external_paths.get(&did)) else { return String::new() }; - let fqp = fqp.iter().map(|sym| sym.as_str()).join("::"); + let mut buf = Buffer::new(); if let &Some(UrlFragment::Item(id)) = fragment { - let name = cx.tcx().item_name(id); - let descr = cx.tcx().def_descr(id); - format!("{descr} {fqp}::{name}") - } else { - format!("{shortty} {fqp}") + write!(buf, "{} ", cx.tcx().def_descr(id)); + for component in fqp { + write!(buf, "{component}::"); + } + write!(buf, "{}", cx.tcx().item_name(id)); + } else if !fqp.is_empty() { + let mut fqp_it = fqp.into_iter(); + write!(buf, "{shortty} {}", fqp_it.next().unwrap()); + for component in fqp_it { + write!(buf, "::{component}"); + } } + buf.into_inner() } /// Used to render a [`clean::Path`]. diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 9ef0b501c08..b5a34814382 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -981,7 +981,7 @@ impl Markdown<'_> { let mut replacer = |broken_link: BrokenLink<'_>| { links .iter() - .find(|link| link.original_text.as_str() == &*broken_link.reference) + .find(|link| &*link.original_text == &*broken_link.reference) .map(|link| (link.href.as_str().into(), link.tooltip.as_str().into())) }; @@ -1064,7 +1064,7 @@ impl MarkdownSummaryLine<'_> { let mut replacer = |broken_link: BrokenLink<'_>| { links .iter() - .find(|link| link.original_text.as_str() == &*broken_link.reference) + .find(|link| &*link.original_text == &*broken_link.reference) .map(|link| (link.href.as_str().into(), link.tooltip.as_str().into())) }; @@ -1111,7 +1111,7 @@ fn markdown_summary_with_limit( let mut replacer = |broken_link: BrokenLink<'_>| { link_names .iter() - .find(|link| link.original_text.as_str() == &*broken_link.reference) + .find(|link| &*link.original_text == &*broken_link.reference) .map(|link| (link.href.as_str().into(), link.tooltip.as_str().into())) }; @@ -1192,7 +1192,7 @@ pub(crate) fn plain_text_summary(md: &str, link_names: &[RenderedLink]) -> Strin let mut replacer = |broken_link: BrokenLink<'_>| { link_names .iter() - .find(|link| link.original_text.as_str() == &*broken_link.reference) + .find(|link| &*link.original_text == &*broken_link.reference) .map(|link| (link.href.as_str().into(), link.tooltip.as_str().into())) }; diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index d5e9010eb4e..18c45fd6991 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -38,7 +38,7 @@ impl JsonRenderer<'_> { Some(UrlFragment::UserWritten(_)) | None => *page_id, }; - (link.clone(), id_from_item_default(id.into(), self.tcx)) + (String::from(&**link), id_from_item_default(id.into(), self.tcx)) }) .collect(); let docs = item.attrs.collapsed_doc_value(); diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 920a3b22f25..cbfc581389c 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -228,7 +228,7 @@ struct ResolutionInfo { item_id: ItemId, module_id: DefId, dis: Option<Disambiguator>, - path_str: String, + path_str: Box<str>, extra_fragment: Option<String>, } @@ -849,10 +849,10 @@ impl PreprocessingError { #[derive(Clone)] struct PreprocessingInfo { - path_str: String, + path_str: Box<str>, disambiguator: Option<Disambiguator>, extra_fragment: Option<String>, - link_text: String, + link_text: Box<str>, } // Not a typedef to avoid leaking several private structures from this module. @@ -937,7 +937,7 @@ fn preprocess_link( path_str, disambiguator, extra_fragment: extra_fragment.map(|frag| frag.to_owned()), - link_text: link_text.to_owned(), + link_text: Box::<str>::from(link_text), })) } @@ -993,7 +993,7 @@ impl LinkCollector<'_, '_> { item_id: item.item_id, module_id, dis: disambiguator, - path_str: path_str.to_owned(), + path_str: path_str.clone(), extra_fragment: extra_fragment.clone(), }, diag_info.clone(), // this struct should really be Copy, but Range is not :( @@ -1067,7 +1067,7 @@ impl LinkCollector<'_, '_> { } res.def_id(self.cx.tcx).map(|page_id| ItemLink { - link: ori_link.link.clone(), + link: Box::<str>::from(&*ori_link.link), link_text: link_text.clone(), page_id, fragment, @@ -1091,7 +1091,7 @@ impl LinkCollector<'_, '_> { let page_id = clean::register_res(self.cx, rustc_hir::def::Res::Def(kind, id)); Some(ItemLink { - link: ori_link.link.clone(), + link: Box::<str>::from(&*ori_link.link), link_text: link_text.clone(), page_id, fragment, diff --git a/src/librustdoc/passes/lint/html_tags.rs b/src/librustdoc/passes/lint/html_tags.rs index eac362b37b2..4f72df5a5cd 100644 --- a/src/librustdoc/passes/lint/html_tags.rs +++ b/src/librustdoc/passes/lint/html_tags.rs @@ -113,7 +113,7 @@ pub(crate) fn visit_item(cx: &DocContext<'_>, item: &Item) { if let Some(link) = link_names.iter().find(|link| *link.original_text == *broken_link.reference) { - Some((link.href.as_str().into(), link.new_text.as_str().into())) + Some((link.href.as_str().into(), link.new_text.to_string().into())) } else if matches!( &broken_link.link_type, LinkType::Reference | LinkType::ReferenceUnknown |
