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