Skip to content

Commit 5cce8cb

Browse files
committed
rustdoc: Sligthly optimize Attributes construction and processing before doc link resolution
1 parent de287df commit 5cce8cb

File tree

3 files changed

+31
-44
lines changed

3 files changed

+31
-44
lines changed

src/librustdoc/clean/types.rs

+28-41
Original file line numberDiff line numberDiff line change
@@ -1089,42 +1089,35 @@ impl Attributes {
10891089
attrs: &[ast::Attribute],
10901090
additional_attrs: Option<(&[ast::Attribute], DefId)>,
10911091
) -> Attributes {
1092-
Attributes::from_ast_iter(attrs.iter(), additional_attrs)
1092+
// Additional documentation should be shown before the original documentation.
1093+
let attrs1 = additional_attrs
1094+
.into_iter()
1095+
.flat_map(|(attrs, def_id)| attrs.iter().map(move |attr| (attr, Some(def_id))));
1096+
let attrs2 = attrs.iter().map(|attr| (attr, None));
1097+
Attributes::from_ast_iter(attrs1.chain(attrs2), false)
10931098
}
10941099

10951100
crate fn from_ast_iter<'a>(
1096-
attrs: impl Iterator<Item = &'a ast::Attribute>,
1097-
additional_attrs: Option<(&[ast::Attribute], DefId)>,
1101+
attrs: impl Iterator<Item = (&'a ast::Attribute, Option<DefId>)>,
1102+
doc_only: bool,
10981103
) -> Attributes {
1099-
let mut doc_strings: Vec<DocFragment> = vec![];
1100-
let clean_attr = |(attr, parent_module): (&ast::Attribute, Option<DefId>)| {
1101-
if let Some((value, kind)) = attr.doc_str_and_comment_kind() {
1102-
trace!("got doc_str={:?}", value);
1103-
let value = beautify_doc_string(value, kind);
1104+
let mut doc_strings = Vec::new();
1105+
let mut other_attrs = Vec::new();
1106+
for (attr, parent_module) in attrs {
1107+
if let Some((doc_str, comment_kind)) = attr.doc_str_and_comment_kind() {
1108+
trace!("got doc_str={doc_str:?}");
1109+
let doc = beautify_doc_string(doc_str, comment_kind);
11041110
let kind = if attr.is_doc_comment() {
11051111
DocFragmentKind::SugaredDoc
11061112
} else {
11071113
DocFragmentKind::RawDoc
11081114
};
1109-
1110-
let frag =
1111-
DocFragment { span: attr.span, doc: value, kind, parent_module, indent: 0 };
1112-
1113-
doc_strings.push(frag);
1114-
1115-
None
1116-
} else {
1117-
Some(attr.clone())
1115+
let fragment = DocFragment { span: attr.span, doc, kind, parent_module, indent: 0 };
1116+
doc_strings.push(fragment);
1117+
} else if !doc_only {
1118+
other_attrs.push(attr.clone());
11181119
}
1119-
};
1120-
1121-
// Additional documentation should be shown before the original documentation
1122-
let other_attrs = additional_attrs
1123-
.into_iter()
1124-
.flat_map(|(attrs, id)| attrs.iter().map(move |attr| (attr, Some(id))))
1125-
.chain(attrs.map(|attr| (attr, None)))
1126-
.filter_map(clean_attr)
1127-
.collect();
1120+
}
11281121

11291122
Attributes { doc_strings, other_attrs }
11301123
}
@@ -1145,23 +1138,17 @@ impl Attributes {
11451138
}
11461139

11471140
/// Return the doc-comments on this item, grouped by the module they came from.
1148-
///
11491141
/// The module can be different if this is a re-export with added documentation.
1150-
crate fn collapsed_doc_value_by_module_level(&self) -> FxHashMap<Option<DefId>, String> {
1151-
let mut ret = FxHashMap::default();
1152-
if self.doc_strings.len() == 0 {
1153-
return ret;
1154-
}
1155-
let last_index = self.doc_strings.len() - 1;
1156-
1157-
for (i, new_frag) in self.doc_strings.iter().enumerate() {
1158-
let out = ret.entry(new_frag.parent_module).or_default();
1159-
add_doc_fragment(out, new_frag);
1160-
if i == last_index {
1161-
out.pop();
1162-
}
1142+
///
1143+
/// The last newline is not trimmed so the produced strings are reusable between
1144+
/// early and late doc link resolution regardless of their position.
1145+
crate fn prepare_to_doc_link_resolution(&self) -> FxHashMap<Option<DefId>, String> {
1146+
let mut res = FxHashMap::default();
1147+
for fragment in &self.doc_strings {
1148+
let out_str = res.entry(fragment.parent_module).or_default();
1149+
add_doc_fragment(out_str, fragment);
11631150
}
1164-
ret
1151+
res
11651152
}
11661153

11671154
/// Finds all `doc` attributes as NameValues and returns their corresponding values, joined

src/librustdoc/passes/collect_intra_doc_links.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1050,7 +1050,7 @@ impl<'a, 'tcx> DocVisitor for LinkCollector<'a, 'tcx> {
10501050
// In the presence of re-exports, this is not the same as the module of the item.
10511051
// Rather than merging all documentation into one, resolve it one attribute at a time
10521052
// so we know which module it came from.
1053-
for (parent_module, doc) in item.attrs.collapsed_doc_value_by_module_level() {
1053+
for (parent_module, doc) in item.attrs.prepare_to_doc_link_resolution() {
10541054
if !may_have_doc_links(&doc) {
10551055
continue;
10561056
}

src/librustdoc/passes/collect_intra_doc_links/early.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ crate fn early_resolve_intra_doc_links(
6363
}
6464

6565
fn doc_attrs<'a>(attrs: impl Iterator<Item = &'a ast::Attribute>) -> Attributes {
66-
let mut attrs = Attributes::from_ast_iter(attrs.filter(|attr| attr.doc_str().is_some()), None);
66+
let mut attrs = Attributes::from_ast_iter(attrs.map(|attr| (attr, None)), true);
6767
attrs.unindent_doc_comments();
6868
attrs
6969
}
@@ -201,7 +201,7 @@ impl EarlyDocLinkResolver<'_, '_> {
201201

202202
fn resolve_doc_links(&mut self, attrs: Attributes, module_id: DefId) {
203203
let mut need_traits_in_scope = false;
204-
for (doc_module, doc) in attrs.collapsed_doc_value_by_module_level() {
204+
for (doc_module, doc) in attrs.prepare_to_doc_link_resolution() {
205205
assert_eq!(doc_module, None);
206206
let links = self
207207
.markdown_links

0 commit comments

Comments
 (0)