@@ -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