diff options
| author | Alejandra González <blyxyas@gmail.com> | 2025-05-22 16:25:49 +0000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-05-22 16:25:49 +0000 |
| commit | 5dccb101ed9efc812ab5acbb0dee915d2b3502b9 (patch) | |
| tree | 4cd2d0628f0e41eaac465c09df42b06a3aa8e5e7 /clippy_lints | |
| parent | a6e40fa9e90f6230fca2bc83c01dfaf02d840e84 (diff) | |
| parent | 520cb092b894f20b79a5e2a3139cc94be238c2af (diff) | |
| download | rust-5dccb101ed9efc812ab5acbb0dee915d2b3502b9.tar.gz rust-5dccb101ed9efc812ab5acbb0dee915d2b3502b9.zip | |
Fix `needless_for_each` suggests wrongly when closure has no braces (#14735)
Closes rust-lang/rust-clippy#14734 changelog: [`needless_for_each`] wrong suggestions when closure has no braces
Diffstat (limited to 'clippy_lints')
| -rw-r--r-- | clippy_lints/src/needless_for_each.rs | 32 |
1 files changed, 28 insertions, 4 deletions
diff --git a/clippy_lints/src/needless_for_each.rs b/clippy_lints/src/needless_for_each.rs index 7dd96f1f037..6a7c8436bad 100644 --- a/clippy_lints/src/needless_for_each.rs +++ b/clippy_lints/src/needless_for_each.rs @@ -74,7 +74,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessForEach { && let body = cx.tcx.hir_body(body) // Skip the lint if the body is not safe, so as not to suggest `for … in … unsafe {}` // and suggesting `for … in … { unsafe { } }` is a little ugly. - && let ExprKind::Block(Block { rules: BlockCheckMode::DefaultBlock, .. }, ..) = body.value.kind + && !matches!(body.value.kind, ExprKind::Block(Block { rules: BlockCheckMode::UnsafeBlock(_), .. }, ..)) { let mut ret_collector = RetCollector::default(); ret_collector.visit_expr(body.value); @@ -99,11 +99,21 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessForEach { ) }; + let body_param_sugg = snippet_with_applicability(cx, body.params[0].pat.span, "..", &mut applicability); + let for_each_rev_sugg = snippet_with_applicability(cx, for_each_recv.span, "..", &mut applicability); + let body_value_sugg = snippet_with_applicability(cx, body.value.span, "..", &mut applicability); + let sugg = format!( "for {} in {} {}", - snippet_with_applicability(cx, body.params[0].pat.span, "..", &mut applicability), - snippet_with_applicability(cx, for_each_recv.span, "..", &mut applicability), - snippet_with_applicability(cx, body.value.span, "..", &mut applicability), + body_param_sugg, + for_each_rev_sugg, + match body.value.kind { + ExprKind::Block(block, _) if is_let_desugar(block) => { + format!("{{ {body_value_sugg} }}") + }, + ExprKind::Block(_, _) => body_value_sugg.to_string(), + _ => format!("{{ {body_value_sugg}; }}"), + } ); span_lint_and_then(cx, NEEDLESS_FOR_EACH, stmt.span, "needless use of `for_each`", |diag| { @@ -116,6 +126,20 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessForEach { } } +/// Check if the block is a desugared `_ = expr` statement. +fn is_let_desugar(block: &Block<'_>) -> bool { + matches!( + block, + Block { + stmts: [Stmt { + kind: StmtKind::Let(_), + .. + },], + .. + } + ) +} + /// This type plays two roles. /// 1. Collect spans of `return` in the closure body. /// 2. Detect use of `return` in `Loop` in the closure body. |
