about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-03-01 12:05:03 +0000
committerbors <bors@rust-lang.org>2024-03-01 12:05:03 +0000
commite865dca4d76a204e002c223cba1dc804ee9b7c56 (patch)
treeff8f7737fa15ec62f90aa2fb111deb36e32ccac5
parent225d3771d744acc59b2a8cd778259bd3aa2383cf (diff)
parentdfedadc179dc3c388e0b0098a910658bc6e820ef (diff)
downloadrust-e865dca4d76a204e002c223cba1dc804ee9b7c56.tar.gz
rust-e865dca4d76a204e002c223cba1dc804ee9b7c56.zip
Auto merge of #12010 - granddaifuku:fix/manual-memcpy-indexing-for-multi-dimension-arrays, r=Alexendoo
fix: `manual_memcpy` wrong indexing for multi dimensional arrays

fixes: #9334

This PR fixes an invalid suggestion for multi-dimensional arrays.

For example,
```rust
let src = vec![vec![0; 5]; 5];
let mut dst = vec![0; 5];

for i in 0..5 {
    dst[i] = src[i][i];
}
```

For the above code, Clippy suggests `dst.copy_from_slice(&src[i]);`, but it is not compilable because `i` is only used to loop the array.
I adjusted it so that Clippy `manual_memcpy` works properly for multi-dimensional arrays.

changelog: [`manual_memcpy`]: Fixes invalid indexing suggestions for multi-dimensional arrays
-rw-r--r--clippy_lints/src/loops/manual_memcpy.rs6
-rw-r--r--tests/ui/manual_memcpy/without_loop_counters.rs57
-rw-r--r--tests/ui/manual_memcpy/without_loop_counters.stderr22
3 files changed, 79 insertions, 6 deletions
diff --git a/clippy_lints/src/loops/manual_memcpy.rs b/clippy_lints/src/loops/manual_memcpy.rs
index 58f713d8187..18f799e875a 100644
--- a/clippy_lints/src/loops/manual_memcpy.rs
+++ b/clippy_lints/src/loops/manual_memcpy.rs
@@ -3,6 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet;
 use clippy_utils::sugg::Sugg;
 use clippy_utils::ty::is_copy;
+use clippy_utils::usage::local_used_in;
 use clippy_utils::{get_enclosing_block, higher, path_to_local, sugg};
 use rustc_ast::ast;
 use rustc_errors::Applicability;
@@ -63,8 +64,9 @@ pub(super) fn check<'tcx>(
                             && get_slice_like_element_ty(cx, cx.typeck_results().expr_ty(base_right)).is_some()
                             && let Some((start_left, offset_left)) = get_details_from_idx(cx, idx_left, &starts)
                             && let Some((start_right, offset_right)) = get_details_from_idx(cx, idx_right, &starts)
-
-                            // Source and destination must be different
+                            && !local_used_in(cx, canonical_id, base_left)
+                            && !local_used_in(cx, canonical_id, base_right)
+							// Source and destination must be different
                             && path_to_local(base_left) != path_to_local(base_right)
                         {
                             Some((
diff --git a/tests/ui/manual_memcpy/without_loop_counters.rs b/tests/ui/manual_memcpy/without_loop_counters.rs
index 8146091a2bb..5210b86a0f4 100644
--- a/tests/ui/manual_memcpy/without_loop_counters.rs
+++ b/tests/ui/manual_memcpy/without_loop_counters.rs
@@ -1,5 +1,5 @@
-#![warn(clippy::needless_range_loop, clippy::manual_memcpy)]
-#![allow(clippy::useless_vec)]
+#![warn(clippy::manual_memcpy)]
+#![allow(clippy::useless_vec, clippy::needless_range_loop)]
 //@no-rustfix
 const LOOP_OFFSET: usize = 5000;
 
@@ -158,6 +158,59 @@ pub fn manual_copy(src: &[i32], dst: &mut [i32], dst2: &mut [i32]) {
         //~^ ERROR: it looks like you're manually copying between slices
         dst[i] = src[i];
     }
+
+    // Don't trigger lint for following multi-dimensional arrays
+    let src = [[0; 5]; 5];
+    for i in 0..4 {
+        dst[i] = src[i + 1][i];
+    }
+    for i in 0..5 {
+        dst[i] = src[i][i];
+    }
+    for i in 0..5 {
+        dst[i] = src[i][3];
+    }
+
+    let src = [0; 5];
+    let mut dst = [[0; 5]; 5];
+    for i in 0..5 {
+        dst[i][i] = src[i];
+    }
+
+    let src = [[[0; 5]; 5]; 5];
+    let mut dst = [0; 5];
+    for i in 0..5 {
+        dst[i] = src[i][i][i];
+    }
+    for i in 0..5 {
+        dst[i] = src[i][i][0];
+    }
+    for i in 0..5 {
+        dst[i] = src[i][0][i];
+    }
+    for i in 0..5 {
+        dst[i] = src[0][i][i];
+    }
+    for i in 0..5 {
+        dst[i] = src[0][i][1];
+    }
+    for i in 0..5 {
+        dst[i] = src[i][0][1];
+    }
+
+    // Trigger lint
+    let src = [[0; 5]; 5];
+    let mut dst = [0; 5];
+    for i in 0..5 {
+        //~^ ERROR: it looks like you're manually copying between slices
+        dst[i] = src[0][i];
+    }
+
+    let src = [[[0; 5]; 5]; 5];
+    for i in 0..5 {
+        //~^ ERROR: it looks like you're manually copying between slices
+        dst[i] = src[0][1][i];
+    }
 }
 
 #[warn(clippy::needless_range_loop, clippy::manual_memcpy)]
diff --git a/tests/ui/manual_memcpy/without_loop_counters.stderr b/tests/ui/manual_memcpy/without_loop_counters.stderr
index 55cca1fb584..6dcc0bf4c55 100644
--- a/tests/ui/manual_memcpy/without_loop_counters.stderr
+++ b/tests/ui/manual_memcpy/without_loop_counters.stderr
@@ -145,7 +145,25 @@ LL | |     }
    | |_____^ help: try replacing the loop by: `dst.copy_from_slice(&src);`
 
 error: it looks like you're manually copying between slices
-  --> tests/ui/manual_memcpy/without_loop_counters.rs:165:5
+  --> tests/ui/manual_memcpy/without_loop_counters.rs:204:5
+   |
+LL | /     for i in 0..5 {
+LL | |
+LL | |         dst[i] = src[0][i];
+LL | |     }
+   | |_____^ help: try replacing the loop by: `dst.copy_from_slice(&src[0]);`
+
+error: it looks like you're manually copying between slices
+  --> tests/ui/manual_memcpy/without_loop_counters.rs:210:5
+   |
+LL | /     for i in 0..5 {
+LL | |
+LL | |         dst[i] = src[0][1][i];
+LL | |     }
+   | |_____^ help: try replacing the loop by: `dst.copy_from_slice(&src[0][1]);`
+
+error: it looks like you're manually copying between slices
+  --> tests/ui/manual_memcpy/without_loop_counters.rs:218:5
    |
 LL | /     for i in 0..src.len() {
 LL | |
@@ -153,5 +171,5 @@ LL | |         dst[i] = src[i].clone();
 LL | |     }
    | |_____^ help: try replacing the loop by: `dst[..src.len()].clone_from_slice(&src[..]);`
 
-error: aborting due to 16 previous errors
+error: aborting due to 18 previous errors