Skip to content

Commit b613f9e

Browse files
committed
Preserve panic behavior for inclusive length bounds
1 parent 85607ab commit b613f9e

4 files changed

Lines changed: 124 additions & 26 deletions

File tree

clippy_lints/src/loops/needless_range_loop.rs

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,8 @@ pub(super) fn check<'tcx>(
117117
end_is_start_plus_val = start_equal_left | start_equal_right;
118118
}
119119

120-
if is_len_call(end, indexed) || is_end_eq_array_len(cx, end, limits, indexed_ty) {
120+
let end_is_indexed_len = matches!(limits, ast::RangeLimits::HalfOpen) && is_len_call(end, indexed);
121+
if end_is_indexed_len || is_end_eq_array_len(cx, end, limits, indexed_ty) {
121122
String::new()
122123
} else if visitor.indexed_mut.contains(&indexed) && contains_name(indexed, take_expr, cx) {
123124
return;
@@ -150,7 +151,27 @@ pub(super) fn check<'tcx>(
150151
mem::swap(&mut method_1, &mut method_2);
151152
}
152153

154+
let panic_behavior_note = "this suggestion preserves panic behavior, but the panic will occur \
155+
before iteration if the range end is out of bounds";
156+
153157
if visitor.nonindex {
158+
let mut applicability = Applicability::HasPlaceholders;
159+
let (repl, note) = if !take_is_empty {
160+
// Use a slice bound to preserve panic behavior.
161+
let end_snippet = snippet_with_applicability(cx, end.unwrap().span, "..", &mut applicability);
162+
let range = match limits {
163+
ast::RangeLimits::Closed => format!("..={end_snippet}"),
164+
ast::RangeLimits::HalfOpen => format!("..{end_snippet}"),
165+
};
166+
167+
(
168+
format!("{indexed}[{range}].{method}().enumerate(){slice_skip}"),
169+
Some(panic_behavior_note),
170+
)
171+
} else {
172+
(format!("{indexed}.{method}().enumerate(){method_1}{method_2}"), None)
173+
};
174+
154175
span_lint_and_then(
155176
cx,
156177
NEEDLESS_RANGE_LOOP,
@@ -159,20 +180,20 @@ pub(super) fn check<'tcx>(
159180
|diag| {
160181
diag.multipart_suggestion(
161182
"consider using an iterator and enumerate()",
162-
vec![
163-
(pat.span, format!("({}, <item>)", ident.name)),
164-
(span, format!("{indexed}.{method}().enumerate(){method_1}{method_2}")),
165-
],
166-
Applicability::HasPlaceholders,
183+
vec![(pat.span, format!("({}, <item>)", ident.name)), (span, repl)],
184+
applicability,
167185
);
186+
if let Some(note) = note {
187+
diag.note(note);
188+
}
168189
},
169190
);
170191
} else {
171192
let mut applicability = Applicability::HasPlaceholders;
172193
let (repl, note) = if starts_at_zero && take_is_empty {
173194
(format!("&{ref_mut}{indexed}"), None)
174195
} else if !take_is_empty {
175-
// Use a slice bound to preserve panic behaviour
196+
// Use a slice bound to preserve panic behavior
176197
let end_snippet = snippet_with_applicability(cx, end.unwrap().span, "..", &mut applicability);
177198
let range = match limits {
178199
ast::RangeLimits::Closed => format!("..={end_snippet}"),
@@ -181,10 +202,7 @@ pub(super) fn check<'tcx>(
181202

182203
(
183204
format!("{indexed}[{range}].{method}(){slice_skip}"),
184-
Some(
185-
"this suggestion preserves panic behavior, but the panic will occur \
186-
before iteration if the upper bound exceeds the collection length",
187-
),
205+
Some(panic_behavior_note),
188206
)
189207
} else {
190208
(format!("{indexed}.{method}(){method_1}{method_2}"), None)
@@ -236,8 +254,8 @@ fn is_end_eq_array_len<'tcx>(
236254
&& let Some(arr_len) = arr_len_const.try_to_target_usize(cx.tcx)
237255
{
238256
return match limits {
239-
ast::RangeLimits::Closed => end_int.get() + 1 >= arr_len.into(),
240-
ast::RangeLimits::HalfOpen => end_int.get() >= arr_len.into(),
257+
ast::RangeLimits::Closed => end_int.get().checked_add(1) == Some(arr_len.into()),
258+
ast::RangeLimits::HalfOpen => end_int.get() == arr_len.into(),
241259
};
242260
}
243261

tests/ui/needless_range_loop.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,3 +242,29 @@ fn issue_15068() {
242242
let _ = a[0][i];
243243
}
244244
}
245+
246+
fn issue_16003() {
247+
let vec = vec![1, 2, 3];
248+
249+
for i in 0..=vec.len() {
250+
//~^ needless_range_loop
251+
let _ = vec[i];
252+
}
253+
254+
for i in 0..=vec.len() {
255+
//~^ needless_range_loop
256+
let _ = (i, vec[i]);
257+
}
258+
259+
let arr = [1, 2, 3];
260+
261+
for i in 0..4 {
262+
//~^ needless_range_loop
263+
let _ = arr[i];
264+
}
265+
266+
for i in 0..=3 {
267+
//~^ needless_range_loop
268+
let _ = arr[i];
269+
}
270+
}

tests/ui/needless_range_loop.stderr

Lines changed: 63 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ error: the loop variable `i` is only used to index `vec2`
6666
LL | for i in 0..vec.len() {
6767
| ^^^^^^^^^^^^
6868
|
69-
= note: this suggestion preserves panic behavior, but the panic will occur before iteration if the upper bound exceeds the collection length
69+
= note: this suggestion preserves panic behavior, but the panic will occur before iteration if the range end is out of bounds
7070
help: consider using an iterator
7171
|
7272
LL - for i in 0..vec.len() {
@@ -91,7 +91,7 @@ error: the loop variable `i` is only used to index `vec`
9191
LL | for i in 0..MAX_LEN {
9292
| ^^^^^^^^^^
9393
|
94-
= note: this suggestion preserves panic behavior, but the panic will occur before iteration if the upper bound exceeds the collection length
94+
= note: this suggestion preserves panic behavior, but the panic will occur before iteration if the range end is out of bounds
9595
help: consider using an iterator
9696
|
9797
LL - for i in 0..MAX_LEN {
@@ -104,7 +104,7 @@ error: the loop variable `i` is only used to index `vec`
104104
LL | for i in 0..=MAX_LEN {
105105
| ^^^^^^^^^^^
106106
|
107-
= note: this suggestion preserves panic behavior, but the panic will occur before iteration if the upper bound exceeds the collection length
107+
= note: this suggestion preserves panic behavior, but the panic will occur before iteration if the range end is out of bounds
108108
help: consider using an iterator
109109
|
110110
LL - for i in 0..=MAX_LEN {
@@ -117,7 +117,7 @@ error: the loop variable `i` is only used to index `vec`
117117
LL | for i in 5..10 {
118118
| ^^^^^
119119
|
120-
= note: this suggestion preserves panic behavior, but the panic will occur before iteration if the upper bound exceeds the collection length
120+
= note: this suggestion preserves panic behavior, but the panic will occur before iteration if the range end is out of bounds
121121
help: consider using an iterator
122122
|
123123
LL - for i in 5..10 {
@@ -130,7 +130,7 @@ error: the loop variable `i` is only used to index `vec`
130130
LL | for i in 5..=10 {
131131
| ^^^^^^
132132
|
133-
= note: this suggestion preserves panic behavior, but the panic will occur before iteration if the upper bound exceeds the collection length
133+
= note: this suggestion preserves panic behavior, but the panic will occur before iteration if the range end is out of bounds
134134
help: consider using an iterator
135135
|
136136
LL - for i in 5..=10 {
@@ -155,10 +155,11 @@ error: the loop variable `i` is used to index `vec`
155155
LL | for i in 5..10 {
156156
| ^^^^^
157157
|
158+
= note: this suggestion preserves panic behavior, but the panic will occur before iteration if the range end is out of bounds
158159
help: consider using an iterator and enumerate()
159160
|
160161
LL - for i in 5..10 {
161-
LL + for (i, <item>) in vec.iter().enumerate().take(10).skip(5) {
162+
LL + for (i, <item>) in vec[..10].iter().enumerate().skip(5) {
162163
|
163164

164165
error: the loop variable `i` is used to index `vec`
@@ -179,10 +180,11 @@ error: the loop variable `i` is used to index `a`
179180
LL | for i in 0..MAX_LEN {
180181
| ^^^^^^^^^^
181182
|
183+
= note: this suggestion preserves panic behavior, but the panic will occur before iteration if the range end is out of bounds
182184
help: consider using an iterator and enumerate()
183185
|
184186
LL - for i in 0..MAX_LEN {
185-
LL + for (i, <item>) in a.iter().enumerate().take(MAX_LEN) {
187+
LL + for (i, <item>) in a[..MAX_LEN].iter().enumerate() {
186188
|
187189

188190
error: the loop variable `i` is only used to index `a`
@@ -191,12 +193,64 @@ error: the loop variable `i` is only used to index `a`
191193
LL | for i in 0..MAX_LEN {
192194
| ^^^^^^^^^^
193195
|
194-
= note: this suggestion preserves panic behavior, but the panic will occur before iteration if the upper bound exceeds the collection length
196+
= note: this suggestion preserves panic behavior, but the panic will occur before iteration if the range end is out of bounds
195197
help: consider using an iterator
196198
|
197199
LL - for i in 0..MAX_LEN {
198200
LL + for <item> in a[..MAX_LEN].iter() {
199201
|
200202

201-
error: aborting due to 16 previous errors
203+
error: the loop variable `i` is only used to index `vec`
204+
--> tests/ui/needless_range_loop.rs:249:14
205+
|
206+
LL | for i in 0..=vec.len() {
207+
| ^^^^^^^^^^^^^
208+
|
209+
= note: this suggestion preserves panic behavior, but the panic will occur before iteration if the range end is out of bounds
210+
help: consider using an iterator
211+
|
212+
LL - for i in 0..=vec.len() {
213+
LL + for <item> in vec[..=vec.len()].iter() {
214+
|
215+
216+
error: the loop variable `i` is used to index `vec`
217+
--> tests/ui/needless_range_loop.rs:254:14
218+
|
219+
LL | for i in 0..=vec.len() {
220+
| ^^^^^^^^^^^^^
221+
|
222+
= note: this suggestion preserves panic behavior, but the panic will occur before iteration if the range end is out of bounds
223+
help: consider using an iterator and enumerate()
224+
|
225+
LL - for i in 0..=vec.len() {
226+
LL + for (i, <item>) in vec[..=vec.len()].iter().enumerate() {
227+
|
228+
229+
error: the loop variable `i` is only used to index `arr`
230+
--> tests/ui/needless_range_loop.rs:261:14
231+
|
232+
LL | for i in 0..4 {
233+
| ^^^^
234+
|
235+
= note: this suggestion preserves panic behavior, but the panic will occur before iteration if the range end is out of bounds
236+
help: consider using an iterator
237+
|
238+
LL - for i in 0..4 {
239+
LL + for <item> in arr[..4].iter() {
240+
|
241+
242+
error: the loop variable `i` is only used to index `arr`
243+
--> tests/ui/needless_range_loop.rs:266:14
244+
|
245+
LL | for i in 0..=3 {
246+
| ^^^^^
247+
|
248+
= note: this suggestion preserves panic behavior, but the panic will occur before iteration if the range end is out of bounds
249+
help: consider using an iterator
250+
|
251+
LL - for i in 0..=3 {
252+
LL + for <item> in arr[..=3].iter() {
253+
|
254+
255+
error: aborting due to 20 previous errors
202256

tests/ui/needless_range_loop2.stderr

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ error: the loop variable `i` is only used to index `ns`
44
LL | for i in 3..10 {
55
| ^^^^^
66
|
7-
= note: this suggestion preserves panic behavior, but the panic will occur before iteration if the upper bound exceeds the collection length
7+
= note: this suggestion preserves panic behavior, but the panic will occur before iteration if the range end is out of bounds
88
= note: `-D clippy::needless-range-loop` implied by `-D warnings`
99
= help: to override `-D warnings` add `#[allow(clippy::needless_range_loop)]`
1010
help: consider using an iterator
@@ -43,7 +43,7 @@ error: the loop variable `i` is only used to index `vec`
4343
LL | for i in x..x + 4 {
4444
| ^^^^^^^^
4545
|
46-
= note: this suggestion preserves panic behavior, but the panic will occur before iteration if the upper bound exceeds the collection length
46+
= note: this suggestion preserves panic behavior, but the panic will occur before iteration if the range end is out of bounds
4747
help: consider using an iterator
4848
|
4949
LL - for i in x..x + 4 {
@@ -56,7 +56,7 @@ error: the loop variable `i` is only used to index `vec`
5656
LL | for i in x..=x + 4 {
5757
| ^^^^^^^^^
5858
|
59-
= note: this suggestion preserves panic behavior, but the panic will occur before iteration if the upper bound exceeds the collection length
59+
= note: this suggestion preserves panic behavior, but the panic will occur before iteration if the range end is out of bounds
6060
help: consider using an iterator
6161
|
6262
LL - for i in x..=x + 4 {
@@ -81,7 +81,7 @@ error: the loop variable `i` is only used to index `arr`
8181
LL | for i in 0..2 {
8282
| ^^^^
8383
|
84-
= note: this suggestion preserves panic behavior, but the panic will occur before iteration if the upper bound exceeds the collection length
84+
= note: this suggestion preserves panic behavior, but the panic will occur before iteration if the range end is out of bounds
8585
help: consider using an iterator
8686
|
8787
LL - for i in 0..2 {

0 commit comments

Comments
 (0)