about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--clippy_lints/src/loops/manual_slice_fill.rs4
-rw-r--r--clippy_utils/src/ty/mod.rs7
-rw-r--r--tests/ui/manual_slice_fill.fixed37
-rw-r--r--tests/ui/manual_slice_fill.rs37
4 files changed, 84 insertions, 1 deletions
diff --git a/clippy_lints/src/loops/manual_slice_fill.rs b/clippy_lints/src/loops/manual_slice_fill.rs
index 343f7c5d2d1..15c656cc7bc 100644
--- a/clippy_lints/src/loops/manual_slice_fill.rs
+++ b/clippy_lints/src/loops/manual_slice_fill.rs
@@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::eager_or_lazy::switch_to_eager_eval;
 use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::source::{HasSession, snippet_with_applicability};
-use clippy_utils::ty::implements_trait;
+use clippy_utils::ty::{implements_trait, is_slice_like};
 use clippy_utils::visitors::is_local_used;
 use clippy_utils::{higher, peel_blocks_with_stmt, span_contains_comment};
 use rustc_ast::ast::LitKind;
@@ -58,6 +58,8 @@ pub(super) fn check<'tcx>(
         && let Res::Local(idx_hir) = idx_path.res
         && !is_local_used(cx, assignval, idx_hir)
         && msrv.meets(cx, msrvs::SLICE_FILL)
+        && let slice_ty = cx.typeck_results().expr_ty(slice).peel_refs()
+        && is_slice_like(cx, slice_ty)
     {
         sugg(cx, body, expr, slice.span, assignval.span);
     }
diff --git a/clippy_utils/src/ty/mod.rs b/clippy_utils/src/ty/mod.rs
index d30acfb75f3..db723312695 100644
--- a/clippy_utils/src/ty/mod.rs
+++ b/clippy_utils/src/ty/mod.rs
@@ -1369,3 +1369,10 @@ pub fn has_non_owning_mutable_access<'tcx>(cx: &LateContext<'tcx>, iter_ty: Ty<'
     let mut phantoms = FxHashSet::default();
     has_non_owning_mutable_access_inner(cx, &mut phantoms, iter_ty)
 }
+
+/// Check if `ty` is slice-like, i.e., `&[T]`, `[T; N]`, or `Vec<T>`.
+pub fn is_slice_like<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
+    ty.is_slice()
+        || ty.is_array()
+        || matches!(ty.kind(), ty::Adt(adt_def, _) if cx.tcx.is_diagnostic_item(sym::Vec, adt_def.did()))
+}
diff --git a/tests/ui/manual_slice_fill.fixed b/tests/ui/manual_slice_fill.fixed
index bba863247f5..d07d1d60e2c 100644
--- a/tests/ui/manual_slice_fill.fixed
+++ b/tests/ui/manual_slice_fill.fixed
@@ -123,3 +123,40 @@ fn issue14189() {
         *b = !*b;
     }
 }
+
+mod issue14685 {
+    use std::ops::{Index, IndexMut};
+
+    #[derive(Clone)]
+    struct ZipList<T>(T);
+
+    impl<T> ZipList<T> {
+        fn len(&self) -> usize {
+            todo!()
+        }
+
+        fn is_empty(&self) -> bool {
+            todo!()
+        }
+    }
+
+    impl<T> Index<usize> for ZipList<T> {
+        type Output = T;
+
+        fn index(&self, _: usize) -> &Self::Output {
+            todo!()
+        }
+    }
+
+    impl<T> IndexMut<usize> for ZipList<T> {
+        fn index_mut(&mut self, _: usize) -> &mut Self::Output {
+            todo!()
+        }
+    }
+
+    fn index_mut(mut zl: ZipList<usize>) {
+        for i in 0..zl.len() {
+            zl[i] = 6;
+        }
+    }
+}
diff --git a/tests/ui/manual_slice_fill.rs b/tests/ui/manual_slice_fill.rs
index 44c60dc40f0..c74ab2225c0 100644
--- a/tests/ui/manual_slice_fill.rs
+++ b/tests/ui/manual_slice_fill.rs
@@ -136,3 +136,40 @@ fn issue14189() {
         *b = !*b;
     }
 }
+
+mod issue14685 {
+    use std::ops::{Index, IndexMut};
+
+    #[derive(Clone)]
+    struct ZipList<T>(T);
+
+    impl<T> ZipList<T> {
+        fn len(&self) -> usize {
+            todo!()
+        }
+
+        fn is_empty(&self) -> bool {
+            todo!()
+        }
+    }
+
+    impl<T> Index<usize> for ZipList<T> {
+        type Output = T;
+
+        fn index(&self, _: usize) -> &Self::Output {
+            todo!()
+        }
+    }
+
+    impl<T> IndexMut<usize> for ZipList<T> {
+        fn index_mut(&mut self, _: usize) -> &mut Self::Output {
+            todo!()
+        }
+    }
+
+    fn index_mut(mut zl: ZipList<usize>) {
+        for i in 0..zl.len() {
+            zl[i] = 6;
+        }
+    }
+}