@@ -4,12 +4,13 @@ use clippy_utils::source::snippet;
4
4
use clippy_utils::{get_parent_node, inherits_cfg, is_from_proc_macro, is_self};
5
5
use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
6
6
use rustc_errors::Applicability;
7
- use rustc_hir::intravisit::{walk_qpath, FnKind, Visitor};
7
+ use rustc_hir::intravisit::{walk_fn, walk_qpath, FnKind, Visitor};
8
8
use rustc_hir::{
9
- Body, Closure, Expr, ExprKind, FnDecl, HirId, HirIdMap, HirIdSet, Impl, ItemKind, Mutability, Node, PatKind, QPath,
9
+ Body, BodyId, Closure, Expr, ExprKind, FnDecl, HirId, HirIdMap, HirIdSet, Impl, ItemKind, Mutability, Node,
10
+ PatKind, QPath,
10
11
};
11
12
use rustc_hir_typeck::expr_use_visitor as euv;
12
- use rustc_infer::infer::TyCtxtInferExt;
13
+ use rustc_infer::infer::{InferCtxt, TyCtxtInferExt} ;
13
14
use rustc_lint::{LateContext, LateLintPass};
14
15
use rustc_middle::hir::map::associated_body;
15
16
use rustc_middle::hir::nested_filter::OnlyBodies;
@@ -95,6 +96,30 @@ fn should_skip<'tcx>(
95
96
is_from_proc_macro(cx, &input)
96
97
}
97
98
99
+ fn check_closures<'tcx>(
100
+ ctx: &mut MutablyUsedVariablesCtxt<'tcx>,
101
+ cx: &LateContext<'tcx>,
102
+ infcx: &InferCtxt<'tcx>,
103
+ checked_closures: &mut FxHashSet<LocalDefId>,
104
+ closures: FxHashSet<LocalDefId>,
105
+ ) {
106
+ let hir = cx.tcx.hir();
107
+ for closure in closures {
108
+ if !checked_closures.insert(closure) {
109
+ continue;
110
+ }
111
+ ctx.prev_bind = None;
112
+ ctx.prev_move_to_closure.clear();
113
+ if let Some(body) = hir
114
+ .find_by_def_id(closure)
115
+ .and_then(associated_body)
116
+ .map(|(_, body_id)| hir.body(body_id))
117
+ {
118
+ euv::ExprUseVisitor::new(ctx, infcx, closure, cx.param_env, cx.typeck_results()).consume_body(body);
119
+ }
120
+ }
121
+ }
122
+
98
123
impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> {
99
124
fn check_fn(
100
125
&mut self,
@@ -161,25 +186,20 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> {
161
186
euv::ExprUseVisitor::new(&mut ctx, &infcx, fn_def_id, cx.param_env, cx.typeck_results()).consume_body(body);
162
187
if is_async {
163
188
let mut checked_closures = FxHashSet::default();
189
+
190
+ // We retrieve all the closures declared in the async function because they will
191
+ // 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);
198
+
164
199
while !ctx.async_closures.is_empty() {
165
200
let closures = ctx.async_closures.clone();
166
201
ctx.async_closures.clear();
167
- let hir = cx.tcx.hir();
168
- for closure in closures {
169
- if !checked_closures.insert(closure) {
170
- continue;
171
- }
172
- ctx.prev_bind = None;
173
- ctx.prev_move_to_closure.clear();
174
- if let Some(body) = hir
175
- .find_by_def_id(closure)
176
- .and_then(associated_body)
177
- .map(|(_, body_id)| hir.body(body_id))
178
- {
179
- euv::ExprUseVisitor::new(&mut ctx, &infcx, closure, cx.param_env, cx.typeck_results())
180
- .consume_body(body);
181
- }
182
- }
202
+ check_closures(&mut ctx, cx, &infcx, &mut checked_closures, closures);
183
203
}
184
204
}
185
205
ctx
@@ -439,3 +459,30 @@ impl<'tcx> Visitor<'tcx> for FnNeedsMutVisitor<'_, 'tcx> {
439
459
}
440
460
}
441
461
}
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