1 #[macro_use]
2 mod macros;
3 
4 use proc_macro2::{Delimiter, Group, Ident, Span, TokenStream, TokenTree};
5 use quote::quote;
6 use std::iter::FromIterator;
7 use syn::{Item, ItemTrait};
8 
9 #[test]
test_macro_variable_attr()10 fn test_macro_variable_attr() {
11     // mimics the token stream corresponding to `$attr fn f() {}`
12     let tokens = TokenStream::from_iter(vec![
13         TokenTree::Group(Group::new(Delimiter::None, quote! { #[test] })),
14         TokenTree::Ident(Ident::new("fn", Span::call_site())),
15         TokenTree::Ident(Ident::new("f", Span::call_site())),
16         TokenTree::Group(Group::new(Delimiter::Parenthesis, TokenStream::new())),
17         TokenTree::Group(Group::new(Delimiter::Brace, TokenStream::new())),
18     ]);
19 
20     snapshot!(tokens as Item, @r###"
21     Item::Fn {
22         attrs: [
23             Attribute {
24                 style: Outer,
25                 path: Path {
26                     segments: [
27                         PathSegment {
28                             ident: "test",
29                             arguments: None,
30                         },
31                     ],
32                 },
33                 tokens: TokenStream(``),
34             },
35         ],
36         vis: Inherited,
37         sig: Signature {
38             ident: "f",
39             generics: Generics,
40             output: Default,
41         },
42         block: Block,
43     }
44     "###);
45 }
46 
47 #[test]
test_negative_impl()48 fn test_negative_impl() {
49     // Rustc parses all of the following.
50 
51     #[cfg(any())]
52     impl ! {}
53     let tokens = quote! {
54         impl ! {}
55     };
56     snapshot!(tokens as Item, @r###"
57     Item::Impl {
58         generics: Generics,
59         self_ty: Type::Never,
60     }
61     "###);
62 
63     #[cfg(any())]
64     #[rustfmt::skip]
65     impl !Trait {}
66     let tokens = quote! {
67         impl !Trait {}
68     };
69     snapshot!(tokens as Item, @r###"
70     Item::Impl {
71         generics: Generics,
72         self_ty: Verbatim(`! Trait`),
73     }
74     "###);
75 
76     #[cfg(any())]
77     impl !Trait for T {}
78     let tokens = quote! {
79         impl !Trait for T {}
80     };
81     snapshot!(tokens as Item, @r###"
82     Item::Impl {
83         generics: Generics,
84         trait_: Some((
85             Some,
86             Path {
87                 segments: [
88                     PathSegment {
89                         ident: "Trait",
90                         arguments: None,
91                     },
92                 ],
93             },
94         )),
95         self_ty: Type::Path {
96             path: Path {
97                 segments: [
98                     PathSegment {
99                         ident: "T",
100                         arguments: None,
101                     },
102                 ],
103             },
104         },
105     }
106     "###);
107 
108     #[cfg(any())]
109     #[rustfmt::skip]
110     impl !! {}
111     let tokens = quote! {
112         impl !! {}
113     };
114     snapshot!(tokens as Item, @r###"
115     Item::Impl {
116         generics: Generics,
117         self_ty: Verbatim(`! !`),
118     }
119     "###);
120 }
121 
122 #[test]
test_macro_variable_impl()123 fn test_macro_variable_impl() {
124     // mimics the token stream corresponding to `impl $trait for $ty {}`
125     let tokens = TokenStream::from_iter(vec![
126         TokenTree::Ident(Ident::new("impl", Span::call_site())),
127         TokenTree::Group(Group::new(Delimiter::None, quote!(Trait))),
128         TokenTree::Ident(Ident::new("for", Span::call_site())),
129         TokenTree::Group(Group::new(Delimiter::None, quote!(Type))),
130         TokenTree::Group(Group::new(Delimiter::Brace, TokenStream::new())),
131     ]);
132 
133     snapshot!(tokens as Item, @r###"
134     Item::Impl {
135         generics: Generics,
136         trait_: Some((
137             None,
138             Path {
139                 segments: [
140                     PathSegment {
141                         ident: "Trait",
142                         arguments: None,
143                     },
144                 ],
145             },
146         )),
147         self_ty: Type::Group {
148             elem: Type::Path {
149                 path: Path {
150                     segments: [
151                         PathSegment {
152                             ident: "Type",
153                             arguments: None,
154                         },
155                     ],
156                 },
157             },
158         },
159     }
160     "###);
161 }
162 
163 #[test]
test_supertraits()164 fn test_supertraits() {
165     // Rustc parses all of the following.
166 
167     #[rustfmt::skip]
168     let tokens = quote!(trait Trait where {});
169     snapshot!(tokens as ItemTrait, @r###"
170     ItemTrait {
171         vis: Inherited,
172         ident: "Trait",
173         generics: Generics {
174             where_clause: Some(WhereClause),
175         },
176     }
177     "###);
178 
179     #[rustfmt::skip]
180     let tokens = quote!(trait Trait: where {});
181     snapshot!(tokens as ItemTrait, @r###"
182     ItemTrait {
183         vis: Inherited,
184         ident: "Trait",
185         generics: Generics {
186             where_clause: Some(WhereClause),
187         },
188         colon_token: Some,
189     }
190     "###);
191 
192     #[rustfmt::skip]
193     let tokens = quote!(trait Trait: Sized where {});
194     snapshot!(tokens as ItemTrait, @r###"
195     ItemTrait {
196         vis: Inherited,
197         ident: "Trait",
198         generics: Generics {
199             where_clause: Some(WhereClause),
200         },
201         colon_token: Some,
202         supertraits: [
203             Trait(TraitBound {
204                 modifier: None,
205                 path: Path {
206                     segments: [
207                         PathSegment {
208                             ident: "Sized",
209                             arguments: None,
210                         },
211                     ],
212                 },
213             }),
214         ],
215     }
216     "###);
217 
218     #[rustfmt::skip]
219     let tokens = quote!(trait Trait: Sized + where {});
220     snapshot!(tokens as ItemTrait, @r###"
221     ItemTrait {
222         vis: Inherited,
223         ident: "Trait",
224         generics: Generics {
225             where_clause: Some(WhereClause),
226         },
227         colon_token: Some,
228         supertraits: [
229             Trait(TraitBound {
230                 modifier: None,
231                 path: Path {
232                     segments: [
233                         PathSegment {
234                             ident: "Sized",
235                             arguments: None,
236                         },
237                     ],
238                 },
239             }),
240         ],
241     }
242     "###);
243 }
244 
245 #[test]
test_type_empty_bounds()246 fn test_type_empty_bounds() {
247     #[rustfmt::skip]
248     let tokens = quote! {
249         trait Foo {
250             type Bar: ;
251         }
252     };
253 
254     snapshot!(tokens as ItemTrait, @r###"
255     ItemTrait {
256         vis: Inherited,
257         ident: "Foo",
258         generics: Generics,
259         items: [
260             TraitItem::Type {
261                 ident: "Bar",
262                 generics: Generics,
263                 colon_token: Some,
264             },
265         ],
266     }
267     "###);
268 }
269