| #![allow(clippy::uninlined_format_args)] |
| |
| #[macro_use] |
| mod macros; |
| |
| use proc_macro2::{Delimiter, Group, Ident, Span, TokenStream, TokenTree}; |
| use quote::quote; |
| use syn::{Item, ItemTrait}; |
| |
| #[test] |
| fn test_macro_variable_attr() { |
| // mimics the token stream corresponding to `$attr fn f() {}` |
| let tokens = TokenStream::from_iter([ |
| TokenTree::Group(Group::new(Delimiter::None, quote! { #[test] })), |
| TokenTree::Ident(Ident::new("fn", Span::call_site())), |
| TokenTree::Ident(Ident::new("f", Span::call_site())), |
| TokenTree::Group(Group::new(Delimiter::Parenthesis, TokenStream::new())), |
| TokenTree::Group(Group::new(Delimiter::Brace, TokenStream::new())), |
| ]); |
| |
| snapshot!(tokens as Item, @r###" |
| Item::Fn { |
| attrs: [ |
| Attribute { |
| style: AttrStyle::Outer, |
| meta: Meta::Path { |
| segments: [ |
| PathSegment { |
| ident: "test", |
| }, |
| ], |
| }, |
| }, |
| ], |
| vis: Visibility::Inherited, |
| sig: Signature { |
| ident: "f", |
| generics: Generics, |
| output: ReturnType::Default, |
| }, |
| block: Block { |
| stmts: [], |
| }, |
| } |
| "###); |
| } |
| |
| #[test] |
| fn test_negative_impl() { |
| // Rustc parses all of the following. |
| |
| #[cfg(any())] |
| impl ! {} |
| let tokens = quote! { |
| impl ! {} |
| }; |
| snapshot!(tokens as Item, @r###" |
| Item::Impl { |
| generics: Generics, |
| self_ty: Type::Never, |
| } |
| "###); |
| |
| #[cfg(any())] |
| #[rustfmt::skip] |
| impl !Trait {} |
| let tokens = quote! { |
| impl !Trait {} |
| }; |
| snapshot!(tokens as Item, @r###" |
| Item::Impl { |
| generics: Generics, |
| self_ty: Type::Verbatim(`! Trait`), |
| } |
| "###); |
| |
| #[cfg(any())] |
| impl !Trait for T {} |
| let tokens = quote! { |
| impl !Trait for T {} |
| }; |
| snapshot!(tokens as Item, @r###" |
| Item::Impl { |
| generics: Generics, |
| trait_: Some(( |
| Some, |
| Path { |
| segments: [ |
| PathSegment { |
| ident: "Trait", |
| }, |
| ], |
| }, |
| )), |
| self_ty: Type::Path { |
| path: Path { |
| segments: [ |
| PathSegment { |
| ident: "T", |
| }, |
| ], |
| }, |
| }, |
| } |
| "###); |
| |
| #[cfg(any())] |
| #[rustfmt::skip] |
| impl !! {} |
| let tokens = quote! { |
| impl !! {} |
| }; |
| snapshot!(tokens as Item, @r###" |
| Item::Impl { |
| generics: Generics, |
| self_ty: Type::Verbatim(`! !`), |
| } |
| "###); |
| } |
| |
| #[test] |
| fn test_macro_variable_impl() { |
| // mimics the token stream corresponding to `impl $trait for $ty {}` |
| let tokens = TokenStream::from_iter([ |
| TokenTree::Ident(Ident::new("impl", Span::call_site())), |
| TokenTree::Group(Group::new(Delimiter::None, quote!(Trait))), |
| TokenTree::Ident(Ident::new("for", Span::call_site())), |
| TokenTree::Group(Group::new(Delimiter::None, quote!(Type))), |
| TokenTree::Group(Group::new(Delimiter::Brace, TokenStream::new())), |
| ]); |
| |
| snapshot!(tokens as Item, @r###" |
| Item::Impl { |
| generics: Generics, |
| trait_: Some(( |
| None, |
| Path { |
| segments: [ |
| PathSegment { |
| ident: "Trait", |
| }, |
| ], |
| }, |
| )), |
| self_ty: Type::Group { |
| elem: Type::Path { |
| path: Path { |
| segments: [ |
| PathSegment { |
| ident: "Type", |
| }, |
| ], |
| }, |
| }, |
| }, |
| } |
| "###); |
| } |
| |
| #[test] |
| fn test_supertraits() { |
| // Rustc parses all of the following. |
| |
| #[rustfmt::skip] |
| let tokens = quote!(trait Trait where {}); |
| snapshot!(tokens as ItemTrait, @r###" |
| ItemTrait { |
| vis: Visibility::Inherited, |
| ident: "Trait", |
| generics: Generics { |
| where_clause: Some(WhereClause), |
| }, |
| } |
| "###); |
| |
| #[rustfmt::skip] |
| let tokens = quote!(trait Trait: where {}); |
| snapshot!(tokens as ItemTrait, @r###" |
| ItemTrait { |
| vis: Visibility::Inherited, |
| ident: "Trait", |
| generics: Generics { |
| where_clause: Some(WhereClause), |
| }, |
| colon_token: Some, |
| } |
| "###); |
| |
| #[rustfmt::skip] |
| let tokens = quote!(trait Trait: Sized where {}); |
| snapshot!(tokens as ItemTrait, @r###" |
| ItemTrait { |
| vis: Visibility::Inherited, |
| ident: "Trait", |
| generics: Generics { |
| where_clause: Some(WhereClause), |
| }, |
| colon_token: Some, |
| supertraits: [ |
| TypeParamBound::Trait(TraitBound { |
| path: Path { |
| segments: [ |
| PathSegment { |
| ident: "Sized", |
| }, |
| ], |
| }, |
| }), |
| ], |
| } |
| "###); |
| |
| #[rustfmt::skip] |
| let tokens = quote!(trait Trait: Sized + where {}); |
| snapshot!(tokens as ItemTrait, @r###" |
| ItemTrait { |
| vis: Visibility::Inherited, |
| ident: "Trait", |
| generics: Generics { |
| where_clause: Some(WhereClause), |
| }, |
| colon_token: Some, |
| supertraits: [ |
| TypeParamBound::Trait(TraitBound { |
| path: Path { |
| segments: [ |
| PathSegment { |
| ident: "Sized", |
| }, |
| ], |
| }, |
| }), |
| Token![+], |
| ], |
| } |
| "###); |
| } |
| |
| #[test] |
| fn test_type_empty_bounds() { |
| #[rustfmt::skip] |
| let tokens = quote! { |
| trait Foo { |
| type Bar: ; |
| } |
| }; |
| |
| snapshot!(tokens as ItemTrait, @r###" |
| ItemTrait { |
| vis: Visibility::Inherited, |
| ident: "Foo", |
| generics: Generics, |
| items: [ |
| TraitItem::Type { |
| ident: "Bar", |
| generics: Generics, |
| colon_token: Some, |
| }, |
| ], |
| } |
| "###); |
| } |
| |
| #[test] |
| fn test_impl_visibility() { |
| let tokens = quote! { |
| pub default unsafe impl union {} |
| }; |
| |
| snapshot!(tokens as Item, @"Item::Verbatim(`pub default unsafe impl union { }`)"); |
| } |
| |
| #[test] |
| fn test_impl_type_parameter_defaults() { |
| #[cfg(any())] |
| impl<T = ()> () {} |
| let tokens = quote! { |
| impl<T = ()> () {} |
| }; |
| snapshot!(tokens as Item, @r###" |
| Item::Impl { |
| generics: Generics { |
| lt_token: Some, |
| params: [ |
| GenericParam::Type(TypeParam { |
| ident: "T", |
| eq_token: Some, |
| default: Some(Type::Tuple), |
| }), |
| ], |
| gt_token: Some, |
| }, |
| self_ty: Type::Tuple, |
| } |
| "###); |
| } |
| |
| #[test] |
| fn test_impl_trait_trailing_plus() { |
| let tokens = quote! { |
| fn f() -> impl Sized + {} |
| }; |
| |
| snapshot!(tokens as Item, @r###" |
| Item::Fn { |
| vis: Visibility::Inherited, |
| sig: Signature { |
| ident: "f", |
| generics: Generics, |
| output: ReturnType::Type( |
| Type::ImplTrait { |
| bounds: [ |
| TypeParamBound::Trait(TraitBound { |
| path: Path { |
| segments: [ |
| PathSegment { |
| ident: "Sized", |
| }, |
| ], |
| }, |
| }), |
| Token![+], |
| ], |
| }, |
| ), |
| }, |
| block: Block { |
| stmts: [], |
| }, |
| } |
| "###); |
| } |