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