@@ -33,26 +33,19 @@ pub(super) fn check(cx: &LateContext<'_>, self_arg: &Expr<'_>, call_expr: &Expr<
3333
3434 let mut applicability = Applicability :: MachineApplicable ;
3535 let object = snippet_with_applicability ( cx, self_arg. span , "_" , & mut applicability) ;
36- let prefix = match adjust {
37- AdjustKind :: None => "" ,
38- AdjustKind :: Borrow => "&" ,
39- AdjustKind :: BorrowMut => "&mut " ,
40- AdjustKind :: Deref => "*" ,
41- AdjustKind :: Reborrow => "&*" ,
42- AdjustKind :: ReborrowMut => "&mut *" ,
43- } ;
4436 span_lint_and_sugg (
4537 cx,
4638 EXPLICIT_ITER_LOOP ,
4739 call_expr. span ,
4840 "it is more concise to loop over references to containers instead of using explicit \
4941 iteration methods",
5042 "to write this more concisely, try" ,
51- format ! ( "{prefix }{object}" ) ,
43+ format ! ( "{}{object}" , adjust . display ( ) ) ,
5244 applicability,
5345 ) ;
5446}
5547
48+ #[ derive( Clone , Copy ) ]
5649enum AdjustKind {
5750 None ,
5851 Borrow ,
@@ -76,16 +69,35 @@ impl AdjustKind {
7669 }
7770 }
7871
79- fn reborrow ( mutbl : AutoBorrowMutability ) -> Self {
72+ fn reborrow ( mutbl : Mutability ) -> Self {
73+ match mutbl {
74+ Mutability :: Not => Self :: Reborrow ,
75+ Mutability :: Mut => Self :: ReborrowMut ,
76+ }
77+ }
78+
79+ fn auto_reborrow ( mutbl : AutoBorrowMutability ) -> Self {
8080 match mutbl {
8181 AutoBorrowMutability :: Not => Self :: Reborrow ,
8282 AutoBorrowMutability :: Mut { .. } => Self :: ReborrowMut ,
8383 }
8484 }
85+
86+ fn display ( self ) -> & ' static str {
87+ match self {
88+ Self :: None => "" ,
89+ Self :: Borrow => "&" ,
90+ Self :: BorrowMut => "&mut " ,
91+ Self :: Deref => "*" ,
92+ Self :: Reborrow => "&*" ,
93+ Self :: ReborrowMut => "&mut *" ,
94+ }
95+ }
8596}
8697
8798/// Checks if an `iter` or `iter_mut` call returns `IntoIterator::IntoIter`. Returns how the
8899/// argument needs to be adjusted.
100+ #[ expect( clippy:: too_many_lines) ]
89101fn is_ref_iterable < ' tcx > (
90102 cx : & LateContext < ' tcx > ,
91103 self_arg : & Expr < ' _ > ,
@@ -108,27 +120,50 @@ fn is_ref_iterable<'tcx>(
108120 let self_is_copy = is_copy ( cx, self_ty) ;
109121
110122 if adjustments. is_empty ( ) && self_is_copy {
123+ // Exact type match, already checked earlier
111124 return Some ( ( AdjustKind :: None , self_ty) ) ;
112125 }
113126
114- let res_ty = cx. tcx . erase_regions ( EarlyBinder :: bind ( req_res_ty) . subst ( cx. tcx , typeck. node_substs ( call_expr. hir_id ) ) ) ;
115- if !adjustments. is_empty ( ) && self_is_copy {
116- if implements_trait ( cx, self_ty, trait_id, & [ ] )
117- && let Some ( ty) = make_normalized_projection ( cx. tcx , cx. param_env , trait_id, sym ! ( IntoIter ) , [ self_ty] )
118- && ty == res_ty
119- {
120- return Some ( ( AdjustKind :: None , self_ty) ) ;
121- }
122- }
123-
127+ let res_ty = cx. tcx . erase_regions ( EarlyBinder :: bind ( req_res_ty)
128+ . subst ( cx. tcx , typeck. node_substs ( call_expr. hir_id ) ) ) ;
124129 let mutbl = if let ty:: Ref ( _, _, mutbl) = * req_self_ty. kind ( ) {
125130 Some ( mutbl)
126131 } else {
127132 None
128133 } ;
134+
135+ if !adjustments. is_empty ( ) {
136+ if self_is_copy {
137+ // Using by value won't consume anything
138+ if implements_trait ( cx, self_ty, trait_id, & [ ] )
139+ && let Some ( ty) =
140+ make_normalized_projection ( cx. tcx , cx. param_env , trait_id, sym ! ( IntoIter ) , [ self_ty] )
141+ && ty == res_ty
142+ {
143+ return Some ( ( AdjustKind :: None , self_ty) ) ;
144+ }
145+ } else if let ty:: Ref ( region, ty, Mutability :: Mut ) = * self_ty. kind ( )
146+ && let Some ( mutbl) = mutbl
147+ {
148+ // Attempt to reborrow the mutable reference
149+ let self_ty = if mutbl. is_mut ( ) {
150+ self_ty
151+ } else {
152+ cx. tcx . mk_ref ( region, TypeAndMut { ty, mutbl } )
153+ } ;
154+ if implements_trait ( cx, self_ty, trait_id, & [ ] )
155+ && let Some ( ty) =
156+ make_normalized_projection ( cx. tcx , cx. param_env , trait_id, sym ! ( IntoIter ) , [ self_ty] )
157+ && ty == res_ty
158+ {
159+ return Some ( ( AdjustKind :: reborrow ( mutbl) , self_ty) ) ;
160+ }
161+ }
162+ }
129163 if let Some ( mutbl) = mutbl
130164 && !self_ty. is_ref ( )
131165 {
166+ // Attempt to borrow
132167 let self_ty = cx. tcx . mk_ref ( cx. tcx . lifetimes . re_erased , TypeAndMut {
133168 ty : self_ty,
134169 mutbl,
@@ -157,7 +192,7 @@ fn is_ref_iterable<'tcx>(
157192 make_normalized_projection ( cx. tcx , cx. param_env , trait_id, sym ! ( IntoIter ) , [ target] )
158193 && ty == res_ty
159194 {
160- Some ( ( AdjustKind :: reborrow ( mutbl) , target) )
195+ Some ( ( AdjustKind :: auto_reborrow ( mutbl) , target) )
161196 } else {
162197 None
163198 }
0 commit comments