diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index dbed66421e56c..df38649e016b9 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -729,15 +729,14 @@ fn clean_fn_or_proc_macro( match macro_kind { Some(kind) => { if kind == MacroKind::Derive { - *name = attrs - .lists(sym::proc_macro_derive) + *name = attr_items(attrs, sym::proc_macro_derive) .find_map(|mi| mi.ident()) .expect("proc-macro derives require a name") .name; } let mut helpers = Vec::new(); - for mi in attrs.lists(sym::proc_macro_derive) { + for mi in attr_items(attrs, sym::proc_macro_derive) { if !mi.has_name(sym::attributes) { continue; } @@ -1955,7 +1954,8 @@ fn clean_use_statement( let visibility = cx.tcx.visibility(import.def_id); let attrs = cx.tcx.hir().attrs(import.hir_id()); - let inline_attr = attrs.lists(sym::doc).get_word_attr(sym::inline); + let inline_attr = + attr_items(attrs, sym::doc).find(|attr| attr.is_word() && attr.has_name(sym::inline)); let pub_underscore = visibility.is_public() && name == kw::Underscore; let current_mod = cx.tcx.parent_module_from_def_id(import.def_id); diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index d928b41cad49a..b7c5696fc1cc7 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -6,7 +6,7 @@ use std::lazy::SyncOnceCell as OnceCell; use std::path::PathBuf; use std::rc::Rc; use std::sync::Arc; -use std::{slice, vec}; +use std::vec; use arrayvec::ArrayVec; @@ -215,8 +215,7 @@ impl ExternalCrate { // Failing that, see if there's an attribute specifying where to find this // external crate let did = DefId { krate: self.crate_num, index: CRATE_DEF_INDEX }; - tcx.get_attrs(did) - .lists(sym::doc) + attr_items(tcx.get_attrs(did), sym::doc) .filter(|a| a.has_name(sym::html_root_url)) .filter_map(|a| a.value_str()) .map(to_remote) @@ -232,7 +231,7 @@ impl ExternalCrate { if let Res::Def(DefKind::Mod, def_id) = res { let attrs = tcx.get_attrs(def_id); let mut keyword = None; - for attr in attrs.lists(sym::doc) { + for attr in attr_items(attrs, sym::doc) { if attr.has_name(sym::keyword) { if let Some(v) = attr.value_str() { keyword = Some(v); @@ -294,7 +293,7 @@ impl ExternalCrate { if let Res::Def(DefKind::Mod, def_id) = res { let attrs = tcx.get_attrs(def_id); let mut prim = None; - for attr in attrs.lists(sym::doc) { + for attr in attr_items(attrs, sym::doc) { if let Some(v) = attr.value_str() { if attr.has_name(sym::primitive) { prim = PrimitiveType::from_symbol(v); @@ -725,44 +724,19 @@ crate struct Module { crate span: Span, } -crate struct ListAttributesIter<'a> { - attrs: slice::Iter<'a, ast::Attribute>, - current_list: vec::IntoIter, +/// Finds attributes with the given name and returns their nested items. +crate fn attr_items( + attrs: &[ast::Attribute], name: Symbol, -} - -impl<'a> Iterator for ListAttributesIter<'a> { - type Item = ast::NestedMetaItem; - - fn next(&mut self) -> Option { - if let Some(nested) = self.current_list.next() { - return Some(nested); - } - - for attr in &mut self.attrs { - if let Some(list) = attr.meta_item_list() { - if attr.has_name(self.name) { - self.current_list = list.into_iter(); - if let Some(nested) = self.current_list.next() { - return Some(nested); - } - } - } - } - - None - } - - fn size_hint(&self) -> (usize, Option) { - let lower = self.current_list.len(); - (lower, None) - } +) -> impl Iterator + '_ { + attrs + .iter() + .filter(move |attr| attr.has_name(name)) + .filter_map(ast::Attribute::meta_item_list) + .flatten() } crate trait AttributesExt { - /// Finds an attribute as List and returns the list of attributes nested inside. - fn lists(&self, name: Symbol) -> ListAttributesIter<'_>; - fn span(&self) -> Option; fn inner_docs(&self) -> bool; @@ -773,10 +747,6 @@ crate trait AttributesExt { } impl AttributesExt for [ast::Attribute] { - fn lists(&self, name: Symbol) -> ListAttributesIter<'_> { - ListAttributesIter { attrs: self.iter(), current_list: Vec::new().into_iter(), name } - } - /// Return the span of the first doc-comment, if it exists. fn span(&self) -> Option { self.iter().find(|attr| attr.doc_str().is_some()).map(|attr| attr.span) @@ -860,7 +830,7 @@ impl AttributesExt for [ast::Attribute] { // treat #[target_feature(enable = "feat")] attributes as if they were // #[doc(cfg(target_feature = "feat"))] attributes as well - for attr in self.lists(sym::target_feature) { + for attr in attr_items(self, sym::target_feature) { if attr.has_name(sym::enable) { if let Some(feat) = attr.value_str() { let meta = attr::mk_name_value_item_str( @@ -882,18 +852,11 @@ impl AttributesExt for [ast::Attribute] { crate trait NestedAttributesExt { /// Returns `true` if the attribute list contains a specific `Word` fn has_word(self, word: Symbol) -> bool; - fn get_word_attr(self, word: Symbol) -> Option; } -impl + IntoIterator> - NestedAttributesExt for I -{ - fn has_word(self, word: Symbol) -> bool { - self.into_iter().any(|attr| attr.is_word() && attr.has_name(word)) - } - - fn get_word_attr(mut self, word: Symbol) -> Option { - self.find(|attr| attr.is_word() && attr.has_name(word)) +impl> NestedAttributesExt for I { + fn has_word(mut self, word: Symbol) -> bool { + self.any(|attr| attr.is_word() && attr.has_name(word)) } } @@ -1001,10 +964,6 @@ crate struct Attributes { } impl Attributes { - crate fn lists(&self, name: Symbol) -> ListAttributesIter<'_> { - self.other_attrs.lists(name) - } - crate fn has_doc_flag(&self, flag: Symbol) -> bool { for attr in &self.other_attrs { if !attr.has_name(sym::doc) { @@ -1110,7 +1069,7 @@ impl Attributes { crate fn get_doc_aliases(&self) -> Box<[Symbol]> { let mut aliases = FxHashSet::default(); - for attr in self.other_attrs.lists(sym::doc).filter(|a| a.has_name(sym::alias)) { + for attr in attr_items(&self.other_attrs, sym::doc).filter(|a| a.has_name(sym::alias)) { if let Some(values) = attr.meta_item_list() { for l in values { match l.literal().unwrap().kind { diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 3948f9fa7e73d..dd077147ee682 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -32,7 +32,7 @@ use std::mem; use std::rc::Rc; use crate::clean::inline::build_external_trait; -use crate::clean::{self, ItemId, TraitWithExtraInfo}; +use crate::clean::{self, attr_items, ItemId, TraitWithExtraInfo}; use crate::config::{Options as RustdocOptions, OutputFormat, RenderOptions}; use crate::formats::cache::Cache; use crate::passes::{self, Condition::*}; @@ -435,7 +435,7 @@ crate fn run_global_ctxt( // Process all of the crate attributes, extracting plugin metadata along // with the passes which we are supposed to run. - for attr in krate.module.attrs.lists(sym::doc) { + for attr in attr_items(&krate.module.attrs.other_attrs, sym::doc) { let diag = ctxt.sess().diagnostic(); let name = attr.name_or_empty(); diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs index 45a436c448710..bce99a6f4b283 100644 --- a/src/librustdoc/html/render/context.rs +++ b/src/librustdoc/html/render/context.rs @@ -22,7 +22,7 @@ use super::{ BASIC_KEYWORDS, }; -use crate::clean::{self, ExternalCrate}; +use crate::clean::{self, attr_items, ExternalCrate}; use crate::config::RenderOptions; use crate::docfs::{DocFS, PathError}; use crate::error::Error; @@ -430,7 +430,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { // Crawl the crate attributes looking for attributes which control how we're // going to emit HTML - for attr in krate.module.attrs.lists(sym::doc) { + for attr in attr_items(&krate.module.attrs.other_attrs, sym::doc) { match (attr.name_or_empty(), attr.value_str()) { (sym::html_favicon_url, Some(s)) => { layout.favicon = s.to_string(); diff --git a/src/librustdoc/passes/check_doc_test_visibility.rs b/src/librustdoc/passes/check_doc_test_visibility.rs index b86ec8abefaae..159304c32b204 100644 --- a/src/librustdoc/passes/check_doc_test_visibility.rs +++ b/src/librustdoc/passes/check_doc_test_visibility.rs @@ -96,7 +96,7 @@ crate fn should_have_doc_example(cx: &DocContext<'_>, item: &clean::Item) -> boo } } - if cx.tcx.hir().attrs(hir_id).lists(sym::doc).has_word(sym::hidden) + if attr_items(&cx.tcx.hir().attrs(hir_id), sym::doc).has_word(sym::hidden) || inherits_doc_hidden(cx.tcx, hir_id) || cx.tcx.hir().span(hir_id).in_derive_expansion() { diff --git a/src/librustdoc/passes/strip_hidden.rs b/src/librustdoc/passes/strip_hidden.rs index e63534659add7..e10e839c65ef5 100644 --- a/src/librustdoc/passes/strip_hidden.rs +++ b/src/librustdoc/passes/strip_hidden.rs @@ -3,7 +3,7 @@ use rustc_span::symbol::sym; use std::mem; use crate::clean; -use crate::clean::{Item, ItemIdSet, NestedAttributesExt}; +use crate::clean::{attr_items, Item, ItemIdSet, NestedAttributesExt}; use crate::core::DocContext; use crate::fold::{strip_item, DocFolder}; use crate::passes::{ImplStripper, Pass}; @@ -36,7 +36,7 @@ struct Stripper<'a> { impl<'a> DocFolder for Stripper<'a> { fn fold_item(&mut self, i: Item) -> Option { - if i.attrs.lists(sym::doc).has_word(sym::hidden) { + if attr_items(&i.attrs.other_attrs, sym::doc).has_word(sym::hidden) { debug!("strip_hidden: stripping {:?} {:?}", i.type_(), i.name); // use a dedicated hidden item for given item type if any match *i.kind { diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index ea7372761ba31..c9eac5da7f1cc 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -16,7 +16,7 @@ use rustc_span::Span; use std::mem; -use crate::clean::{self, cfg::Cfg, AttributesExt, NestedAttributesExt}; +use crate::clean::{self, attr_items, cfg::Cfg, NestedAttributesExt}; use crate::core; /// This module is used to store stuff from Rust's AST in a more convenient @@ -55,7 +55,7 @@ fn def_id_to_path(tcx: TyCtxt<'_>, did: DefId) -> Vec { crate fn inherits_doc_hidden(tcx: TyCtxt<'_>, mut node: hir::HirId) -> bool { while let Some(id) = tcx.hir().get_enclosing_scope(node) { node = id; - if tcx.hir().attrs(node).lists(sym::doc).has_word(sym::hidden) { + if attr_items(tcx.hir().attrs(node), sym::doc).has_word(sym::hidden) { return true; } } @@ -199,8 +199,9 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { let use_attrs = tcx.hir().attrs(id); // Don't inline `doc(hidden)` imports so they can be stripped at a later stage. - let is_no_inline = use_attrs.lists(sym::doc).has_word(sym::no_inline) - || use_attrs.lists(sym::doc).has_word(sym::hidden); + let is_no_inline = attr_items(&use_attrs, sym::doc).any(|attr| { + attr.is_word() && (attr.has_name(sym::no_inline) || attr.has_name(sym::hidden)) + }); // For cross-crate impl inlining we need to know whether items are // reachable in documentation -- a previously unreachable item can be @@ -208,7 +209,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { // (this is done here because we need to know this upfront). if !res_did.is_local() && !is_no_inline { let attrs = clean::inline::load_attrs(self.cx, res_did); - let self_is_hidden = attrs.lists(sym::doc).has_word(sym::hidden); + let self_is_hidden = attr_items(attrs, sym::doc).has_word(sym::hidden); if !self_is_hidden { if let Res::Def(kind, did) = res { if kind == DefKind::Mod {