From 5cce8cb4ec4159851d8f5089eefc9979d480f0ec Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 17 Apr 2022 02:01:46 +0300 Subject: [PATCH] rustdoc: Sligthly optimize `Attributes` construction and processing before doc link resolution --- src/librustdoc/clean/types.rs | 69 ++++++++----------- .../passes/collect_intra_doc_links.rs | 2 +- .../passes/collect_intra_doc_links/early.rs | 4 +- 3 files changed, 31 insertions(+), 44 deletions(-) diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index bc9f64e1afc..95ac3ab622a 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -1089,42 +1089,35 @@ impl Attributes { attrs: &[ast::Attribute], additional_attrs: Option<(&[ast::Attribute], DefId)>, ) -> Attributes { - Attributes::from_ast_iter(attrs.iter(), additional_attrs) + // Additional documentation should be shown before the original documentation. + let attrs1 = additional_attrs + .into_iter() + .flat_map(|(attrs, def_id)| attrs.iter().map(move |attr| (attr, Some(def_id)))); + let attrs2 = attrs.iter().map(|attr| (attr, None)); + Attributes::from_ast_iter(attrs1.chain(attrs2), false) } crate fn from_ast_iter<'a>( - attrs: impl Iterator, - additional_attrs: Option<(&[ast::Attribute], DefId)>, + attrs: impl Iterator)>, + doc_only: bool, ) -> Attributes { - let mut doc_strings: Vec = vec![]; - let clean_attr = |(attr, parent_module): (&ast::Attribute, Option)| { - if let Some((value, kind)) = attr.doc_str_and_comment_kind() { - trace!("got doc_str={:?}", value); - let value = beautify_doc_string(value, kind); + let mut doc_strings = Vec::new(); + let mut other_attrs = Vec::new(); + for (attr, parent_module) in attrs { + if let Some((doc_str, comment_kind)) = attr.doc_str_and_comment_kind() { + trace!("got doc_str={doc_str:?}"); + let doc = beautify_doc_string(doc_str, comment_kind); let kind = if attr.is_doc_comment() { DocFragmentKind::SugaredDoc } else { DocFragmentKind::RawDoc }; - - let frag = - DocFragment { span: attr.span, doc: value, kind, parent_module, indent: 0 }; - - doc_strings.push(frag); - - None - } else { - Some(attr.clone()) + let fragment = DocFragment { span: attr.span, doc, kind, parent_module, indent: 0 }; + doc_strings.push(fragment); + } else if !doc_only { + other_attrs.push(attr.clone()); } - }; - - // Additional documentation should be shown before the original documentation - let other_attrs = additional_attrs - .into_iter() - .flat_map(|(attrs, id)| attrs.iter().map(move |attr| (attr, Some(id)))) - .chain(attrs.map(|attr| (attr, None))) - .filter_map(clean_attr) - .collect(); + } Attributes { doc_strings, other_attrs } } @@ -1145,23 +1138,17 @@ impl Attributes { } /// Return the doc-comments on this item, grouped by the module they came from. - /// /// The module can be different if this is a re-export with added documentation. - crate fn collapsed_doc_value_by_module_level(&self) -> FxHashMap, String> { - let mut ret = FxHashMap::default(); - if self.doc_strings.len() == 0 { - return ret; + /// + /// The last newline is not trimmed so the produced strings are reusable between + /// early and late doc link resolution regardless of their position. + crate fn prepare_to_doc_link_resolution(&self) -> FxHashMap, String> { + let mut res = FxHashMap::default(); + for fragment in &self.doc_strings { + let out_str = res.entry(fragment.parent_module).or_default(); + add_doc_fragment(out_str, fragment); } - let last_index = self.doc_strings.len() - 1; - - for (i, new_frag) in self.doc_strings.iter().enumerate() { - let out = ret.entry(new_frag.parent_module).or_default(); - add_doc_fragment(out, new_frag); - if i == last_index { - out.pop(); - } - } - ret + res } /// Finds all `doc` attributes as NameValues and returns their corresponding values, joined diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index c9fc14d5f71..42e87f3f961 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -1050,7 +1050,7 @@ impl<'a, 'tcx> DocVisitor for LinkCollector<'a, 'tcx> { // In the presence of re-exports, this is not the same as the module of the item. // Rather than merging all documentation into one, resolve it one attribute at a time // so we know which module it came from. - for (parent_module, doc) in item.attrs.collapsed_doc_value_by_module_level() { + for (parent_module, doc) in item.attrs.prepare_to_doc_link_resolution() { if !may_have_doc_links(&doc) { continue; } diff --git a/src/librustdoc/passes/collect_intra_doc_links/early.rs b/src/librustdoc/passes/collect_intra_doc_links/early.rs index a285c300b75..e2359da870e 100644 --- a/src/librustdoc/passes/collect_intra_doc_links/early.rs +++ b/src/librustdoc/passes/collect_intra_doc_links/early.rs @@ -63,7 +63,7 @@ crate fn early_resolve_intra_doc_links( } fn doc_attrs<'a>(attrs: impl Iterator) -> Attributes { - let mut attrs = Attributes::from_ast_iter(attrs.filter(|attr| attr.doc_str().is_some()), None); + let mut attrs = Attributes::from_ast_iter(attrs.map(|attr| (attr, None)), true); attrs.unindent_doc_comments(); attrs } @@ -201,7 +201,7 @@ impl EarlyDocLinkResolver<'_, '_> { fn resolve_doc_links(&mut self, attrs: Attributes, module_id: DefId) { let mut need_traits_in_scope = false; - for (doc_module, doc) in attrs.collapsed_doc_value_by_module_level() { + for (doc_module, doc) in attrs.prepare_to_doc_link_resolution() { assert_eq!(doc_module, None); let links = self .markdown_links