Skip to content

Commit b1d047b

Browse files
Rollup merge of #135428 - camelid:attr-cleanup, r=GuillaumeGomez
rustdoc: Remove `AttributesExt` trait magic that added needless complexity The new code is more explicit and avoids trait magic that added needless complexity to this part of rustdoc.
2 parents 369d135 + f92b32c commit b1d047b

File tree

5 files changed

+119
-148
lines changed

5 files changed

+119
-148
lines changed

src/librustdoc/clean/inline.rs

+10-7
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,12 @@ use rustc_span::symbol::{Symbol, sym};
1717
use thin_vec::{ThinVec, thin_vec};
1818
use tracing::{debug, trace};
1919

20-
use super::Item;
20+
use super::{Item, extract_cfg_from_attrs};
2121
use crate::clean::{
22-
self, Attributes, AttributesExt, ImplKind, ItemId, Type, clean_bound_vars, clean_generics,
23-
clean_impl_item, clean_middle_assoc_item, clean_middle_field, clean_middle_ty,
24-
clean_poly_fn_sig, clean_trait_ref_with_constraints, clean_ty, clean_ty_alias_inner_type,
25-
clean_ty_generics, clean_variant_def, utils,
22+
self, Attributes, ImplKind, ItemId, Type, clean_bound_vars, clean_generics, clean_impl_item,
23+
clean_middle_assoc_item, clean_middle_field, clean_middle_ty, clean_poly_fn_sig,
24+
clean_trait_ref_with_constraints, clean_ty, clean_ty_alias_inner_type, clean_ty_generics,
25+
clean_variant_def, utils,
2626
};
2727
use crate::core::DocContext;
2828
use crate::formats::item_type::ItemType;
@@ -408,10 +408,13 @@ pub(crate) fn merge_attrs(
408408
} else {
409409
Attributes::from_hir(&both)
410410
},
411-
both.cfg(cx.tcx, &cx.cache.hidden_cfg),
411+
extract_cfg_from_attrs(both.iter(), cx.tcx, &cx.cache.hidden_cfg),
412412
)
413413
} else {
414-
(Attributes::from_hir(old_attrs), old_attrs.cfg(cx.tcx, &cx.cache.hidden_cfg))
414+
(
415+
Attributes::from_hir(old_attrs),
416+
extract_cfg_from_attrs(old_attrs.iter(), cx.tcx, &cx.cache.hidden_cfg),
417+
)
415418
}
416419
}
417420

src/librustdoc/clean/mod.rs

