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