1#![allow(
2 clippy::assertions_on_result_states,
3 clippy::non_ascii_literal,
4 clippy::uninlined_format_args
5)]
6
7#[macro_use]
8mod macros;
9
10use proc_macro2::{Delimiter, Group, Ident, Span, TokenStream, TokenTree};
11use quote::{quote, ToTokens as _};
12use syn::parse::Parser as _;
13use syn::{Block, Stmt};
14
15#[test]
16fn 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]
30fn 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]
54fn test_raw_invalid() {
55 assert!(syn::parse_str::<Stmt>("let _ = &raw x;").is_err());
56}
57
58#[test]
59fn 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]
114fn 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]
132fn 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]
183fn 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]
267fn 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