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