@@ -4,12 +4,13 @@ use clippy_utils::source::snippet;
44use clippy_utils:: { get_parent_node, inherits_cfg, is_from_proc_macro, is_self} ;
55use rustc_data_structures:: fx:: { FxHashSet , FxIndexMap } ;
66use rustc_errors:: Applicability ;
7- use rustc_hir:: intravisit:: { walk_qpath, FnKind , Visitor } ;
7+ use rustc_hir:: intravisit:: { walk_fn , walk_qpath, FnKind , Visitor } ;
88use 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 ,
1011} ;
1112use rustc_hir_typeck:: expr_use_visitor as euv;
12- use rustc_infer:: infer:: TyCtxtInferExt ;
13+ use rustc_infer:: infer:: { InferCtxt , TyCtxtInferExt } ;
1314use rustc_lint:: { LateContext , LateLintPass } ;
1415use rustc_middle:: hir:: map:: associated_body;
1516use rustc_middle:: hir:: nested_filter:: OnlyBodies ;
@@ -95,6 +96,30 @@ fn should_skip<'tcx>(
9596 is_from_proc_macro ( cx, & input)
9697}
9798
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+
98123impl < ' tcx > LateLintPass < ' tcx > for NeedlessPassByRefMut < ' tcx > {
99124 fn check_fn (
100125 & mut self ,
@@ -161,25 +186,20 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> {
161186 euv:: ExprUseVisitor :: new ( & mut ctx, & infcx, fn_def_id, cx. param_env , cx. typeck_results ( ) ) . consume_body ( body) ;
162187 if is_async {
163188 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+
164199 while !ctx. async_closures . is_empty ( ) {
165200 let closures = ctx. async_closures . clone ( ) ;
166201 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) ;
183203 }
184204 }
185205 ctx
@@ -439,3 +459,30 @@ impl<'tcx> Visitor<'tcx> for FnNeedsMutVisitor<'_, 'tcx> {
439459 }
440460 }
441461}
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