Skip to content

Commit f6a921c

Browse files
committed
fix: [manual_slice_fill] detect for in loops over &mut [T; n] slices
1 parent da29c3e commit f6a921c

4 files changed

Lines changed: 120 additions & 1 deletion

File tree

clippy_lints/src/loops/manual_slice_fill.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use rustc_hir::QPath::Resolved;
1313
use rustc_hir::def::Res;
1414
use rustc_hir::{Expr, ExprKind, Pat};
1515
use rustc_lint::LateContext;
16+
use rustc_middle::ty;
1617
use rustc_span::{Spanned, sym};
1718

1819
use super::MANUAL_SLICE_FILL;
@@ -84,6 +85,24 @@ pub(super) fn check<'tcx>(
8485
{
8586
sugg(cx, body, expr, recv_path.span, assignval.span);
8687
}
88+
// `for slot in s { *slot = value; }` where `s` is already `&mut [T; N]`
89+
else if let ExprKind::Assign(assignee, assignval, _) = peel_blocks_with_stmt(body).kind
90+
&& let ExprKind::Unary(UnOp::Deref, slice_iter) = assignee.kind
91+
&& let ExprKind::Path(Resolved(_, slice_path)) = slice_iter.kind
92+
&& let Res::Local(local) = slice_path.res
93+
&& local == pat.hir_id
94+
&& !assignval.span.from_expansion()
95+
&& switch_to_eager_eval(cx, assignval)
96+
&& !is_local_used(cx, assignval, local)
97+
&& let arg_ty = cx.typeck_results().expr_ty(arg)
98+
&& let ty::Ref(_, inner_ty, rustc_ast::Mutability::Mut) = arg_ty.kind()
99+
&& is_slice_like(cx, *inner_ty)
100+
&& let Some(clone_trait) = cx.tcx.lang_items().clone_trait()
101+
&& implements_trait(cx, *inner_ty, clone_trait, &[])
102+
&& msrv.meets(cx, msrvs::SLICE_FILL)
103+
{
104+
sugg(cx, body, expr, arg.span, assignval.span);
105+
}
87106
}
88107

89108
fn sugg<'tcx>(

tests/ui/manual_slice_fill.fixed

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,38 @@ fn should_lint() {
3434
some_slice.fill(0);
3535
}
3636

37+
fn should_lint_direct_mutref_array(s: &mut [u8; 1]) {
38+
s.fill(0);
39+
}
40+
41+
fn should_lint_direct_mutref_array_non_zero(s: &mut [u8; 4]) {
42+
s.fill(42);
43+
}
44+
45+
fn should_lint_direct_mutref_array_variable(s: &mut [i32; 3]) {
46+
let x = 7;
47+
s.fill(x);
48+
}
49+
50+
fn should_not_lint_direct_mutref_array_fn(s: &mut [usize; 2]) {
51+
for slot in s {
52+
*slot = num();
53+
}
54+
}
55+
56+
fn should_not_lint_direct_mutref_array_iter_used(s: &mut [u8; 3]) {
57+
for slot in s {
58+
*slot = !*slot;
59+
}
60+
}
61+
62+
fn should_not_lint_direct_mutref_array_extra_stmt(s: &mut [u8; 2]) {
63+
for slot in s {
64+
*slot = 0;
65+
println!("foo");
66+
}
67+
}
68+
3769
fn should_not_lint() {
3870
let mut some_slice = [1, 2, 3, 4, 5];
3971

tests/ui/manual_slice_fill.rs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,47 @@ fn should_lint() {
4747
}
4848
}
4949

50+
fn should_lint_direct_mutref_array(s: &mut [u8; 1]) {
51+
for slot in s {
52+
//~^ manual_slice_fill
53+
*slot = 0;
54+
}
55+
}
56+
57+
fn should_lint_direct_mutref_array_non_zero(s: &mut [u8; 4]) {
58+
for slot in s {
59+
//~^ manual_slice_fill
60+
*slot = 42;
61+
}
62+
}
63+
64+
fn should_lint_direct_mutref_array_variable(s: &mut [i32; 3]) {
65+
let x = 7;
66+
for slot in s {
67+
//~^ manual_slice_fill
68+
*slot = x;
69+
}
70+
}
71+
72+
fn should_not_lint_direct_mutref_array_fn(s: &mut [usize; 2]) {
73+
for slot in s {
74+
*slot = num();
75+
}
76+
}
77+
78+
fn should_not_lint_direct_mutref_array_iter_used(s: &mut [u8; 3]) {
79+
for slot in s {
80+
*slot = !*slot;
81+
}
82+
}
83+
84+
fn should_not_lint_direct_mutref_array_extra_stmt(s: &mut [u8; 2]) {
85+
for slot in s {
86+
*slot = 0;
87+
println!("foo");
88+
}
89+
}
90+
5091
fn should_not_lint() {
5192
let mut some_slice = [1, 2, 3, 4, 5];
5293

tests/ui/manual_slice_fill.stderr

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,5 +38,32 @@ LL | | // foo
3838
LL | | }
3939
| |_____^ help: try: `some_slice.fill(0);`
4040

41-
error: aborting due to 4 previous errors
41+
error: manually filling a slice
42+
--> tests/ui/manual_slice_fill.rs:51:5
43+
|
44+
LL | / for slot in s {
45+
LL | |
46+
LL | | *slot = 0;
47+
LL | | }
48+
| |_____^ help: try: `s.fill(0);`
49+
50+
error: manually filling a slice
51+
--> tests/ui/manual_slice_fill.rs:58:5
52+
|
53+
LL | / for slot in s {
54+
LL | |
55+
LL | | *slot = 42;
56+
LL | | }
57+
| |_____^ help: try: `s.fill(42);`
58+
59+
error: manually filling a slice
60+
--> tests/ui/manual_slice_fill.rs:66:5
61+
|
62+
LL | / for slot in s {
63+
LL | |
64+
LL | | *slot = x;
65+
LL | | }
66+
| |_____^ help: try: `s.fill(x);`
67+
68+
error: aborting due to 7 previous errors
4269

0 commit comments

Comments
 (0)