Skip to content

Commit 4ee4882

Browse files
Rollup merge of rust-lang#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 2c81e35 + f92b32c commit 4ee4882

File tree

5 files changed

+119
-148
lines changed

5 files changed

+119
-148
lines changed

src/librustdoc/clean/inline.rs

Lines changed: 10 additions & 7 deletions
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

Lines changed: 13 additions & 7 deletions
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

Lines changed: 89 additions & 128 deletions
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

@@ -985,147 +984,107 @@ pub(crate) struct Module {
985984
pub(crate) span: Span,
986985
}
987986

988-
pub(crate) trait AttributesExt {
989-
type AttributeIterator<'a>: Iterator<Item = ast::MetaItemInner>
990-
where
991-
Self: 'a;
992-
type Attributes<'a>: Iterator<Item = &'a hir::Attribute>
993-
where
994-
Self: 'a;
995-
996-
fn lists(&self, name: Symbol) -> Self::AttributeIterator<'_>;
997-
998-
fn iter(&self) -> Self::Attributes<'_>;
999-
1000-
fn cfg(&self, tcx: TyCtxt<'_>, hidden_cfg: &FxHashSet<Cfg>) -> Option<Arc<Cfg>> {
1001-
let sess = tcx.sess;
1002-
let doc_cfg_active = tcx.features().doc_cfg();
1003-
let doc_auto_cfg_active = tcx.features().doc_auto_cfg();
1004-
1005-
fn single<T: IntoIterator>(it: T) -> Option<T::Item> {
1006-
let mut iter = it.into_iter();
1007-
let item = iter.next()?;
1008-
if iter.next().is_some() {
1009-
return None;
1010-
}
1011-
Some(item)
987+
pub(crate) fn hir_attr_lists<'a, I: IntoIterator<Item = &'a hir::Attribute>>(
988+
attrs: I,
989+
name: Symbol,
990+
) -> impl Iterator<Item = ast::MetaItemInner> + use<'a, I> {
991+
attrs
992+
.into_iter()
993+
.filter(move |attr| attr.has_name(name))
994+
.filter_map(ast::attr::AttributeExt::meta_item_list)
995+
.flatten()
996+
}
997+
998+
pub(crate) fn extract_cfg_from_attrs<'a, I: Iterator<Item = &'a hir::Attribute> + Clone>(
999+
attrs: I,
1000+
tcx: TyCtxt<'_>,
1001+
hidden_cfg: &FxHashSet<Cfg>,
1002+
) -> Option<Arc<Cfg>> {
1003+
let sess = tcx.sess;
1004+
let doc_cfg_active = tcx.features().doc_cfg();
1005+
let doc_auto_cfg_active = tcx.features().doc_auto_cfg();
1006+
1007+
fn single<T: IntoIterator>(it: T) -> Option<T::Item> {
1008+
let mut iter = it.into_iter();
1009+
let item = iter.next()?;
1010+
if iter.next().is_some() {
1011+
return None;
10121012
}
1013+
Some(item)
1014+
}
10131015

1014-
let mut cfg = if doc_cfg_active || doc_auto_cfg_active {
1015-
let mut doc_cfg = self
1016-
.iter()
1017-
.filter(|attr| attr.has_name(sym::doc))
1018-
.flat_map(|attr| attr.meta_item_list().unwrap_or_default())
1016+
let mut cfg = if doc_cfg_active || doc_auto_cfg_active {
1017+
let mut doc_cfg = attrs
1018+
.clone()
1019+
.filter(|attr| attr.has_name(sym::doc))
1020+
.flat_map(|attr| attr.meta_item_list().unwrap_or_default())
1021+
.filter(|attr| attr.has_name(sym::cfg))
1022+
.peekable();
1023+
if doc_cfg.peek().is_some() && doc_cfg_active {
1024+
doc_cfg
1025+
.filter_map(|attr| Cfg::parse(&attr).ok())
1026+
.fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg)
1027+
} else if doc_auto_cfg_active {
1028+
// If there is no `doc(cfg())`, then we retrieve the `cfg()` attributes (because
1029+
// `doc(cfg())` overrides `cfg()`).
1030+
attrs
1031+
.clone()
10191032
.filter(|attr| attr.has_name(sym::cfg))
1020-
.peekable();
1021-
if doc_cfg.peek().is_some() && doc_cfg_active {
1022-
doc_cfg
1023-
.filter_map(|attr| Cfg::parse(&attr).ok())
1024-
.fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg)
1025-
} else if doc_auto_cfg_active {
1026-
// If there is no `doc(cfg())`, then we retrieve the `cfg()` attributes (because
1027-
// `doc(cfg())` overrides `cfg()`).
1028-
self.iter()
1029-
.filter(|attr| attr.has_name(sym::cfg))
1030-
.filter_map(|attr| single(attr.meta_item_list()?))
1031-
.filter_map(|attr| {
1032-
Cfg::parse_without(attr.meta_item()?, hidden_cfg).ok().flatten()
1033-
})
1034-
.fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg)
1035-
} else {
1036-
Cfg::True
1037-
}
1033+
.filter_map(|attr| single(attr.meta_item_list()?))
1034+
.filter_map(|attr| Cfg::parse_without(attr.meta_item()?, hidden_cfg).ok().flatten())
1035+
.fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg)
10381036
} else {
10391037
Cfg::True
1040-
};
1041-
1042-
for attr in self.iter() {
1043-
// #[doc]
1044-
if attr.doc_str().is_none() && attr.has_name(sym::doc) {
1045-
// #[doc(...)]
1046-
if let Some(list) = attr.meta_item_list() {
1047-
for item in list {
1048-
// #[doc(hidden)]
1049-
if !item.has_name(sym::cfg) {
1050-
continue;
1051-
}
1052-
// #[doc(cfg(...))]
1053-
if let Some(cfg_mi) = item
1054-
.meta_item()
1055-
.and_then(|item| rustc_expand::config::parse_cfg(item, sess))
1056-
{
1057-
match Cfg::parse(cfg_mi) {
1058-
Ok(new_cfg) => cfg &= new_cfg,
1059-
Err(e) => {
1060-
sess.dcx().span_err(e.span, e.msg);
1061-
}
1038+
}
1039+
} else {
1040+
Cfg::True
1041+
};
1042+
1043+
for attr in attrs.clone() {
1044+
// #[doc]
1045+
if attr.doc_str().is_none() && attr.has_name(sym::doc) {
1046+
// #[doc(...)]
1047+
if let Some(list) = attr.meta_item_list() {
1048+
for item in list {
1049+
// #[doc(hidden)]
1050+
if !item.has_name(sym::cfg) {
1051+
continue;
1052+
}
1053+
// #[doc(cfg(...))]
1054+
if let Some(cfg_mi) = item
1055+
.meta_item()
1056+
.and_then(|item| rustc_expand::config::parse_cfg(item, sess))
1057+
{
1058+
match Cfg::parse(cfg_mi) {
1059+
Ok(new_cfg) => cfg &= new_cfg,
1060+
Err(e) => {
1061+
sess.dcx().span_err(e.span, e.msg);
10621062
}
10631063
}
10641064
}
10651065
}
10661066
}
10671067
}
1068+
}
10681069

1069-
// treat #[target_feature(enable = "feat")] attributes as if they were
1070-
// #[doc(cfg(target_feature = "feat"))] attributes as well
1071-
for attr in self.lists(sym::target_feature) {
1072-
if attr.has_name(sym::enable) {
1073-
if attr.value_str().is_some() {
1074-
// Clone `enable = "feat"`, change to `target_feature = "feat"`.
1075-
// Unwrap is safe because `value_str` succeeded above.
1076-
let mut meta = attr.meta_item().unwrap().clone();
1077-
meta.path = ast::Path::from_ident(Ident::with_dummy_span(sym::target_feature));
1078-
1079-
if let Ok(feat_cfg) = Cfg::parse(&ast::MetaItemInner::MetaItem(meta)) {
1080-
cfg &= feat_cfg;
1081-
}
1070+
// treat #[target_feature(enable = "feat")] attributes as if they were
1071+
// #[doc(cfg(target_feature = "feat"))] attributes as well
1072+
for attr in hir_attr_lists(attrs, sym::target_feature) {
1073+
if attr.has_name(sym::enable) {
1074+
if attr.value_str().is_some() {
1075+
// Clone `enable = "feat"`, change to `target_feature = "feat"`.
1076+
// Unwrap is safe because `value_str` succeeded above.
1077+
let mut meta = attr.meta_item().unwrap().clone();
1078+
meta.path = ast::Path::from_ident(Ident::with_dummy_span(sym::target_feature));
1079+
1080+
if let Ok(feat_cfg) = Cfg::parse(&ast::MetaItemInner::MetaItem(meta)) {
1081+
cfg &= feat_cfg;
10821082
}
10831083
}
10841084
}
1085-
1086-
if cfg == Cfg::True { None } else { Some(Arc::new(cfg)) }
10871085
}
1088-
}
1089-
1090-
impl AttributesExt for [hir::Attribute] {
1091-
type AttributeIterator<'a> = impl Iterator<Item = ast::MetaItemInner> + 'a;
1092-
type Attributes<'a> = impl Iterator<Item = &'a hir::Attribute> + 'a;
10931086

1094-
fn lists(&self, name: Symbol) -> Self::AttributeIterator<'_> {
1095-
self.iter()
1096-
.filter(move |attr| attr.has_name(name))
1097-
.filter_map(ast::attr::AttributeExt::meta_item_list)
1098-
.flatten()
1099-
}
1100-
1101-
fn iter(&self) -> Self::Attributes<'_> {
1102-
self.iter()
1103-
}
1104-
}
1105-
1106-
impl AttributesExt for [(Cow<'_, hir::Attribute>, Option<DefId>)] {
1107-
type AttributeIterator<'a>
1108-
= impl Iterator<Item = ast::MetaItemInner> + 'a
1109-
where
1110-
Self: 'a;
1111-
type Attributes<'a>
1112-
= impl Iterator<Item = &'a hir::Attribute> + 'a
1113-
where
1114-
Self: 'a;
1115-
1116-
fn lists(&self, name: Symbol) -> Self::AttributeIterator<'_> {
1117-
AttributesExt::iter(self)
1118-
.filter(move |attr| attr.has_name(name))
1119-
.filter_map(hir::Attribute::meta_item_list)
1120-
.flatten()
1121-
}
1122-
1123-
fn iter(&self) -> Self::Attributes<'_> {
1124-
self.iter().map(move |(attr, _)| match attr {
1125-
Cow::Borrowed(attr) => *attr,
1126-
Cow::Owned(attr) => attr,
1127-
})
1128-
}
1087+
if cfg == Cfg::True { None } else { Some(Arc::new(cfg)) }
11291088
}
11301089

11311090
pub(crate) trait NestedAttributesExt {
@@ -1191,7 +1150,7 @@ pub(crate) struct Attributes {
11911150

11921151
impl Attributes {
11931152
pub(crate) fn lists(&self, name: Symbol) -> impl Iterator<Item = ast::MetaItemInner> + '_ {
1194-
self.other_attrs.lists(name)
1153+
hir_attr_lists(&self.other_attrs[..], name)
11951154
}
11961155

11971156
pub(crate) fn has_doc_flag(&self, flag: Symbol) -> bool {
@@ -1258,7 +1217,9 @@ impl Attributes {
12581217
pub(crate) fn get_doc_aliases(&self) -> Box<[Symbol]> {
12591218
let mut aliases = FxIndexSet::default();
12601219

1261-
for attr in self.other_attrs.lists(sym::doc).filter(|a| a.has_name(sym::alias)) {
1220+
for attr in
1221+
hir_attr_lists(&self.other_attrs[..], sym::doc).filter(|a| a.has_name(sym::alias))
1222+
{
12621223
if let Some(values) = attr.meta_item_list() {
12631224
for l in values {
12641225
if let Some(lit) = l.lit()

src/librustdoc/doctest/rust.rs

Lines changed: 4 additions & 3 deletions
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

Lines changed: 3 additions & 3 deletions
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)