Skip to main content

rustc_attr_ir/
attr.rs

1use std::fmt;
2
3use rustc_ast::attr::AttributeExt;
4use rustc_ast::token::DocFragmentKind;
5use rustc_ast::{AttrStyle, DelimArgs, MetaItemInner, MetaItemLit, ast, join_path_idents};
6use rustc_data_structures::stable_hash::{StableHash, StableHashCtxt, StableHasher};
7use rustc_error_messages::{DiagArgValue, IntoDiagArg};
8use rustc_macros::{Decodable, Encodable, StableHash};
9use rustc_span::{AttrId, DUMMY_SP, Ident, Span, Symbol, sym};
10use smallvec::SmallVec;
11use thin_vec::ThinVec;
12
13use crate::AttributeKind;
14/// Arguments passed to an attribute macro.
15#[derive(#[automatically_derived]
impl ::core::clone::Clone for AttrArgs {
    #[inline]
    fn clone(&self) -> AttrArgs {
        match self {
            AttrArgs::Empty => AttrArgs::Empty,
            AttrArgs::Delimited(__self_0) =>
                AttrArgs::Delimited(::core::clone::Clone::clone(__self_0)),
            AttrArgs::Eq { eq_span: __self_0, expr: __self_1 } =>
                AttrArgs::Eq {
                    eq_span: ::core::clone::Clone::clone(__self_0),
                    expr: ::core::clone::Clone::clone(__self_1),
                },
        }
    }
}Clone, #[automatically_derived]
impl ::core::fmt::Debug for AttrArgs {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            AttrArgs::Empty => ::core::fmt::Formatter::write_str(f, "Empty"),
            AttrArgs::Delimited(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f,
                    "Delimited", &__self_0),
            AttrArgs::Eq { eq_span: __self_0, expr: __self_1 } =>
                ::core::fmt::Formatter::debug_struct_field2_finish(f, "Eq",
                    "eq_span", __self_0, "expr", &__self_1),
        }
    }
}Debug, const _: () =
    {
        impl ::rustc_data_structures::stable_hash::StableHash for AttrArgs {
            #[inline]
            fn stable_hash<__Hcx: ::rustc_data_structures::stable_hash::StableHashCtxt>(&self,
                __hcx: &mut __Hcx,
                __hasher:
                    &mut ::rustc_data_structures::stable_hash::StableHasher) {
                ::std::mem::discriminant(self).stable_hash(__hcx, __hasher);
                match *self {
                    AttrArgs::Empty => {}
                    AttrArgs::Delimited(ref __binding_0) => {
                        { __binding_0.stable_hash(__hcx, __hasher); }
                    }
                    AttrArgs::Eq {
                        eq_span: ref __binding_0, expr: ref __binding_1 } => {
                        { __binding_0.stable_hash(__hcx, __hasher); }
                        { __binding_1.stable_hash(__hcx, __hasher); }
                    }
                }
            }
        }
    };StableHash, const _: () =
    {
        impl<__E: ::rustc_span::SpanEncoder> ::rustc_serialize::Encodable<__E>
            for AttrArgs {
            fn encode(&self, __encoder: &mut __E) {
                let disc =
                    match *self {
                        AttrArgs::Empty => { 0usize }
                        AttrArgs::Delimited(ref __binding_0) => { 1usize }
                        AttrArgs::Eq {
                            eq_span: ref __binding_0, expr: ref __binding_1 } => {
                            2usize
                        }
                    };
                ::rustc_serialize::Encoder::emit_u8(__encoder, disc as u8);
                match *self {
                    AttrArgs::Empty => {}
                    AttrArgs::Delimited(ref __binding_0) => {
                        ::rustc_serialize::Encodable::<__E>::encode(__binding_0,
                            __encoder);
                    }
                    AttrArgs::Eq {
                        eq_span: ref __binding_0, expr: ref __binding_1 } => {
                        ::rustc_serialize::Encodable::<__E>::encode(__binding_0,
                            __encoder);
                        ::rustc_serialize::Encodable::<__E>::encode(__binding_1,
                            __encoder);
                    }
                }
            }
        }
    };Encodable, const _: () =
    {
        impl<__D: ::rustc_span::SpanDecoder> ::rustc_serialize::Decodable<__D>
            for AttrArgs {
            fn decode(__decoder: &mut __D) -> Self {
                match ::rustc_serialize::Decoder::read_u8(__decoder) as usize
                    {
                    0usize => { AttrArgs::Empty }
                    1usize => {
                        AttrArgs::Delimited(::rustc_serialize::Decodable::decode(__decoder))
                    }
                    2usize => {
                        AttrArgs::Eq {
                            eq_span: ::rustc_serialize::Decodable::decode(__decoder),
                            expr: ::rustc_serialize::Decodable::decode(__decoder),
                        }
                    }
                    n => {
                        ::core::panicking::panic_fmt(format_args!("invalid enum variant tag while decoding `AttrArgs`, expected 0..3, actual {0}",
                                n));
                    }
                }
            }
        }
    };Decodable)]
