1#[macro_use]
2mod macros;
3
4use proc_macro2::{Delimiter, Group, Ident, Span, TokenStream, TokenTree};
5use quote::quote;
6use std::iter::FromIterator;
7use syn::{Item, ItemTrait};
8
9#[test]
10fn 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]
48fn 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]
123fn 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]
164fn 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]
246fn 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
270#[test]
271fn test_impl_visibility() {
272 let tokens = quote! {
273 pub default unsafe impl union {}
274 };
275
276 snapshot!(tokens as Item, @"Verbatim(`pub default unsafe impl union { }`)");
277}
278
279#[test]
280fn test_impl_type_parameter_defaults() {
281 #[cfg(any())]
282 impl<T = ()> () {}
283 let tokens = quote! {
284 impl<T = ()> () {}
285 };
286 snapshot!(tokens as Item, @r###"
287 Item::Impl {
288 generics: Generics {
289 lt_token: Some,
290 params: [
291 Type(TypeParam {
292 ident: "T",
293 eq_token: Some,
294 default: Some(Type::Tuple),
295 }),
296 ],
297 gt_token: Some,
298 },
299 self_ty: Type::Tuple,
300 }"###);
301}
302
303#[test]
304fn test_impl_trait_trailing_plus() {
305 let tokens = quote! {
306 fn f() -> impl Sized + {}
307 };
308
309 snapshot!(tokens as Item, @r###"
310 Item::Fn {
311 vis: Inherited,
312 sig: Signature {
313 ident: "f",
314 generics: Generics,
315 output: Type(
316 Type::ImplTrait {
317 bounds: [
318 Trait(TraitBound {
319 modifier: None,
320 path: Path {
321 segments: [
322 PathSegment {
323 ident: "Sized",
324 arguments: None,
325 },
326 ],
327 },
328 }),
329 ],
330 },
331 ),
332 },
333 block: Block,
334 }
335 "###);
336}
337