@@ -33,26 +33,19 @@ pub(super) fn check(cx: &LateContext<'_>, self_arg: &Expr<'_>, call_expr: &Expr<
33
33
34
34
let mut applicability = Applicability :: MachineApplicable ;
35
35
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
- } ;
44
36
span_lint_and_sugg (
45
37
cx,
46
38
EXPLICIT_ITER_LOOP ,
47
39
call_expr. span ,
48
40
"it is more concise to loop over references to containers instead of using explicit \
49
41
iteration methods",
50
42
"to write this more concisely, try" ,
51
- format ! ( "{prefix }{object}" ) ,
43
+ format ! ( "{}{object}" , adjust . display ( ) ) ,
52
44
applicability,
53
45
) ;
54
46
}
55
47
48
+ #[ derive( Clone , Copy ) ]
56
49
enum AdjustKind {
57
50
None ,
58
51
Borrow ,
@@ -76,16 +69,35 @@ impl AdjustKind {
76
69
}
77
70
}
78
71
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 {
80
80
match mutbl {
81
81
AutoBorrowMutability :: Not => Self :: Reborrow ,
82
82
AutoBorrowMutability :: Mut { .. } => Self :: ReborrowMut ,
83
83
}
84
84
}
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
+ }
85
96
}
86
97
87
98
/// Checks if an `iter` or `iter_mut` call returns `IntoIterator::IntoIter`. Returns how the
88
99
/// argument needs to be adjusted.
100
+ #[ expect( clippy:: too_many_lines) ]
89
101
fn is_ref_iterable < ' tcx > (
90
102
cx : & LateContext < ' tcx > ,
91
103
self_arg : & Expr < ' _ > ,
@@ -108,27 +120,50 @@ fn is_ref_iterable<'tcx>(
108
120
let self_is_copy = is_copy ( cx, self_ty) ;
109
121
110
122
if adjustments. is_empty ( ) && self_is_copy {
123
+ // Exact type match, already checked earlier
111
124
return Some ( ( AdjustKind :: None , self_ty) ) ;
112
125
}
113
126
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 ) ) ) ;
124
129
let mutbl = if let ty:: Ref ( _, _, mutbl) = * req_self_ty. kind ( ) {
125
130
Some ( mutbl)
126
131
} else {
127
132
None
128
133
} ;
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
+ }
129
163
if let Some ( mutbl) = mutbl
130
164
&& !self_ty. is_ref ( )
131
165
{
166
+ // Attempt to borrow
132
167
let self_ty = cx. tcx . mk_ref ( cx. tcx . lifetimes . re_erased , TypeAndMut {
133
168
ty : self_ty,
134
169
mutbl,
@@ -157,7 +192,7 @@ fn is_ref_iterable<'tcx>(
157
192
make_normalized_projection ( cx. tcx , cx. param_env , trait_id, sym ! ( IntoIter ) , [ target] )
158
193
&& ty == res_ty
159
194
{
160
- Some ( ( AdjustKind :: reborrow ( mutbl) , target) )
195
+ Some ( ( AdjustKind :: auto_reborrow ( mutbl) , target) )
161
196
} else {
162
197
None
163
198
}
0 commit comments