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