Skip to content

Commit b7fabb8

Browse files
committed
Simplify manual_memcpy suggestion in some cases
1 parent 0f4b13b commit b7fabb8

File tree

4 files changed

+71
-13
lines changed

4 files changed

+71
-13
lines changed

clippy_lints/src/loops.rs

Lines changed: 49 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -950,8 +950,20 @@ fn detect_manual_memcpy<'a, 'tcx>(
950950
("0", _, x, false) | (x, false, "0", false) => x.into(),
951951
("0", _, x, true) | (x, false, "0", true) => format!("-{}", x),
952952
(x, false, y, false) => format!("({} + {})", x, y),
953-
(x, false, y, true) => format!("({} - {})", x, y),
954-
(x, true, y, false) => format!("({} - {})", y, x),
953+
(x, false, y, true) => {
954+
if x == y {
955+
"0".into()
956+
} else {
957+
format!("({} - {})", x, y)
958+
}
959+
},
960+
(x, true, y, false) => {
961+
if x == y {
962+
"0".into()
963+
} else {
964+
format!("({} - {})", y, x)
965+
}
966+
},
955967
(x, true, y, true) => format!("-({} + {})", x, y),
956968
}
957969
};
@@ -972,15 +984,41 @@ fn detect_manual_memcpy<'a, 'tcx>(
972984
}
973985
}
974986

987+
let mut end_expr = end;
988+
let mut reduced_end_expr = false;
989+
990+
if_chain! {
991+
if let ExprKind::Binary(ref op, ref left, ref right) = end.node;
992+
if let BinOpKind::Add = op.node;
993+
then {
994+
if let Some(left) = sugg::Sugg::hir_opt(cx, left) {
995+
if left.to_string() == offset.value {
996+
end_expr = right;
997+
reduced_end_expr = true;
998+
}
999+
}
1000+
if let Some(right) = sugg::Sugg::hir_opt(cx, right) {
1001+
if right.to_string() == offset.value {
1002+
end_expr = left;
1003+
reduced_end_expr = true;
1004+
}
1005+
}
1006+
}
1007+
}
1008+
9751009
let end_str = match limits {
9761010
ast::RangeLimits::Closed => {
977-
let end = sugg::Sugg::hir(cx, end, "<count>");
1011+
let end = sugg::Sugg::hir(cx, end_expr, "<count>");
9781012
format!("{}", end + sugg::ONE)
9791013
},
980-
ast::RangeLimits::HalfOpen => format!("{}", snippet(cx, end.span, "..")),
1014+
ast::RangeLimits::HalfOpen => format!("{}", snippet(cx, end_expr.span, "..")),
9811015
};
9821016

983-
print_sum(&Offset::positive(end_str), &offset)
1017+
if reduced_end_expr {
1018+
end_str
1019+
} else {
1020+
print_sum(&Offset::positive(end_str), &offset)
1021+
}
9841022
} else {
9851023
"..".into()
9861024
};
@@ -1003,7 +1041,12 @@ fn detect_manual_memcpy<'a, 'tcx>(
10031041
format!("{}[{}..{}]", dst_var.var_name, dst_offset, dst_limit)
10041042
};
10051043

1006-
format!("{}.clone_from_slice(&{}[{}..{}])", dst, src_var.var_name, src_offset, src_limit)
1044+
// If the src range is simply `0..src.len()`, suggest copying the entire slice
1045+
if src_offset == "0" && src_limit == format!("{}.len()", src_var.var_name) {
1046+
format!("{}.clone_from_slice(&{})", dst, src_var.var_name)
1047+
} else {
1048+
format!("{}.clone_from_slice(&{}[{}..{}])", dst, src_var.var_name, src_offset, src_limit)
1049+
}
10071050
})
10081051
.join("\n ");
10091052

tests/ui/for_loop.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -550,6 +550,15 @@ pub fn manual_copy(src: &[i32], dst: &mut [i32], dst2: &mut [i32]) {
550550
for i in 0..10 {
551551
dst_vec[i] = src[i];
552552
}
553+
554+
// Copying entire source slice - simplify suggestion (issue #3004)
555+
let src = [0, 1, 2, 3, 4];
556+
let mut dst = [0, 0, 0, 0, 0, 0];
557+
let from = 1;
558+
559+
for i in from..from + src.len() {
560+
dst[i] = src[i - from];
561+
}
553562
}
554563

555564
#[warn(clippy::needless_range_loop)]

tests/ui/for_loop.stderr

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -482,22 +482,28 @@ error: it looks like you're manually copying between slices
482482
| ^^^^^^^^^^^^^^^^ help: try replacing the loop by: `dst_vec[..src_vec.len()].clone_from_slice(&src_vec[..])`
483483

484484
error: it looks like you're manually copying between slices
485-
--> $DIR/for_loop.rs:557:14
485+
--> $DIR/for_loop.rs:559:14
486486
|
487-
557 | for i in 0..src.len() {
487+
559 | for i in from..from + src.len() {
488+
| ^^^^^^^^^^^^^^^^^^^^^^ help: try replacing the loop by: `dst[from..from + src.len()].clone_from_slice(&src)`
489+
490+
error: it looks like you're manually copying between slices
491+
--> $DIR/for_loop.rs:566:14
492+
|
493+
566 | for i in 0..src.len() {
488494
| ^^^^^^^^^^^^ help: try replacing the loop by: `dst[..src.len()].clone_from_slice(&src[..])`
489495

490496
error: the variable `count` is used as a loop counter. Consider using `for (count, item) in text.chars().enumerate()` or similar iterators
491-
--> $DIR/for_loop.rs:618:19
497+
--> $DIR/for_loop.rs:627:19
492498
|
493-
618 | for ch in text.chars() {
499+
627 | for ch in text.chars() {
494500
| ^^^^^^^^^^^^
495501

496502
error: the variable `count` is used as a loop counter. Consider using `for (count, item) in text.chars().enumerate()` or similar iterators
497-
--> $DIR/for_loop.rs:629:19
503+
--> $DIR/for_loop.rs:638:19
498504
|
499-
629 | for ch in text.chars() {
505+
638 | for ch in text.chars() {
500506
| ^^^^^^^^^^^^
501507

502-
error: aborting due to 61 previous errors
508+
error: aborting due to 62 previous errors
503509

tests/ui/for_loop.stdout

Whitespace-only changes.

0 commit comments

Comments
 (0)