16pub enum AttrArgs {
17    /// No arguments: `#[attr]`.
18    Empty,
19    /// Delimited arguments: `#[attr()/[]/{}]`.
20    Delimited(DelimArgs),
21    /// Arguments of a key-value attribute: `#[attr = "value"]`.
22    Eq {
23        /// Span of the `=` token.
24        eq_span: Span,
25        /// The "value".
26        expr: MetaItemLit,
27    },
28}
29
30#[derive(#[automatically_derived]
impl ::core::clone::Clone for AttrPath {
    #[inline]
    fn clone(&self) -> AttrPath {
        AttrPath {
            segments: ::core::clone::Clone::clone(&self.segments),
            span: ::core::clone::Clone::clone(&self.span),
        }
    }
}Clone, #[automatically_derived]
impl ::core::fmt::Debug for AttrPath {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field2_finish(f, "AttrPath",
            "segments", &self.segments, "span", &&self.span)
    }
}Debug, const _: () =
    {
        impl ::rustc_data_structures::stable_hash::StableHash for AttrPath {
            #[inline]
            fn stable_hash<__Hcx: ::rustc_data_structures::stable_hash::StableHashCtxt>(&self,
                __hcx: &mut __Hcx,
                __hasher:
                    &mut ::rustc_data_structures::stable_hash::StableHasher) {
                match *self {
                    AttrPath { segments: ref __binding_0, span: ref __binding_1
                        } => {
                        { __binding_0.stable_hash(__hcx, __hasher); }
                        { __binding_1.stable_hash(__hcx, __hasher); }
                    }
                }
            }
        }
    };StableHash, const _: () =
    {
        impl<__E: ::rustc_span::SpanEncoder> ::rustc_serialize::Encodable<__E>
            for AttrPath {
            fn encode(&self, __encoder: &mut __E) {
                match *self {
                    AttrPath { segments: ref __binding_0, span: ref __binding_1
                        } => {
                        ::rustc_serialize::Encodable::<__E>::encode(__binding_0,
                            __encoder);
                        ::rustc_serialize::Encodable::<__E>::encode(__binding_1,
                            __encoder);
                    }
                }
            }
        }
    };Encodable, const _: () =
    {
        impl<__D: ::rustc_span::SpanDecoder> ::rustc_serialize::Decodable<__D>
            for AttrPath {
            fn decode(__decoder: &mut __D) -> Self {
                AttrPath {
                    segments: ::rustc_serialize::Decodable::decode(__decoder),
                    span: ::rustc_serialize::Decodable::decode(__decoder),
                }
            }
        }
    };Decodable)]