+13-7
Original file line numberDiff line numberDiff line change
@@ -186,8 +186,7 @@ fn generate_item_with_correct_attrs(
186186
// For glob re-exports the item may or may not exist to be re-exported (potentially the cfgs
187187
// on the path up until the glob can be removed, and only cfgs on the globbed item itself
188188
// matter), for non-inlined re-exports see #85043.
189-
let is_inline = inline::load_attrs(cx, import_id.to_def_id())
190-
.lists(sym::doc)
189+
let is_inline = hir_attr_lists(inline::load_attrs(cx, import_id.to_def_id()), sym::doc)
191190
.get_word_attr(sym::inline)
192191
.is_some()
193192
|| (is_glob_import(cx.tcx, import_id)
@@ -199,8 +198,14 @@ fn generate_item_with_correct_attrs(
199198
// We only keep the item's attributes.
200199
target_attrs.iter().map(|attr| (Cow::Borrowed(attr), None)).collect()
201200
};
202-
203-
let cfg = attrs.cfg(cx.tcx, &cx.cache.hidden_cfg);
201+
let cfg = extract_cfg_from_attrs(
202+
attrs.iter().map(move |(attr, _)| match attr {
203+
Cow::Borrowed(attr) => *attr,
204+
Cow::Owned(attr) => attr,
205+
}),
206+
cx.tcx,
207+
&cx.cache.hidden_cfg,
208+
);
204209
let attrs = Attributes::from_hir_iter(attrs.iter().map(|(attr, did)| (&**attr, *did)), false);
205210

206211
let name = renamed.or(Some(name));
@@ -979,13 +984,14 @@ fn clean_proc_macro<'tcx>(
979984
) -> ItemKind {
980985
let attrs = cx.tcx.hir().attrs(item.hir_id());
981986
if kind == MacroKind::Derive
982-
&& let Some(derive_name) = attrs.lists(sym::proc_macro_derive).find_map(|mi| mi.ident())
987+
&& let Some(derive_name) =
988+
hir_attr_lists(attrs, sym::proc_macro_derive).find_map(|mi| mi.ident())
983989
{
984990
*name = derive_name.name;
985991
}
986992

987993
let mut helpers = Vec::new();
988-
for mi in attrs.lists(sym::proc_macro_derive) {
994+
for mi in hir_attr_lists(attrs, sym::proc_macro_derive) {
989995
if !mi.has_name(sym::attributes) {
990996
continue;
991997
}
@@ -2985,7 +2991,7 @@ fn clean_use_statement_inner<'tcx>(
29852991

29862992
let visibility = cx.tcx.visibility(import.owner_id);
29872993
let attrs = cx.tcx.hir().attrs(import.hir_id());
2988-
let inline_attr = attrs.lists(sym::doc).get_word_attr(sym::inline);
2994+
let inline_attr = hir_attr_lists(attrs, sym::doc).get_word_attr(sym::inline);
29892995
let pub_underscore = visibility.is_public() && name == kw::Underscore;
29902996
let current_mod = cx.tcx.parent_module_from_def_id(import.owner_id.def_id);
29912997
let import_def_id = import.owner_id.def_id;

src/librustdoc/clean/types.rs

+89-128
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
use std::borrow::Cow;
21
use std::hash::Hash;
32
use std::path::PathBuf;
43
use std::sync::{Arc, OnceLock as OnceCell};
@@ -485,7 +484,7 @@ impl Item {
485484
name,
486485
kind,
487486
Attributes::from_hir(hir_attrs),
488-
hir_attrs.cfg(cx.tcx, &cx.cache.hidden_cfg),
487+
extract_cfg_from_attrs(hir_attrs.iter(), cx.tcx, &cx.cache.hidden_cfg),
489488
)
490489
}
491490

@@ -996,147 +995,107 @@ pub(crate) struct Module {
996995
pub(crate) span: Span,
997996
}
998997

999-
pub(crate) trait AttributesExt {
1000-
type AttributeIterator<'a>: Iterator<Item = ast::MetaItemInner>
1001-
where
1002-
Self: 'a;
1003-
type Attributes<'a>: Iterator<Item = &'a hir::Attribute>
1004-
where
1005-
Self: 'a;
1006-
1007-
fn lists(&self, name: Symbol) -> Self::AttributeIterator<'_>;
1008-
1009-
fn iter(&self) -> Self::Attributes<'_>;
1010-
1011-
fn cfg(&self, tcx: TyCtxt<'_>, hidden_cfg: &FxHashSet<Cfg>) -> Option<Arc<Cfg>> {
1012-
let sess = tcx.sess;
1013-
let doc_cfg_active = tcx.features().doc_cfg();
1014-
let doc_auto_cfg_active = tcx.features().doc_auto_cfg();
1015-
1016-
fn single<T: IntoIterator>(it: T) -> Option<T::Item> {
1017-
let mut iter = it.into_iter();
1018-
let item = iter.next()?;
1019-
if iter.next().is_some() {
1020-
return None;
1021-
}
1022-
Some(item)
998+
pub(crate) fn hir_attr_lists<'a, I: IntoIterator<Item = &'a hir::Attribute>>(
999+
attrs: I,
1000+
name: Symbol,
1001+
) -> impl Iterator<Item = ast::MetaItemInner> + use<'a, I> {
1002+
attrs
1003+
.into_iter()
1004+
.filter(move |attr| attr.has_name(name))
1005+
.filter_map(ast::attr::AttributeExt::meta_item_list)
1006+
.flatten()
1007+
}
1008+
1009+
pub(crate) fn extract_cfg_from_attrs<'a, I: Iterator<Item = &'a hir::Attribute> + Clone>(
1010+
attrs: I,
1011+
tcx: TyCtxt<'_>,
1012+
hidden_cfg: &FxHashSet<Cfg>,
1013+
) -> Option<Arc<Cfg>> {
1014+
let sess = tcx.sess;
1015+
let doc_cfg_active = tcx.features().doc_cfg();
1016+
let doc_auto_cfg_active = tcx.features().doc_auto_cfg();
1017+
1018+
fn single<T: IntoIterator>(it: T) -> Option<T::Item> {
1019+
let mut iter = it.into_iter();
1020+
let item = iter.next()?;
1021+
if iter.next().is_some() {
1022+
return None;
10231023
}
1024+
Some(item)
1025+
}
10241026

1025-
let mut cfg = if doc_cfg_active || doc_auto_cfg_active {
1026-
let mut doc_cfg = self
1027-
.iter()
1028-
.filter(|attr| attr.has_name(sym::doc))
1029-
.flat_map(|attr| attr.meta_item_list().unwrap_or_default())
1027+
let mut cfg = if doc_cfg_active || doc_auto_cfg_active {
1028+
let mut doc_cfg = attrs
1029+
.clone()
1030+
.filter(|attr| attr.has_name(sym::doc))
1031+
.flat_map(|attr| attr.meta_item_list().unwrap_or_default())
1032+
.filter(|attr| attr.has_name(sym::cfg))
1033+
.peekable();
1034+
if doc_cfg.peek().is_some() && doc_cfg_active {
1035+
doc_cfg
1036+
.filter_map(|attr| Cfg::parse(&attr).ok())
1037+
.fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg)
1038+
} else if doc_auto_cfg_active {
1039+
// If there is no `doc(cfg())`, then we retrieve the `cfg()` attributes (because
1040+
// `doc(cfg())` overrides `cfg()`).
1041+
attrs
1042+
.clone()
10301043
.filter(|attr| attr.has_name(sym::cfg))
1031-
.peekable();
1032-
if doc_cfg.peek().is_some() && doc_cfg_active {
1033-
doc_cfg
1034-
.filter_map(|attr| Cfg::parse(&attr).ok())
1035-
.fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg)
1036-
} else if doc_auto_cfg_active {
1037-
// If there is no `doc(cfg())`, then we retrieve the `cfg()` attributes (because
1038-
// `doc(cfg())` overrides `cfg()`).
1039-
self.iter()
1040-
.filter(|attr| attr.has_name(sym::cfg))
1041-
.filter_map(|attr| single(attr.meta_item_list()?))
1042-
.filter_map(|attr| {
1043-
Cfg::parse_without(attr.meta_item()?, hidden_cfg).ok().flatten()
1044-
})
1045-
.fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg)
1046-
} else {
1047-
Cfg::True
1048-
}
1044+
.filter_map(|attr| single(attr.meta_item_list()?))
1045+
.filter_map(|attr| Cfg::parse_without(attr.meta_item()?, hidden_cfg).ok().flatten())
1046+
.fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg)
10491047
} else {
10501048
Cfg::True
1051-
};
1052-
1053-
for attr in self.iter() {
1054-
// #[doc]
1055-
if attr.doc_str().is_none() && attr.has_name(sym::doc) {
1056-
// #[doc(...)]
1057-
if let Some(list) = attr.meta_item_list() {
1058-
for item in list {
1059-
// #[doc(hidden)]
1060-
if !item.has_name(sym::cfg) {
1061-
continue;
1062-
}
1063-
// #[doc(cfg(...))]
1064-
if let Some(cfg_mi) = item
1065-
.meta_item()
1066-
.and_then(|item| rustc_expand::config::parse_cfg(item, sess))
1067-
{
1068-
match Cfg::parse(cfg_mi) {
1069-
Ok(new_cfg) => cfg &= new_cfg,
1070-
Err(e) => {
1071-
sess.dcx().span_err(e.span, e.msg);
1072-
}
1049+
}
1050+
} else {
1051+
Cfg::True
1052+
};
1053+
1054+
for attr in attrs.clone() {
1055+
// #[doc]
1056+
if attr.doc_str().is_none() && attr.has_name(sym::doc) {
1057+
// #[doc(...)]
1058+
if let Some(list) = attr.meta_item_list() {
1059+
for item in list {
1060+
// #[doc(hidden)]
1061+
if !item.has_name(sym::cfg) {
1062+
continue;
1063+
}
1064+
// #[doc(cfg(...))]
1065+
if let Some(cfg_mi) = item
1066+
.meta_item()
1067+
.and_then(|item| rustc_expand::config::parse_cfg(item, sess))
1068+
{
1069+
match Cfg::parse(cfg_mi) {
1070+
Ok(new_cfg) => cfg &= new_cfg,
1071+
Err(e) => {
1072+
sess.dcx().span_err(e.span, e.msg);
10731073
}
10741074
}
10751075
}
10761076
}
10771077
}
10781078
}
1079+
}
10791080

1080-
// treat #[target_feature(enable = "feat")] attributes as if they were
1081-
// #[doc(cfg(target_feature = "feat"))] attributes as well
1082-
for attr in self.lists(sym::target_feature) {
1083-
if attr.has_name(sym::enable) {
1084-
if attr.value_str().is_some() {
1085-
// Clone `enable = "feat"`, change to `target_feature = "feat"`.
1086-
// Unwrap is safe because `value_str` succeeded above.
1087-
let mut meta = attr.meta_item().unwrap().clone();
1088-
meta.path = ast::Path::from_ident(Ident::with_dummy_span(sym::target_feature));
1089-
1090-
if let Ok(feat_cfg) = Cfg::parse(&ast::MetaItemInner::MetaItem(meta)) {
1091-
cfg &= feat_cfg;
1092-
}
1081+
// treat #[target_feature(enable = "feat")] attributes as if they were
1082+
// #[doc(cfg(target_feature = "feat"))] attributes as well
1083+
for attr in hir_attr_lists(attrs, sym::target_feature) {
1084+
if attr.has_name(sym::enable) {
1085+
if attr.value_str().is_some() {
1086+
// Clone `enable = "feat"`, change to `target_feature = "feat"`.
1087+
// Unwrap is safe because `value_str` succeeded above.
1088+
let mut meta = attr.meta_item().unwrap().clone();
1089+
meta.path = ast::Path::from_ident(Ident::with_dummy_span(sym::target_feature));
1090+
1091+
if let Ok(feat_cfg) = Cfg::parse(&ast::MetaItemInner::MetaItem(meta)) {
1092+
cfg &= feat_cfg;
10931093
}
10941094
}
10951095
}
1096-
1097-
if cfg == Cfg::True { None } else { Some(Arc::new(cfg)) }
10981096
}
1099-
}
1100-
1101-
impl AttributesExt for [hir::Attribute] {
1102-
type AttributeIterator<'a> = impl Iterator<Item = ast::MetaItemInner> + 'a;
1103-
type Attributes<'a> = impl Iterator<Item = &'a hir::Attribute> + 'a;
11041097

1105-
fn lists(&self, name: Symbol) -> Self::AttributeIterator<'_> {
1106-
self.iter()
1107-
.filter(move |attr| attr.has_name(name))
1108-
.filter_map(ast::attr::AttributeExt::meta_item_list)
1109-
.flatten()
1110-
}
1111-
1112-
fn iter(&self) -> Self::Attributes<'_> {
1113-
self.iter()
1114-
}
1115-
}
1116-
1117-
impl AttributesExt for [(Cow<'_, hir::Attribute>, Option<DefId>)] {
1118-
type AttributeIterator<'a>
1119-
= impl Iterator<Item = ast::MetaItemInner> + 'a
1120-
where
1121-
Self: 'a;
1122-
type Attributes<'a>
1123-
= impl Iterator<Item = &'a hir::Attribute> + 'a
1124-
where
1125-
Self: 'a;
1126-
1127-
fn lists(&self, name: Symbol) -> Self::AttributeIterator<'_> {
1128-
AttributesExt::iter(self)
1129-
.filter(move |attr| attr.has_name(name))
1130-
.filter_map(hir::Attribute::meta_item_list)
1131-
.flatten()
1132-
}
1133-
1134-
fn iter(&self) -> Self::Attributes<'_> {
1135-
self.iter().map(move |(attr, _)| match attr {
1136-
Cow::Borrowed(attr) => *attr,
1137-
Cow::Owned(attr) => attr,
1138-
})
1139-
}
1098+
if cfg == Cfg::True { None } else { Some(Arc::new(cfg)) }
11401099
}
11411100

11421101
pub(crate) trait NestedAttributesExt {
@@ -1202,7 +1161,7 @@ pub(crate) struct Attributes {
12021161

12031162
impl Attributes {
12041163
pub(crate) fn lists(&self, name: Symbol) -> impl Iterator<Item = ast::MetaItemInner> + '_ {
1205-
self.other_attrs.lists(name)
1164+
hir_attr_lists(&self.other_attrs[..], name)
12061165
}
12071166

12081167
pub(crate) fn has_doc_flag(&self, flag: Symbol) -> bool {
@@ -1269,7 +1228,9 @@ impl Attributes {
12691228
pub(crate) fn get_doc_aliases(&self) -> Box<[Symbol]> {
12701229
let mut aliases = FxIndexSet::default();
12711230

1272-
for attr in self.other_attrs.lists(sym::doc).filter(|a| a.has_name(sym::alias)) {
1231+
for attr in
1232+
hir_attr_lists(&self.other_attrs[..], sym::doc).filter(|a| a.has_name(sym::alias))
1233+
{
12731234
if let Some(values) = attr.meta_item_list() {
12741235
for l in values {
12751236
if let Some(lit) = l.lit()

src/librustdoc/doctest/rust.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,7 @@ use rustc_span::source_map::SourceMap;
1313
use rustc_span::{BytePos, DUMMY_SP, FileName, Pos, Span};
1414

1515
use super::{DocTestVisitor, ScrapedDocTest};
16-
use crate::clean::Attributes;
17-
use crate::clean::types::AttributesExt;
16+
use crate::clean::{Attributes, extract_cfg_from_attrs};
1817
use crate::html::markdown::{self, ErrorCodes, LangString, MdRelLine};
1918

2019
struct RustCollector {
@@ -97,7 +96,9 @@ impl HirCollector<'_> {
9796
nested: F,
9897
) {
9998
let ast_attrs = self.tcx.hir().attrs(self.tcx.local_def_id_to_hir_id(def_id));
100-
if let Some(ref cfg) = ast_attrs.cfg(self.tcx, &FxHashSet::default()) {
99+
if let Some(ref cfg) =
100+
extract_cfg_from_attrs(ast_attrs.iter(), self.tcx, &FxHashSet::default())
101+
{
101102
if !cfg.matches(&self.tcx.sess.psess, Some(self.tcx.features())) {
102103
return;
103104
}

src/librustdoc/visit_ast.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use tracing::debug;
1919

2020
use crate::clean::cfg::Cfg;
2121
use crate::clean::utils::{inherits_doc_hidden, should_ignore_res};
22-
use crate::clean::{AttributesExt, NestedAttributesExt, reexport_chain};
22+
use crate::clean::{NestedAttributesExt, hir_attr_lists, reexport_chain};
2323
use crate::core;
2424

2525
/// This module is used to store stuff from Rust's AST in a more convenient
@@ -247,8 +247,8 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
247247
let document_hidden = self.cx.render_options.document_hidden;
248248
let use_attrs = tcx.hir().attrs(tcx.local_def_id_to_hir_id(def_id));
249249
// Don't inline `doc(hidden)` imports so they can be stripped at a later stage.
250-
let is_no_inline = use_attrs.lists(sym::doc).has_word(sym::no_inline)
251-
|| (document_hidden && use_attrs.lists(sym::doc).has_word(sym::hidden));
250+
let is_no_inline = hir_attr_lists(use_attrs, sym::doc).has_word(sym::no_inline)
251+
|| (document_hidden && hir_attr_lists(use_attrs, sym::doc).has_word(sym::hidden));
252252

253253
if is_no_inline {
254254
return false;

0 commit comments

Comments
 (0)