xref: /linux/rust/syn/classify.rs (revision 784faa8eca8270671e0ed6d9d21f04bbb80fc5f7)
1*69942c0aSMiguel Ojeda // SPDX-License-Identifier: Apache-2.0 OR MIT
2*69942c0aSMiguel Ojeda 
3808c999fSMiguel Ojeda #[cfg(feature = "full")]
4808c999fSMiguel Ojeda use crate::expr::Expr;
5808c999fSMiguel Ojeda #[cfg(any(feature = "printing", feature = "full"))]
6808c999fSMiguel Ojeda use crate::generics::TypeParamBound;
7808c999fSMiguel Ojeda #[cfg(any(feature = "printing", feature = "full"))]
8808c999fSMiguel Ojeda use crate::path::{Path, PathArguments};
9808c999fSMiguel Ojeda #[cfg(any(feature = "printing", feature = "full"))]
10808c999fSMiguel Ojeda use crate::punctuated::Punctuated;
11808c999fSMiguel Ojeda #[cfg(any(feature = "printing", feature = "full"))]
12808c999fSMiguel Ojeda use crate::ty::{ReturnType, Type};
13808c999fSMiguel Ojeda #[cfg(feature = "full")]
14808c999fSMiguel Ojeda use proc_macro2::{Delimiter, TokenStream, TokenTree};
15808c999fSMiguel Ojeda #[cfg(any(feature = "printing", feature = "full"))]
16808c999fSMiguel Ojeda use std::ops::ControlFlow;
17808c999fSMiguel Ojeda 
18808c999fSMiguel Ojeda #[cfg(feature = "full")]
requires_semi_to_be_stmt(expr: &Expr) -> bool19808c999fSMiguel Ojeda pub(crate) fn requires_semi_to_be_stmt(expr: &Expr) -> bool {
20808c999fSMiguel Ojeda     match expr {
21808c999fSMiguel Ojeda         Expr::Macro(expr) => !expr.mac.delimiter.is_brace(),
22808c999fSMiguel Ojeda         _ => requires_comma_to_be_match_arm(expr),
23808c999fSMiguel Ojeda     }
24808c999fSMiguel Ojeda }
25808c999fSMiguel Ojeda 
26808c999fSMiguel Ojeda #[cfg(feature = "full")]
requires_comma_to_be_match_arm(expr: &Expr) -> bool27808c999fSMiguel Ojeda pub(crate) fn requires_comma_to_be_match_arm(expr: &Expr) -> bool {
28808c999fSMiguel Ojeda     match expr {
29808c999fSMiguel Ojeda         Expr::If(_)
30808c999fSMiguel Ojeda         | Expr::Match(_)
31808c999fSMiguel Ojeda         | Expr::Block(_) | Expr::Unsafe(_) // both under ExprKind::Block in rustc
32808c999fSMiguel Ojeda         | Expr::While(_)
33808c999fSMiguel Ojeda         | Expr::Loop(_)
34808c999fSMiguel Ojeda         | Expr::ForLoop(_)
35808c999fSMiguel Ojeda         | Expr::TryBlock(_)
36808c999fSMiguel Ojeda         | Expr::Const(_) => false,
37808c999fSMiguel Ojeda 
38808c999fSMiguel Ojeda         Expr::Array(_)
39808c999fSMiguel Ojeda         | Expr::Assign(_)
40808c999fSMiguel Ojeda         | Expr::Async(_)
41808c999fSMiguel Ojeda         | Expr::Await(_)
42808c999fSMiguel Ojeda         | Expr::Binary(_)
43808c999fSMiguel Ojeda         | Expr::Break(_)
44808c999fSMiguel Ojeda         | Expr::Call(_)
45808c999fSMiguel Ojeda         | Expr::Cast(_)
46808c999fSMiguel Ojeda         | Expr::Closure(_)
47808c999fSMiguel Ojeda         | Expr::Continue(_)
48808c999fSMiguel Ojeda         | Expr::Field(_)
49808c999fSMiguel Ojeda         | Expr::Group(_)
50808c999fSMiguel Ojeda         | Expr::Index(_)
51808c999fSMiguel Ojeda         | Expr::Infer(_)
52808c999fSMiguel Ojeda         | Expr::Let(_)
53808c999fSMiguel Ojeda         | Expr::Lit(_)
54808c999fSMiguel Ojeda         | Expr::Macro(_)
55808c999fSMiguel Ojeda         | Expr::MethodCall(_)
56808c999fSMiguel Ojeda         | Expr::Paren(_)
57808c999fSMiguel Ojeda         | Expr::Path(_)
58808c999fSMiguel Ojeda         | Expr::Range(_)
59808c999fSMiguel Ojeda         | Expr::RawAddr(_)
60808c999fSMiguel Ojeda         | Expr::Reference(_)
61808c999fSMiguel Ojeda         | Expr::Repeat(_)
62808c999fSMiguel Ojeda         | Expr::Return(_)
63808c999fSMiguel Ojeda         | Expr::Struct(_)
64808c999fSMiguel Ojeda         | Expr::Try(_)
65808c999fSMiguel Ojeda         | Expr::Tuple(_)
66808c999fSMiguel Ojeda         | Expr::Unary(_)
67808c999fSMiguel Ojeda         | Expr::Yield(_)
68808c999fSMiguel Ojeda         | Expr::Verbatim(_) => true,
69808c999fSMiguel Ojeda     }
70808c999fSMiguel Ojeda }
71808c999fSMiguel Ojeda 
72808c999fSMiguel Ojeda #[cfg(feature = "printing")]
trailing_unparameterized_path(mut ty: &Type) -> bool73808c999fSMiguel Ojeda pub(crate) fn trailing_unparameterized_path(mut ty: &Type) -> bool {
74808c999fSMiguel Ojeda     loop {
75808c999fSMiguel Ojeda         match ty {
76808c999fSMiguel Ojeda             Type::BareFn(t) => match &t.output {
77808c999fSMiguel Ojeda                 ReturnType::Default => return false,
78808c999fSMiguel Ojeda                 ReturnType::Type(_, ret) => ty = ret,
79808c999fSMiguel Ojeda             },
80808c999fSMiguel Ojeda             Type::ImplTrait(t) => match last_type_in_bounds(&t.bounds) {
81808c999fSMiguel Ojeda                 ControlFlow::Break(trailing_path) => return trailing_path,
82808c999fSMiguel Ojeda                 ControlFlow::Continue(t) => ty = t,
83808c999fSMiguel Ojeda             },
84808c999fSMiguel Ojeda             Type::Path(t) => match last_type_in_path(&t.path) {
85808c999fSMiguel Ojeda                 ControlFlow::Break(trailing_path) => return trailing_path,
86808c999fSMiguel Ojeda                 ControlFlow::Continue(t) => ty = t,
87808c999fSMiguel Ojeda             },
88808c999fSMiguel Ojeda             Type::Ptr(t) => ty = &t.elem,
89808c999fSMiguel Ojeda             Type::Reference(t) => ty = &t.elem,
90808c999fSMiguel Ojeda             Type::TraitObject(t) => match last_type_in_bounds(&t.bounds) {
91808c999fSMiguel Ojeda                 ControlFlow::Break(trailing_path) => return trailing_path,
92808c999fSMiguel Ojeda                 ControlFlow::Continue(t) => ty = t,
93808c999fSMiguel Ojeda             },
94808c999fSMiguel Ojeda 
95808c999fSMiguel Ojeda             Type::Array(_)
96808c999fSMiguel Ojeda             | Type::Group(_)
97808c999fSMiguel Ojeda             | Type::Infer(_)
98808c999fSMiguel Ojeda             | Type::Macro(_)
99808c999fSMiguel Ojeda             | Type::Never(_)
100808c999fSMiguel Ojeda             | Type::Paren(_)
101808c999fSMiguel Ojeda             | Type::Slice(_)
102808c999fSMiguel Ojeda             | Type::Tuple(_)
103808c999fSMiguel Ojeda             | Type::Verbatim(_) => return false,
104808c999fSMiguel Ojeda         }
105808c999fSMiguel Ojeda     }
106808c999fSMiguel Ojeda 
107808c999fSMiguel Ojeda     fn last_type_in_path(path: &Path) -> ControlFlow<bool, &Type> {
108808c999fSMiguel Ojeda         match &path.segments.last().unwrap().arguments {
109808c999fSMiguel Ojeda             PathArguments::None => ControlFlow::Break(true),
110808c999fSMiguel Ojeda             PathArguments::AngleBracketed(_) => ControlFlow::Break(false),
111808c999fSMiguel Ojeda             PathArguments::Parenthesized(arg) => match &arg.output {
112808c999fSMiguel Ojeda                 ReturnType::Default => ControlFlow::Break(false),
113808c999fSMiguel Ojeda                 ReturnType::Type(_, ret) => ControlFlow::Continue(ret),
114808c999fSMiguel Ojeda             },
115808c999fSMiguel Ojeda         }
116808c999fSMiguel Ojeda     }
117808c999fSMiguel Ojeda 
118808c999fSMiguel Ojeda     fn last_type_in_bounds(
119808c999fSMiguel Ojeda         bounds: &Punctuated<TypeParamBound, Token![+]>,
120808c999fSMiguel Ojeda     ) -> ControlFlow<bool, &Type> {
121808c999fSMiguel Ojeda         match bounds.last().unwrap() {
122808c999fSMiguel Ojeda             TypeParamBound::Trait(t) => last_type_in_path(&t.path),
123808c999fSMiguel Ojeda             TypeParamBound::Lifetime(_)
124808c999fSMiguel Ojeda             | TypeParamBound::PreciseCapture(_)
125808c999fSMiguel Ojeda             | TypeParamBound::Verbatim(_) => ControlFlow::Break(false),
126808c999fSMiguel Ojeda         }
127808c999fSMiguel Ojeda     }
128808c999fSMiguel Ojeda }
129808c999fSMiguel Ojeda 
130808c999fSMiguel Ojeda /// Whether the expression's first token is the label of a loop/block.
131808c999fSMiguel Ojeda #[cfg(all(feature = "printing", feature = "full"))]
expr_leading_label(mut expr: &Expr) -> bool132808c999fSMiguel Ojeda pub(crate) fn expr_leading_label(mut expr: &Expr) -> bool {
133808c999fSMiguel Ojeda     loop {
134808c999fSMiguel Ojeda         match expr {
135808c999fSMiguel Ojeda             Expr::Block(e) => return e.label.is_some(),
136808c999fSMiguel Ojeda             Expr::ForLoop(e) => return e.label.is_some(),
137808c999fSMiguel Ojeda             Expr::Loop(e) => return e.label.is_some(),
138808c999fSMiguel Ojeda             Expr::While(e) => return e.label.is_some(),
139808c999fSMiguel Ojeda 
140808c999fSMiguel Ojeda             Expr::Assign(e) => expr = &e.left,
141808c999fSMiguel Ojeda             Expr::Await(e) => expr = &e.base,
142808c999fSMiguel Ojeda             Expr::Binary(e) => expr = &e.left,
143808c999fSMiguel Ojeda             Expr::Call(e) => expr = &e.func,
144808c999fSMiguel Ojeda             Expr::Cast(e) => expr = &e.expr,
145808c999fSMiguel Ojeda             Expr::Field(e) => expr = &e.base,
146808c999fSMiguel Ojeda             Expr::Index(e) => expr = &e.expr,
147808c999fSMiguel Ojeda             Expr::MethodCall(e) => expr = &e.receiver,
148808c999fSMiguel Ojeda             Expr::Range(e) => match &e.start {
149808c999fSMiguel Ojeda                 Some(start) => expr = start,
150808c999fSMiguel Ojeda                 None => return false,
151808c999fSMiguel Ojeda             },
152808c999fSMiguel Ojeda             Expr::Try(e) => expr = &e.expr,
153808c999fSMiguel Ojeda 
154808c999fSMiguel Ojeda             Expr::Array(_)
155808c999fSMiguel Ojeda             | Expr::Async(_)
156808c999fSMiguel Ojeda             | Expr::Break(_)
157808c999fSMiguel Ojeda             | Expr::Closure(_)
158808c999fSMiguel Ojeda             | Expr::Const(_)
159808c999fSMiguel Ojeda             | Expr::Continue(_)
160808c999fSMiguel Ojeda             | Expr::Group(_)
161808c999fSMiguel Ojeda             | Expr::If(_)
162808c999fSMiguel Ojeda             | Expr::Infer(_)
163808c999fSMiguel Ojeda             | Expr::Let(_)
164808c999fSMiguel Ojeda             | Expr::Lit(_)
165808c999fSMiguel Ojeda             | Expr::Macro(_)
166808c999fSMiguel Ojeda             | Expr::Match(_)
167808c999fSMiguel Ojeda             | Expr::Paren(_)
168808c999fSMiguel Ojeda             | Expr::Path(_)
169808c999fSMiguel Ojeda             | Expr::RawAddr(_)
170808c999fSMiguel Ojeda             | Expr::Reference(_)
171808c999fSMiguel Ojeda             | Expr::Repeat(_)
172808c999fSMiguel Ojeda             | Expr::Return(_)
173808c999fSMiguel Ojeda             | Expr::Struct(_)
174808c999fSMiguel Ojeda             | Expr::TryBlock(_)
175808c999fSMiguel Ojeda             | Expr::Tuple(_)
176808c999fSMiguel Ojeda             | Expr::Unary(_)
177808c999fSMiguel Ojeda             | Expr::Unsafe(_)
178808c999fSMiguel Ojeda             | Expr::Verbatim(_)
179808c999fSMiguel Ojeda             | Expr::Yield(_) => return false,
180808c999fSMiguel Ojeda         }
181808c999fSMiguel Ojeda     }
182808c999fSMiguel Ojeda }
183808c999fSMiguel Ojeda 
184808c999fSMiguel Ojeda /// Whether the expression's last token is `}`.
185808c999fSMiguel Ojeda #[cfg(feature = "full")]
expr_trailing_brace(mut expr: &Expr) -> bool186808c999fSMiguel Ojeda pub(crate) fn expr_trailing_brace(mut expr: &Expr) -> bool {
187808c999fSMiguel Ojeda     loop {
188808c999fSMiguel Ojeda         match expr {
189808c999fSMiguel Ojeda             Expr::Async(_)
190808c999fSMiguel Ojeda             | Expr::Block(_)
191808c999fSMiguel Ojeda             | Expr::Const(_)
192808c999fSMiguel Ojeda             | Expr::ForLoop(_)
193808c999fSMiguel Ojeda             | Expr::If(_)
194808c999fSMiguel Ojeda             | Expr::Loop(_)
195808c999fSMiguel Ojeda             | Expr::Match(_)
196808c999fSMiguel Ojeda             | Expr::Struct(_)
197808c999fSMiguel Ojeda             | Expr::TryBlock(_)
198808c999fSMiguel Ojeda             | Expr::Unsafe(_)
199808c999fSMiguel Ojeda             | Expr::While(_) => return true,
200808c999fSMiguel Ojeda 
201808c999fSMiguel Ojeda             Expr::Assign(e) => expr = &e.right,
202808c999fSMiguel Ojeda             Expr::Binary(e) => expr = &e.right,
203808c999fSMiguel Ojeda             Expr::Break(e) => match &e.expr {
204808c999fSMiguel Ojeda                 Some(e) => expr = e,
205808c999fSMiguel Ojeda                 None => return false,
206808c999fSMiguel Ojeda             },
207808c999fSMiguel Ojeda             Expr::Cast(e) => return type_trailing_brace(&e.ty),
208808c999fSMiguel Ojeda             Expr::Closure(e) => expr = &e.body,
209808c999fSMiguel Ojeda             Expr::Let(e) => expr = &e.expr,
210808c999fSMiguel Ojeda             Expr::Macro(e) => return e.mac.delimiter.is_brace(),
211808c999fSMiguel Ojeda             Expr::Range(e) => match &e.end {
212808c999fSMiguel Ojeda                 Some(end) => expr = end,
213808c999fSMiguel Ojeda                 None => return false,
214808c999fSMiguel Ojeda             },
215808c999fSMiguel Ojeda             Expr::RawAddr(e) => expr = &e.expr,
216808c999fSMiguel Ojeda             Expr::Reference(e) => expr = &e.expr,
217808c999fSMiguel Ojeda             Expr::Return(e) => match &e.expr {
218808c999fSMiguel Ojeda                 Some(e) => expr = e,
219808c999fSMiguel Ojeda                 None => return false,
220808c999fSMiguel Ojeda             },
221808c999fSMiguel Ojeda             Expr::Unary(e) => expr = &e.expr,
222808c999fSMiguel Ojeda             Expr::Verbatim(e) => return tokens_trailing_brace(e),
223808c999fSMiguel Ojeda             Expr::Yield(e) => match &e.expr {
224808c999fSMiguel Ojeda                 Some(e) => expr = e,
225808c999fSMiguel Ojeda                 None => return false,
226808c999fSMiguel Ojeda             },
227808c999fSMiguel Ojeda 
228808c999fSMiguel Ojeda             Expr::Array(_)
229808c999fSMiguel Ojeda             | Expr::Await(_)
230808c999fSMiguel Ojeda             | Expr::Call(_)
231808c999fSMiguel Ojeda             | Expr::Continue(_)
232808c999fSMiguel Ojeda             | Expr::Field(_)
233808c999fSMiguel Ojeda             | Expr::Group(_)
234808c999fSMiguel Ojeda             | Expr::Index(_)
235808c999fSMiguel Ojeda             | Expr::Infer(_)
236808c999fSMiguel Ojeda             | Expr::Lit(_)
237808c999fSMiguel Ojeda             | Expr::MethodCall(_)
238808c999fSMiguel Ojeda             | Expr::Paren(_)
239808c999fSMiguel Ojeda             | Expr::Path(_)
240808c999fSMiguel Ojeda             | Expr::Repeat(_)
241808c999fSMiguel Ojeda             | Expr::Try(_)
242808c999fSMiguel Ojeda             | Expr::Tuple(_) => return false,
243808c999fSMiguel Ojeda         }
244808c999fSMiguel Ojeda     }
245808c999fSMiguel Ojeda 
246808c999fSMiguel Ojeda     fn type_trailing_brace(mut ty: &Type) -> bool {
247808c999fSMiguel Ojeda         loop {
248808c999fSMiguel Ojeda             match ty {
249808c999fSMiguel Ojeda                 Type::BareFn(t) => match &t.output {
250808c999fSMiguel Ojeda                     ReturnType::Default => return false,
251808c999fSMiguel Ojeda                     ReturnType::Type(_, ret) => ty = ret,
252808c999fSMiguel Ojeda                 },
253808c999fSMiguel Ojeda                 Type::ImplTrait(t) => match last_type_in_bounds(&t.bounds) {
254808c999fSMiguel Ojeda                     ControlFlow::Break(trailing_brace) => return trailing_brace,
255808c999fSMiguel Ojeda                     ControlFlow::Continue(t) => ty = t,
256808c999fSMiguel Ojeda                 },
257808c999fSMiguel Ojeda                 Type::Macro(t) => return t.mac.delimiter.is_brace(),
258808c999fSMiguel Ojeda                 Type::Path(t) => match last_type_in_path(&t.path) {
259808c999fSMiguel Ojeda                     Some(t) => ty = t,
260808c999fSMiguel Ojeda                     None => return false,
261808c999fSMiguel Ojeda                 },
262808c999fSMiguel Ojeda                 Type::Ptr(t) => ty = &t.elem,
263808c999fSMiguel Ojeda                 Type::Reference(t) => ty = &t.elem,
264808c999fSMiguel Ojeda                 Type::TraitObject(t) => match last_type_in_bounds(&t.bounds) {
265808c999fSMiguel Ojeda                     ControlFlow::Break(trailing_brace) => return trailing_brace,
266808c999fSMiguel Ojeda                     ControlFlow::Continue(t) => ty = t,
267808c999fSMiguel Ojeda                 },
268808c999fSMiguel Ojeda                 Type::Verbatim(t) => return tokens_trailing_brace(t),
269808c999fSMiguel Ojeda 
270808c999fSMiguel Ojeda                 Type::Array(_)
271808c999fSMiguel Ojeda                 | Type::Group(_)
272808c999fSMiguel Ojeda                 | Type::Infer(_)
273808c999fSMiguel Ojeda                 | Type::Never(_)
274808c999fSMiguel Ojeda                 | Type::Paren(_)
275808c999fSMiguel Ojeda                 | Type::Slice(_)
276808c999fSMiguel Ojeda                 | Type::Tuple(_) => return false,
277808c999fSMiguel Ojeda             }
278808c999fSMiguel Ojeda         }
279808c999fSMiguel Ojeda     }
280808c999fSMiguel Ojeda 
281808c999fSMiguel Ojeda     fn last_type_in_path(path: &Path) -> Option<&Type> {
282808c999fSMiguel Ojeda         match &path.segments.last().unwrap().arguments {
283808c999fSMiguel Ojeda             PathArguments::None | PathArguments::AngleBracketed(_) => None,
284808c999fSMiguel Ojeda             PathArguments::Parenthesized(arg) => match &arg.output {
285808c999fSMiguel Ojeda                 ReturnType::Default => None,
286808c999fSMiguel Ojeda                 ReturnType::Type(_, ret) => Some(ret),
287808c999fSMiguel Ojeda             },
288808c999fSMiguel Ojeda         }
289808c999fSMiguel Ojeda     }
290808c999fSMiguel Ojeda 
291808c999fSMiguel Ojeda     fn last_type_in_bounds(
292808c999fSMiguel Ojeda         bounds: &Punctuated<TypeParamBound, Token![+]>,
293808c999fSMiguel Ojeda     ) -> ControlFlow<bool, &Type> {
294808c999fSMiguel Ojeda         match bounds.last().unwrap() {
295808c999fSMiguel Ojeda             TypeParamBound::Trait(t) => match last_type_in_path(&t.path) {
296808c999fSMiguel Ojeda                 Some(t) => ControlFlow::Continue(t),
297808c999fSMiguel Ojeda                 None => ControlFlow::Break(false),
298808c999fSMiguel Ojeda             },
299808c999fSMiguel Ojeda             TypeParamBound::Lifetime(_) | TypeParamBound::PreciseCapture(_) => {
300808c999fSMiguel Ojeda                 ControlFlow::Break(false)
301808c999fSMiguel Ojeda             }
302808c999fSMiguel Ojeda             TypeParamBound::Verbatim(t) => ControlFlow::Break(tokens_trailing_brace(t)),
303808c999fSMiguel Ojeda         }
304808c999fSMiguel Ojeda     }
305808c999fSMiguel Ojeda 
306808c999fSMiguel Ojeda     fn tokens_trailing_brace(tokens: &TokenStream) -> bool {
307808c999fSMiguel Ojeda         if let Some(TokenTree::Group(last)) = tokens.clone().into_iter().last() {
308808c999fSMiguel Ojeda             last.delimiter() == Delimiter::Brace
309808c999fSMiguel Ojeda         } else {
310808c999fSMiguel Ojeda             false
311808c999fSMiguel Ojeda         }
312808c999fSMiguel Ojeda     }
313808c999fSMiguel Ojeda }
314