31pub struct AttrPath {
32    pub segments: Box<[Symbol]>,
33    pub span: Span,
34}
35
36impl IntoDiagArg for AttrPath {
37    fn into_diag_arg(self, path: &mut Option<std::path::PathBuf>) -> DiagArgValue {
38        self.to_string().into_diag_arg(path)
39    }
40}
41
42impl AttrPath {
43    pub fn from_ast(path: &ast::Path, lower_span: impl Copy + Fn(Span) -> Span) -> Self {
44        AttrPath {
45            segments: path
46                .segments
47                .iter()
48                .map(|i| i.ident.name)
49                .collect::<Vec<_>>()
50                .into_boxed_slice(),
51            span: lower_span(path.span),
52        }
53    }
54}
55
56impl fmt::Display for AttrPath {
57    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
58        f.write_fmt(format_args!("{0}",
        join_path_idents(self.segments.iter().map(|i|
                    Ident { name: *i, span: DUMMY_SP }))))write!(
59            f,
60            "{}",
61            join_path_idents(self.segments.iter().map(|i| Ident { name: *i, span: DUMMY_SP }))
62        )
63    }
64}
65
66#[derive(#[automatically_derived]
impl ::core::clone::Clone for AttrItem {
    #[inline]
    fn clone(&self) -> AttrItem {
        AttrItem {
            path: ::core::clone::Clone::clone(&self.path),
            args: ::core::clone::Clone::clone(&self.args),
            id: ::core::clone::Clone::clone(&self.id),
            style: ::core::clone::Clone::clone(&self.style),
            span: ::core::clone::Clone::clone(&self.span),
        }
    }
}Clone, #[automatically_derived]
impl ::core::fmt::Debug for AttrItem {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field5_finish(f, "AttrItem",
            "path", &self.path, "args", &self.args, "id", &self.id, "style",
            &self.style, "span", &&self.span)
    }
}Debug, const _: () =
    {
        impl ::rustc_data_structures::stable_hash::StableHash for AttrItem {
            #[inline]
            fn stable_hash<__Hcx: ::rustc_data_structures::stable_hash::StableHashCtxt>(&self,
                __hcx: &mut __Hcx,
                __hasher:
                    &mut ::rustc_data_structures::stable_hash::StableHasher) {
                match *self {
                    AttrItem {
                        path: ref __binding_0,
                        args: ref __binding_1,
                        id: ref __binding_2,
                        style: ref __binding_3,
                        span: ref __binding_4 } => {
                        { __binding_0.stable_hash(__hcx, __hasher); }
                        { __binding_1.stable_hash(__hcx, __hasher); }
                        { __binding_2.stable_hash(__hcx, __hasher); }
                        { __binding_3.stable_hash(__hcx, __hasher); }
                        { __binding_4.stable_hash(__hcx, __hasher); }
                    }
                }
            }
        }
    };StableHash, const _: () =
    {
        impl<__E: ::rustc_span::SpanEncoder> ::rustc_serialize::Encodable<__E>
            for AttrItem {
            fn encode(&self, __encoder: &mut __E) {
                match *self {
                    AttrItem {
                        path: ref __binding_0,
                        args: ref __binding_1,
                        id: ref __binding_2,
                        style: ref __binding_3,
                        span: ref __binding_4 } => {
                        ::rustc_serialize::Encodable::<__E>::encode(__binding_0,
                            __encoder);
                        ::rustc_serialize::Encodable::<__E>::encode(__binding_1,
                            __encoder);
                        ::rustc_serialize::Encodable::<__E>::encode(__binding_2,
                            __encoder);
                        ::rustc_serialize::Encodable::<__E>::encode(__binding_3,
                            __encoder);
                        ::rustc_serialize::Encodable::<__E>::encode(__binding_4,
                            __encoder);
                    }
                }
            }
        }
    };Encodable, const _: () =
    {
        impl<__D: ::rustc_span::SpanDecoder> ::rustc_serialize::Decodable<__D>
            for AttrItem {
            fn decode(__decoder: &mut __D) -> Self {
                AttrItem {
                    path: ::rustc_serialize::Decodable::decode(__decoder),
                    args: ::rustc_serialize::Decodable::decode(__decoder),
                    id: ::rustc_serialize::Decodable::decode(__decoder),
                    style: ::rustc_serialize::Decodable::decode(__decoder),
                    span: ::rustc_serialize::Decodable::decode(__decoder),
                }
            }
        }
    };Decodable)]
