838 lines · 27.7 KB · Rust
RawDownload
// SPDX-License-Identifier: Apache-2.0 OR MIT #[cfg(feature = "parsing")]use crate::error::Error;#[cfg(feature = "parsing")]use crate::error::Result;use crate::expr::Expr;use crate::mac::MacroDelimiter;#[cfg(feature = "parsing")]use crate::meta::{self, ParseNestedMeta};#[cfg(feature = "parsing")]use crate::parse::{Parse, ParseStream, Parser};use crate::path::Path;use crate::token;use proc_macro2::TokenStream;#[cfg(feature = "printing")]use std::iter;#[cfg(feature = "printing")]use std::slice; ast_struct! {    /// An attribute, like `#[repr(transparent)]`.    ///    /// <br>    ///    /// # Syntax    ///    /// Rust has six types of attributes.    ///    /// - Outer attributes like `#[repr(transparent)]`. These appear outside or    ///   in front of the item they describe.    ///    /// - Inner attributes like `#![feature(proc_macro)]`. These appear inside    ///   of the item they describe, usually a module.    ///    /// - Outer one-line doc comments like `/// Example`.    ///    /// - Inner one-line doc comments like `//! Please file an issue`.    ///    /// - Outer documentation blocks `/** Example */`.    ///    /// - Inner documentation blocks `/*! Please file an issue */`.    ///    /// The `style` field of type `AttrStyle` distinguishes whether an attribute    /// is outer or inner.    ///    /// Every attribute has a `path` that indicates the intended interpretation    /// of the rest of the attribute's contents. The path and the optional    /// additional contents are represented together in the `meta` field of the    /// attribute in three possible varieties:    ///    /// - Meta::Path &mdash; attributes whose information content conveys just a    ///   path, for example the `#[test]` attribute.    ///    /// - Meta::List &mdash; attributes that carry arbitrary tokens after the    ///   path, surrounded by a delimiter (parenthesis, bracket, or brace). For    ///   example `#[derive(Copy)]` or `#[precondition(x < 5)]`.    ///    /// - Meta::NameValue &mdash; attributes with an `=` sign after the path,    ///   followed by a Rust expression. For example `#[path =    ///   "sys/windows.rs"]`.    ///    /// All doc comments are represented in the NameValue style with a path of    /// "doc", as this is how they are processed by the compiler and by    /// `macro_rules!` macros.    ///    /// ```text    /// #[derive(Copy, Clone)]    ///   ~~~~~~Path    ///   ^^^^^^^^^^^^^^^^^^^Meta::List    ///    /// #[path = "sys/windows.rs"]    ///   ~~~~Path    ///   ^^^^^^^^^^^^^^^^^^^^^^^Meta::NameValue    ///    /// #[test]    ///   ^^^^Meta::Path    /// ```    ///    /// <br>    ///    /// # Parsing from tokens to Attribute    ///    /// This type does not implement the [`Parse`] trait and thus cannot be    /// parsed directly by [`ParseStream::parse`]. Instead use    /// [`ParseStream::call`] with one of the two parser functions    /// [`Attribute::parse_outer`] or [`Attribute::parse_inner`] depending on    /// which you intend to parse.    ///    /// [`Parse`]: crate::parse::Parse    /// [`ParseStream::parse`]: crate::parse::ParseBuffer::parse    /// [`ParseStream::call`]: crate::parse::ParseBuffer::call    ///    /// ```    /// use syn::{Attribute, Ident, Result, Token};    /// use syn::parse::{Parse, ParseStream};    ///    /// // Parses a unit struct with attributes.    /// //    /// //     #[path = "s.tmpl"]    /// //     struct S;    /// struct UnitStruct {    ///     attrs: Vec<Attribute>,    ///     struct_token: Token![struct],    ///     name: Ident,    ///     semi_token: Token![;],    /// }    ///    /// impl Parse for UnitStruct {    ///     fn parse(input: ParseStream) -> Result<Self> {    ///         Ok(UnitStruct {    ///             attrs: input.call(Attribute::parse_outer)?,    ///             struct_token: input.parse()?,    ///             name: input.parse()?,    ///             semi_token: input.parse()?,    ///         })    ///     }    /// }    /// ```    ///    /// <p><br></p>    ///    /// # Parsing from Attribute to structured arguments    ///    /// The grammar of attributes in Rust is very flexible, which makes the    /// syntax tree not that useful on its own. In particular, arguments of the    /// `Meta::List` variety of attribute are held in an arbitrary `tokens:    /// TokenStream`. Macros are expected to check the `path` of the attribute,    /// decide whether they recognize it, and then parse the remaining tokens    /// according to whatever grammar they wish to require for that kind of    /// attribute. Use [`parse_args()`] to parse those tokens into the expected    /// data structure.    ///    /// [`parse_args()`]: Attribute::parse_args    ///    /// <p><br></p>    ///    /// # Doc comments    ///    /// The compiler transforms doc comments, such as `/// comment` and `/*!    /// comment */`, into attributes before macros are expanded. Each comment is    /// expanded into an attribute of the form `#[doc = r"comment"]`.    ///    /// As an example, the following `mod` items are expanded identically:    ///    /// ```    /// # use syn::{ItemMod, parse_quote};    /// let doc: ItemMod = parse_quote! {    ///     /// Single line doc comments    ///     /// We write so many!    ///     /**    ///      * Multi-line comments...    ///      * May span many lines    ///      */    ///     mod example {    ///         //! Of course, they can be inner too    ///         /*! And fit in a single line */    ///     }    /// };    /// let attr: ItemMod = parse_quote! {    ///     #[doc = r" Single line doc comments"]    ///     #[doc = r" We write so many!"]    ///     #[doc = r"    ///      * Multi-line comments...    ///      * May span many lines    ///      "]    ///     mod example {    ///         #![doc = r" Of course, they can be inner too"]    ///         #![doc = r" And fit in a single line "]    ///     }    /// };    /// assert_eq!(doc, attr);    /// ```    #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]    pub struct Attribute {        pub pound_token: Token![#],        pub style: AttrStyle,        pub bracket_token: token::Bracket,        pub meta: Meta,    }} impl Attribute {    /// Returns the path that identifies the interpretation of this attribute.    ///    /// For example this would return the `test` in `#[test]`, the `derive` in    /// `#[derive(Copy)]`, and the `path` in `#[path = "sys/windows.rs"]`.    pub fn path(&self) -> &Path {        self.meta.path()    }     /// Parse the arguments to the attribute as a syntax tree.    ///    /// This is similar to pulling out the `TokenStream` from `Meta::List` and    /// doing `syn::parse2::<T>(meta_list.tokens)`, except that using    /// `parse_args` the error message has a more useful span when `tokens` is    /// empty.    ///    /// The surrounding delimiters are *not* included in the input to the    /// parser.    ///    /// ```text    /// #[my_attr(value < 5)]    ///           ^^^^^^^^^ what gets parsed    /// ```    ///    /// # Example    ///    /// ```    /// use syn::{parse_quote, Attribute, Expr};    ///    /// let attr: Attribute = parse_quote! {    ///     #[precondition(value < 5)]    /// };    ///    /// if attr.path().is_ident("precondition") {    ///     let precondition: Expr = attr.parse_args()?;    ///     // ...    /// }    /// # anyhow::Ok(())    /// ```    #[cfg(feature = "parsing")]    #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]    pub fn parse_args<T: Parse>(&self) -> Result<T> {        self.parse_args_with(T::parse)    }     /// Parse the arguments to the attribute using the given parser.    ///    /// # Example    ///    /// ```    /// use syn::{parse_quote, Attribute};    ///    /// let attr: Attribute = parse_quote! {    ///     #[inception { #[brrrrrrraaaaawwwwrwrrrmrmrmmrmrmmmmm] }]    /// };    ///    /// let bwom = attr.parse_args_with(Attribute::parse_outer)?;    ///    /// // Attribute does not have a Parse impl, so we couldn't directly do:    /// // let bwom: Attribute = attr.parse_args()?;    /// # anyhow::Ok(())    /// ```    #[cfg(feature = "parsing")]    #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]    pub fn parse_args_with<F: Parser>(&self, parser: F) -> Result<F::Output> {        match &self.meta {            Meta::Path(path) => Err(crate::error::new2(                path.segments.first().unwrap().ident.span(),                path.segments.last().unwrap().ident.span(),                format!(                    "expected attribute arguments in parentheses: {}[{}(...)]",                    parsing::DisplayAttrStyle(&self.style),                    parsing::DisplayPath(path),                ),            )),            Meta::NameValue(meta) => Err(Error::new(                meta.eq_token.span,                format_args!(                    "expected parentheses: {}[{}(...)]",                    parsing::DisplayAttrStyle(&self.style),                    parsing::DisplayPath(&meta.path),                ),            )),            Meta::List(meta) => meta.parse_args_with(parser),        }    }     /// Parse the arguments to the attribute, expecting it to follow the    /// conventional structure used by most of Rust's built-in attributes.    ///    /// The [*Meta Item Attribute Syntax*][syntax] section in the Rust reference    /// explains the convention in more detail. Not all attributes follow this    /// convention, so [`parse_args()`][Self::parse_args] is available if you    /// need to parse arbitrarily goofy attribute syntax.    ///    /// [syntax]: https://doc.rust-lang.org/reference/attributes.html#meta-item-attribute-syntax    ///    /// # Example    ///    /// We'll parse a struct, and then parse some of Rust's `#[repr]` attribute    /// syntax.    ///    /// ```    /// use syn::{parenthesized, parse_quote, token, ItemStruct, LitInt};    ///    /// let input: ItemStruct = parse_quote! {    ///     #[repr(C, align(4))]    ///     pub struct MyStruct(u16, u32);    /// };    ///    /// let mut repr_c = false;    /// let mut repr_transparent = false;    /// let mut repr_align = None::<usize>;    /// let mut repr_packed = None::<usize>;    /// for attr in &input.attrs {    ///     if attr.path().is_ident("repr") {    ///         attr.parse_nested_meta(|meta| {    ///             // #[repr(C)]    ///             if meta.path.is_ident("C") {    ///                 repr_c = true;    ///                 return Ok(());    ///             }    ///    ///             // #[repr(transparent)]    ///             if meta.path.is_ident("transparent") {    ///                 repr_transparent = true;    ///                 return Ok(());    ///             }    ///    ///             // #[repr(align(N))]    ///             if meta.path.is_ident("align") {    ///                 let content;    ///                 parenthesized!(content in meta.input);    ///                 let lit: LitInt = content.parse()?;    ///                 let n: usize = lit.base10_parse()?;    ///                 repr_align = Some(n);    ///                 return Ok(());    ///             }    ///    ///             // #[repr(packed)] or #[repr(packed(N))], omitted N means 1    ///             if meta.path.is_ident("packed") {    ///                 if meta.input.peek(token::Paren) {    ///                     let content;    ///                     parenthesized!(content in meta.input);    ///                     let lit: LitInt = content.parse()?;    ///                     let n: usize = lit.base10_parse()?;    ///                     repr_packed = Some(n);    ///                 } else {    ///                     repr_packed = Some(1);    ///                 }    ///                 return Ok(());    ///             }    ///    ///             Err(meta.error("unrecognized repr"))    ///         })?;    ///     }    /// }    /// # anyhow::Ok(())    /// ```    ///    /// # Alternatives    ///    /// In some cases, for attributes which have nested layers of structured    /// content, the following less flexible approach might be more convenient:    ///    /// ```    /// # use syn::{parse_quote, ItemStruct};    /// #    /// # let input: ItemStruct = parse_quote! {    /// #     #[repr(C, align(4))]    /// #     pub struct MyStruct(u16, u32);    /// # };    /// #    /// use syn::punctuated::Punctuated;    /// use syn::{parenthesized, token, Error, LitInt, Meta, Token};    ///    /// let mut repr_c = false;    /// let mut repr_transparent = false;    /// let mut repr_align = None::<usize>;    /// let mut repr_packed = None::<usize>;    /// for attr in &input.attrs {    ///     if attr.path().is_ident("repr") {    ///         let nested = attr.parse_args_with(Punctuated::<Meta, Token![,]>::parse_terminated)?;    ///         for meta in nested {    ///             match meta {    ///                 // #[repr(C)]    ///                 Meta::Path(path) if path.is_ident("C") => {    ///                     repr_c = true;    ///                 }    ///    ///                 // #[repr(align(N))]    ///                 Meta::List(meta) if meta.path.is_ident("align") => {    ///                     let lit: LitInt = meta.parse_args()?;    ///                     let n: usize = lit.base10_parse()?;    ///                     repr_align = Some(n);    ///                 }    ///    ///                 /* ... */    ///    ///                 _ => {    ///                     return Err(Error::new_spanned(meta, "unrecognized repr"));    ///                 }    ///             }    ///         }    ///     }    /// }    /// # Ok(())    /// ```    #[cfg(feature = "parsing")]    #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]    pub fn parse_nested_meta(        &self,        logic: impl FnMut(ParseNestedMeta) -> Result<()>,    ) -> Result<()> {        self.parse_args_with(meta::parser(logic))    }     /// Parses zero or more outer attributes from the stream.    ///    /// # Example    ///    /// See    /// [*Parsing from tokens to Attribute*](#parsing-from-tokens-to-attribute).    #[cfg(feature = "parsing")]    #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]    pub fn parse_outer(input: ParseStream) -> Result<Vec<Self>> {        let mut attrs = Vec::new();        while input.peek(Token![#]) {            attrs.push(input.call(parsing::single_parse_outer)?);        }        Ok(attrs)    }     /// Parses zero or more inner attributes from the stream.    ///    /// # Example    ///    /// See    /// [*Parsing from tokens to Attribute*](#parsing-from-tokens-to-attribute).    #[cfg(feature = "parsing")]    #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]    pub fn parse_inner(input: ParseStream) -> Result<Vec<Self>> {        let mut attrs = Vec::new();        parsing::parse_inner(input, &mut attrs)?;        Ok(attrs)    }} ast_enum! {    /// Distinguishes between attributes that decorate an item and attributes    /// that are contained within an item.    ///    /// # Outer attributes    ///    /// - `#[repr(transparent)]`    /// - `/// # Example`    /// - `/** Please file an issue */`    ///    /// # Inner attributes    ///    /// - `#![feature(proc_macro)]`    /// - `//! # Example`    /// - `/*! Please file an issue */`    #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]    pub enum AttrStyle {        Outer,        Inner(Token![!]),    }} ast_enum! {    /// Content of a compile-time structured attribute.    ///    /// ## Path    ///    /// A meta path is like the `test` in `#[test]`.    ///    /// ## List    ///    /// A meta list is like the `derive(Copy)` in `#[derive(Copy)]`.    ///    /// ## NameValue    ///    /// A name-value meta is like the `path = "..."` in `#[path =    /// "sys/windows.rs"]`.    ///    /// # Syntax tree enum    ///    /// This type is a [syntax tree enum].    ///    /// [syntax tree enum]: crate::expr::Expr#syntax-tree-enums    #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]    pub enum Meta {        Path(Path),         /// A structured list within an attribute, like `derive(Copy, Clone)`.        List(MetaList),         /// A name-value pair within an attribute, like `feature = "nightly"`.        NameValue(MetaNameValue),    }} ast_struct! {    /// A structured list within an attribute, like `derive(Copy, Clone)`.    #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]    pub struct MetaList {        pub path: Path,        pub delimiter: MacroDelimiter,        pub tokens: TokenStream,    }} ast_struct! {    /// A name-value pair within an attribute, like `feature = "nightly"`.    #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]    pub struct MetaNameValue {        pub path: Path,

Lines 1–500 of 838.