1 #![allow(
2     clippy::assertions_on_result_states,
3     clippy::non_ascii_literal,
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, ToTokens as _};
12 use syn::parse::Parser as _;
13 use syn::{Block, Stmt};
14 
15 #[test]
test_raw_operator()16 fn test_raw_operator() {
17     let stmt = syn::parse_str::<Stmt>("let _ = &raw const x;").unwrap();
18 
19     snapshot!(stmt, @r###"
20     Stmt::Local {
21         pat: Pat::Wild,
22         init: Some(LocalInit {
23             expr: Expr::Verbatim(`& raw const x`),
24         }),
25     }
26     "###);
27 }
28 
29 #[test]
test_raw_variable()30 fn test_raw_variable() {
31     let stmt = syn::parse_str::<Stmt>("let _ = &raw;").unwrap();
32 
33     snapshot!(stmt, @r###"
34     Stmt::Local {
35         pat: Pat::Wild,
36         init: Some(LocalInit {
37             expr: Expr::Reference {
38                 expr: Expr::Path {
39                     path: Path {
40                         segments: [
41                             PathSegment {
42                                 ident: "raw",
43                             },
44                         ],
45                     },
46                 },
47             },
48         }),
49     }
50     "###);
51 }
52 
53 #[test]
test_raw_invalid()54 fn test_raw_invalid() {
55     assert!(syn::parse_str::<Stmt>("let _ = &raw x;").is_err());
56 }
57 
58 #[test]
test_none_group()59 fn test_none_group() {
60     // <Ø async fn f() {} Ø>
61     let tokens = TokenStream::from_iter(vec![TokenTree::Group(Group::new(
62         Delimiter::None,
63         TokenStream::from_iter(vec![
64             TokenTree::Ident(Ident::new("async", Span::call_site())),
65             TokenTree::Ident(Ident::new("fn", Span::call_site())),
66             TokenTree::Ident(Ident::new("f", Span::call_site())),
67             TokenTree::Group(Group::new(Delimiter::Parenthesis, TokenStream::new())),
68             TokenTree::Group(Group::new(Delimiter::Brace, TokenStream::new())),
69         ]),
70     ))]);
71     snapshot!(tokens as Stmt, @r###"
72     Stmt::Item(Item::Fn {
73         vis: Visibility::Inherited,
74         sig: Signature {
75             asyncness: Some,
76             ident: "f",
77             generics: Generics,
78             output: ReturnType::Default,
79         },
80         block: Block {
81             stmts: [],
82         },
83     })
84     "###);
85 
86     let tokens = Group::new(Delimiter::None, quote!(let None = None)).to_token_stream();
87     let stmts = Block::parse_within.parse2(tokens).unwrap();
88     snapshot!(stmts, @r###"
89     [
90         Stmt::Expr(
91             Expr::Group {
92                 expr: Expr::Let {
93                     pat: Pat::Ident {
94                         ident: "None",
95                     },
96                     expr: Expr::Path {
97                         path: Path {
98                             segments: [
99                                 PathSegment {
100                                     ident: "None",
101                                 },
102                             ],
103                         },
104                     },
105                 },
106             },
107             None,
108         ),
109     ]
110     "###);
111 }
112 
113 #[test]
test_let_dot_dot()114 fn test_let_dot_dot() {
115     let tokens = quote! {
116         let .. = 10;
117     };
118 
119     snapshot!(tokens as Stmt, @r###"
120     Stmt::Local {
121         pat: Pat::Rest,
122         init: Some(LocalInit {
123             expr: Expr::Lit {
124                 lit: 10,
125             },
126         }),
127     }
128     "###);
129 }
130 
131 #[test]
test_let_else()132 fn test_let_else() {
133     let tokens = quote! {
134         let Some(x) = None else { return 0; };
135     };
136 
137     snapshot!(tokens as Stmt, @r###"
138     Stmt::Local {
139         pat: Pat::TupleStruct {
140             path: Path {
141                 segments: [
142                     PathSegment {
143                         ident: "Some",
144                     },
145                 ],
146             },
147             elems: [
148                 Pat::Ident {
149                     ident: "x",
150                 },
151             ],
152         },
153         init: Some(LocalInit {
154             expr: Expr::Path {
155                 path: Path {
156                     segments: [
157                         PathSegment {
158                             ident: "None",
159                         },
160                     ],
161                 },
162             },
163             diverge: Some(Expr::Block {
164                 block: Block {
165                     stmts: [
166                         Stmt::Expr(
167                             Expr::Return {
168                                 expr: Some(Expr::Lit {
169                                     lit: 0,
170                                 }),
171                             },
172                             Some,
173                         ),
174                     ],
175                 },
176             }),
177         }),
178     }
179     "###);
180 }
181 
182 #[test]
test_macros()183 fn test_macros() {
184     let tokens = quote! {
185         fn main() {
186             macro_rules! mac {}
187             thread_local! { static FOO }
188             println!("");
189             vec![]
190         }
191     };
192 
193     snapshot!(tokens as Stmt, @r###"
194     Stmt::Item(Item::Fn {
195         vis: Visibility::Inherited,
196         sig: Signature {
197             ident: "main",
198             generics: Generics,
199             output: ReturnType::Default,
200         },
201         block: Block {
202             stmts: [
203                 Stmt::Item(Item::Macro {
204                     ident: Some("mac"),
205                     mac: Macro {
206                         path: Path {
207                             segments: [
208                                 PathSegment {
209                                     ident: "macro_rules",
210                                 },
211                             ],
212                         },
213                         delimiter: MacroDelimiter::Brace,
214                         tokens: TokenStream(``),
215                     },
216                 }),
217                 Stmt::Macro {
218                     mac: Macro {
219                         path: Path {
220                             segments: [
221                                 PathSegment {
222                                     ident: "thread_local",
223                                 },
224                             ],
225                         },
226                         delimiter: MacroDelimiter::Brace,
227                         tokens: TokenStream(`static FOO`),
228                     },
229                 },
230                 Stmt::Macro {
231                     mac: Macro {
232                         path: Path {
233                             segments: [
234                                 PathSegment {
235                                     ident: "println",
236                                 },
237                             ],
238                         },
239                         delimiter: MacroDelimiter::Paren,
240                         tokens: TokenStream(`""`),
241                     },
242                     semi_token: Some,
243                 },
244                 Stmt::Expr(
245                     Expr::Macro {
246                         mac: Macro {
247                             path: Path {
248                                 segments: [
249                                     PathSegment {
250                                         ident: "vec",
251                                     },
252                                 ],
253                             },
254                             delimiter: MacroDelimiter::Bracket,
255                             tokens: TokenStream(``),
256                         },
257                     },
258                     None,
259                 ),
260             ],
261         },
262     })
263     "###);
264 }
265 
266 #[test]
test_early_parse_loop()267 fn test_early_parse_loop() {
268     // The following is an Expr::Loop followed by Expr::Tuple. It is not an
269     // Expr::Call.
270     let tokens = quote! {
271         loop {}
272         ()
273     };
274 
275     let stmts = Block::parse_within.parse2(tokens).unwrap();
276 
277     snapshot!(stmts, @r###"
278     [
279         Stmt::Expr(
280             Expr::Loop {
281                 body: Block {
282                     stmts: [],
283                 },
284             },
285             None,
286         ),
287         Stmt::Expr(
288             Expr::Tuple,
289             None,
290         ),
291     ]
292     "###);
293 
294     let tokens = quote! {
295         'a: loop {}
296         ()
297     };
298 
299     let stmts = Block::parse_within.parse2(tokens).unwrap();
300 
301     snapshot!(stmts, @r###"
302     [
303         Stmt::Expr(
304             Expr::Loop {
305                 label: Some(Label {
306                     name: Lifetime {
307                         ident: "a",
308                     },
309                 }),
310                 body: Block {
311                     stmts: [],
312                 },
313             },
314             None,
315         ),
316         Stmt::Expr(
317             Expr::Tuple,
318             None,
319         ),
320     ]
321     "###);
322 }
323