67pub struct AttrItem {
68    // Not lowered to hir::Path because we have no NodeId to resolve to.
69    pub path: AttrPath,
70    pub args: AttrArgs,
71    pub id: HashIgnoredAttrId,
72    /// Denotes if the attribute decorates the following construct (outer)
73    /// or the construct this attribute is contained within (inner).
74    pub style: AttrStyle,
75    /// Span of the entire attribute
76    pub span: Span,
77}
78
79/// The derived implementation of [`StableHash`] on [`Attribute`]s shouldn't hash
80/// [`AttrId`]s. By wrapping them in this, we make sure we never do.
81#[derive(#[automatically_derived]
impl ::core::marker::Copy for HashIgnoredAttrId { }Copy, #[automatically_derived]
impl ::core::fmt::Debug for HashIgnoredAttrId {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field1_finish(f,
            "HashIgnoredAttrId", "attr_id", &&self.attr_id)
    }
}Debug, const _: () =
    {
        impl<__E: ::rustc_span::SpanEncoder> ::rustc_serialize::Encodable<__E>
            for HashIgnoredAttrId {
            fn encode(&self, __encoder: &mut __E) {
                match *self {
                    HashIgnoredAttrId { attr_id: ref __binding_0 } => {
                        ::rustc_serialize::Encodable::<__E>::encode(__binding_0,
                            __encoder);
                    }
                }
            }
        }
    };Encodable, const _: () =
    {
        impl<__D: ::rustc_span::SpanDecoder> ::rustc_serialize::Decodable<__D>
            for HashIgnoredAttrId {
            fn decode(__decoder: &mut __D) -> Self {
                HashIgnoredAttrId {
                    attr_id: ::rustc_serialize::Decodable::decode(__decoder),
                }
            }
        }
    };Decodable, #[automatically_derived]
impl ::core::clone::Clone for HashIgnoredAttrId {
    #[inline]
    fn clone(&self) -> HashIgnoredAttrId {
        let _: ::core::clone::AssertParamIsClone<AttrId>;
        *self
    }
}Clone)]
82pub struct HashIgnoredAttrId {
83    pub attr_id: AttrId,
84}
85
86impl StableHash for HashIgnoredAttrId {
87    fn stable_hash<Hcx: StableHashCtxt>(&self, _hcx: &mut Hcx, _hasher: &mut StableHasher) {
88        /* we don't hash HashIgnoredAttrId, we ignore them */
89    }
90}
91
92/// Many functions on this type have their documentation in the [`AttributeExt`] trait,
93/// since they defer their implementation directly to that trait.
94#[derive(#[automatically_derived]
impl ::core::clone::Clone for Attribute {
    #[inline]
    fn clone(&self) -> Attribute {
        match self {
            Attribute::Parsed(__self_0) =>
                Attribute::Parsed(::core::clone::Clone::clone(__self_0)),
            Attribute::Unparsed(__self_0) =>
                Attribute::Unparsed(::core::clone::Clone::clone(__self_0)),
        }
    }
}Clone, #[automatically_derived]
impl ::core::fmt::Debug for Attribute {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            Attribute::Parsed(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f, "Parsed",
                    &__self_0),
            Attribute::Unparsed(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f,
                    "Unparsed", &__self_0),
        }
    }
}Debug, const _: () =
    {
        impl<__E: ::rustc_span::SpanEncoder> ::rustc_serialize::Encodable<__E>
            for Attribute {
            fn encode(&self, __encoder: &mut __E) {
                let disc =
                    match *self {
                        Attribute::Parsed(ref __binding_0) => { 0usize }
                        Attribute::Unparsed(ref __binding_0) => { 1usize }
                    };
                ::rustc_serialize::Encoder::emit_u8(__encoder, disc as u8);
                match *self {
                    Attribute::Parsed(ref __binding_0) => {
                        ::rustc_serialize::Encodable::<__E>::encode(__binding_0,
                            __encoder);
                    }
                    Attribute::Unparsed(ref __binding_0) => {
                        ::rustc_serialize::Encodable::<__E>::encode(__binding_0,
                            __encoder);
                    }
                }
            }
        }
    };Encodable, const _: () =
    {
        impl<__D: ::rustc_span::SpanDecoder> ::rustc_serialize::Decodable<__D>
            for Attribute {
            fn decode(__decoder: &mut __D) -> Self {
                match ::rustc_serialize::Decoder::read_u8(__decoder) as usize
                    {
                    0usize => {
                        Attribute::Parsed(::rustc_serialize::Decodable::decode(__decoder))
                    }
                    1usize => {
                        Attribute::Unparsed(::rustc_serialize::Decodable::decode(__decoder))
                    }
                    n => {
                        ::core::panicking::panic_fmt(format_args!("invalid enum variant tag while decoding `Attribute`, expected 0..2, actual {0}",
                                n));
                    }
                }
            }
        }
    };Decodable, const _: () =
    {
        impl ::rustc_data_structures::stable_hash::StableHash for Attribute {
            #[inline]
            fn stable_hash<__Hcx: ::rustc_data_structures::stable_hash::StableHashCtxt>(&self,
                __hcx: &mut __Hcx,
                __hasher:
                    &mut ::rustc_data_structures::stable_hash::StableHasher) {
                ::std::mem::discriminant(self).stable_hash(__hcx, __hasher);
                match *self {
                    Attribute::Parsed(ref __binding_0) => {
                        { __binding_0.stable_hash(__hcx, __hasher); }
                    }
                    Attribute::Unparsed(ref __binding_0) => {
                        { __binding_0.stable_hash(__hcx, __hasher); }
                    }
                }
            }
        }
    };StableHash)]
