1#[cfg(feature = "full")]
2use crate::expr::Expr;
3#[cfg(any(feature = "printing", feature = "full"))]
4use crate::generics::TypeParamBound;
5#[cfg(any(feature = "printing", feature = "full"))]
6use crate::path::{Path, PathArguments};
7#[cfg(any(feature = "printing", feature = "full"))]
8use crate::punctuated::Punctuated;
9#[cfg(any(feature = "printing", feature = "full"))]
10use crate::ty::{ReturnType, Type};
11#[cfg(feature = "full")]
12use proc_macro2::{Delimiter, TokenStream, TokenTree};
13#[cfg(any(feature = "printing", feature = "full"))]
14use std::ops::ControlFlow;
15
16#[cfg(feature = "full")]
17pub(crate) fn requires_semi_to_be_stmt(expr: &Expr) -> bool {
18 match expr {
19 Expr::Macro(expr) => !expr.mac.delimiter.is_brace(),
20 _ => requires_comma_to_be_match_arm(expr),
21 }
22}
23
24#[cfg(feature = "full")]
25pub(crate) fn requires_comma_to_be_match_arm(expr: &Expr) -> bool {
26 match expr {
27 Expr::If(_)
28 | Expr::Match(_)
29 | Expr::Block(_) | Expr::Unsafe(_) | Expr::While(_)
31 | Expr::Loop(_)
32 | Expr::ForLoop(_)
33 | Expr::TryBlock(_)
34 | Expr::Const(_) => false,
35
36 Expr::Array(_)
37 | Expr::Assign(_)
38 | Expr::Async(_)
39 | Expr::Await(_)
40 | Expr::Binary(_)
41 | Expr::Break(_)
42 | Expr::Call(_)
43 | Expr::Cast(_)
44 | Expr::Closure(_)
45 | Expr::Continue(_)
46 | Expr::Field(_)
47 | Expr::Group(_)
48 | Expr::Index(_)
49 | Expr::Infer(_)
50 | Expr::Let(_)
51 | Expr::Lit(_)
52 | Expr::Macro(_)
53 | Expr::MethodCall(_)
54 | Expr::Paren(_)
55 | Expr::Path(_)
56 | Expr::Range(_)
57 | Expr::RawAddr(_)
58 | Expr::Reference(_)
59 | Expr::Repeat(_)
60 | Expr::Return(_)
61 | Expr::Struct(_)
62 | Expr::Try(_)
63 | Expr::Tuple(_)
64 | Expr::Unary(_)
65 | Expr::Yield(_)
66 | Expr::Verbatim(_) => true
67 }
68}
69
70#[cfg(all(feature = "printing", feature = "full"))]
71pub(crate) fn confusable_with_adjacent_block(mut expr: &Expr) -> bool {
72 let mut stack = Vec::new();
73
74 while let Some(next) = match expr {
75 Expr::Assign(e) => {
76 stack.push(&e.right);
77 Some(&e.left)
78 }
79 Expr::Await(e) => Some(&e.base),
80 Expr::Binary(e) => {
81 stack.push(&e.right);
82 Some(&e.left)
83 }
84 Expr::Break(e) => {
85 if let Some(Expr::Block(_)) = e.expr.as_deref() {
86 return true;
87 }
88 stack.pop()
89 }
90 Expr::Call(e) => Some(&e.func),
91 Expr::Cast(e) => Some(&e.expr),
92 Expr::Closure(e) => Some(&e.body),
93 Expr::Field(e) => Some(&e.base),
94 Expr::Index(e) => Some(&e.expr),
95 Expr::MethodCall(e) => Some(&e.receiver),
96 Expr::Range(e) => {
97 if let Some(Expr::Block(_)) = e.end.as_deref() {
98 return true;
99 }
100 match (&e.start, &e.end) {
101 (Some(start), end) => {
102 stack.extend(end);
103 Some(start)
104 }
105 (None, Some(end)) => Some(end),
106 (None, None) => stack.pop(),
107 }
108 }
109 Expr::RawAddr(e) => Some(&e.expr),
110 Expr::Reference(e) => Some(&e.expr),
111 Expr::Return(e) => {
112 if e.expr.is_none() && stack.is_empty() {
113 return true;
114 }
115 stack.pop()
116 }
117 Expr::Struct(_) => return true,
118 Expr::Try(e) => Some(&e.expr),
119 Expr::Unary(e) => Some(&e.expr),
120 Expr::Yield(e) => {
121 if e.expr.is_none() && stack.is_empty() {
122 return true;
123 }
124 stack.pop()
125 }
126
127 Expr::Array(_)
128 | Expr::Async(_)
129 | Expr::Block(_)
130 | Expr::Const(_)
131 | Expr::Continue(_)
132 | Expr::ForLoop(_)
133 | Expr::Group(_)
134 | Expr::If(_)
135 | Expr::Infer(_)
136 | Expr::Let(_)
137 | Expr::Lit(_)
138 | Expr::Loop(_)
139 | Expr::Macro(_)
140 | Expr::Match(_)
141 | Expr::Paren(_)
142 | Expr::Path(_)
143 | Expr::Repeat(_)
144 | Expr::TryBlock(_)
145 | Expr::Tuple(_)
146 | Expr::Unsafe(_)
147 | Expr::Verbatim(_)
148 | Expr::While(_) => stack.pop(),
149 } {
150 expr = next;
151 }
152
153 false
154}
155
156#[cfg(feature = "printing")]
157pub(crate) fn trailing_unparameterized_path(mut ty: &Type) -> bool {
158 loop {
159 match ty {
160 Type::BareFn(t) => match &t.output {
161 ReturnType::Default => return false,
162 ReturnType::Type(_, ret) => ty = ret,
163 },
164 Type::ImplTrait(t) => match last_type_in_bounds(&t.bounds) {
165 ControlFlow::Break(trailing_path) => return trailing_path,
166 ControlFlow::Continue(t) => ty = t,
167 },
168 Type::Path(t) => match last_type_in_path(&t.path) {
169 ControlFlow::Break(trailing_path) => return trailing_path,
170 ControlFlow::Continue(t) => ty = t,
171 },
172 Type::Ptr(t) => ty = &t.elem,
173 Type::Reference(t) => ty = &t.elem,
174 Type::TraitObject(t) => match last_type_in_bounds(&t.bounds) {
175 ControlFlow::Break(trailing_path) => return trailing_path,
176 ControlFlow::Continue(t) => ty = t,
177 },
178
179 Type::Array(_)
180 | Type::Group(_)
181 | Type::Infer(_)
182 | Type::Macro(_)
183 | Type::Never(_)
184 | Type::Paren(_)
185 | Type::Slice(_)
186 | Type::Tuple(_)
187 | Type::Verbatim(_) => return false,
188 }
189 }
190
191 fn last_type_in_path(path: &Path) -> ControlFlow<bool, &Type> {
192 match &path.segments.last().unwrap().arguments {
193 PathArguments::None => ControlFlow::Break(true),
194 PathArguments::AngleBracketed(_) => ControlFlow::Break(false),
195 PathArguments::Parenthesized(arg) => match &arg.output {
196 ReturnType::Default => ControlFlow::Break(false),
197 ReturnType::Type(_, ret) => ControlFlow::Continue(ret),
198 },
199 }
200 }
201
202 fn last_type_in_bounds(
203 bounds: &Punctuated<TypeParamBound, Token![+]>,
204 ) -> ControlFlow<bool, &Type> {
205 match bounds.last().unwrap() {
206 TypeParamBound::Trait(t) => last_type_in_path(&t.path),
207 TypeParamBound::Lifetime(_)
208 | TypeParamBound::PreciseCapture(_)
209 | TypeParamBound::Verbatim(_) => ControlFlow::Break(false),
210 }
211 }
212}
213
214#[cfg(all(feature = "printing", feature = "full"))]
216pub(crate) fn expr_leading_label(mut expr: &Expr) -> bool {
217 loop {
218 match expr {
219 Expr::Block(e) => return e.label.is_some(),
220 Expr::ForLoop(e) => return e.label.is_some(),
221 Expr::Loop(e) => return e.label.is_some(),
222 Expr::While(e) => return e.label.is_some(),
223
224 Expr::Assign(e) => expr = &e.left,
225 Expr::Await(e) => expr = &e.base,
226 Expr::Binary(e) => expr = &e.left,
227 Expr::Call(e) => expr = &e.func,
228 Expr::Cast(e) => expr = &e.expr,
229 Expr::Field(e) => expr = &e.base,
230 Expr::Index(e) => expr = &e.expr,
231 Expr::MethodCall(e) => expr = &e.receiver,
232 Expr::Range(e) => match &e.start {
233 Some(start) => expr = start,
234 None => return false,
235 },
236 Expr::Try(e) => expr = &e.expr,
237
238 Expr::Array(_)
239 | Expr::Async(_)
240 | Expr::Break(_)
241 | Expr::Closure(_)
242 | Expr::Const(_)
243 | Expr::Continue(_)
244 | Expr::Group(_)
245 | Expr::If(_)
246 | Expr::Infer(_)
247 | Expr::Let(_)
248 | Expr::Lit(_)
249 | Expr::Macro(_)
250 | Expr::Match(_)
251 | Expr::Paren(_)
252 | Expr::Path(_)
253 | Expr::RawAddr(_)
254 | Expr::Reference(_)
255 | Expr::Repeat(_)
256 | Expr::Return(_)
257 | Expr::Struct(_)
258 | Expr::TryBlock(_)
259 | Expr::Tuple(_)
260 | Expr::Unary(_)
261 | Expr::Unsafe(_)
262 | Expr::Verbatim(_)
263 | Expr::Yield(_) => return false,
264 }
265 }
266}
267
268#[cfg(feature = "full")]
270pub(crate) fn expr_trailing_brace(mut expr: &Expr) -> bool {
271 loop {
272 match expr {
273 Expr::Async(_)
274 | Expr::Block(_)
275 | Expr::Const(_)
276 | Expr::ForLoop(_)
277 | Expr::If(_)
278 | Expr::Loop(_)
279 | Expr::Match(_)
280 | Expr::Struct(_)
281 | Expr::TryBlock(_)
282 | Expr::Unsafe(_)
283 | Expr::While(_) => return true,
284
285 Expr::Assign(e) => expr = &e.right,
286 Expr::Binary(e) => expr = &e.right,
287 Expr::Break(e) => match &e.expr {
288 Some(e) => expr = e,
289 None => return false,
290 },
291 Expr::Cast(e) => return type_trailing_brace(&e.ty),
292 Expr::Closure(e) => expr = &e.body,
293 Expr::Let(e) => expr = &e.expr,
294 Expr::Macro(e) => return e.mac.delimiter.is_brace(),
295 Expr::Range(e) => match &e.end {
296 Some(end) => expr = end,
297 None => return false,
298 },
299 Expr::RawAddr(e) => expr = &e.expr,
300 Expr::Reference(e) => expr = &e.expr,
301 Expr::Return(e) => match &e.expr {
302 Some(e) => expr = e,
303 None => return false,
304 },
305 Expr::Unary(e) => expr = &e.expr,
306 Expr::Verbatim(e) => return tokens_trailing_brace(e),
307 Expr::Yield(e) => match &e.expr {
308 Some(e) => expr = e,
309 None => return false,
310 },
311
312 Expr::Array(_)
313 | Expr::Await(_)
314 | Expr::Call(_)
315 | Expr::Continue(_)
316 | Expr::Field(_)
317 | Expr::Group(_)
318 | Expr::Index(_)
319 | Expr::Infer(_)
320 | Expr::Lit(_)
321 | Expr::MethodCall(_)
322 | Expr::Paren(_)
323 | Expr::Path(_)
324 | Expr::Repeat(_)
325 | Expr::Try(_)
326 | Expr::Tuple(_) => return false,
327 }
328 }
329
330 fn type_trailing_brace(mut ty: &Type) -> bool {
331 loop {
332 match ty {
333 Type::BareFn(t) => match &t.output {
334 ReturnType::Default => return false,
335 ReturnType::Type(_, ret) => ty = ret,
336 },
337 Type::ImplTrait(t) => match last_type_in_bounds(&t.bounds) {
338 ControlFlow::Break(trailing_brace) => return trailing_brace,
339 ControlFlow::Continue(t) => ty = t,
340 },
341 Type::Macro(t) => return t.mac.delimiter.is_brace(),
342 Type::Path(t) => match last_type_in_path(&t.path) {
343 Some(t) => ty = t,
344 None => return false,
345 },
346 Type::Ptr(t) => ty = &t.elem,
347 Type::Reference(t) => ty = &t.elem,
348 Type::TraitObject(t) => match last_type_in_bounds(&t.bounds) {
349 ControlFlow::Break(trailing_brace) => return trailing_brace,
350 ControlFlow::Continue(t) => ty = t,
351 },
352 Type::Verbatim(t) => return tokens_trailing_brace(t),
353
354 Type::Array(_)
355 | Type::Group(_)
356 | Type::Infer(_)
357 | Type::Never(_)
358 | Type::Paren(_)
359 | Type::Slice(_)
360 | Type::Tuple(_) => return false,
361 }
362 }
363 }
364
365 fn last_type_in_path(path: &Path) -> Option<&Type> {
366 match &path.segments.last().unwrap().arguments {
367 PathArguments::None | PathArguments::AngleBracketed(_) => None,
368 PathArguments::Parenthesized(arg) => match &arg.output {
369 ReturnType::Default => None,
370 ReturnType::Type(_, ret) => Some(ret),
371 },
372 }
373 }
374
375 fn last_type_in_bounds(
376 bounds: &Punctuated<TypeParamBound, Token![+]>,
377 ) -> ControlFlow<bool, &Type> {
378 match bounds.last().unwrap() {
379 TypeParamBound::Trait(t) => match last_type_in_path(&t.path) {
380 Some(t) => ControlFlow::Continue(t),
381 None => ControlFlow::Break(false),
382 },
383 TypeParamBound::Lifetime(_) | TypeParamBound::PreciseCapture(_) => {
384 ControlFlow::Break(false)
385 }
386 TypeParamBound::Verbatim(t) => ControlFlow::Break(tokens_trailing_brace(t)),
387 }
388 }
389
390 fn tokens_trailing_brace(tokens: &TokenStream) -> bool {
391 if let Some(TokenTree::Group(last)) = tokens.clone().into_iter().last() {
392 last.delimiter() == Delimiter::Brace
393 } else {
394 false
395 }
396 }
397}