Skip to content

Commit b8b420c

Browse files
Improve code readability by moving the retrieval of closures inside async functions right besides other closures handling.
Add doc comment explaining what `MutablyUsedVariablesCtxt::prev_move_to_closure` is about.
1 parent e3267b1 commit b8b420c

File tree

1 file changed

+19
-38
lines changed

1 file changed

+19
-38
lines changed

clippy_lints/src/needless_pass_by_ref_mut.rs

+19-38
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
use super::needless_pass_by_value::requires_exact_signature;
22
use clippy_utils::diagnostics::span_lint_hir_and_then;
33
use clippy_utils::source::snippet;
4+
use clippy_utils::visitors::for_each_expr_with_closures;
45
use clippy_utils::{get_parent_node, inherits_cfg, is_from_proc_macro, is_self};
56
use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
67
use rustc_errors::Applicability;
7-
use rustc_hir::intravisit::{walk_fn, walk_qpath, FnKind, Visitor};
8+
use rustc_hir::intravisit::{walk_qpath, FnKind, Visitor};
89
use rustc_hir::{
9-
Body, BodyId, Closure, Expr, ExprKind, FnDecl, HirId, HirIdMap, HirIdSet, Impl, ItemKind, Mutability, Node,
10-
PatKind, QPath,
10+
Body, Closure, Expr, ExprKind, FnDecl, HirId, HirIdMap, HirIdSet, Impl, ItemKind, Mutability, Node, PatKind, QPath,
1111
};
1212
use rustc_hir_typeck::expr_use_visitor as euv;
1313
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
@@ -22,6 +22,8 @@ use rustc_span::symbol::kw;
2222
use rustc_span::Span;
2323
use rustc_target::spec::abi::Abi;
2424

25+
use core::ops::ControlFlow;
26+
2527
declare_clippy_lint! {
2628
/// ### What it does
2729
/// Check if a `&mut` function argument is actually used mutably.
@@ -189,17 +191,19 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> {
189191

190192
// We retrieve all the closures declared in the async function because they will
191193
// not be found by `euv::Delegate`.
192-
let mut closures_retriever = ClosuresRetriever {
193-
cx,
194-
closures: FxHashSet::default(),
195-
};
196-
walk_fn(&mut closures_retriever, kind, decl, body.id(), fn_def_id);
197-
check_closures(&mut ctx, cx, &infcx, &mut checked_closures, closures_retriever.closures);
194+
let mut closures: FxHashSet<LocalDefId> = FxHashSet::default();
195+
for_each_expr_with_closures(cx, body, |expr| {
196+
if let ExprKind::Closure(closure) = expr.kind {
197+
closures.insert(closure.def_id);
198+
}
199+
ControlFlow::<()>::Continue(())
200+
});
201+
check_closures(&mut ctx, cx, &infcx, &mut checked_closures, closures);
198202

199203
while !ctx.async_closures.is_empty() {
200-
let closures = ctx.async_closures.clone();
204+
let async_closures = ctx.async_closures.clone();
201205
ctx.async_closures.clear();
202-
check_closures(&mut ctx, cx, &infcx, &mut checked_closures, closures);
206+
check_closures(&mut ctx, cx, &infcx, &mut checked_closures, async_closures);
203207
}
204208
}
205209
ctx
@@ -264,6 +268,10 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> {
264268
struct MutablyUsedVariablesCtxt<'tcx> {
265269
mutably_used_vars: HirIdSet,
266270
prev_bind: Option<HirId>,
271+
/// In async functions, the inner AST is composed of multiple layers until we reach the code
272+
/// defined by the user. Because of that, some variables are marked as mutably borrowed even
273+
/// though they're not. This field lists the `HirId` that should not be considered as mutable
274+
/// use of a variable.
267275
prev_move_to_closure: HirIdSet,
268276
aliases: HirIdMap<HirId>,
269277
async_closures: FxHashSet<LocalDefId>,
@@ -459,30 +467,3 @@ impl<'tcx> Visitor<'tcx> for FnNeedsMutVisitor<'_, 'tcx> {
459467
}
460468
}
461469
}
462-
463-
struct ClosuresRetriever<'a, 'tcx> {
464-
cx: &'a LateContext<'tcx>,
465-
closures: FxHashSet<LocalDefId>,
466-
}
467-
468-
impl<'a, 'tcx> Visitor<'tcx> for ClosuresRetriever<'a, 'tcx> {
469-
type NestedFilter = OnlyBodies;
470-
471-
fn nested_visit_map(&mut self) -> Self::Map {
472-
self.cx.tcx.hir()
473-
}
474-
475-
fn visit_fn(
476-
&mut self,
477-
kind: FnKind<'tcx>,
478-
decl: &'tcx FnDecl<'tcx>,
479-
body_id: BodyId,
480-
_span: Span,
481-
fn_def_id: LocalDefId,
482-
) {
483-
if matches!(kind, FnKind::Closure) {
484-
self.closures.insert(fn_def_id);
485-
}
486-
walk_fn(self, kind, decl, body_id, fn_def_id);
487-
}
488-
}

0 commit comments

Comments
 (0)