File Index
Files and directories
Sign in
FILE

classify.rs

File preview with syntax highlighting.

linux-6.19.14/rust/syn/classify.rs RUST
  1// SPDX-License-Identifier: Apache-2.0 OR MIT
  2
  3#[cfg(feature = "full")]
  4use crate::expr::Expr;
  5#[cfg(any(feature = "printing", feature = "full"))]
  6use crate::generics::TypeParamBound;
  7#[cfg(any(feature = "printing", feature = "full"))]
  8use crate::path::{Path, PathArguments};
  9#[cfg(any(feature = "printing", feature = "full"))]
 10use crate::punctuated::Punctuated;
 11#[cfg(any(feature = "printing", feature = "full"))]
 12use crate::ty::{ReturnType, Type};
 13#[cfg(feature = "full")]
 14use proc_macro2::{Delimiter, TokenStream, TokenTree};
 15#[cfg(any(feature = "printing", feature = "full"))]
 16use std::ops::ControlFlow;
 17
 18#[cfg(feature = "full")]
 19pub(crate) fn requires_semi_to_be_stmt(expr: &Expr) -> bool {
 20    match expr {
 21        Expr::Macro(expr) => !expr.mac.delimiter.is_brace(),
 22        _ => requires_comma_to_be_match_arm(expr),
 23    }
 24}
 25
 26#[cfg(feature = "full")]
 27pub(crate) fn requires_comma_to_be_match_arm(expr: &Expr) -> bool {
 28    match expr {
 29        Expr::If(_)
 30        | Expr::Match(_)
 31        | Expr::Block(_) | Expr::Unsafe(_) // both under ExprKind::Block in rustc
 32        | Expr::While(_)
 33        | Expr::Loop(_)
 34        | Expr::ForLoop(_)
 35        | Expr::TryBlock(_)
 36        | Expr::Const(_) => false,
 37
 38        Expr::Array(_)
 39        | Expr::Assign(_)
 40        | Expr::Async(_)
 41        | Expr::Await(_)
 42        | Expr::Binary(_)
 43        | Expr::Break(_)
 44        | Expr::Call(_)
 45        | Expr::Cast(_)
 46        | Expr::Closure(_)
 47        | Expr::Continue(_)
 48        | Expr::Field(_)
 49        | Expr::Group(_)
 50        | Expr::Index(_)
 51        | Expr::Infer(_)
 52        | Expr::Let(_)
 53        | Expr::Lit(_)
 54        | Expr::Macro(_)
 55        | Expr::MethodCall(_)
 56        | Expr::Paren(_)
 57        | Expr::Path(_)
 58        | Expr::Range(_)
 59        | Expr::RawAddr(_)
 60        | Expr::Reference(_)
 61        | Expr::Repeat(_)
 62        | Expr::Return(_)
 63        | Expr::Struct(_)
 64        | Expr::Try(_)
 65        | Expr::Tuple(_)
 66        | Expr::Unary(_)
 67        | Expr::Yield(_)
 68        | Expr::Verbatim(_) => true,
 69    }
 70}
 71
 72#[cfg(feature = "printing")]
 73pub(crate) fn trailing_unparameterized_path(mut ty: &Type) -> bool {
 74    loop {
 75        match ty {
 76            Type::BareFn(t) => match &t.output {
 77                ReturnType::Default => return false,
 78                ReturnType::Type(_, ret) => ty = ret,
 79            },
 80            Type::ImplTrait(t) => match last_type_in_bounds(&t.bounds) {
 81                ControlFlow::Break(trailing_path) => return trailing_path,
 82                ControlFlow::Continue(t) => ty = t,
 83            },
 84            Type::Path(t) => match last_type_in_path(&t.path) {
 85                ControlFlow::Break(trailing_path) => return trailing_path,
 86                ControlFlow::Continue(t) => ty = t,
 87            },
 88            Type::Ptr(t) => ty = &t.elem,
 89            Type::Reference(t) => ty = &t.elem,
 90            Type::TraitObject(t) => match last_type_in_bounds(&t.bounds) {
 91                ControlFlow::Break(trailing_path) => return trailing_path,
 92                ControlFlow::Continue(t) => ty = t,
 93            },
 94
 95            Type::Array(_)
 96            | Type::Group(_)
 97            | Type::Infer(_)
 98            | Type::Macro(_)
 99            | Type::Never(_)
100            | Type::Paren(_)
101            | Type::Slice(_)
102            | Type::Tuple(_)
103            | Type::Verbatim(_) => return false,
104        }
105    }
106
107    fn last_type_in_path(path: &Path) -> ControlFlow<bool, &Type> {
108        match &path.segments.last().unwrap().arguments {
109            PathArguments::None => ControlFlow::Break(true),
110            PathArguments::AngleBracketed(_) => ControlFlow::Break(false),
111            PathArguments::Parenthesized(arg) => match &arg.output {
112                ReturnType::Default => ControlFlow::Break(false),
113                ReturnType::Type(_, ret) => ControlFlow::Continue(ret),
114            },
115        }
116    }
117
118    fn last_type_in_bounds(
119        bounds: &Punctuated<TypeParamBound, Token![+]>,
120    ) -> ControlFlow<bool, &Type> {
121        match bounds.last().unwrap() {
122            TypeParamBound::Trait(t) => last_type_in_path(&t.path),
123            TypeParamBound::Lifetime(_)
124            | TypeParamBound::PreciseCapture(_)
125            | TypeParamBound::Verbatim(_) => ControlFlow::Break(false),
126        }
127    }
128}
129
130/// Whether the expression's first token is the label of a loop/block.
131#[cfg(all(feature = "printing", feature = "full"))]
132pub(crate) fn expr_leading_label(mut expr: &Expr) -> bool {
133    loop {
134        match expr {
135            Expr::Block(e) => return e.label.is_some(),
136            Expr::ForLoop(e) => return e.label.is_some(),
137            Expr::Loop(e) => return e.label.is_some(),
138            Expr::While(e) => return e.label.is_some(),
139
140            Expr::Assign(e) => expr = &e.left,
141            Expr::Await(e) => expr = &e.base,
142            Expr::Binary(e) => expr = &e.left,
143            Expr::Call(e) => expr = &e.func,
144            Expr::Cast(e) => expr = &e.expr,
145            Expr::Field(e) => expr = &e.base,
146            Expr::Index(e) => expr = &e.expr,
147            Expr::MethodCall(e) => expr = &e.receiver,
148            Expr::Range(e) => match &e.start {
149                Some(start) => expr = start,
150                None => return false,
151            },
152            Expr::Try(e) => expr = &e.expr,
153
154            Expr::Array(_)
155            | Expr::Async(_)
156            | Expr::Break(_)
157            | Expr::Closure(_)
158            | Expr::Const(_)
159            | Expr::Continue(_)
160            | Expr::Group(_)
161            | Expr::If(_)
162            | Expr::Infer(_)
163            | Expr::Let(_)
164            | Expr::Lit(_)
165            | Expr::Macro(_)
166            | Expr::Match(_)
167            | Expr::Paren(_)
168            | Expr::Path(_)
169            | Expr::RawAddr(_)
170            | Expr::Reference(_)
171            | Expr::Repeat(_)
172            | Expr::Return(_)
173            | Expr::Struct(_)
174            | Expr::TryBlock(_)
175            | Expr::Tuple(_)
176            | Expr::Unary(_)
177            | Expr::Unsafe(_)
178            | Expr::Verbatim(_)
179            | Expr::Yield(_) => return false,
180        }
181    }
182}
183
184/// Whether the expression's last token is `}`.
185#[cfg(feature = "full")]
186pub(crate) fn expr_trailing_brace(mut expr: &Expr) -> bool {
187    loop {
188        match expr {
189            Expr::Async(_)
190            | Expr::Block(_)
191            | Expr::Const(_)
192            | Expr::ForLoop(_)
193            | Expr::If(_)
194            | Expr::Loop(_)
195            | Expr::Match(_)
196            | Expr::Struct(_)
197            | Expr::TryBlock(_)
198            | Expr::Unsafe(_)
199            | Expr::While(_) => return true,
200
201            Expr::Assign(e) => expr = &e.right,
202            Expr::Binary(e) => expr = &e.right,
203            Expr::Break(e) => match &e.expr {
204                Some(e) => expr = e,
205                None => return false,
206            },
207            Expr::Cast(e) => return type_trailing_brace(&e.ty),
208            Expr::Closure(e) => expr = &e.body,
209            Expr::Let(e) => expr = &e.expr,
210            Expr::Macro(e) => return e.mac.delimiter.is_brace(),
211            Expr::Range(e) => match &e.end {
212                Some(end) => expr = end,
213                None => return false,
214            },
215            Expr::RawAddr(e) => expr = &e.expr,
216            Expr::Reference(e) => expr = &e.expr,
217            Expr::Return(e) => match &e.expr {
218                Some(e) => expr = e,
219                None => return false,
220            },
221            Expr::Unary(e) => expr = &e.expr,
222            Expr::Verbatim(e) => return tokens_trailing_brace(e),
223            Expr::Yield(e) => match &e.expr {
224                Some(e) => expr = e,
225                None => return false,
226            },
227
228            Expr::Array(_)
229            | Expr::Await(_)
230            | Expr::Call(_)
231            | Expr::Continue(_)
232            | Expr::Field(_)
233            | Expr::Group(_)
234            | Expr::Index(_)
235            | Expr::Infer(_)
236            | Expr::Lit(_)
237            | Expr::MethodCall(_)
238            | Expr::Paren(_)
239            | Expr::Path(_)
240            | Expr::Repeat(_)
241            | Expr::Try(_)
242            | Expr::Tuple(_) => return false,
243        }
244    }
245
246    fn type_trailing_brace(mut ty: &Type) -> bool {
247        loop {
248            match ty {
249                Type::BareFn(t) => match &t.output {
250                    ReturnType::Default => return false,
251                    ReturnType::Type(_, ret) => ty = ret,
252                },
253                Type::ImplTrait(t) => match last_type_in_bounds(&t.bounds) {
254                    ControlFlow::Break(trailing_brace) => return trailing_brace,
255                    ControlFlow::Continue(t) => ty = t,
256                },
257                Type::Macro(t) => return t.mac.delimiter.is_brace(),
258                Type::Path(t) => match last_type_in_path(&t.path) {
259                    Some(t) => ty = t,
260                    None => return false,
261                },
262                Type::Ptr(t) => ty = &t.elem,
263                Type::Reference(t) => ty = &t.elem,
264                Type::TraitObject(t) => match last_type_in_bounds(&t.bounds) {
265                    ControlFlow::Break(trailing_brace) => return trailing_brace,
266                    ControlFlow::Continue(t) => ty = t,
267                },
268                Type::Verbatim(t) => return tokens_trailing_brace(t),
269
270                Type::Array(_)
271                | Type::Group(_)
272                | Type::Infer(_)
273                | Type::Never(_)
274                | Type::Paren(_)
275                | Type::Slice(_)
276                | Type::Tuple(_) => return false,
277            }
278        }
279    }
280
281    fn last_type_in_path(path: &Path) -> Option<&Type> {
282        match &path.segments.last().unwrap().arguments {
283            PathArguments::None | PathArguments::AngleBracketed(_) => None,
284            PathArguments::Parenthesized(arg) => match &arg.output {
285                ReturnType::Default => None,
286                ReturnType::Type(_, ret) => Some(ret),
287            },
288        }
289    }
290
291    fn last_type_in_bounds(
292        bounds: &Punctuated<TypeParamBound, Token![+]>,
293    ) -> ControlFlow<bool, &Type> {
294        match bounds.last().unwrap() {
295            TypeParamBound::Trait(t) => match last_type_in_path(&t.path) {
296                Some(t) => ControlFlow::Continue(t),
297                None => ControlFlow::Break(false),
298            },
299            TypeParamBound::Lifetime(_) | TypeParamBound::PreciseCapture(_) => {
300                ControlFlow::Break(false)
301            }
302            TypeParamBound::Verbatim(t) => ControlFlow::Break(tokens_trailing_brace(t)),
303        }
304    }
305
306    fn tokens_trailing_brace(tokens: &TokenStream) -> bool {
307        if let Some(TokenTree::Group(last)) = tokens.clone().into_iter().last() {
308            last.delimiter() == Delimiter::Brace
309        } else {
310            false
311        }
312    }
313}
~/ Read-only file preview.