• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #![allow(clippy::uninlined_format_args)]
2 
3 #[macro_use]
4 mod macros;
5 
6 use proc_macro2::{Delimiter, Group, Ident, Punct, Spacing, Span, TokenStream, TokenTree};
7 use quote::quote;
8 use syn::{Expr, ExprRange};
9 
10 #[test]
test_expr_parse()11 fn test_expr_parse() {
12     let tokens = quote!(..100u32);
13     snapshot!(tokens as Expr, @r###"
14     Expr::Range {
15         limits: RangeLimits::HalfOpen,
16         end: Some(Expr::Lit {
17             lit: 100u32,
18         }),
19     }
20     "###);
21 
22     let tokens = quote!(..100u32);
23     snapshot!(tokens as ExprRange, @r###"
24     ExprRange {
25         limits: RangeLimits::HalfOpen,
26         end: Some(Expr::Lit {
27             lit: 100u32,
28         }),
29     }
30     "###);
31 }
32 
33 #[test]
test_await()34 fn test_await() {
35     // Must not parse as Expr::Field.
36     let tokens = quote!(fut.await);
37 
38     snapshot!(tokens as Expr, @r###"
39     Expr::Await {
40         base: Expr::Path {
41             path: Path {
42                 segments: [
43                     PathSegment {
44                         ident: "fut",
45                     },
46                 ],
47             },
48         },
49     }
50     "###);
51 }
52 
53 #[rustfmt::skip]
54 #[test]
test_tuple_multi_index()55 fn test_tuple_multi_index() {
56     let expected = snapshot!("tuple.0.0" as Expr, @r###"
57     Expr::Field {
58         base: Expr::Field {
59             base: Expr::Path {
60                 path: Path {
61                     segments: [
62                         PathSegment {
63                             ident: "tuple",
64                         },
65                     ],
66                 },
67             },
68             member: Member::Unnamed(Index {
69                 index: 0,
70             }),
71         },
72         member: Member::Unnamed(Index {
73             index: 0,
74         }),
75     }
76     "###);
77 
78     for &input in &[
79         "tuple .0.0",
80         "tuple. 0.0",
81         "tuple.0 .0",
82         "tuple.0. 0",
83         "tuple . 0 . 0",
84     ] {
85         assert_eq!(expected, syn::parse_str(input).unwrap());
86     }
87 
88     for tokens in [
89         quote!(tuple.0.0),
90         quote!(tuple .0.0),
91         quote!(tuple. 0.0),
92         quote!(tuple.0 .0),
93         quote!(tuple.0. 0),
94         quote!(tuple . 0 . 0),
95     ] {
96         assert_eq!(expected, syn::parse2(tokens).unwrap());
97     }
98 }
99 
100 #[test]
test_macro_variable_func()101 fn test_macro_variable_func() {
102     // mimics the token stream corresponding to `$fn()`
103     let tokens = TokenStream::from_iter(vec![
104         TokenTree::Group(Group::new(Delimiter::None, quote! { f })),
105         TokenTree::Group(Group::new(Delimiter::Parenthesis, TokenStream::new())),
106     ]);
107 
108     snapshot!(tokens as Expr, @r###"
109     Expr::Call {
110         func: Expr::Group {
111             expr: Expr::Path {
112                 path: Path {
113                     segments: [
114                         PathSegment {
115                             ident: "f",
116                         },
117                     ],
118                 },
119             },
120         },
121     }
122     "###);
123 
124     let tokens = TokenStream::from_iter(vec![
125         TokenTree::Punct(Punct::new('#', Spacing::Alone)),
126         TokenTree::Group(Group::new(Delimiter::Bracket, quote! { outside })),
127         TokenTree::Group(Group::new(Delimiter::None, quote! { #[inside] f })),
128         TokenTree::Group(Group::new(Delimiter::Parenthesis, TokenStream::new())),
129     ]);
130 
131     snapshot!(tokens as Expr, @r###"
132     Expr::Call {
133         attrs: [
134             Attribute {
135                 style: AttrStyle::Outer,
136                 meta: Meta::Path {
137                     segments: [
138                         PathSegment {
139                             ident: "outside",
140                         },
141                     ],
142                 },
143             },
144         ],
145         func: Expr::Group {
146             expr: Expr::Path {
147                 attrs: [
148                     Attribute {
149                         style: AttrStyle::Outer,
150                         meta: Meta::Path {
151                             segments: [
152                                 PathSegment {
153                                     ident: "inside",
154                                 },
155                             ],
156                         },
157                     },
158                 ],
159                 path: Path {
160                     segments: [
161                         PathSegment {
162                             ident: "f",
163                         },
164                     ],
165                 },
166             },
167         },
168     }
169     "###);
170 }
171 
172 #[test]
test_macro_variable_macro()173 fn test_macro_variable_macro() {
174     // mimics the token stream corresponding to `$macro!()`
175     let tokens = TokenStream::from_iter(vec![
176         TokenTree::Group(Group::new(Delimiter::None, quote! { m })),
177         TokenTree::Punct(Punct::new('!', Spacing::Alone)),
178         TokenTree::Group(Group::new(Delimiter::Parenthesis, TokenStream::new())),
179     ]);
180 
181     snapshot!(tokens as Expr, @r###"
182     Expr::Macro {
183         mac: Macro {
184             path: Path {
185                 segments: [
186                     PathSegment {
187                         ident: "m",
188                     },
189                 ],
190             },
191             delimiter: MacroDelimiter::Paren,
192             tokens: TokenStream(``),
193         },
194     }
195     "###);
196 }
197 
198 #[test]
test_macro_variable_struct()199 fn test_macro_variable_struct() {
200     // mimics the token stream corresponding to `$struct {}`
201     let tokens = TokenStream::from_iter(vec![
202         TokenTree::Group(Group::new(Delimiter::None, quote! { S })),
203         TokenTree::Group(Group::new(Delimiter::Brace, TokenStream::new())),
204     ]);
205 
206     snapshot!(tokens as Expr, @r###"
207     Expr::Struct {
208         path: Path {
209             segments: [
210                 PathSegment {
211                     ident: "S",
212                 },
213             ],
214         },
215     }
216     "###);
217 }
218 
219 #[test]
test_macro_variable_match_arm()220 fn test_macro_variable_match_arm() {
221     // mimics the token stream corresponding to `match v { _ => $expr }`
222     let tokens = TokenStream::from_iter(vec![
223         TokenTree::Ident(Ident::new("match", Span::call_site())),
224         TokenTree::Ident(Ident::new("v", Span::call_site())),
225         TokenTree::Group(Group::new(
226             Delimiter::Brace,
227             TokenStream::from_iter(vec![
228                 TokenTree::Punct(Punct::new('_', Spacing::Alone)),
229                 TokenTree::Punct(Punct::new('=', Spacing::Joint)),
230                 TokenTree::Punct(Punct::new('>', Spacing::Alone)),
231                 TokenTree::Group(Group::new(Delimiter::None, quote! { #[a] () })),
232             ]),
233         )),
234     ]);
235 
236     snapshot!(tokens as Expr, @r###"
237     Expr::Match {
238         expr: Expr::Path {
239             path: Path {
240                 segments: [
241                     PathSegment {
242                         ident: "v",
243                     },
244                 ],
245             },
246         },
247         arms: [
248             Arm {
249                 pat: Pat::Wild,
250                 body: Expr::Group {
251                     expr: Expr::Tuple {
252                         attrs: [
253                             Attribute {
254                                 style: AttrStyle::Outer,
255                                 meta: Meta::Path {
256                                     segments: [
257                                         PathSegment {
258                                             ident: "a",
259                                         },
260                                     ],
261                                 },
262                             },
263                         ],
264                     },
265                 },
266             },
267         ],
268     }
269     "###);
270 }
271 
272 // https://github.com/dtolnay/syn/issues/1019
273 #[test]
test_closure_vs_rangefull()274 fn test_closure_vs_rangefull() {
275     #[rustfmt::skip] // rustfmt bug: https://github.com/rust-lang/rustfmt/issues/4808
276     let tokens = quote!(|| .. .method());
277     snapshot!(tokens as Expr, @r###"
278     Expr::MethodCall {
279         receiver: Expr::Closure {
280             output: ReturnType::Default,
281             body: Expr::Range {
282                 limits: RangeLimits::HalfOpen,
283             },
284         },
285         method: "method",
286     }
287     "###);
288 }
289 
290 #[test]
test_postfix_operator_after_cast()291 fn test_postfix_operator_after_cast() {
292     syn::parse_str::<Expr>("|| &x as T[0]").unwrap_err();
293     syn::parse_str::<Expr>("|| () as ()()").unwrap_err();
294 }
295 
296 #[test]
test_ranges()297 fn test_ranges() {
298     syn::parse_str::<Expr>("..").unwrap();
299     syn::parse_str::<Expr>("..hi").unwrap();
300     syn::parse_str::<Expr>("lo..").unwrap();
301     syn::parse_str::<Expr>("lo..hi").unwrap();
302 
303     syn::parse_str::<Expr>("..=").unwrap_err();
304     syn::parse_str::<Expr>("..=hi").unwrap();
305     syn::parse_str::<Expr>("lo..=").unwrap_err();
306     syn::parse_str::<Expr>("lo..=hi").unwrap();
307 
308     syn::parse_str::<Expr>("...").unwrap_err();
309     syn::parse_str::<Expr>("...hi").unwrap_err();
310     syn::parse_str::<Expr>("lo...").unwrap_err();
311     syn::parse_str::<Expr>("lo...hi").unwrap_err();
312 }
313