classify.rs 11 KB

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