From 12ea83216538545a91ecbb6b0d0b7af3563587fc Mon Sep 17 00:00:00 2001 From: Yotam Ofek Date: Sat, 21 Jun 2025 20:57:00 +0000 Subject: [PATCH 1/5] Simplify `filter_doc_attr` and update stale doc comment --- src/librustdoc/clean/mod.rs | 31 +++++++++++++------------------ 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index d77bdf09d010a..406c1ada5ab18 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2671,31 +2671,26 @@ fn filter_tokens_from_list( fn filter_doc_attr_ident(ident: Symbol, is_inline: bool) -> bool { if is_inline { - ident == sym::hidden || ident == sym::inline || ident == sym::no_inline + matches!(ident, sym::hidden | sym::inline | sym::no_inline) } else { - ident == sym::cfg + matches!(ident, sym::cfg) } } -/// Remove attributes from `normal` that should not be inherited by `use` re-export. -/// Before calling this function, make sure `normal` is a `#[doc]` attribute. +/// Assuming `args` are the arguments to a `doc` attribute (i.e. `#[doc(args...)]`), +/// remove attribute arguments that should not be inherited by `use` re-export. fn filter_doc_attr(args: &mut hir::AttrArgs, is_inline: bool) { + fn ident(tt: &TokenTree) -> Option { + match *tt { + TokenTree::Token(Token { kind: TokenKind::Ident(ident, _), .. }, ..) => Some(ident), + _ => None, + } + } + match args { hir::AttrArgs::Delimited(args) => { - let tokens = filter_tokens_from_list(&args.tokens, |token| { - !matches!( - token, - TokenTree::Token( - Token { - kind: TokenKind::Ident( - ident, - _, - ), - .. - }, - _, - ) if filter_doc_attr_ident(*ident, is_inline), - ) + let tokens = filter_tokens_from_list(&args.tokens, |tt| { + !ident(tt).is_some_and(|ident| filter_doc_attr_ident(ident, is_inline)) }); args.tokens = TokenStream::new(tokens); } From 408dc5084a9604cccaa9193f54d39fe4d2114f37 Mon Sep 17 00:00:00 2001 From: Yotam Ofek Date: Sat, 21 Jun 2025 21:07:44 +0000 Subject: [PATCH 2/5] In `add_without_unwanted_attributes`, return an `Iterator` instead of receving `&mut Vec` to populate Also, don't clone `AttrItem`s if they don't need to be modified --- src/librustdoc/clean/mod.rs | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 406c1ada5ab18..1f193d31cb58e 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -198,7 +198,7 @@ fn generate_item_with_correct_attrs( || (is_glob_import(cx.tcx, import_id) && (cx.render_options.document_hidden || !cx.tcx.is_doc_hidden(def_id))); let mut attrs = get_all_import_attributes(cx, import_id, def_id, is_inline); - add_without_unwanted_attributes(&mut attrs, target_attrs, is_inline, None); + attrs.extend(add_without_unwanted_attributes(target_attrs, is_inline, None)); attrs } else { // We only keep the item's attributes. @@ -2640,7 +2640,7 @@ fn get_all_import_attributes<'hir>( first = false; // We don't add attributes of an intermediate re-export if it has `#[doc(hidden)]`. } else if cx.render_options.document_hidden || !cx.tcx.is_doc_hidden(def_id) { - add_without_unwanted_attributes(&mut attrs, import_attrs, is_inline, Some(def_id)); + attrs.extend(add_without_unwanted_attributes(import_attrs, is_inline, Some(def_id))); } } attrs @@ -2719,34 +2719,32 @@ fn filter_doc_attr(args: &mut hir::AttrArgs, is_inline: bool) { /// * `doc(no_inline)` /// * `doc(hidden)` fn add_without_unwanted_attributes<'hir>( - attrs: &mut Vec<(Cow<'hir, hir::Attribute>, Option)>, new_attrs: &'hir [hir::Attribute], is_inline: bool, import_parent: Option, -) { - for attr in new_attrs { +) -> impl Iterator, Option)> { + new_attrs.iter().filter_map(move |attr| { if attr.is_doc_comment() { - attrs.push((Cow::Borrowed(attr), import_parent)); - continue; + return Some((Cow::Borrowed(attr), import_parent)); } - let mut attr = attr.clone(); match attr { - hir::Attribute::Unparsed(ref mut normal) if let [ident] = &*normal.path.segments => { + hir::Attribute::Unparsed(normal) if let [ident] = &*normal.path.segments => { let ident = ident.name; if ident == sym::doc { + let mut normal = normal.clone(); filter_doc_attr(&mut normal.args, is_inline); - attrs.push((Cow::Owned(attr), import_parent)); + Some((Cow::Owned(hir::Attribute::Unparsed(normal)), import_parent)) } else if is_inline || ident != sym::cfg_trace { // If it's not a `cfg()` attribute, we keep it. - attrs.push((Cow::Owned(attr), import_parent)); + Some((Cow::Borrowed(attr), import_parent)) + } else { + None } } - hir::Attribute::Parsed(..) if is_inline => { - attrs.push((Cow::Owned(attr), import_parent)); - } - _ => {} + hir::Attribute::Parsed(..) if is_inline => Some((Cow::Borrowed(attr), import_parent)), + _ => None, } - } + }) } fn clean_maybe_renamed_item<'tcx>( From c861695e728af3699300b891622a05509e703b3e Mon Sep 17 00:00:00 2001 From: Yotam Ofek Date: Sat, 21 Jun 2025 21:10:03 +0000 Subject: [PATCH 3/5] In `get_all_import_attributes`, use an `Option` instead of `bool` to keep track of firsts --- src/librustdoc/clean/mod.rs | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 1f193d31cb58e..c02583a739703 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2627,23 +2627,33 @@ fn get_all_import_attributes<'hir>( target_def_id: DefId, is_inline: bool, ) -> Vec<(Cow<'hir, hir::Attribute>, Option)> { - let mut attrs = Vec::new(); - let mut first = true; + let mut attrs = None; for def_id in reexport_chain(cx.tcx, import_def_id, target_def_id) .iter() - .flat_map(|reexport| reexport.id()) + .filter_map(|reexport| reexport.id()) { let import_attrs = inline::load_attrs(cx, def_id); - if first { - // This is the "original" reexport so we get all its attributes without filtering them. - attrs = import_attrs.iter().map(|attr| (Cow::Borrowed(attr), Some(def_id))).collect(); - first = false; - // We don't add attributes of an intermediate re-export if it has `#[doc(hidden)]`. - } else if cx.render_options.document_hidden || !cx.tcx.is_doc_hidden(def_id) { - attrs.extend(add_without_unwanted_attributes(import_attrs, is_inline, Some(def_id))); + match &mut attrs { + None => { + // This is the "original" reexport so we get all its attributes without filtering them. + attrs = Some( + import_attrs + .iter() + .map(|attr| (Cow::Borrowed(attr), Some(def_id))) + .collect::>(), + ); + } + Some(attrs) if cx.render_options.document_hidden || !cx.tcx.is_doc_hidden(def_id) => { + attrs.extend(add_without_unwanted_attributes( + import_attrs, + is_inline, + Some(def_id), + )); + } + Some(_) => {} } } - attrs + attrs.unwrap_or_default() } fn filter_tokens_from_list( From 78443c56b3019a7806e1b99819e9b15399d2ef78 Mon Sep 17 00:00:00 2001 From: Yotam Ofek Date: Sat, 21 Jun 2025 21:10:32 +0000 Subject: [PATCH 4/5] Receive immutable referenes where mutable ones aren't needed --- src/librustdoc/clean/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index c02583a739703..19e0801faaf60 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -178,7 +178,7 @@ fn is_glob_import(tcx: TyCtxt<'_>, import_id: LocalDefId) -> bool { } fn generate_item_with_correct_attrs( - cx: &mut DocContext<'_>, + cx: &DocContext<'_>, kind: ItemKind, def_id: DefId, name: Symbol, @@ -2622,7 +2622,7 @@ pub(crate) fn reexport_chain( /// Collect attributes from the whole import chain. fn get_all_import_attributes<'hir>( - cx: &mut DocContext<'hir>, + cx: &DocContext<'hir>, import_def_id: LocalDefId, target_def_id: DefId, is_inline: bool, From eb8e7d41bf4fe6945106e9f262f9e00846db2cd4 Mon Sep 17 00:00:00 2001 From: Yotam Ofek Date: Sat, 21 Jun 2025 21:10:47 +0000 Subject: [PATCH 5/5] Missing closing-quote in comment --- compiler/rustc_span/src/symbol.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 812a254990caf..a70f66e926688 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -2384,7 +2384,7 @@ pub const STDLIB_STABLE_CRATES: &[Symbol] = &[sym::std, sym::core, sym::alloc, s #[derive(Copy, Clone, Eq, HashStable_Generic, Encodable, Decodable)] pub struct Ident { // `name` should never be the empty symbol. If you are considering that, - // you are probably conflating "empty identifer with "no identifier" and + // you are probably conflating "empty identifer" with "no identifier" and // you should use `Option` instead. pub name: Symbol, pub span: Span,