From de61a789af309f60bd55f989ed6593c8db3f4fa3 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 23 Mar 2023 17:31:26 +0100 Subject: [PATCH] Use Cow to reduce numbers of memory clone --- src/librustdoc/clean/mod.rs | 54 +++++++++++++++++++---------------- src/librustdoc/clean/types.rs | 14 ++++++--- 2 files changed, 39 insertions(+), 29 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index b419c81301c..dd4e652de06 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -32,6 +32,7 @@ use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{self, ExpnKind}; use std::assert_matches::assert_matches; +use std::borrow::Cow; use std::collections::hash_map::Entry; use std::collections::BTreeMap; use std::default::Default; @@ -2171,26 +2172,25 @@ fn get_all_import_attributes<'hir>( target_def_id: LocalDefId, is_inline: bool, mut prev_import: LocalDefId, -) -> Vec<(ast::Attribute, Option)> { - let mut attributes: Vec<(ast::Attribute, Option)> = Vec::new(); +) -> Vec<(Cow<'hir, ast::Attribute>, Option)> { + let mut attributes: Vec<(Cow<'hir, ast::Attribute>, Option)> = Vec::new(); let mut first = true; let hir_map = cx.tcx.hir(); let mut visitor = OneLevelVisitor::new(hir_map, target_def_id); let mut visited = FxHashSet::default(); - let mut import_attrs = Vec::new(); // If the item is an import and has at least a path with two parts, we go into it. while let hir::ItemKind::Use(path, _) = item.kind && visited.insert(item.hir_id()) { let import_parent = cx.tcx.opt_local_parent(prev_import).map(|def_id| def_id.to_def_id()); if first { // This is the "original" reexport so we get all its attributes without filtering them. - attributes = hir_map.attrs(item.hir_id()).iter().cloned().map(|attr| (attr, import_parent)).collect::>(); + attributes = hir_map.attrs(item.hir_id()) + .iter() + .map(|attr| (Cow::Borrowed(attr), import_parent)) + .collect::>(); first = false; } else { - add_without_unwanted_attributes(&mut import_attrs, hir_map.attrs(item.hir_id()), is_inline); - for attr in import_attrs.drain(..) { - attributes.push((attr, import_parent)); - } + add_without_unwanted_attributes(&mut attributes, hir_map.attrs(item.hir_id()), is_inline, import_parent); } if let Some(i) = visitor.find_target(cx.tcx, item.owner_id.def_id.to_def_id(), path) { @@ -2246,17 +2246,24 @@ fn filter_tokens_from_list( /// * `doc(inline)` /// * `doc(no_inline)` /// * `doc(hidden)` -fn add_without_unwanted_attributes( - attrs: &mut Vec, - new_attrs: &[ast::Attribute], +fn add_without_unwanted_attributes<'hir>( + attrs: &mut Vec<(Cow<'hir, ast::Attribute>, Option)>, + new_attrs: &'hir [ast::Attribute], is_inline: bool, + import_parent: Option, ) { // If it's not `#[doc(inline)]`, we don't want all attributes, otherwise we keep everything. if !is_inline { - attrs.extend_from_slice(new_attrs); + for attr in new_attrs { + attrs.push((Cow::Borrowed(attr), import_parent)); + } return; } for attr in new_attrs { + if matches!(attr.kind, ast::AttrKind::DocComment(..)) { + attrs.push((Cow::Borrowed(attr), import_parent)); + continue; + } let mut attr = attr.clone(); match attr.kind { ast::AttrKind::Normal(ref mut normal) => { @@ -2283,18 +2290,15 @@ fn add_without_unwanted_attributes( ) }); args.tokens = TokenStream::new(tokens); - attrs.push(attr); + attrs.push((Cow::Owned(attr), import_parent)); } ast::AttrArgs::Empty | ast::AttrArgs::Eq(..) => { - attrs.push(attr); - continue; + attrs.push((Cow::Owned(attr), import_parent)); } } } } - ast::AttrKind::DocComment(..) => { - attrs.push(attr); - } + _ => unreachable!(), } } } @@ -2397,23 +2401,23 @@ fn clean_maybe_renamed_item<'tcx>( import_id, ); - let mut target_attrs = Vec::new(); add_without_unwanted_attributes( - &mut target_attrs, + &mut attrs, inline::load_attrs(cx, def_id), is_inline, + None ); - for attr in target_attrs.into_iter() { - attrs.push((attr, None)); - } attrs } else { // We only keep the item's attributes. - inline::load_attrs(cx, def_id).iter().cloned().map(|attr| (attr, None)).collect::>() + inline::load_attrs(cx, def_id).iter().map(|attr| (Cow::Borrowed(attr), None)).collect::>() }; let cfg = attrs.cfg(cx.tcx, &cx.cache.hidden_cfg); - let attrs = Attributes::from_ast_iter(attrs.iter().map(|(attr, did)| (attr, *did)), false); + let attrs = Attributes::from_ast_iter(attrs.iter().map(|(attr, did)| match attr { + Cow::Borrowed(attr) => (*attr, *did), + Cow::Owned(attr) => (attr, *did) + }), false); let mut item = Item::from_def_id_and_attrs_and_parts(def_id, Some(name), kind, Box::new(attrs), cfg); diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 74831811aa2..3e7e311cfc5 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -1,3 +1,4 @@ +use std::borrow::Cow; use std::cell::RefCell; use std::default::Default; use std::hash::Hash; @@ -985,9 +986,11 @@ impl AttributesExt for [ast::Attribute] { } } -impl AttributesExt for [(ast::Attribute, Option)] { - type AttributeIterator<'a> = impl Iterator + 'a; - type Attributes<'a> = impl Iterator + 'a; +impl AttributesExt for [(Cow<'_, ast::Attribute>, Option)] { + type AttributeIterator<'a> = impl Iterator + 'a + where Self: 'a; + type Attributes<'a> = impl Iterator + 'a + where Self: 'a; fn lists<'a>(&'a self, name: Symbol) -> Self::AttributeIterator<'a> { AttributesExt::iter(self) @@ -997,7 +1000,10 @@ impl AttributesExt for [(ast::Attribute, Option)] { } fn iter<'a>(&'a self) -> Self::Attributes<'a> { - self.into_iter().map(|(attr, _)| attr) + self.into_iter().map(move |(attr, _)| match attr { + Cow::Borrowed(attr) => *attr, + Cow::Owned(attr) => attr, + }) } }