968 lines · 32.8 KB · Rust
RawDownload
// SPDX-License-Identifier: Apache-2.0 OR MIT #[cfg(feature = "parsing")]use crate::error::Result;use crate::expr::Expr;use crate::generics::TypeParamBound;use crate::ident::Ident;use crate::lifetime::Lifetime;use crate::punctuated::Punctuated;use crate::token;use crate::ty::{ReturnType, Type}; ast_struct! {    /// A path at which a named item is exported (e.g. `std::collections::HashMap`).    #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]    pub struct Path {        pub leading_colon: Option<Token![::]>,        pub segments: Punctuated<PathSegment, Token![::]>,    }} impl<T> From<T> for Pathwhere    T: Into<PathSegment>,{    fn from(segment: T) -> Self {        let mut path = Path {            leading_colon: None,            segments: Punctuated::new(),        };        path.segments.push_value(segment.into());        path    }} impl Path {    /// Determines whether this is a path of length 1 equal to the given    /// ident.    ///    /// For them to compare equal, it must be the case that:    ///    /// - the path has no leading colon,    /// - the number of path segments is 1,    /// - the first path segment has no angle bracketed or parenthesized    ///   path arguments, and    /// - the ident of the first path segment is equal to the given one.    ///    /// # Example    ///    /// ```    /// use proc_macro2::TokenStream;    /// use syn::{Attribute, Error, Meta, Result};    ///    /// fn get_serde_meta_item(attr: &Attribute) -> Result<Option<&TokenStream>> {    ///     if attr.path().is_ident("serde") {    ///         match &attr.meta {    ///             Meta::List(meta) => Ok(Some(&meta.tokens)),    ///             bad => Err(Error::new_spanned(bad, "unrecognized attribute")),    ///         }    ///     } else {    ///         Ok(None)    ///     }    /// }    /// ```    pub fn is_ident<I>(&self, ident: &I) -> bool    where        I: ?Sized,        Ident: PartialEq<I>,    {        match self.get_ident() {            Some(id) => id == ident,            None => false,        }    }     /// If this path consists of a single ident, returns the ident.    ///    /// A path is considered an ident if:    ///    /// - the path has no leading colon,    /// - the number of path segments is 1, and    /// - the first path segment has no angle bracketed or parenthesized    ///   path arguments.    pub fn get_ident(&self) -> Option<&Ident> {        if self.leading_colon.is_none()            && self.segments.len() == 1            && self.segments[0].arguments.is_none()        {            Some(&self.segments[0].ident)        } else {            None        }    }     /// An error if this path is not a single ident, as defined in `get_ident`.    #[cfg(feature = "parsing")]    #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]    pub fn require_ident(&self) -> Result<&Ident> {        self.get_ident().ok_or_else(|| {            crate::error::new2(                self.segments.first().unwrap().ident.span(),                self.segments.last().unwrap().ident.span(),                "expected this path to be an identifier",            )        })    }} ast_struct! {    /// A segment of a path together with any path arguments on that segment.    #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]    pub struct PathSegment {        pub ident: Ident,        pub arguments: PathArguments,    }} impl<T> From<T> for PathSegmentwhere    T: Into<Ident>,{    fn from(ident: T) -> Self {        PathSegment {            ident: ident.into(),            arguments: PathArguments::None,        }    }} ast_enum! {    /// Angle bracketed or parenthesized arguments of a path segment.    ///    /// ## Angle bracketed    ///    /// The `<'a, T>` in `std::slice::iter<'a, T>`.    ///    /// ## Parenthesized    ///    /// The `(A, B) -> C` in `Fn(A, B) -> C`.    #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]    pub enum PathArguments {        None,        /// The `<'a, T>` in `std::slice::iter<'a, T>`.        AngleBracketed(AngleBracketedGenericArguments),        /// The `(A, B) -> C` in `Fn(A, B) -> C`.        Parenthesized(ParenthesizedGenericArguments),    }} impl Default for PathArguments {    fn default() -> Self {        PathArguments::None    }} impl PathArguments {    pub fn is_empty(&self) -> bool {        match self {            PathArguments::None => true,            PathArguments::AngleBracketed(bracketed) => bracketed.args.is_empty(),            PathArguments::Parenthesized(_) => false,        }    }     pub fn is_none(&self) -> bool {        match self {            PathArguments::None => true,            PathArguments::AngleBracketed(_) | PathArguments::Parenthesized(_) => false,        }    }} ast_enum! {    /// An individual generic argument, like `'a`, `T`, or `Item = T`.    #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]    #[non_exhaustive]    pub enum GenericArgument {        /// A lifetime argument.        Lifetime(Lifetime),        /// A type argument.        Type(Type),        /// A const expression. Must be inside of a block.        ///        /// NOTE: Identity expressions are represented as Type arguments, as        /// they are indistinguishable syntactically.        Const(Expr),        /// A binding (equality constraint) on an associated type: the `Item =        /// u8` in `Iterator<Item = u8>`.        AssocType(AssocType),        /// An equality constraint on an associated constant: the `PANIC =        /// false` in `Trait<PANIC = false>`.        AssocConst(AssocConst),        /// An associated type bound: `Iterator<Item: Display>`.        Constraint(Constraint),    }} ast_struct! {    /// Angle bracketed arguments of a path segment: the `<K, V>` in `HashMap<K,    /// V>`.    #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]    pub struct AngleBracketedGenericArguments {        pub colon2_token: Option<Token![::]>,        pub lt_token: Token![<],        pub args: Punctuated<GenericArgument, Token![,]>,        pub gt_token: Token![>],    }} ast_struct! {    /// A binding (equality constraint) on an associated type: the `Item = u8`    /// in `Iterator<Item = u8>`.    #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]    pub struct AssocType {        pub ident: Ident,        pub generics: Option<AngleBracketedGenericArguments>,        pub eq_token: Token![=],        pub ty: Type,    }} ast_struct! {    /// An equality constraint on an associated constant: the `PANIC = false` in    /// `Trait<PANIC = false>`.    #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]    pub struct AssocConst {        pub ident: Ident,        pub generics: Option<AngleBracketedGenericArguments>,        pub eq_token: Token![=],        pub value: Expr,    }} ast_struct! {    /// An associated type bound: `Iterator<Item: Display>`.    #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]    pub struct Constraint {        pub ident: Ident,        pub generics: Option<AngleBracketedGenericArguments>,        pub colon_token: Token![:],        pub bounds: Punctuated<TypeParamBound, Token![+]>,    }} ast_struct! {    /// Arguments of a function path segment: the `(A, B) -> C` in `Fn(A,B) ->    /// C`.    #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]    pub struct ParenthesizedGenericArguments {        pub paren_token: token::Paren,        /// `(A, B)`        pub inputs: Punctuated<Type, Token![,]>,        /// `C`        pub output: ReturnType,    }} ast_struct! {    /// The explicit Self type in a qualified path: the `T` in `<T as    /// Display>::fmt`.    ///    /// The actual path, including the trait and the associated item, is stored    /// separately. The `position` field represents the index of the associated    /// item qualified with this Self type.    ///    /// ```text    /// <Vec<T> as a::b::Trait>::AssociatedItem    ///  ^~~~~~    ~~~~~~~~~~~~~~^    ///  ty        position = 3    ///    /// <Vec<T>>::AssociatedItem    ///  ^~~~~~   ^    ///  ty       position = 0    /// ```    #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]    pub struct QSelf {        pub lt_token: Token![<],        pub ty: Box<Type>,        pub position: usize,        pub as_token: Option<Token![as]>,        pub gt_token: Token![>],    }} #[cfg(feature = "parsing")]pub(crate) mod parsing {    use crate::error::Result;    #[cfg(feature = "full")]    use crate::expr::ExprBlock;    use crate::expr::{Expr, ExprPath};    use crate::ext::IdentExt as _;    #[cfg(feature = "full")]    use crate::generics::TypeParamBound;    use crate::ident::Ident;    use crate::lifetime::Lifetime;    use crate::lit::Lit;    use crate::parse::{Parse, ParseStream};    #[cfg(feature = "full")]    use crate::path::Constraint;    use crate::path::{        AngleBracketedGenericArguments, AssocConst, AssocType, GenericArgument,        ParenthesizedGenericArguments, Path, PathArguments, PathSegment, QSelf,    };    use crate::punctuated::Punctuated;    use crate::token;    use crate::ty::{ReturnType, Type};    #[cfg(not(feature = "full"))]    use crate::verbatim;     #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]    impl Parse for Path {        fn parse(input: ParseStream) -> Result<Self> {            Self::parse_helper(input, false)        }    }     #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]    impl Parse for GenericArgument {        fn parse(input: ParseStream) -> Result<Self> {            if input.peek(Lifetime) && !input.peek2(Token![+]) {                return Ok(GenericArgument::Lifetime(input.parse()?));            }             if input.peek(Lit) || input.peek(token::Brace) {                return const_argument(input).map(GenericArgument::Const);            }             let mut argument: Type = input.parse()?;             match argument {                Type::Path(mut ty)                    if ty.qself.is_none()                        && ty.path.leading_colon.is_none()                        && ty.path.segments.len() == 1                        && match &ty.path.segments[0].arguments {                            PathArguments::None | PathArguments::AngleBracketed(_) => true,                            PathArguments::Parenthesized(_) => false,                        } =>                {                    if let Some(eq_token) = input.parse::<Option<Token![=]>>()? {                        let segment = ty.path.segments.pop().unwrap().into_value();                        let ident = segment.ident;                        let generics = match segment.arguments {                            PathArguments::None => None,                            PathArguments::AngleBracketed(arguments) => Some(arguments),                            PathArguments::Parenthesized(_) => unreachable!(),                        };                        return if input.peek(Lit) || input.peek(token::Brace) {                            Ok(GenericArgument::AssocConst(AssocConst {                                ident,                                generics,                                eq_token,                                value: const_argument(input)?,                            }))                        } else {                            Ok(GenericArgument::AssocType(AssocType {                                ident,                                generics,                                eq_token,                                ty: input.parse()?,                            }))                        };                    }                     #[cfg(feature = "full")]                    if let Some(colon_token) = input.parse::<Option<Token![:]>>()? {                        let segment = ty.path.segments.pop().unwrap().into_value();                        return Ok(GenericArgument::Constraint(Constraint {                            ident: segment.ident,                            generics: match segment.arguments {                                PathArguments::None => None,                                PathArguments::AngleBracketed(arguments) => Some(arguments),                                PathArguments::Parenthesized(_) => unreachable!(),                            },                            colon_token,                            bounds: {                                let mut bounds = Punctuated::new();                                loop {                                    if input.peek(Token![,]) || input.peek(Token![>]) {                                        break;                                    }                                    bounds.push_value({                                        let allow_precise_capture = false;                                        let allow_const = true;                                        TypeParamBound::parse_single(                                            input,                                            allow_precise_capture,                                            allow_const,                                        )?                                    });                                    if !input.peek(Token![+]) {                                        break;                                    }                                    let punct: Token![+] = input.parse()?;                                    bounds.push_punct(punct);                                }                                bounds                            },                        }));                    }                     argument = Type::Path(ty);                }                _ => {}            }             Ok(GenericArgument::Type(argument))        }    }     pub(crate) fn const_argument(input: ParseStream) -> Result<Expr> {        let lookahead = input.lookahead1();         if input.peek(Lit) {            let lit = input.parse()?;            return Ok(Expr::Lit(lit));        }         if input.peek(Ident) {            let ident: Ident = input.parse()?;            return Ok(Expr::Path(ExprPath {                attrs: Vec::new(),                qself: None,                path: Path::from(ident),            }));        }         if input.peek(token::Brace) {            #[cfg(feature = "full")]            {                let block: ExprBlock = input.parse()?;                return Ok(Expr::Block(block));            }             #[cfg(not(feature = "full"))]            {                let begin = input.fork();                let content;                braced!(content in input);                content.parse::<Expr>()?;                let verbatim = verbatim::between(&begin, input);                return Ok(Expr::Verbatim(verbatim));            }        }         Err(lookahead.error())    }     impl AngleBracketedGenericArguments {        /// Parse `::<…>` with mandatory leading `::`.        ///        /// The ordinary [`Parse`] impl for `AngleBracketedGenericArguments`        /// parses optional leading `::`.        #[cfg(feature = "full")]        #[cfg_attr(docsrs, doc(cfg(all(feature = "parsing", feature = "full"))))]        pub fn parse_turbofish(input: ParseStream) -> Result<Self> {            let colon2_token: Token![::] = input.parse()?;            Self::do_parse(Some(colon2_token), input)        }         pub(crate) fn do_parse(            colon2_token: Option<Token![::]>,            input: ParseStream,        ) -> Result<Self> {            Ok(AngleBracketedGenericArguments {                colon2_token,                lt_token: input.parse()?,                args: {                    let mut args = Punctuated::new();                    loop {                        if input.peek(Token![>]) {                            break;                        }                        let value: GenericArgument = input.parse()?;                        args.push_value(value);                        if input.peek(Token![>]) {                            break;                        }                        let punct: Token![,] = input.parse()?;                        args.push_punct(punct);                    }                    args                },                gt_token: input.parse()?,            })        }    }     #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]    impl Parse for AngleBracketedGenericArguments {        fn parse(input: ParseStream) -> Result<Self> {            let colon2_token: Option<Token![::]> = input.parse()?;            Self::do_parse(colon2_token, input)        }    }     #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]    impl Parse for ParenthesizedGenericArguments {        fn parse(input: ParseStream) -> Result<Self> {            let content;

Lines 1–500 of 968.