Skip to content

Commit 0f4b13b

Browse files
authored
Merge pull request #3316 from pengowen123/fix_needless_range_loop
Swap order of methods in `needless_range_loop` suggestion for efficiency in some cases
2 parents 3ad9290 + 456843f commit 0f4b13b

File tree

5 files changed

+69
-7
lines changed

5 files changed

+69
-7
lines changed

clippy_lints/src/loops.rs

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ use crate::rustc::ty::subst::Subst;
2727
use crate::rustc_errors::Applicability;
2828
use crate::rustc_data_structures::fx::{FxHashMap, FxHashSet};
2929
use std::iter::{once, Iterator};
30+
use std::mem;
3031
use crate::syntax::ast;
3132
use crate::syntax::source_map::Span;
3233
use crate::syntax_pos::BytePos;
@@ -1082,16 +1083,35 @@ fn check_for_loop_range<'a, 'tcx>(
10821083
format!(".skip({})", snippet(cx, start.span, ".."))
10831084
};
10841085

1086+
let mut end_is_start_plus_val = false;
1087+
10851088
let take = if let Some(end) = *end {
1089+
let mut take_expr = end;
1090+
1091+
if let ExprKind::Binary(ref op, ref left, ref right) = end.node {
1092+
if let BinOpKind::Add = op.node {
1093+
let start_equal_left = SpanlessEq::new(cx).eq_expr(start, left);
1094+
let start_equal_right = SpanlessEq::new(cx).eq_expr(start, right);
1095+
1096+
if start_equal_left {
1097+
take_expr = right;
1098+
} else if start_equal_right {
1099+
take_expr = left;
1100+
}
1101+
1102+
end_is_start_plus_val = start_equal_left | start_equal_right;
1103+
}
1104+
}
1105+
10861106
if is_len_call(end, indexed) {
10871107
String::new()
10881108
} else {
10891109
match limits {
10901110
ast::RangeLimits::Closed => {
1091-
let end = sugg::Sugg::hir(cx, end, "<count>");
1092-
format!(".take({})", end + sugg::ONE)
1111+
let take_expr = sugg::Sugg::hir(cx, take_expr, "<count>");
1112+
format!(".take({})", take_expr + sugg::ONE)
10931113
},
1094-
ast::RangeLimits::HalfOpen => format!(".take({})", snippet(cx, end.span, "..")),
1114+
ast::RangeLimits::HalfOpen => format!(".take({})", snippet(cx, take_expr.span, "..")),
10951115
}
10961116
}
10971117
} else {
@@ -1104,6 +1124,14 @@ fn check_for_loop_range<'a, 'tcx>(
11041124
("", "iter")
11051125
};
11061126

1127+
let take_is_empty = take.is_empty();
1128+
let mut method_1 = take;
1129+
let mut method_2 = skip;
1130+
1131+
if end_is_start_plus_val {
1132+
mem::swap(&mut method_1, &mut method_2);
1133+
}
1134+
11071135
if visitor.nonindex {
11081136
span_lint_and_then(
11091137
cx,
@@ -1116,16 +1144,16 @@ fn check_for_loop_range<'a, 'tcx>(
11161144
"consider using an iterator".to_string(),
11171145
vec![
11181146
(pat.span, format!("({}, <item>)", ident.name)),
1119-
(arg.span, format!("{}.{}().enumerate(){}{}", indexed, method, take, skip)),
1147+
(arg.span, format!("{}.{}().enumerate(){}{}", indexed, method, method_1, method_2)),
11201148
],
11211149
);
11221150
},
11231151
);
11241152
} else {
1125-
let repl = if starts_at_zero && take.is_empty() {
1153+
let repl = if starts_at_zero && take_is_empty {
11261154
format!("&{}{}", ref_mut, indexed)
11271155
} else {
1128-
format!("{}.{}(){}{}", indexed, method, take, skip)
1156+
format!("{}.{}(){}{}", indexed, method, method_1, method_2)
11291157
};
11301158

11311159
span_lint_and_then(

tests/ui/author/for_loop.stderr

Whitespace-only changes.

tests/ui/needless_range_loop.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,4 +62,18 @@ fn main() {
6262
g[i] = g[i+1..].iter().sum();
6363
}
6464
assert_eq!(g, vec![20, 18, 15, 11, 6, 0]);
65+
66+
let x = 5;
67+
let mut vec = vec![0; 9];
68+
69+
for i in x..x + 4 {
70+
vec[i] += 1;
71+
}
72+
73+
let x = 5;
74+
let mut vec = vec![0; 10];
75+
76+
for i in x..=x + 4 {
77+
vec[i] += 1;
78+
}
6579
}

tests/ui/needless_range_loop.stderr

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,5 +30,25 @@ help: consider using an iterator
3030
45 | for <item> in &mut ms {
3131
| ^^^^^^ ^^^^^^^
3232

33-
error: aborting due to 3 previous errors
33+
error: the loop variable `i` is only used to index `vec`.
34+
--> $DIR/needless_range_loop.rs:69:14
35+
|
36+
69 | for i in x..x + 4 {
37+
| ^^^^^^^^
38+
help: consider using an iterator
39+
|
40+
69 | for <item> in vec.iter_mut().skip(x).take(4) {
41+
| ^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
42+
43+
error: the loop variable `i` is only used to index `vec`.
44+
--> $DIR/needless_range_loop.rs:76:14
45+
|
46+
76 | for i in x..=x + 4 {
47+
| ^^^^^^^^^
48+
help: consider using an iterator
49+
|
50+
76 | for <item> in vec.iter_mut().skip(x).take(4 + 1) {
51+
| ^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
52+
53+
error: aborting due to 5 previous errors
3454

tests/ui/ty_fn_sig.stderr

Whitespace-only changes.

0 commit comments

Comments
 (0)