1 #![allow(clippy::uninlined_format_args)]
2 
3 #[macro_use]
4 mod macros;
5 
6 use proc_macro2::{Delimiter, Group, Ident, Span, TokenStream, TokenTree};
7 use quote::quote;
8 use syn::{Item, ItemTrait};
9 
10 #[test]
test_macro_variable_attr()11 fn test_macro_variable_attr() {
12     // mimics the token stream corresponding to `$attr fn f() {}`
13     let tokens = TokenStream::from_iter(vec![
14         TokenTree::Group(Group::new(Delimiter::None, quote! { #[test] })),
15         TokenTree::Ident(Ident::new("fn", Span::call_site())),
16         TokenTree::Ident(Ident::new("f", Span::call_site())),
17         TokenTree::Group(Group::new(Delimiter::Parenthesis, TokenStream::new())),
18         TokenTree::Group(Group::new(Delimiter::Brace, TokenStream::new())),
19     ]);
20 
21     snapshot!(tokens as Item, @r###"
22     Item::Fn {
23         attrs: [
24             Attribute {
25                 style: AttrStyle::Outer,
26                 meta: Meta::Path {
27                     segments: [
28                         PathSegment {
29                             ident: "test",
30                         },
31                     ],
32                 },
33             },
34         ],
35         vis: Visibility::Inherited,
36         sig: Signature {
37             ident: "f",
38             generics: Generics,
39             output: ReturnType::Default,
40         },
41         block: Block {
42             stmts: [],
43         },
44     }
45     "###);
46 }
47 
48 #[test]
test_negative_impl()49 fn test_negative_impl() {
50     // Rustc parses all of the following.
51 
52     #[cfg(any())]
53     impl ! {}
54     let tokens = quote! {
55         impl ! {}
56     };
57     snapshot!(tokens as Item, @r###"
58     Item::Impl {
59         generics: Generics,
60         self_ty: Type::Never,
61     }
62     "###);
63 
64     #[cfg(any())]
65     #[rustfmt::skip]
66     impl !Trait {}
67     let tokens = quote! {
68         impl !Trait {}
69     };
70     snapshot!(tokens as Item, @r###"
71     Item::Impl {
72         generics: Generics,
73         self_ty: Type::Verbatim(`! Trait`),
74     }
75     "###);
76 
77     #[cfg(any())]
78     impl !Trait for T {}
79     let tokens = quote! {
80         impl !Trait for T {}
81     };
82     snapshot!(tokens as Item, @r###"
83     Item::Impl {
84         generics: Generics,
85         trait_: Some((
86             Some,
87             Path {
88                 segments: [
89                     PathSegment {
90                         ident: "Trait",
91                     },
92                 ],
93             },
94         )),
95         self_ty: Type::Path {
96             path: Path {
97                 segments: [
98                     PathSegment {
99                         ident: "T",
100                     },
101                 ],
102             },
103         },
104     }
105     "###);
106 
107     #[cfg(any())]
108     #[rustfmt::skip]
109     impl !! {}
110     let tokens = quote! {
111         impl !! {}
112     };
113     snapshot!(tokens as Item, @r###"
114     Item::Impl {
115         generics: Generics,
116         self_ty: Type::Verbatim(`! !`),
117     }
118     "###);
119 }
120 
121 #[test]
test_macro_variable_impl()122 fn test_macro_variable_impl() {
123     // mimics the token stream corresponding to `impl $trait for $ty {}`
124     let tokens = TokenStream::from_iter(vec![
125         TokenTree::Ident(Ident::new("impl", Span::call_site())),
126         TokenTree::Group(Group::new(Delimiter::None, quote!(Trait))),
127         TokenTree::Ident(Ident::new("for", Span::call_site())),
128         TokenTree::Group(Group::new(Delimiter::None, quote!(Type))),
129         TokenTree::Group(Group::new(Delimiter::Brace, TokenStream::new())),
130     ]);
131 
132     snapshot!(tokens as Item, @r###"
133     Item::Impl {
134         generics: Generics,
135         trait_: Some((
136             None,
137             Path {
138                 segments: [
139                     PathSegment {
140                         ident: "Trait",
141                     },
142                 ],
143             },
144         )),
145         self_ty: Type::Group {
146             elem: Type::Path {
147                 path: Path {
148                     segments: [
149                         PathSegment {
150                             ident: "Type",
151                         },
152                     ],
153                 },
154             },
155         },
156     }
157     "###);
158 }
159 
160 #[test]
test_supertraits()161 fn test_supertraits() {
162     // Rustc parses all of the following.
163 
164     #[rustfmt::skip]
165     let tokens = quote!(trait Trait where {});
166     snapshot!(tokens as ItemTrait, @r###"
167     ItemTrait {
168         vis: Visibility::Inherited,
169         ident: "Trait",
170         generics: Generics {
171             where_clause: Some(WhereClause),
172         },
173     }
174     "###);
175 
176     #[rustfmt::skip]
177     let tokens = quote!(trait Trait: where {});
178     snapshot!(tokens as ItemTrait, @r###"
179     ItemTrait {
180         vis: Visibility::Inherited,
181         ident: "Trait",
182         generics: Generics {
183             where_clause: Some(WhereClause),
184         },
185         colon_token: Some,
186     }
187     "###);
188 
189     #[rustfmt::skip]
190     let tokens = quote!(trait Trait: Sized where {});
191     snapshot!(tokens as ItemTrait, @r###"
192     ItemTrait {
193         vis: Visibility::Inherited,
194         ident: "Trait",
195         generics: Generics {
196             where_clause: Some(WhereClause),
197         },
198         colon_token: Some,
199         supertraits: [
200             TypeParamBound::Trait(TraitBound {
201                 path: Path {
202                     segments: [
203                         PathSegment {
204                             ident: "Sized",
205                         },
206                     ],
207                 },
208             }),
209         ],
210     }
211     "###);
212 
213     #[rustfmt::skip]
214     let tokens = quote!(trait Trait: Sized + where {});
215     snapshot!(tokens as ItemTrait, @r###"
216     ItemTrait {
217         vis: Visibility::Inherited,
218         ident: "Trait",
219         generics: Generics {
220             where_clause: Some(WhereClause),
221         },
222         colon_token: Some,
223         supertraits: [
224             TypeParamBound::Trait(TraitBound {
225                 path: Path {
226                     segments: [
227                         PathSegment {
228                             ident: "Sized",
229                         },
230                     ],
231                 },
232             }),
233             Token![+],
234         ],
235     }
236     "###);
237 }
238 
239 #[test]
test_type_empty_bounds()240 fn test_type_empty_bounds() {
241     #[rustfmt::skip]
242     let tokens = quote! {
243         trait Foo {
244             type Bar: ;
245         }
246     };
247 
248     snapshot!(tokens as ItemTrait, @r###"
249     ItemTrait {
250         vis: Visibility::Inherited,
251         ident: "Foo",
252         generics: Generics,
253         items: [
254             TraitItem::Type {
255                 ident: "Bar",
256                 generics: Generics,
257                 colon_token: Some,
258             },
259         ],
260     }
261     "###);
262 }
263 
264 #[test]
test_impl_visibility()265 fn test_impl_visibility() {
266     let tokens = quote! {
267         pub default unsafe impl union {}
268     };
269 
270     snapshot!(tokens as Item, @"Item::Verbatim(`pub default unsafe impl union { }`)");
271 }
272 
273 #[test]
test_impl_type_parameter_defaults()274 fn test_impl_type_parameter_defaults() {
275     #[cfg(any())]
276     impl<T = ()> () {}
277     let tokens = quote! {
278         impl<T = ()> () {}
279     };
280     snapshot!(tokens as Item, @r###"
281     Item::Impl {
282         generics: Generics {
283             lt_token: Some,
284             params: [
285                 GenericParam::Type(TypeParam {
286                     ident: "T",
287                     eq_token: Some,
288                     default: Some(Type::Tuple),
289                 }),
290             ],
291             gt_token: Some,
292         },
293         self_ty: Type::Tuple,
294     }
295     "###);
296 }
297 
298 #[test]
test_impl_trait_trailing_plus()299 fn test_impl_trait_trailing_plus() {
300     let tokens = quote! {
301         fn f() -> impl Sized + {}
302     };
303 
304     snapshot!(tokens as Item, @r###"
305     Item::Fn {
306         vis: Visibility::Inherited,
307         sig: Signature {
308             ident: "f",
309             generics: Generics,
310             output: ReturnType::Type(
311                 Type::ImplTrait {
312                     bounds: [
313                         TypeParamBound::Trait(TraitBound {
314                             path: Path {
315                                 segments: [
316                                     PathSegment {
317                                         ident: "Sized",
318                                     },
319                                 ],
320                             },
321                         }),
322                         Token![+],
323                     ],
324                 },
325             ),
326         },
327         block: Block {
328             stmts: [],
329         },
330     }
331     "###);
332 }
333