95pub enum Attribute {
96    /// A parsed built-in attribute.
97    ///
98    /// Each attribute has a span connected to it. However, you must be somewhat careful using it.
99    /// That's because sometimes we merge multiple attributes together, like when an item has
100    /// multiple `repr` attributes. In this case the span might not be very useful.
101    Parsed(AttributeKind),
102
103    /// An attribute that could not be parsed, out of a token-like representation.
104    /// This is the case for custom tool attributes.
105    Unparsed(Box<AttrItem>),
106}
107
108impl Attribute {
109    pub fn get_normal_item(&self) -> &AttrItem {
110        match &self {
111            Attribute::Unparsed(normal) => &normal,
112            _ => { ::core::panicking::panic_fmt(format_args!("unexpected parsed attribute")); }panic!("unexpected parsed attribute"),
113        }
114    }
115
116    pub fn value_lit(&self) -> Option<&MetaItemLit> {
117        match &self {
118            Attribute::Unparsed(n) => match n.as_ref() {
119                AttrItem { args: AttrArgs::Eq { eq_span: _, expr }, .. } => Some(expr),
120                _ => None,
121            },
122            _ => None,
123        }
124    }
125
126    pub fn is_parsed_attr(&self) -> bool {
127        match self {
128            Attribute::Parsed(_) => true,
129            Attribute::Unparsed(_) => false,
130        }
131    }
132
133    pub fn is_prefix_attr_for_suggestions(&self) -> bool {
134        match self {
135            Attribute::Unparsed(attr) => attr.span.desugaring_kind().is_none(),
136            // Other parsed attributes that can appear on expressions originate from source and
137            // should make suggestions treat the expression like a prefixed form.
138            Attribute::Parsed(_) => true,
139        }
140    }
141}
142
143impl AttributeExt for Attribute {
144    #[inline]
145    fn id(&self) -> AttrId {
146        match &self {
147            Attribute::Unparsed(u) => u.id.attr_id,
148            _ => ::core::panicking::panic("explicit panic")panic!(),
149        }
150    }
151
152    #[inline]
153    fn meta_item_list(&self) -> Option<ThinVec<ast::MetaItemInner>> {
154        match &self {
155            Attribute::Unparsed(n) => match n.as_ref() {
156                AttrItem { args: AttrArgs::Delimited(d), .. } => {
157                    ast::MetaItemKind::list_from_tokens(d.tokens.clone())
158                }
159                _ => None,
160            },
161            _ => None,
162        }
163    }
164
165    #[inline]
166    fn value_str(&self) -> Option<Symbol> {
167        self.value_lit().and_then(|x| x.value_as_str())
168    }
169
170    #[inline]
171    fn value_span(&self) -> Option<Span> {
172        self.value_lit().map(|i| i.span)
173    }
174
175    /// For a single-segment attribute, returns its name; otherwise, returns `None`.
176    #[inline]
177    fn name(&self) -> Option<Symbol> {
178        match &self {
179            Attribute::Unparsed(n) => {
180                if let [ident] = n.path.segments.as_ref() {
181                    Some(*ident)
182                } else {
183                    None
184                }
185            }
186            _ => None,
187        }
188    }
189
190    #[inline]
191    fn path_matches(&self, name: &[Symbol]) -> bool {
192        match &self {
193            Attribute::Unparsed(n) => n.path.segments.iter().eq(name),
194            _ => false,
195        }
196    }
197
198    #[inline]
199    fn is_doc_comment(&self) -> Option<Span> {
200        if let Attribute::Parsed(AttributeKind::DocComment { span, .. }) = self {
201            Some(*span)
202        } else {
203            None
204        }
205    }
206
207    #[inline]
208    fn span(&self) -> Span {
209        match &self {
210            Attribute::Unparsed(u) => u.span,
211            // FIXME: should not be needed anymore when all attrs are parsed
212            Attribute::Parsed(AttributeKind::DocComment { span, .. }) => *span,
213            Attribute::Parsed(AttributeKind::Deprecated { span, .. }) => *span,
214            Attribute::Parsed(AttributeKind::CfgTrace(cfgs)) => cfgs[0].1,
215            a => {
    ::core::panicking::panic_fmt(format_args!("can\'t get the span of an arbitrary parsed attribute: {0:?}",
            a));
}panic!("can't get the span of an arbitrary parsed attribute: {a:?}"),
216        }
217    }
218
219    #[inline]
220    fn is_word(&self) -> bool {
221        match &self {
222            Attribute::Unparsed(n) => {
223                #[allow(non_exhaustive_omitted_patterns)] match n.args {
    AttrArgs::Empty => true,
    _ => false,
}matches!(n.args, AttrArgs::Empty)
224            }
225            _ => false,
226        }
227    }
228
229    #[inline]
230    fn symbol_path(&self) -> Option<SmallVec<[Symbol; 1]>> {
231        match &self {
232            Attribute::Unparsed(n) => Some(n.path.segments.iter().copied().collect()),
233            _ => None,
234        }
235    }
236
237    fn path_span(&self) -> Option<Span> {
238        match &self {
239            Attribute::Unparsed(attr) => Some(attr.path.span),
240            Attribute::Parsed(_) => None,
241        }
242    }
243
244    #[inline]
245    fn doc_str(&self) -> Option<Symbol> {
246        match &self {
247            Attribute::Parsed(AttributeKind::DocComment { comment, .. }) => Some(*comment),
248            _ => None,
249        }
250    }
251
252    fn is_automatically_derived_attr(&self) -> bool {
253        #[allow(non_exhaustive_omitted_patterns)] match self {
    Attribute::Parsed(AttributeKind::AutomaticallyDerived) => true,
    _ => false,
}matches!(self, Attribute::Parsed(AttributeKind::AutomaticallyDerived))
254    }
255
256    #[inline]
257    fn doc_str_and_fragment_kind(&self) -> Option<(Symbol, DocFragmentKind)> {
258        match &self {
259            Attribute::Parsed(AttributeKind::DocComment { kind, comment, .. }) => {
260                Some((*comment, *kind))
261            }
262            _ => None,
263        }
264    }
265
266    fn doc_resolution_scope(&self) -> Option<AttrStyle> {
267        match self {
268            Attribute::Parsed(AttributeKind::DocComment { style, .. }) => Some(*style),
269            Attribute::Unparsed(attr) if self.has_name(sym::doc) && self.value_str().is_some() => {
270                Some(attr.style)
271            }
272            _ => None,
273        }
274    }
275
276    fn is_proc_macro_attr(&self) -> bool {
277        #[allow(non_exhaustive_omitted_patterns)] match self {
    Attribute::Parsed(AttributeKind::ProcMacro |
        AttributeKind::ProcMacroAttribute | AttributeKind::ProcMacroDerive {
        .. }) => true,
    _ => false,
}matches!(
278            self,
279            Attribute::Parsed(
280                AttributeKind::ProcMacro
281                    | AttributeKind::ProcMacroAttribute
282                    | AttributeKind::ProcMacroDerive { .. }
283            )
284        )
285    }
286
287    fn is_doc_hidden(&self) -> bool {
288        #[allow(non_exhaustive_omitted_patterns)] match self {
    Attribute::Parsed(AttributeKind::Doc(d)) if d.hidden.is_some() => true,
    _ => false,
}matches!(self, Attribute::Parsed(AttributeKind::Doc(d)) if d.hidden.is_some())
289    }
290
291    fn is_doc_keyword_or_attribute(&self) -> bool {
292        #[allow(non_exhaustive_omitted_patterns)] match self {
    Attribute::Parsed(AttributeKind::Doc(d)) if
        d.attribute.is_some() || d.keyword.is_some() => true,
    _ => false,
}matches!(self, Attribute::Parsed(AttributeKind::Doc(d)) if d.attribute.is_some() || d.keyword.is_some())
293    }
294
295    fn is_rustc_doc_primitive(&self) -> bool {
296        #[allow(non_exhaustive_omitted_patterns)] match self {
    Attribute::Parsed(AttributeKind::RustcDocPrimitive(..)) => true,
    _ => false,
}matches!(self, Attribute::Parsed(AttributeKind::RustcDocPrimitive(..)))
297    }
298}
299
300// FIXME(fn_delegation): use function delegation instead of manually forwarding
301impl Attribute {
302    #[inline]
303    pub fn id(&self) -> AttrId {
304        AttributeExt::id(self)
305    }
306
307    #[inline]
308    pub fn name(&self) -> Option<Symbol> {
309        AttributeExt::name(self)
310    }
311
312    #[inline]
313    pub fn meta_item_list(&self) -> Option<ThinVec<MetaItemInner>> {
314        AttributeExt::meta_item_list(self)
315    }
316
317    #[inline]
318    pub fn value_str(&self) -> Option<Symbol> {
319        AttributeExt::value_str(self)
320    }
321
322    #[inline]
323    pub fn value_span(&self) -> Option<Span> {
324        AttributeExt::value_span(self)
325    }
326
327    #[inline]
328    pub fn path_matches(&self, name: &[Symbol]) -> bool {
329        AttributeExt::path_matches(self, name)
330    }
331
332    #[inline]
333    pub fn is_doc_comment(&self) -> Option<Span> {
334        AttributeExt::is_doc_comment(self)
335    }
336
337    #[inline]
338    pub fn has_name(&self, name: Symbol) -> bool {
339        AttributeExt::has_name(self, name)
340    }
341
342    #[inline]
343    pub fn has_any_name(&self, names: &[Symbol]) -> bool {
344        AttributeExt::has_any_name(self, names)
345    }
346
347    #[inline]
348    pub fn span(&self) -> Span {
349        AttributeExt::span(self)
350    }
351
352    #[inline]
353    pub fn is_word(&self) -> bool {
354        AttributeExt::is_word(self)
355    }
356
357    #[inline]
358    pub fn path(&self) -> SmallVec<[Symbol; 1]> {
359        AttributeExt::path(self)
360    }
361
362    #[inline]
363    pub fn doc_str(&self) -> Option<Symbol> {
364        AttributeExt::doc_str(self)
365    }
366
367    #[inline]
368    pub fn is_proc_macro_attr(&self) -> bool {
369        AttributeExt::is_proc_macro_attr(self)
370    }
371
372    #[inline]
373    pub fn doc_str_and_fragment_kind(&self) -> Option<(Symbol, DocFragmentKind)> {
374        AttributeExt::doc_str_and_fragment_kind(self)
375    }
376}