11use clippy_config:: Conf ;
22use clippy_utils:: diagnostics:: span_lint_and_help;
3- use clippy_utils:: is_from_proc_macro;
43use clippy_utils:: msrvs:: { self , Msrv } ;
54use clippy_utils:: res:: MaybeResPath ;
6- use clippy_utils:: visitors:: for_each_local_use_after_expr;
5+ use clippy_utils:: visitors:: local_used_once;
6+ use clippy_utils:: { get_enclosing_block, is_from_proc_macro} ;
77use itertools:: Itertools ;
88use rustc_ast:: LitKind ;
99use rustc_hir:: { Expr , ExprKind , Node , PatKind } ;
1010use rustc_lint:: { LateContext , LateLintPass , LintContext } ;
1111use rustc_middle:: ty:: { self , Ty } ;
1212use rustc_session:: impl_lint_pass;
1313use std:: iter:: once;
14- use std:: ops:: ControlFlow ;
1514
1615declare_clippy_lint ! {
1716 /// ### What it does
@@ -86,7 +85,7 @@ fn check_array<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, elements: &
8685 ExprKind :: Path ( _) => Some ( elements. iter ( ) . collect ( ) ) ,
8786 _ => None ,
8887 } )
89- && all_bindings_are_for_conv ( cx, & [ ty] , expr , elements, & locals, ToType :: Array )
88+ && all_bindings_are_for_conv ( cx, & [ ty] , elements, & locals, ToType :: Array )
9089 && !is_from_proc_macro ( cx, expr)
9190 {
9291 span_lint_and_help (
@@ -123,7 +122,7 @@ fn check_tuple<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, elements: &
123122 ExprKind :: Path ( _) => Some ( elements. iter ( ) . collect ( ) ) ,
124123 _ => None ,
125124 } )
126- && all_bindings_are_for_conv ( cx, tys, expr , elements, & locals, ToType :: Tuple )
125+ && all_bindings_are_for_conv ( cx, tys, elements, & locals, ToType :: Tuple )
127126 && !is_from_proc_macro ( cx, expr)
128127 {
129128 span_lint_and_help (
@@ -148,7 +147,6 @@ fn check_tuple<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, elements: &
148147fn all_bindings_are_for_conv < ' tcx > (
149148 cx : & LateContext < ' tcx > ,
150149 final_tys : & [ Ty < ' tcx > ] ,
151- expr : & Expr < ' _ > ,
152150 elements : & [ Expr < ' _ > ] ,
153151 locals : & [ & Expr < ' _ > ] ,
154152 kind : ToType ,
@@ -166,13 +164,30 @@ fn all_bindings_are_for_conv<'tcx>(
166164 _ => None ,
167165 } )
168166 . all_equal ( )
169- // Fix #11124, very convenient utils function! ❤️
170- && locals
171- . iter ( )
172- . all ( |& l| for_each_local_use_after_expr ( cx, l, expr. hir_id , |_| ControlFlow :: Break :: < ( ) > ( ( ) ) ) . is_continue ( ) )
167+ && locals. iter ( ) . zip ( local_parents. iter ( ) ) . all ( |( & l, & parent) | {
168+ if let Node :: LetStmt ( _) = parent {
169+ return true ;
170+ }
171+
172+ let Some ( b) = get_enclosing_block ( cx, l) else {
173+ return true ;
174+ } ;
175+ local_used_once ( cx, b, l) . is_some ( )
176+ } )
173177 && local_parents. first ( ) . is_some_and ( |node| {
174178 let Some ( ty) = match node {
175- Node :: Pat ( pat) => Some ( pat. hir_id ) ,
179+ Node :: Pat ( pat)
180+ if let PatKind :: Tuple ( pats, _) | PatKind :: Slice ( pats, None , [ ] ) = & pat. kind
181+ && pats. iter ( ) . zip ( locals. iter ( ) ) . all ( |( p, l) | {
182+ if let PatKind :: Binding ( _, id, _, _) = p. kind {
183+ id == * l
184+ } else {
185+ true
186+ }
187+ } ) =>
188+ {
189+ Some ( pat. hir_id )
190+ } ,
176191 Node :: LetStmt ( l) => Some ( l. hir_id ) ,
177192 _ => None ,
178193 }
@@ -186,7 +201,9 @@ fn all_bindings_are_for_conv<'tcx>(
186201 tys. len ( ) == elements. len ( ) && tys. iter ( ) . chain ( final_tys. iter ( ) . copied ( ) ) . all_equal ( )
187202 } ,
188203 ( ToType :: Tuple , ty:: Array ( ty, len) ) => {
189- let Some ( len) = len. try_to_target_usize ( cx. tcx ) else { return false } ;
204+ let Some ( len) = len. try_to_target_usize ( cx. tcx ) else {
205+ return false ;
206+ } ;
190207 len as usize == elements. len ( ) && final_tys. iter ( ) . chain ( once ( ty) ) . all_equal ( )
191208 } ,
192209 _ => false ,
0 commit comments