diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index b3b85655bb261..320bf5b65ff4b 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -34,7 +34,6 @@ use rustc_span::{ ByteSymbol, DUMMY_SP, ErrorGuaranteed, Ident, LocalExpnId, Span, Spanned, Symbol, kw, respan, sym, }; -use smallvec::{SmallVec, smallvec}; use thin_vec::{ThinVec, thin_vec}; use crate::attr::data_structures::CfgEntry; @@ -3523,43 +3522,26 @@ impl GeneratedAttr { } } - pub fn is_doc_comment(&self) -> Option { + pub fn is_doc_comment(&self) -> bool { match self { - GeneratedAttr::AutomaticallyDerived => None, - GeneratedAttr::RustcConstUnstableDerived => None, - GeneratedAttr::Inline => None, - GeneratedAttr::DocHidden => None, - GeneratedAttr::CoverageOff => None, - GeneratedAttr::RustcTestMarker(_) => None, + GeneratedAttr::AutomaticallyDerived => false, + GeneratedAttr::RustcConstUnstableDerived => false, + GeneratedAttr::Inline => false, + GeneratedAttr::DocHidden => false, + GeneratedAttr::CoverageOff => false, + GeneratedAttr::RustcTestMarker(_) => false, } } - pub fn name(&self) -> Option { + pub fn path(&self) -> &[Symbol] { match self { - GeneratedAttr::AutomaticallyDerived => Some(sym::automatically_derived), - GeneratedAttr::RustcConstUnstableDerived => Some(sym::rustc_const_unstable), - GeneratedAttr::Inline => Some(sym::inline), - GeneratedAttr::DocHidden => Some(sym::doc), - GeneratedAttr::CoverageOff => Some(sym::coverage), - GeneratedAttr::RustcTestMarker(_) => Some(sym::rustc_test_marker), - } - } - - pub fn path_matches(&self, name: &[Symbol]) -> bool { - let path = match self { GeneratedAttr::AutomaticallyDerived => &[sym::automatically_derived], GeneratedAttr::RustcConstUnstableDerived => &[sym::rustc_const_unstable], GeneratedAttr::Inline => &[sym::inline], GeneratedAttr::DocHidden => &[sym::doc], GeneratedAttr::CoverageOff => &[sym::coverage], GeneratedAttr::RustcTestMarker(_) => &[sym::rustc_test_marker], - }; - - path == name - } - - pub fn symbol_path(&self) -> Option> { - self.name().map(|n| smallvec![n]) + } } pub fn path_span(&self) -> Option { diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index 8ab79eb4068ea..88eec44407fa6 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -80,28 +80,6 @@ impl Attribute { } impl AttributeExt for Attribute { - fn value_span(&self) -> Option { - match &self.kind { - AttrKind::Normal(normal) => match &normal.item.args { - AttrArgs::Eq { expr, .. } => Some(expr.span), - _ => None, - }, - AttrKind::Synthetic(..) | AttrKind::DocComment(..) => None, - AttrKind::Generated(generated) => generated.value_span(), - } - } - - /// Returns `true` if it is a sugared doc comment (`///` or `//!` for example). - /// So `#[doc = "doc"]` (which is a doc comment) and `#[doc(...)]` (which is not - /// a doc comment) will return `false`. - fn is_doc_comment(&self) -> Option { - match &self.kind { - AttrKind::Normal(..) | AttrKind::Synthetic(..) => None, - AttrKind::DocComment(..) => Some(self.span), - AttrKind::Generated(generated) => generated.is_doc_comment(), - } - } - /// For a single-segment attribute, returns its name; otherwise, returns `None`. fn name(&self) -> Option { use SyntheticAttr::*; @@ -109,28 +87,10 @@ impl AttributeExt for Attribute { AttrKind::Normal(normal) => normal.item.name(), AttrKind::Synthetic(CfgTrace(_) | CfgAttrTrace(_)) => None, AttrKind::DocComment(..) => None, - AttrKind::Generated(generated) => generated.name(), - } - } - - fn symbol_path(&self) -> Option> { - use SyntheticAttr::*; - match &self.kind { - AttrKind::Normal(normal) => { - Some(normal.item.path.segments.iter().map(|i| i.ident.name).collect()) - } - AttrKind::Synthetic(CfgTrace(_) | CfgAttrTrace(_)) => None, - AttrKind::DocComment(_, _) => None, - AttrKind::Generated(generated) => generated.symbol_path(), - } - } - - fn path_span(&self) -> Option { - match &self.kind { - AttrKind::Normal(attr) => Some(attr.item.path.span), - AttrKind::Synthetic(..) => unreachable!(), - AttrKind::DocComment(_, _) => None, - AttrKind::Generated(generated) => generated.path_span(), + AttrKind::Generated(generated) => match generated.path() { + [name] => Some(*name), + _ => None, + }, } } @@ -147,30 +107,7 @@ impl AttributeExt for Attribute { .all(|(s, n)| s.args.is_none() && s.ident.name == *n) } AttrKind::Synthetic(..) | AttrKind::DocComment(..) => false, - AttrKind::Generated(generated) => generated.path_matches(name), - } - } - - fn is_word(&self) -> bool { - match &self.kind { - AttrKind::Normal(normal) => matches!(normal.item.args, AttrArgs::Empty), - AttrKind::Synthetic(..) => unreachable!(), - AttrKind::DocComment(..) => false, - AttrKind::Generated(generated) => generated.is_word(), - } - } - - /// Returns a list of meta items if the attribute is delimited with parenthesis: - /// - /// ```text - /// #[attr(a, b = "c")] // Returns `Some()`. - /// #[attr = ""] // Returns `None`. - /// #[attr] // Returns `None`. - /// ``` - fn meta_item_list(&self) -> Option> { - match &self.kind { - AttrKind::Normal(normal) => normal.item.meta_item_list(), - AttrKind::Synthetic(..) | AttrKind::DocComment(..) | AttrKind::Generated(..) => None, + AttrKind::Generated(generated) => generated.path() == name, } } @@ -222,18 +159,6 @@ impl AttributeExt for Attribute { } } - /// Returns the documentation if this is a doc comment or a sugared doc comment. - /// * `///doc` returns `Some("doc")`. - /// * `#[doc = "doc"]` returns `Some("doc")`. - /// * `#[doc(...)]` returns `None`. - fn doc_str(&self) -> Option { - match &self.kind { - AttrKind::DocComment(.., data) => Some(*data), - AttrKind::Normal(normal) if normal.item.path == sym::doc => normal.item.value_str(), - _ => None, - } - } - fn doc_resolution_scope(&self) -> Option { match &self.kind { AttrKind::DocComment(..) => Some(self.style), @@ -245,14 +170,6 @@ impl AttributeExt for Attribute { _ => None, } } - - /// Returns whether this attribute is any of the proc macro attributes. - /// i.e. `proc_macro`, `proc_macro_attribute` or `proc_macro_derive`. - fn is_proc_macro_attr(&self) -> bool { - [sym::proc_macro, sym::proc_macro_attribute, sym::proc_macro_derive] - .iter() - .any(|kind| self.has_name(*kind)) - } } impl Attribute { @@ -326,6 +243,29 @@ impl Attribute { _ => None, } } + + /// Returns a list of meta items if the attribute is delimited with parenthesis: + /// + /// ```text + /// #[attr(a, b = "c")] // Returns `Some()`. + /// #[attr = ""] // Returns `None`. + /// #[attr] // Returns `None`. + /// ``` + pub fn meta_item_list(&self) -> Option> { + match &self.kind { + AttrKind::Normal(normal) => normal.item.meta_item_list(), + AttrKind::Synthetic(..) | AttrKind::DocComment(..) | AttrKind::Generated(..) => None, + } + } + + pub fn path_span(&self) -> Option { + match &self.kind { + AttrKind::Normal(attr) => Some(attr.item.path.span), + AttrKind::Synthetic(..) => unreachable!(), + AttrKind::DocComment(_, _) => None, + AttrKind::Generated(generated) => generated.path_span(), + } + } } impl AttrItem { @@ -901,60 +841,14 @@ pub trait AttributeExt: Debug + 'static { /// return the name of the attribute; otherwise, returns `None`. fn name(&self) -> Option; - /// Get the meta item list, `#[attr(meta item list)]` - fn meta_item_list(&self) -> Option>; - /// Gets the value literal, as string, when using `#[attr = value]` fn value_str(&self) -> Option; - /// Gets the span of the value literal, as string, when using `#[attr = value]` - fn value_span(&self) -> Option; - /// Checks whether the path of this attribute matches the name. /// /// Matches one segment of the path to each element in `name` fn path_matches(&self, name: &[Symbol]) -> bool; - /// Returns `true` if it is a sugared doc comment (`///` or `//!` for example). - /// So `#[doc = "doc"]` (which is a doc comment) and `#[doc(...)]` (which is not - /// a doc comment) will return `false`. - fn is_doc_comment(&self) -> Option; - - /// Returns true if the attribute's first *and only* path segment is equal to the passed-in - /// symbol. - #[inline] - fn has_name(&self, name: Symbol) -> bool { - self.name().map(|x| x == name).unwrap_or(false) - } - - /// Returns true if the attribute's first *and only* path segment is any of the passed-in - /// symbols. - #[inline] - fn has_any_name(&self, names: &[Symbol]) -> bool { - names.iter().any(|&name| self.has_name(name)) - } - /// Returns whether the attribute is a path, without any arguments. - fn is_word(&self) -> bool; - - fn path(&self) -> SmallVec<[Symbol; 1]> { - self.symbol_path().unwrap_or(smallvec![sym::doc]) - } - - fn path_span(&self) -> Option; - - /// Returns None for doc comments - fn symbol_path(&self) -> Option>; - - /// Returns the documentation if this is a doc comment or a sugared doc comment. - /// * `///doc` returns `Some("doc")`. - /// * `#[doc = "doc"]` returns `Some("doc")`. - /// * `#[doc(...)]` returns `None`. - fn doc_str(&self) -> Option; - - /// Returns whether this attribute is any of the proc macro attributes. - /// i.e. `proc_macro`, `proc_macro_attribute` or `proc_macro_derive`. - fn is_proc_macro_attr(&self) -> bool; - /// Returns the documentation and its kind if this is a doc comment or a sugared doc comment. /// * `///doc` returns `Some(("doc", CommentKind::Line))`. /// * `/** doc */` returns `Some(("doc", CommentKind::Block))`. @@ -979,51 +873,92 @@ impl Attribute { AttributeExt::name(self) } - pub fn meta_item_list(&self) -> Option> { - AttributeExt::meta_item_list(self) - } - pub fn value_str(&self) -> Option { AttributeExt::value_str(self) } + /// Gets the span of the value literal, as string, when using `#[attr = value]` pub fn value_span(&self) -> Option { - AttributeExt::value_span(self) + match &self.kind { + AttrKind::Normal(normal) => match &normal.item.args { + AttrArgs::Eq { expr, .. } => Some(expr.span), + _ => None, + }, + AttrKind::Synthetic(..) | AttrKind::DocComment(..) => None, + AttrKind::Generated(generated) => generated.value_span(), + } } pub fn path_matches(&self, name: &[Symbol]) -> bool { AttributeExt::path_matches(self, name) } - // on ast attributes we return a bool since that's what most code already expects + /// Returns `true` if it is a sugared doc comment (`///` or `//!` for example). + /// So `#[doc = "doc"]` (which is a doc comment) and `#[doc(...)]` (which is not + /// a doc comment) will return `false`. pub fn is_doc_comment(&self) -> bool { - AttributeExt::is_doc_comment(self).is_some() + match &self.kind { + AttrKind::Normal(..) | AttrKind::Synthetic(..) => false, + AttrKind::DocComment(..) => true, + AttrKind::Generated(generated) => generated.is_doc_comment(), + } } + /// Returns true if the attribute's first *and only* path segment is equal to the passed-in + /// symbol. #[inline] pub fn has_name(&self, name: Symbol) -> bool { - AttributeExt::has_name(self, name) + self.name().map(|x| x == name).unwrap_or(false) } + /// Returns true if the attribute's first *and only* path segment is any of the passed-in + /// symbols. #[inline] pub fn has_any_name(&self, names: &[Symbol]) -> bool { - AttributeExt::has_any_name(self, names) + names.iter().any(|&name| self.has_name(name)) } + /// Returns whether the attribute is a path, without any arguments. pub fn is_word(&self) -> bool { - AttributeExt::is_word(self) + match &self.kind { + AttrKind::Normal(normal) => matches!(normal.item.args, AttrArgs::Empty), + AttrKind::Synthetic(..) => unreachable!(), + AttrKind::DocComment(..) => false, + AttrKind::Generated(generated) => generated.is_word(), + } } pub fn path(&self) -> SmallVec<[Symbol; 1]> { - AttributeExt::path(self) + use SyntheticAttr::*; + match &self.kind { + AttrKind::Normal(normal) => { + normal.item.path.segments.iter().map(|i| i.ident.name).collect() + } + AttrKind::Synthetic(CfgTrace(_)) => smallvec![sym::cfg], + AttrKind::Synthetic(CfgAttrTrace(_)) => smallvec![sym::cfg_attr], + AttrKind::DocComment(_, _) => smallvec![sym::doc], + AttrKind::Generated(generated) => generated.path().iter().copied().collect(), + } } + /// Returns the documentation if this is a doc comment or a sugared doc comment. + /// * `///doc` returns `Some("doc")`. + /// * `#[doc = "doc"]` returns `Some("doc")`. + /// * `#[doc(...)]` returns `None`. pub fn doc_str(&self) -> Option { - AttributeExt::doc_str(self) + match &self.kind { + AttrKind::DocComment(.., data) => Some(*data), + AttrKind::Normal(normal) if normal.item.path == sym::doc => normal.item.value_str(), + _ => None, + } } + /// Returns whether this attribute is any of the proc macro attributes. + /// i.e. `proc_macro`, `proc_macro_attribute` or `proc_macro_derive`. pub fn is_proc_macro_attr(&self) -> bool { - AttributeExt::is_proc_macro_attr(self) + [sym::proc_macro, sym::proc_macro_attribute, sym::proc_macro_derive] + .iter() + .any(|kind| self.has_name(*kind)) } pub fn doc_str_and_fragment_kind(&self) -> Option<(Symbol, DocFragmentKind, Span)> { diff --git a/compiler/rustc_attr_ir/src/attr.rs b/compiler/rustc_attr_ir/src/attr.rs index 44fe94fcd44f4..760e498a736a8 100644 --- a/compiler/rustc_attr_ir/src/attr.rs +++ b/compiler/rustc_attr_ir/src/attr.rs @@ -7,8 +7,6 @@ use rustc_data_structures::stable_hash::{StableHash, StableHashCtxt, StableHashe use rustc_error_messages::{DiagArgValue, IntoDiagArg}; use rustc_macros::{Decodable, Encodable, StableHash}; use rustc_span::{AttrId, DUMMY_SP, Ident, Span, Symbol}; -use smallvec::SmallVec; -use thin_vec::ThinVec; use crate::AttributeKind; @@ -148,29 +146,11 @@ impl Attribute { } impl AttributeExt for Attribute { - #[inline] - fn meta_item_list(&self) -> Option> { - match &self { - Attribute::Tool(n) | Attribute::DeriveHelper(n) => match n.as_ref() { - AttrItem { args: AttrArgs::Delimited(d), .. } => { - ast::MetaItemKind::list_from_tokens(d.tokens.clone()) - } - _ => None, - }, - _ => None, - } - } - #[inline] fn value_str(&self) -> Option { self.value_lit().and_then(|x| x.value_as_str()) } - #[inline] - fn value_span(&self) -> Option { - self.value_lit().map(|i| i.span) - } - /// For a single-segment attribute, returns its name; otherwise, returns `None`. #[inline] fn name(&self) -> Option { @@ -196,50 +176,6 @@ impl AttributeExt for Attribute { } } - #[inline] - fn is_doc_comment(&self) -> Option { - if let Attribute::Parsed(AttributeKind::DocComment { span, .. }) = self { - Some(*span) - } else { - None - } - } - - #[inline] - fn is_word(&self) -> bool { - match &self { - Attribute::Tool(n) | Attribute::DeriveHelper(n) => { - matches!(n.args, AttrArgs::Empty) - } - _ => false, - } - } - - #[inline] - fn symbol_path(&self) -> Option> { - match &self { - Attribute::Tool(n) | Attribute::DeriveHelper(n) => { - Some(n.path.segments.iter().copied().collect()) - } - _ => None, - } - } - - fn path_span(&self) -> Option { - match &self { - Attribute::Tool(attr) | Attribute::DeriveHelper(attr) => Some(attr.path.span), - Attribute::Parsed(_) => None, - } - } - - #[inline] - fn doc_str(&self) -> Option { - match &self { - Attribute::Parsed(AttributeKind::DocComment { comment, .. }) => Some(*comment), - _ => None, - } - } - #[inline] fn doc_str_and_fragment_kind(&self) -> Option<(Symbol, DocFragmentKind, Span)> { match &self { @@ -256,15 +192,4 @@ impl AttributeExt for Attribute { _ => None, } } - - fn is_proc_macro_attr(&self) -> bool { - matches!( - self, - Attribute::Parsed( - AttributeKind::ProcMacro - | AttributeKind::ProcMacroAttribute - | AttributeKind::ProcMacroDerive { .. } - ) - ) - } } diff --git a/src/tools/clippy/clippy_lints/src/attrs/allow_attributes.rs b/src/tools/clippy/clippy_lints/src/attrs/allow_attributes.rs index 6b493afddb486..01d442133ccf0 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/allow_attributes.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/allow_attributes.rs @@ -1,7 +1,6 @@ use super::ALLOW_ATTRIBUTES; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_from_proc_macro; -use rustc_ast::attr::AttributeExt as _; use rustc_ast::{AttrStyle, Attribute}; use rustc_errors::Applicability; use rustc_lint::EarlyContext; diff --git a/src/tools/clippy/clippy_lints/src/attrs/mixed_attributes_style.rs b/src/tools/clippy/clippy_lints/src/attrs/mixed_attributes_style.rs index dc38fc4c11cd2..e26e215d71dc0 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/mixed_attributes_style.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/mixed_attributes_style.rs @@ -34,7 +34,7 @@ impl From<&AttrKind> for SimpleAttrKind { SyntheticAttr::CfgAttrTrace(_) => Self::CfgAttrTrace, }, AttrKind::DocComment(..) => Self::Doc, - AttrKind::Generated(generated) => Self::Normal(vec![generated.name().unwrap()]), + AttrKind::Generated(generated) => Self::Normal(generated.path().iter().copied().collect()), } } } diff --git a/src/tools/clippy/clippy_lints/src/derivable_impls.rs b/src/tools/clippy/clippy_lints/src/derivable_impls.rs index 21bd1a5cf39d7..c6566f89841a4 100644 --- a/src/tools/clippy/clippy_lints/src/derivable_impls.rs +++ b/src/tools/clippy/clippy_lints/src/derivable_impls.rs @@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::indent_of; use clippy_utils::{is_default_equivalent, peel_blocks}; -use rustc_ast::attr::AttributeExt as _; +use rustc_attr_ir::find_attr; use rustc_errors::Applicability; use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; use rustc_hir::{ @@ -250,7 +250,7 @@ impl<'tcx> LateLintPass<'tcx> for DerivableImpls { .skip_norm_wip() .kind() && let attrs = cx.tcx.hir_attrs(item.hir_id()) - && !attrs.iter().any(|attr| attr.doc_str().is_some()) + && !find_attr!(attrs, DocComment { .. }) && cx.tcx.hir_attrs(impl_item_hir).is_empty() { let is_const = matches!(constness, hir::Constness::Const { always: false }); diff --git a/src/tools/clippy/clippy_utils/src/attrs.rs b/src/tools/clippy/clippy_utils/src/attrs.rs index b1e32de466d1e..be112441d0b1b 100644 --- a/src/tools/clippy/clippy_utils/src/attrs.rs +++ b/src/tools/clippy/clippy_utils/src/attrs.rs @@ -14,7 +14,7 @@ use rustc_span::{Span, Symbol}; use std::str::FromStr as _; /// Validates a single clippy attribute and emits errors for unknown or deprecated ones. -pub fn check_clippy_attr(sess: &Session, attr: &A) { +pub fn check_clippy_attr(sess: &Session, attr: &rustc_ast::ast::Attribute) { if let [clippy, segment2] = &*attr.path() && *clippy == sym::clippy { @@ -84,8 +84,13 @@ pub fn get_clippy_attr(tcx: TyCtxt<'_>, did: impl Into, name: Symbol) -> /// Checks whether `attrs` contain any of `proc_macro`, `proc_macro_derive` or /// `proc_macro_attribute` -pub fn is_proc_macro(attrs: &[impl AttributeExt]) -> bool { - attrs.iter().any(AttributeExt::is_proc_macro_attr) +pub fn is_proc_macro(attrs: &[rustc_attr_ir::Attribute]) -> bool { + find_attr!( + attrs, + ProcMacro + | ProcMacroAttribute + | ProcMacroDerive { .. } + ) } /// Checks whether `attrs` contain `#[doc(hidden)]`