|
1 | 1 | use crate::path_to_local_id; |
| 2 | +use core::ops::ControlFlow; |
2 | 3 | use rustc_hir as hir; |
3 | 4 | use rustc_hir::def::{DefKind, Res}; |
4 | 5 | use rustc_hir::intravisit::{self, walk_block, walk_expr, Visitor}; |
@@ -402,3 +403,36 @@ pub fn contains_unsafe_block<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) |
402 | 403 | v.visit_expr(e); |
403 | 404 | v.found_unsafe |
404 | 405 | } |
| 406 | + |
| 407 | +/// Runs the given function for each sub-expression producing the final value consumed by the parent |
| 408 | +/// of the give expression. |
| 409 | +/// |
| 410 | +/// e.g. for the following expression |
| 411 | +/// ```rust,ignore |
| 412 | +/// if foo { |
| 413 | +/// f(0) |
| 414 | +/// } else { |
| 415 | +/// 1 + 1 |
| 416 | +/// } |
| 417 | +/// ``` |
| 418 | +/// this will pass both `f(0)` and `1+1` to the given function. |
| 419 | +pub fn for_each_value_source<'tcx, B>( |
| 420 | + e: &'tcx Expr<'tcx>, |
| 421 | + f: &mut impl FnMut(&'tcx Expr<'tcx>) -> ControlFlow<B>, |
| 422 | +) -> ControlFlow<B> { |
| 423 | + match e.kind { |
| 424 | + ExprKind::Block(Block { expr: Some(e), .. }, _) => for_each_value_source(e, f), |
| 425 | + ExprKind::Match(_, arms, _) => { |
| 426 | + for arm in arms { |
| 427 | + for_each_value_source(arm.body, f)?; |
| 428 | + } |
| 429 | + ControlFlow::Continue(()) |
| 430 | + }, |
| 431 | + ExprKind::If(_, if_expr, Some(else_expr)) => { |
| 432 | + for_each_value_source(if_expr, f)?; |
| 433 | + for_each_value_source(else_expr, f) |
| 434 | + }, |
| 435 | + ExprKind::DropTemps(e) => for_each_value_source(e, f), |
| 436 | + _ => f(e), |
| 437 | + } |
| 438 | +} |
0 commit comments