11use super :: needless_pass_by_value:: requires_exact_signature;
22use clippy_utils:: diagnostics:: span_lint_hir_and_then;
33use clippy_utils:: source:: snippet;
4+ use clippy_utils:: visitors:: for_each_expr_with_closures;
45use clippy_utils:: { get_parent_node, inherits_cfg, is_from_proc_macro, is_self} ;
56use rustc_data_structures:: fx:: { FxHashSet , FxIndexMap } ;
67use rustc_errors:: Applicability ;
7- use rustc_hir:: intravisit:: { walk_fn , walk_qpath, FnKind , Visitor } ;
8+ use rustc_hir:: intravisit:: { walk_qpath, FnKind , Visitor } ;
89use 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} ;
1212use rustc_hir_typeck:: expr_use_visitor as euv;
1313use rustc_infer:: infer:: { InferCtxt , TyCtxtInferExt } ;
@@ -22,6 +22,8 @@ use rustc_span::symbol::kw;
2222use rustc_span:: Span ;
2323use rustc_target:: spec:: abi:: Abi ;
2424
25+ use core:: ops:: ControlFlow ;
26+
2527declare_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> {
264268struct 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