|
1 | 1 | use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; |
2 | | -use clippy_utils::higher; |
3 | 2 | use clippy_utils::higher::VecArgs; |
4 | 3 | use clippy_utils::source::snippet_opt; |
5 | 4 | use clippy_utils::ty::{implements_trait, type_is_unsafe_function}; |
| 5 | +use clippy_utils::usage::UsedAfterExprVisitor; |
| 6 | +use clippy_utils::{get_enclosing_loop_or_closure, higher}; |
6 | 7 | use clippy_utils::{is_adjusted, iter_input_pats}; |
7 | 8 | use if_chain::if_chain; |
8 | 9 | use rustc_errors::Applicability; |
9 | 10 | use rustc_hir::{def_id, Expr, ExprKind, Param, PatKind, QPath}; |
10 | 11 | use rustc_lint::{LateContext, LateLintPass, LintContext}; |
11 | 12 | use rustc_middle::lint::in_external_macro; |
12 | | -use rustc_middle::ty::{self, Ty}; |
| 13 | +use rustc_middle::ty::{self, ClosureKind, Ty}; |
13 | 14 | use rustc_session::{declare_lint_pass, declare_tool_lint}; |
14 | 15 |
|
15 | 16 | declare_clippy_lint! { |
@@ -86,7 +87,7 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction { |
86 | 87 | } |
87 | 88 | } |
88 | 89 |
|
89 | | -fn check_closure(cx: &LateContext<'_>, expr: &Expr<'_>) { |
| 90 | +fn check_closure<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { |
90 | 91 | if let ExprKind::Closure(_, decl, eid, _, _) = expr.kind { |
91 | 92 | let body = cx.tcx.hir().body(eid); |
92 | 93 | let ex = &body.value; |
@@ -131,7 +132,18 @@ fn check_closure(cx: &LateContext<'_>, expr: &Expr<'_>) { |
131 | 132 |
|
132 | 133 | then { |
133 | 134 | span_lint_and_then(cx, REDUNDANT_CLOSURE, expr.span, "redundant closure", |diag| { |
134 | | - if let Some(snippet) = snippet_opt(cx, caller.span) { |
| 135 | + if let Some(mut snippet) = snippet_opt(cx, caller.span) { |
| 136 | + if_chain! { |
| 137 | + if let ty::Closure(_, substs) = fn_ty.kind(); |
| 138 | + if let ClosureKind::FnMut = substs.as_closure().kind(); |
| 139 | + if UsedAfterExprVisitor::is_found(cx, caller) |
| 140 | + || get_enclosing_loop_or_closure(cx.tcx, expr).is_some(); |
| 141 | + |
| 142 | + then { |
| 143 | + // Mutable closure is used after current expr; we cannot consume it. |
| 144 | + snippet = format!("&mut {}", snippet); |
| 145 | + } |
| 146 | + } |
135 | 147 | diag.span_suggestion( |
136 | 148 | expr.span, |
137 | 149 | "replace the closure with the function itself", |
|
0 commit comments