| #[macro_use] |
| mod macros; |
| |
| use proc_macro2::{Delimiter, Group, Ident, Span, TokenStream, TokenTree}; |
| use quote::quote; |
| use std::iter::FromIterator; |
| use syn::Item; |
| |
| #[test] |
| fn test_macro_variable_attr() { |
| // mimics the token stream corresponding to `$attr fn f() {}` |
| let tokens = TokenStream::from_iter(vec![ |
| 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: Outer, |
| path: Path { |
| segments: [ |
| PathSegment { |
| ident: "test", |
| arguments: None, |
| }, |
| ], |
| }, |
| tokens: TokenStream(``), |
| }, |
| ], |
| vis: Inherited, |
| sig: Signature { |
| ident: "f", |
| generics: Generics, |
| output: Default, |
| }, |
| block: Block, |
| } |
| "###); |
| } |
| |
| #[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: 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", |
| arguments: None, |
| }, |
| ], |
| }, |
| )), |
| self_ty: Type::Path { |
| path: Path { |
| segments: [ |
| PathSegment { |
| ident: "T", |
| arguments: None, |
| }, |
| ], |
| }, |
| }, |
| } |
| "###); |
| |
| #[cfg(any())] |
| #[rustfmt::skip] |
| impl !! {} |
| let tokens = quote! { |
| impl !! {} |
| }; |
| snapshot!(tokens as Item, @r###" |
| Item::Impl { |
| generics: Generics, |
| self_ty: Verbatim(`! !`), |
| } |
| "###); |
| } |
| |
| #[test] |
| fn test_macro_variable_impl() { |
| // mimics the token stream corresponding to `impl $trait for $ty {}` |
| let tokens = TokenStream::from_iter(vec![ |
| 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", |
| arguments: None, |
| }, |
| ], |
| }, |
| )), |
| self_ty: Type::Group { |
| elem: Type::Path { |
| path: Path { |
| segments: [ |
| PathSegment { |
| ident: "Type", |
| arguments: None, |
| }, |
| ], |
| }, |
| }, |
| }, |
| } |
| "###); |
| } |