From 3d3d2bef1058f547623cf7894b9ec11dc2f9b129 Mon Sep 17 00:00:00 2001 From: rommeld <138243859+rommeld@users.noreply.github.com> Date: Sat, 1 Nov 2025 12:00:47 +0100 Subject: [PATCH 01/23] Add lint to suggest as_chunks over chunks_exact with constant Suggest using slice.as_chunks::() when chunks_exact(N) is called with a compile-time constant. This provides better ergonomics and type safety. Fixes #15882 --- CHANGELOG.md | 1 + clippy_lints/src/declared_lints.rs | 1 + .../src/methods/chunks_exact_to_as_chunks.rs | 47 +++++++++++++++++++ clippy_lints/src/methods/mod.rs | 30 ++++++++++++ clippy_utils/src/msrvs.rs | 2 +- tests/ui/chunks_exact_to_as_chunks.rs | 34 ++++++++++++++ tests/ui/chunks_exact_to_as_chunks.stderr | 36 ++++++++++++++ tests/ui/explicit_write_in_test.stderr | 0 8 files changed, 150 insertions(+), 1 deletion(-) create mode 100644 clippy_lints/src/methods/chunks_exact_to_as_chunks.rs create mode 100644 tests/ui/chunks_exact_to_as_chunks.rs create mode 100644 tests/ui/chunks_exact_to_as_chunks.stderr delete mode 100644 tests/ui/explicit_write_in_test.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index 6cb2755be0ee..073eea64320d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6252,6 +6252,7 @@ Released 2018-09-13 [`chars_last_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#chars_last_cmp [`chars_next_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#chars_next_cmp [`checked_conversions`]: https://rust-lang.github.io/rust-clippy/master/index.html#checked_conversions +[`chunks_exact_to_as_chunks`]: https://rust-lang.github.io/rust-clippy/master/index.html#chunks_exact_to_as_chunks [`clear_with_drain`]: https://rust-lang.github.io/rust-clippy/master/index.html#clear_with_drain [`clone_double_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#clone_double_ref [`clone_on_copy`]: https://rust-lang.github.io/rust-clippy/master/index.html#clone_on_copy diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index a754eea31165..f51ba620d68c 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -352,6 +352,7 @@ pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[ crate::methods::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS_INFO, crate::methods::CHARS_LAST_CMP_INFO, crate::methods::CHARS_NEXT_CMP_INFO, + crate::methods::CHUNKS_EXACT_TO_AS_CHUNKS_INFO, crate::methods::CLEAR_WITH_DRAIN_INFO, crate::methods::CLONED_INSTEAD_OF_COPIED_INFO, crate::methods::CLONE_ON_COPY_INFO, diff --git a/clippy_lints/src/methods/chunks_exact_to_as_chunks.rs b/clippy_lints/src/methods/chunks_exact_to_as_chunks.rs new file mode 100644 index 000000000000..918b816d8d23 --- /dev/null +++ b/clippy_lints/src/methods/chunks_exact_to_as_chunks.rs @@ -0,0 +1,47 @@ +use clippy_utils::consts::{ConstEvalCtxt, Constant}; +use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::msrvs::{self, Msrv}; +use rustc_hir::Expr; +use rustc_lint::LateContext; + +use super::CHUNKS_EXACT_TO_AS_CHUNKS; + +pub(super) fn check( + cx: &LateContext<'_>, + expr: &Expr<'_>, + recv: &Expr<'_>, + arg: &Expr<'_>, + method_name: &str, + msrv: &Msrv, +) { + // Check for Rust version + if !msrv.meets(cx, msrvs::AS_CHUNKS) { + return; + } + + // Check receiver is slice or array type + let recv_ty = cx.typeck_results().expr_ty(recv).peel_refs(); + if !recv_ty.is_slice() && !recv_ty.is_array() { + return; + } + + // Check if argument is a constant + let constant_eval = ConstEvalCtxt::new(cx); + if let Some(Constant::Int(chunk_size)) = constant_eval.eval(arg) { + // Emit the lint + let suggestion = if method_name == "chunks_exact_mut" { + "as_chunks_mut" + } else { + "as_chunks" + }; + + span_lint_and_help( + cx, + CHUNKS_EXACT_TO_AS_CHUNKS, + expr.span, + format!("using `{method_name}` with a constant chunk size"), + None, + format!("consider using `{suggestion}::<{chunk_size}>()` for better ergonomics"), + ); + } +} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 5b917e2bfefa..3778dcda86bb 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -9,6 +9,7 @@ mod chars_last_cmp; mod chars_last_cmp_with_unwrap; mod chars_next_cmp; mod chars_next_cmp_with_unwrap; +mod chunks_exact_to_as_chunks; mod clear_with_drain; mod clone_on_copy; mod clone_on_ref_ptr; @@ -2087,6 +2088,32 @@ declare_clippy_lint! { "replace `.bytes().nth()` with `.as_bytes().get()`" } +declare_clippy_lint! { + /// ### What it does + /// Checks for usage of `chunks_exact` or `chunks_exact_mut` with a constant chunk size. + /// + /// ### Why is this bad? + /// `as_chunks` provides better ergonomics and type safety by returning arrays instead of slices. + /// It was stabilized in Rust 1.88. + /// + /// ### Example + /// ```no_run + /// let slice = [1, 2, 3, 4, 5, 6]; + /// let mut it = slice.chunks_exact(2); + /// for chunk in it {} + /// ``` + /// Use instead: + /// ```no_run + /// let slice = [1, 2, 3, 4, 5, 6]; + /// let (chunks, remainder) = slice.as_chunks::<2>(); + /// for chunk in chunks {} + /// ``` + #[clippy::version = "1.93.0"] + pub CHUNKS_EXACT_TO_AS_CHUNKS, + style, + "using `chunks_exact` with constant when `as_chunks` is more ergonomic" +} + declare_clippy_lint! { /// ### What it does /// Checks for the usage of `_.to_owned()`, `vec.to_vec()`, or similar when calling `_.clone()` would be clearer. @@ -5715,6 +5742,9 @@ impl Methods { unwrap_expect_used::Variant::Unwrap, ); }, + (name, [arg]) if matches!(name.as_str(), "chunks_exact" | "chunks_exact_mut") => { + chunks_exact_to_as_chunks::check(cx, expr, recv, arg, name.as_str(), &self.msrv); + }, _ => {}, } } diff --git a/clippy_utils/src/msrvs.rs b/clippy_utils/src/msrvs.rs index 86d17a8231d5..d82ee2487ee9 100644 --- a/clippy_utils/src/msrvs.rs +++ b/clippy_utils/src/msrvs.rs @@ -23,7 +23,7 @@ macro_rules! msrv_aliases { // names may refer to stabilized feature flags or library items msrv_aliases! { - 1,88,0 { LET_CHAINS } + 1,88,0 { LET_CHAINS, AS_CHUNKS } 1,87,0 { OS_STR_DISPLAY, INT_MIDPOINT, CONST_CHAR_IS_DIGIT, UNSIGNED_IS_MULTIPLE_OF, INTEGER_SIGN_CAST } 1,85,0 { UINT_FLOAT_MIDPOINT, CONST_SIZE_OF_VAL } 1,84,0 { CONST_OPTION_AS_SLICE, MANUAL_DANGLING_PTR } diff --git a/tests/ui/chunks_exact_to_as_chunks.rs b/tests/ui/chunks_exact_to_as_chunks.rs new file mode 100644 index 000000000000..a1422437cccc --- /dev/null +++ b/tests/ui/chunks_exact_to_as_chunks.rs @@ -0,0 +1,34 @@ +#![warn(clippy::chunks_exact_to_as_chunks)] +#![allow(unused)] + +fn main() { + let slice = [1, 2, 3, 4, 5, 6, 7, 8]; + + // Should trigger lint - literal constant + let mut it = slice.chunks_exact(4); + //~^ ERROR: using `chunks_exact` with a constant chunk size + for chunk in it {} + + // Should trigger lint - const value + const CHUNK_SIZE: usize = 4; + let mut it = slice.chunks_exact(CHUNK_SIZE); + //~^ ERROR: using `chunks_exact` with a constant chunk size + for chunk in it {} + + // Should NOT trigger - runtime value + let size = 4; + let mut it = slice.chunks_exact(size); + for chunk in it {} + + // Should trigger lint - with remainder + let mut it = slice.chunks_exact(3); + //~^ ERROR: using `chunks_exact` with a constant chunk size + for chunk in &mut it {} + for e in it.remainder() {} + + // Should trigger - mutable variant + let mut arr = [1, 2, 3, 4, 5, 6, 7, 8]; + let mut it = arr.chunks_exact_mut(4); + //~^ ERROR: using `chunks_exact_mut` with a constant chunk size + for chunk in it {} +} diff --git a/tests/ui/chunks_exact_to_as_chunks.stderr b/tests/ui/chunks_exact_to_as_chunks.stderr new file mode 100644 index 000000000000..3c14b355e1a2 --- /dev/null +++ b/tests/ui/chunks_exact_to_as_chunks.stderr @@ -0,0 +1,36 @@ +error: using `chunks_exact` with a constant chunk size + --> tests/ui/chunks_exact_to_as_chunks.rs:8:18 + | +LL | let mut it = slice.chunks_exact(4); + | ^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using `as_chunks::<4>()` for better ergonomics + = note: `-D clippy::chunks-exact-to-as-chunks` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::chunks_exact_to_as_chunks)]` + +error: using `chunks_exact` with a constant chunk size + --> tests/ui/chunks_exact_to_as_chunks.rs:14:18 + | +LL | let mut it = slice.chunks_exact(CHUNK_SIZE); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using `as_chunks::<4>()` for better ergonomics + +error: using `chunks_exact` with a constant chunk size + --> tests/ui/chunks_exact_to_as_chunks.rs:24:18 + | +LL | let mut it = slice.chunks_exact(3); + | ^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using `as_chunks::<3>()` for better ergonomics + +error: using `chunks_exact_mut` with a constant chunk size + --> tests/ui/chunks_exact_to_as_chunks.rs:31:18 + | +LL | let mut it = arr.chunks_exact_mut(4); + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using `as_chunks_mut::<4>()` for better ergonomics + +error: aborting due to 4 previous errors + diff --git a/tests/ui/explicit_write_in_test.stderr b/tests/ui/explicit_write_in_test.stderr deleted file mode 100644 index e69de29bb2d1..000000000000 From 4a4c955042da1c5e375346297f5f627740563e1a Mon Sep 17 00:00:00 2001 From: rommeld <138243859+rommeld@users.noreply.github.com> Date: Sat, 1 Nov 2025 12:23:24 +0100 Subject: [PATCH 02/23] Fix pass value instead of reference --- clippy_lints/src/methods/chunks_exact_to_as_chunks.rs | 2 +- clippy_lints/src/methods/mod.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/methods/chunks_exact_to_as_chunks.rs b/clippy_lints/src/methods/chunks_exact_to_as_chunks.rs index 918b816d8d23..9669f4fb98f2 100644 --- a/clippy_lints/src/methods/chunks_exact_to_as_chunks.rs +++ b/clippy_lints/src/methods/chunks_exact_to_as_chunks.rs @@ -12,7 +12,7 @@ pub(super) fn check( recv: &Expr<'_>, arg: &Expr<'_>, method_name: &str, - msrv: &Msrv, + msrv: Msrv, ) { // Check for Rust version if !msrv.meets(cx, msrvs::AS_CHUNKS) { diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 3778dcda86bb..9997c63ff87f 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -5743,7 +5743,7 @@ impl Methods { ); }, (name, [arg]) if matches!(name.as_str(), "chunks_exact" | "chunks_exact_mut") => { - chunks_exact_to_as_chunks::check(cx, expr, recv, arg, name.as_str(), &self.msrv); + chunks_exact_to_as_chunks::check(cx, expr, recv, arg, name.as_str(), self.msrv); }, _ => {}, } From d332ec55e861996b6c4fbbdcf18345e354fa969b Mon Sep 17 00:00:00 2001 From: rommeld <138243859+rommeld@users.noreply.github.com> Date: Sat, 1 Nov 2025 17:36:47 +0100 Subject: [PATCH 03/23] Switched to symbols instead of using strings --- clippy_lints/src/methods/chunks_exact_to_as_chunks.rs | 6 ++++-- clippy_lints/src/methods/mod.rs | 5 +++-- clippy_utils/src/sym.rs | 2 ++ 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/clippy_lints/src/methods/chunks_exact_to_as_chunks.rs b/clippy_lints/src/methods/chunks_exact_to_as_chunks.rs index 9669f4fb98f2..c477e1c7a72b 100644 --- a/clippy_lints/src/methods/chunks_exact_to_as_chunks.rs +++ b/clippy_lints/src/methods/chunks_exact_to_as_chunks.rs @@ -1,8 +1,10 @@ use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::msrvs::{self, Msrv}; +use clippy_utils::sym; use rustc_hir::Expr; use rustc_lint::LateContext; +use rustc_span::Symbol; use super::CHUNKS_EXACT_TO_AS_CHUNKS; @@ -11,7 +13,7 @@ pub(super) fn check( expr: &Expr<'_>, recv: &Expr<'_>, arg: &Expr<'_>, - method_name: &str, + method_name: Symbol, msrv: Msrv, ) { // Check for Rust version @@ -29,7 +31,7 @@ pub(super) fn check( let constant_eval = ConstEvalCtxt::new(cx); if let Some(Constant::Int(chunk_size)) = constant_eval.eval(arg) { // Emit the lint - let suggestion = if method_name == "chunks_exact_mut" { + let suggestion = if method_name == sym::chunks_exact_mut { "as_chunks_mut" } else { "as_chunks" diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 9997c63ff87f..583503f90b0c 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -4814,6 +4814,7 @@ impl_lint_pass!(Methods => [ ITER_NTH, ITER_NTH_ZERO, BYTES_NTH, + CHUNKS_EXACT_TO_AS_CHUNKS, ITER_SKIP_NEXT, GET_UNWRAP, GET_LAST_WITH_LEN, @@ -5742,8 +5743,8 @@ impl Methods { unwrap_expect_used::Variant::Unwrap, ); }, - (name, [arg]) if matches!(name.as_str(), "chunks_exact" | "chunks_exact_mut") => { - chunks_exact_to_as_chunks::check(cx, expr, recv, arg, name.as_str(), self.msrv); + (name @ (sym::chunks_exact | sym::chunks_exact_mut), [arg]) => { + chunks_exact_to_as_chunks::check(cx, expr, recv, arg, name, self.msrv); }, _ => {}, } diff --git a/clippy_utils/src/sym.rs b/clippy_utils/src/sym.rs index 8e8a80a6a9c9..969bb2e47eec 100644 --- a/clippy_utils/src/sym.rs +++ b/clippy_utils/src/sym.rs @@ -111,6 +111,8 @@ generate! { checked_pow, checked_rem_euclid, checked_sub, + chunks_exact, + chunks_exact_mut, clamp, clippy_utils, clone_into, From 610acda5e059a12847190685cf7f5e4d877007a0 Mon Sep 17 00:00:00 2001 From: rommeld <138243859+rommeld@users.noreply.github.com> Date: Tue, 4 Nov 2025 19:36:08 +0100 Subject: [PATCH 04/23] Added suggestions and changes from review Changed example suggestion from const to snippet Shortend error message Followed clippy naming conventions --- clippy_lints/src/declared_lints.rs | 2 +- ...nks.rs => chunks_exact_with_const_size.rs} | 13 ++++++----- clippy_lints/src/methods/mod.rs | 8 +++---- ...nks.rs => chunks_exact_with_const_size.rs} | 10 ++++----- ...rr => chunks_exact_with_const_size.stderr} | 22 +++++++++---------- 5 files changed, 28 insertions(+), 27 deletions(-) rename clippy_lints/src/methods/{chunks_exact_to_as_chunks.rs => chunks_exact_with_const_size.rs} (74%) rename tests/ui/{chunks_exact_to_as_chunks.rs => chunks_exact_with_const_size.rs} (71%) rename tests/ui/{chunks_exact_to_as_chunks.stderr => chunks_exact_with_const_size.stderr} (55%) diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index f51ba620d68c..733ed29f2760 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -352,7 +352,7 @@ pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[ crate::methods::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS_INFO, crate::methods::CHARS_LAST_CMP_INFO, crate::methods::CHARS_NEXT_CMP_INFO, - crate::methods::CHUNKS_EXACT_TO_AS_CHUNKS_INFO, + crate::methods::CHUNKS_EXACT_WITH_CONST_SIZE_INFO, crate::methods::CLEAR_WITH_DRAIN_INFO, crate::methods::CLONED_INSTEAD_OF_COPIED_INFO, crate::methods::CLONE_ON_COPY_INFO, diff --git a/clippy_lints/src/methods/chunks_exact_to_as_chunks.rs b/clippy_lints/src/methods/chunks_exact_with_const_size.rs similarity index 74% rename from clippy_lints/src/methods/chunks_exact_to_as_chunks.rs rename to clippy_lints/src/methods/chunks_exact_with_const_size.rs index c477e1c7a72b..592eb7fae529 100644 --- a/clippy_lints/src/methods/chunks_exact_to_as_chunks.rs +++ b/clippy_lints/src/methods/chunks_exact_with_const_size.rs @@ -1,12 +1,13 @@ use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::msrvs::{self, Msrv}; +use clippy_utils::source::snippet; use clippy_utils::sym; use rustc_hir::Expr; use rustc_lint::LateContext; use rustc_span::Symbol; -use super::CHUNKS_EXACT_TO_AS_CHUNKS; +use super::CHUNKS_EXACT_WITH_CONST_SIZE; pub(super) fn check( cx: &LateContext<'_>, @@ -29,21 +30,21 @@ pub(super) fn check( // Check if argument is a constant let constant_eval = ConstEvalCtxt::new(cx); - if let Some(Constant::Int(chunk_size)) = constant_eval.eval(arg) { + if let Some(Constant::Int(_)) = constant_eval.eval(arg) { // Emit the lint let suggestion = if method_name == sym::chunks_exact_mut { "as_chunks_mut" } else { "as_chunks" }; - + let arg_str = snippet(cx, arg.span, "_"); span_lint_and_help( cx, - CHUNKS_EXACT_TO_AS_CHUNKS, + CHUNKS_EXACT_WITH_CONST_SIZE, expr.span, - format!("using `{method_name}` with a constant chunk size"), + "chunks_exact_with_const_size", None, - format!("consider using `{suggestion}::<{chunk_size}>()` for better ergonomics"), + format!("consider using `{suggestion}::<{arg_str}>()` for better ergonomics"), ); } } diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 583503f90b0c..5f8e3b434649 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -9,7 +9,7 @@ mod chars_last_cmp; mod chars_last_cmp_with_unwrap; mod chars_next_cmp; mod chars_next_cmp_with_unwrap; -mod chunks_exact_to_as_chunks; +mod chunks_exact_with_const_size; mod clear_with_drain; mod clone_on_copy; mod clone_on_ref_ptr; @@ -2109,7 +2109,7 @@ declare_clippy_lint! { /// for chunk in chunks {} /// ``` #[clippy::version = "1.93.0"] - pub CHUNKS_EXACT_TO_AS_CHUNKS, + pub CHUNKS_EXACT_WITH_CONST_SIZE, style, "using `chunks_exact` with constant when `as_chunks` is more ergonomic" } @@ -4814,7 +4814,7 @@ impl_lint_pass!(Methods => [ ITER_NTH, ITER_NTH_ZERO, BYTES_NTH, - CHUNKS_EXACT_TO_AS_CHUNKS, + CHUNKS_EXACT_WITH_CONST_SIZE, ITER_SKIP_NEXT, GET_UNWRAP, GET_LAST_WITH_LEN, @@ -5744,7 +5744,7 @@ impl Methods { ); }, (name @ (sym::chunks_exact | sym::chunks_exact_mut), [arg]) => { - chunks_exact_to_as_chunks::check(cx, expr, recv, arg, name, self.msrv); + chunks_exact_with_const_size::check(cx, expr, recv, arg, name, self.msrv); }, _ => {}, } diff --git a/tests/ui/chunks_exact_to_as_chunks.rs b/tests/ui/chunks_exact_with_const_size.rs similarity index 71% rename from tests/ui/chunks_exact_to_as_chunks.rs rename to tests/ui/chunks_exact_with_const_size.rs index a1422437cccc..6da486b0718d 100644 --- a/tests/ui/chunks_exact_to_as_chunks.rs +++ b/tests/ui/chunks_exact_with_const_size.rs @@ -1,4 +1,4 @@ -#![warn(clippy::chunks_exact_to_as_chunks)] +#![warn(clippy::chunks_exact_with_const_size)] #![allow(unused)] fn main() { @@ -6,13 +6,13 @@ fn main() { // Should trigger lint - literal constant let mut it = slice.chunks_exact(4); - //~^ ERROR: using `chunks_exact` with a constant chunk size + //~^ ERROR: chunks_exact_with_const_size for chunk in it {} // Should trigger lint - const value const CHUNK_SIZE: usize = 4; let mut it = slice.chunks_exact(CHUNK_SIZE); - //~^ ERROR: using `chunks_exact` with a constant chunk size + //~^ ERROR: chunks_exact_with_const_size for chunk in it {} // Should NOT trigger - runtime value @@ -22,13 +22,13 @@ fn main() { // Should trigger lint - with remainder let mut it = slice.chunks_exact(3); - //~^ ERROR: using `chunks_exact` with a constant chunk size + //~^ ERROR: chunks_exact_with_const_size for chunk in &mut it {} for e in it.remainder() {} // Should trigger - mutable variant let mut arr = [1, 2, 3, 4, 5, 6, 7, 8]; let mut it = arr.chunks_exact_mut(4); - //~^ ERROR: using `chunks_exact_mut` with a constant chunk size + //~^ ERROR: chunks_exact_with_const_size for chunk in it {} } diff --git a/tests/ui/chunks_exact_to_as_chunks.stderr b/tests/ui/chunks_exact_with_const_size.stderr similarity index 55% rename from tests/ui/chunks_exact_to_as_chunks.stderr rename to tests/ui/chunks_exact_with_const_size.stderr index 3c14b355e1a2..7112146bd41f 100644 --- a/tests/ui/chunks_exact_to_as_chunks.stderr +++ b/tests/ui/chunks_exact_with_const_size.stderr @@ -1,31 +1,31 @@ -error: using `chunks_exact` with a constant chunk size - --> tests/ui/chunks_exact_to_as_chunks.rs:8:18 +error: chunks_exact_with_const_size + --> tests/ui/chunks_exact_with_const_size.rs:8:18 | LL | let mut it = slice.chunks_exact(4); | ^^^^^^^^^^^^^^^^^^^^^ | = help: consider using `as_chunks::<4>()` for better ergonomics - = note: `-D clippy::chunks-exact-to-as-chunks` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::chunks_exact_to_as_chunks)]` + = note: `-D clippy::chunks-exact-with-const-size` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::chunks_exact_with_const_size)]` -error: using `chunks_exact` with a constant chunk size - --> tests/ui/chunks_exact_to_as_chunks.rs:14:18 +error: chunks_exact_with_const_size + --> tests/ui/chunks_exact_with_const_size.rs:14:18 | LL | let mut it = slice.chunks_exact(CHUNK_SIZE); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: consider using `as_chunks::<4>()` for better ergonomics + = help: consider using `as_chunks::()` for better ergonomics -error: using `chunks_exact` with a constant chunk size - --> tests/ui/chunks_exact_to_as_chunks.rs:24:18 +error: chunks_exact_with_const_size + --> tests/ui/chunks_exact_with_const_size.rs:24:18 | LL | let mut it = slice.chunks_exact(3); | ^^^^^^^^^^^^^^^^^^^^^ | = help: consider using `as_chunks::<3>()` for better ergonomics -error: using `chunks_exact_mut` with a constant chunk size - --> tests/ui/chunks_exact_to_as_chunks.rs:31:18 +error: chunks_exact_with_const_size + --> tests/ui/chunks_exact_with_const_size.rs:31:18 | LL | let mut it = arr.chunks_exact_mut(4); | ^^^^^^^^^^^^^^^^^^^^^^^ From 632e37be0a085d7e7f92c2fb2ad45dcf409c1c61 Mon Sep 17 00:00:00 2001 From: rommeld <138243859+rommeld@users.noreply.github.com> Date: Tue, 4 Nov 2025 20:09:35 +0100 Subject: [PATCH 05/23] Updated CHANGELOG.md via --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 073eea64320d..c8cd55feb1e3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6252,7 +6252,7 @@ Released 2018-09-13 [`chars_last_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#chars_last_cmp [`chars_next_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#chars_next_cmp [`checked_conversions`]: https://rust-lang.github.io/rust-clippy/master/index.html#checked_conversions -[`chunks_exact_to_as_chunks`]: https://rust-lang.github.io/rust-clippy/master/index.html#chunks_exact_to_as_chunks +[`chunks_exact_with_const_size`]: https://rust-lang.github.io/rust-clippy/master/index.html#chunks_exact_with_const_size [`clear_with_drain`]: https://rust-lang.github.io/rust-clippy/master/index.html#clear_with_drain [`clone_double_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#clone_double_ref [`clone_on_copy`]: https://rust-lang.github.io/rust-clippy/master/index.html#clone_on_copy From bc1d010dc3d83c39787bac9f654f99ab219b0b5c Mon Sep 17 00:00:00 2001 From: rommeld <138243859+rommeld@users.noreply.github.com> Date: Tue, 4 Nov 2025 22:05:46 +0100 Subject: [PATCH 06/23] Reduced error message verbosity --- clippy_lints/src/methods/chunks_exact_with_const_size.rs | 2 +- tests/ui/chunks_exact_with_const_size.rs | 8 ++++---- tests/ui/chunks_exact_with_const_size.stderr | 8 ++++---- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/clippy_lints/src/methods/chunks_exact_with_const_size.rs b/clippy_lints/src/methods/chunks_exact_with_const_size.rs index 592eb7fae529..a4f1daeab799 100644 --- a/clippy_lints/src/methods/chunks_exact_with_const_size.rs +++ b/clippy_lints/src/methods/chunks_exact_with_const_size.rs @@ -42,7 +42,7 @@ pub(super) fn check( cx, CHUNKS_EXACT_WITH_CONST_SIZE, expr.span, - "chunks_exact_with_const_size", + format!("using `{method_name}` with a constant chunk size"), None, format!("consider using `{suggestion}::<{arg_str}>()` for better ergonomics"), ); diff --git a/tests/ui/chunks_exact_with_const_size.rs b/tests/ui/chunks_exact_with_const_size.rs index 6da486b0718d..c205b36aa9a3 100644 --- a/tests/ui/chunks_exact_with_const_size.rs +++ b/tests/ui/chunks_exact_with_const_size.rs @@ -6,13 +6,13 @@ fn main() { // Should trigger lint - literal constant let mut it = slice.chunks_exact(4); - //~^ ERROR: chunks_exact_with_const_size + //~^ chunks_exact_with_const_size for chunk in it {} // Should trigger lint - const value const CHUNK_SIZE: usize = 4; let mut it = slice.chunks_exact(CHUNK_SIZE); - //~^ ERROR: chunks_exact_with_const_size + //~^ chunks_exact_with_const_size for chunk in it {} // Should NOT trigger - runtime value @@ -22,13 +22,13 @@ fn main() { // Should trigger lint - with remainder let mut it = slice.chunks_exact(3); - //~^ ERROR: chunks_exact_with_const_size + //~^ chunks_exact_with_const_size for chunk in &mut it {} for e in it.remainder() {} // Should trigger - mutable variant let mut arr = [1, 2, 3, 4, 5, 6, 7, 8]; let mut it = arr.chunks_exact_mut(4); - //~^ ERROR: chunks_exact_with_const_size + //~^ chunks_exact_with_const_size for chunk in it {} } diff --git a/tests/ui/chunks_exact_with_const_size.stderr b/tests/ui/chunks_exact_with_const_size.stderr index 7112146bd41f..a858d2a3322c 100644 --- a/tests/ui/chunks_exact_with_const_size.stderr +++ b/tests/ui/chunks_exact_with_const_size.stderr @@ -1,4 +1,4 @@ -error: chunks_exact_with_const_size +error: using `chunks_exact` with a constant chunk size --> tests/ui/chunks_exact_with_const_size.rs:8:18 | LL | let mut it = slice.chunks_exact(4); @@ -8,7 +8,7 @@ LL | let mut it = slice.chunks_exact(4); = note: `-D clippy::chunks-exact-with-const-size` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::chunks_exact_with_const_size)]` -error: chunks_exact_with_const_size +error: using `chunks_exact` with a constant chunk size --> tests/ui/chunks_exact_with_const_size.rs:14:18 | LL | let mut it = slice.chunks_exact(CHUNK_SIZE); @@ -16,7 +16,7 @@ LL | let mut it = slice.chunks_exact(CHUNK_SIZE); | = help: consider using `as_chunks::()` for better ergonomics -error: chunks_exact_with_const_size +error: using `chunks_exact` with a constant chunk size --> tests/ui/chunks_exact_with_const_size.rs:24:18 | LL | let mut it = slice.chunks_exact(3); @@ -24,7 +24,7 @@ LL | let mut it = slice.chunks_exact(3); | = help: consider using `as_chunks::<3>()` for better ergonomics -error: chunks_exact_with_const_size +error: using `chunks_exact_mut` with a constant chunk size --> tests/ui/chunks_exact_with_const_size.rs:31:18 | LL | let mut it = arr.chunks_exact_mut(4); From 1d99b91395e9cdd6a9f650b6bffee866518220c0 Mon Sep 17 00:00:00 2001 From: rommeld <138243859+rommeld@users.noreply.github.com> Date: Tue, 4 Nov 2025 22:16:16 +0100 Subject: [PATCH 07/23] Added check for types that can be adjusted as slices --- clippy_lints/src/methods/chunks_exact_with_const_size.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/methods/chunks_exact_with_const_size.rs b/clippy_lints/src/methods/chunks_exact_with_const_size.rs index a4f1daeab799..04dee4f736e0 100644 --- a/clippy_lints/src/methods/chunks_exact_with_const_size.rs +++ b/clippy_lints/src/methods/chunks_exact_with_const_size.rs @@ -22,9 +22,8 @@ pub(super) fn check( return; } - // Check receiver is slice or array type - let recv_ty = cx.typeck_results().expr_ty(recv).peel_refs(); - if !recv_ty.is_slice() && !recv_ty.is_array() { + // Check if receiver is slice-like + if !cx.typeck_results().expr_ty_adjusted(recv).peel_refs().is_slice() { return; } From 27317710f725a559dd3187f2f2b4ced32a7fe9f1 Mon Sep 17 00:00:00 2001 From: rommeld <138243859+rommeld@users.noreply.github.com> Date: Tue, 4 Nov 2025 22:26:33 +0100 Subject: [PATCH 08/23] Moved Rust version check and removed --- clippy_lints/src/methods/chunks_exact_with_const_size.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/clippy_lints/src/methods/chunks_exact_with_const_size.rs b/clippy_lints/src/methods/chunks_exact_with_const_size.rs index 04dee4f736e0..a31ec4048acc 100644 --- a/clippy_lints/src/methods/chunks_exact_with_const_size.rs +++ b/clippy_lints/src/methods/chunks_exact_with_const_size.rs @@ -17,11 +17,6 @@ pub(super) fn check( method_name: Symbol, msrv: Msrv, ) { - // Check for Rust version - if !msrv.meets(cx, msrvs::AS_CHUNKS) { - return; - } - // Check if receiver is slice-like if !cx.typeck_results().expr_ty_adjusted(recv).peel_refs().is_slice() { return; @@ -46,4 +41,7 @@ pub(super) fn check( format!("consider using `{suggestion}::<{arg_str}>()` for better ergonomics"), ); } + + // Check for Rust version + if !msrv.meets(cx, msrvs::AS_CHUNKS) {} } From 7082eef1c3d5dd765686e705f1557f14b05e60c2 Mon Sep 17 00:00:00 2001 From: rommeld <138243859+rommeld@users.noreply.github.com> Date: Fri, 7 Nov 2025 18:46:06 +0100 Subject: [PATCH 09/23] Added lint suggestion --- .../methods/chunks_exact_with_const_size.rs | 25 +++++++++----- tests/ui/chunks_exact_with_const_size.fixed | 33 +++++++++++++++++++ tests/ui/chunks_exact_with_const_size.rs | 5 ++- tests/ui/chunks_exact_with_const_size.stderr | 17 +++------- 4 files changed, 57 insertions(+), 23 deletions(-) create mode 100644 tests/ui/chunks_exact_with_const_size.fixed diff --git a/clippy_lints/src/methods/chunks_exact_with_const_size.rs b/clippy_lints/src/methods/chunks_exact_with_const_size.rs index a31ec4048acc..97294a268820 100644 --- a/clippy_lints/src/methods/chunks_exact_with_const_size.rs +++ b/clippy_lints/src/methods/chunks_exact_with_const_size.rs @@ -1,8 +1,9 @@ use clippy_utils::consts::{ConstEvalCtxt, Constant}; -use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::msrvs::{self, Msrv}; -use clippy_utils::source::snippet; +use clippy_utils::source::snippet_with_applicability; use clippy_utils::sym; +use rustc_errors::Applicability; use rustc_hir::Expr; use rustc_lint::LateContext; use rustc_span::Symbol; @@ -25,20 +26,28 @@ pub(super) fn check( // Check if argument is a constant let constant_eval = ConstEvalCtxt::new(cx); if let Some(Constant::Int(_)) = constant_eval.eval(arg) { - // Emit the lint - let suggestion = if method_name == sym::chunks_exact_mut { + // Determine the suggested method name + let suggestion_method = if method_name == sym::chunks_exact_mut { "as_chunks_mut" } else { "as_chunks" }; - let arg_str = snippet(cx, arg.span, "_"); - span_lint_and_help( + + // Build the suggestion with proper applicability tracking + let mut applicability = Applicability::MachineApplicable; + let recv_str = snippet_with_applicability(cx, recv.span, "_", &mut applicability); + let arg_str = snippet_with_applicability(cx, arg.span, "_", &mut applicability); + + let suggestion = format!("{recv_str}.{suggestion_method}::<{arg_str}>().0.iter()"); + + span_lint_and_sugg( cx, CHUNKS_EXACT_WITH_CONST_SIZE, expr.span, format!("using `{method_name}` with a constant chunk size"), - None, - format!("consider using `{suggestion}::<{arg_str}>()` for better ergonomics"), + "consider using `as_chunks` instead", + suggestion, + applicability, ); } diff --git a/tests/ui/chunks_exact_with_const_size.fixed b/tests/ui/chunks_exact_with_const_size.fixed new file mode 100644 index 000000000000..63c3632a505a --- /dev/null +++ b/tests/ui/chunks_exact_with_const_size.fixed @@ -0,0 +1,33 @@ +#![warn(clippy::chunks_exact_with_const_size)] +#![allow(unused)] + +fn main() { + let slice = [1, 2, 3, 4, 5, 6, 7, 8]; + + // Should trigger lint - literal constant + let mut it = slice.as_chunks::<4>().0.iter(); + //~^ chunks_exact_with_const_size + for chunk in it {} + + // Should trigger lint - const value + const CHUNK_SIZE: usize = 4; + let mut it = slice.as_chunks::().0.iter(); + //~^ chunks_exact_with_const_size + for chunk in it {} + + // Should NOT trigger - runtime value + let size = 4; + let mut it = slice.chunks_exact(size); + for chunk in it {} + + // Should trigger lint - simple iteration + let mut it = slice.as_chunks::<3>().0.iter(); + //~^ chunks_exact_with_const_size + for chunk in it {} + + // Should trigger - mutable variant + let mut arr = [1, 2, 3, 4, 5, 6, 7, 8]; + let mut it = arr.as_chunks_mut::<4>().0.iter(); + //~^ chunks_exact_with_const_size + for chunk in it {} +} diff --git a/tests/ui/chunks_exact_with_const_size.rs b/tests/ui/chunks_exact_with_const_size.rs index c205b36aa9a3..48585b84a5b7 100644 --- a/tests/ui/chunks_exact_with_const_size.rs +++ b/tests/ui/chunks_exact_with_const_size.rs @@ -20,11 +20,10 @@ fn main() { let mut it = slice.chunks_exact(size); for chunk in it {} - // Should trigger lint - with remainder + // Should trigger lint - simple iteration let mut it = slice.chunks_exact(3); //~^ chunks_exact_with_const_size - for chunk in &mut it {} - for e in it.remainder() {} + for chunk in it {} // Should trigger - mutable variant let mut arr = [1, 2, 3, 4, 5, 6, 7, 8]; diff --git a/tests/ui/chunks_exact_with_const_size.stderr b/tests/ui/chunks_exact_with_const_size.stderr index a858d2a3322c..7bccc0bcaf2d 100644 --- a/tests/ui/chunks_exact_with_const_size.stderr +++ b/tests/ui/chunks_exact_with_const_size.stderr @@ -2,9 +2,8 @@ error: using `chunks_exact` with a constant chunk size --> tests/ui/chunks_exact_with_const_size.rs:8:18 | LL | let mut it = slice.chunks_exact(4); - | ^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^ help: consider using `as_chunks` instead: `slice.as_chunks::<4>().0.iter()` | - = help: consider using `as_chunks::<4>()` for better ergonomics = note: `-D clippy::chunks-exact-with-const-size` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::chunks_exact_with_const_size)]` @@ -12,25 +11,19 @@ error: using `chunks_exact` with a constant chunk size --> tests/ui/chunks_exact_with_const_size.rs:14:18 | LL | let mut it = slice.chunks_exact(CHUNK_SIZE); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: consider using `as_chunks::()` for better ergonomics + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `as_chunks` instead: `slice.as_chunks::().0.iter()` error: using `chunks_exact` with a constant chunk size --> tests/ui/chunks_exact_with_const_size.rs:24:18 | LL | let mut it = slice.chunks_exact(3); - | ^^^^^^^^^^^^^^^^^^^^^ - | - = help: consider using `as_chunks::<3>()` for better ergonomics + | ^^^^^^^^^^^^^^^^^^^^^ help: consider using `as_chunks` instead: `slice.as_chunks::<3>().0.iter()` error: using `chunks_exact_mut` with a constant chunk size - --> tests/ui/chunks_exact_with_const_size.rs:31:18 + --> tests/ui/chunks_exact_with_const_size.rs:30:18 | LL | let mut it = arr.chunks_exact_mut(4); - | ^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: consider using `as_chunks_mut::<4>()` for better ergonomics + | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `as_chunks` instead: `arr.as_chunks_mut::<4>().0.iter()` error: aborting due to 4 previous errors From dc9fa9ded59ed90abc31eab8614a3faafb6d4934 Mon Sep 17 00:00:00 2001 From: rommeld <138243859+rommeld@users.noreply.github.com> Date: Fri, 7 Nov 2025 19:38:32 +0100 Subject: [PATCH 10/23] Reduced highlighting to method call for better understanding --- .../methods/chunks_exact_with_const_size.rs | 24 ++++++++------ clippy_lints/src/methods/mod.rs | 4 +-- tests/ui/chunks_exact_with_const_size.fixed | 12 +++---- tests/ui/chunks_exact_with_const_size.rs | 12 +++---- tests/ui/chunks_exact_with_const_size.stderr | 32 ++++++++++++------- 5 files changed, 45 insertions(+), 39 deletions(-) diff --git a/clippy_lints/src/methods/chunks_exact_with_const_size.rs b/clippy_lints/src/methods/chunks_exact_with_const_size.rs index 97294a268820..6fbc4a6fc349 100644 --- a/clippy_lints/src/methods/chunks_exact_with_const_size.rs +++ b/clippy_lints/src/methods/chunks_exact_with_const_size.rs @@ -1,20 +1,21 @@ use clippy_utils::consts::{ConstEvalCtxt, Constant}; -use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_applicability; use clippy_utils::sym; use rustc_errors::Applicability; use rustc_hir::Expr; use rustc_lint::LateContext; -use rustc_span::Symbol; +use rustc_span::{Span, Symbol}; use super::CHUNKS_EXACT_WITH_CONST_SIZE; pub(super) fn check( cx: &LateContext<'_>, - expr: &Expr<'_>, recv: &Expr<'_>, arg: &Expr<'_>, + expr_span: Span, + call_span: Span, method_name: Symbol, msrv: Msrv, ) { @@ -38,16 +39,21 @@ pub(super) fn check( let recv_str = snippet_with_applicability(cx, recv.span, "_", &mut applicability); let arg_str = snippet_with_applicability(cx, arg.span, "_", &mut applicability); - let suggestion = format!("{recv_str}.{suggestion_method}::<{arg_str}>().0.iter()"); + let suggestion = format!("{recv_str}.{suggestion_method}::<{arg_str}>()"); - span_lint_and_sugg( + span_lint_and_then( cx, CHUNKS_EXACT_WITH_CONST_SIZE, - expr.span, + call_span, format!("using `{method_name}` with a constant chunk size"), - "consider using `as_chunks` instead", - suggestion, - applicability, + |diag| { + diag.span_suggestion( + expr_span, + "consider using `as_chunks` instead", + suggestion, + applicability, + ); + }, ); } diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 5f8e3b434649..ae881d1dd1ec 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -5677,7 +5677,7 @@ impl Methods { } } // Handle method calls whose receiver and arguments may come from expansion - if let ExprKind::MethodCall(path, recv, args, _call_span) = expr.kind { + if let ExprKind::MethodCall(path, recv, args, call_span) = expr.kind { let method_span = path.ident.span; // Those methods do their own method name checking as they deal with multiple methods. @@ -5744,7 +5744,7 @@ impl Methods { ); }, (name @ (sym::chunks_exact | sym::chunks_exact_mut), [arg]) => { - chunks_exact_with_const_size::check(cx, expr, recv, arg, name, self.msrv); + chunks_exact_with_const_size::check(cx, recv, arg, expr.span, call_span, name, self.msrv); }, _ => {}, } diff --git a/tests/ui/chunks_exact_with_const_size.fixed b/tests/ui/chunks_exact_with_const_size.fixed index 63c3632a505a..d3e46981115f 100644 --- a/tests/ui/chunks_exact_with_const_size.fixed +++ b/tests/ui/chunks_exact_with_const_size.fixed @@ -5,15 +5,13 @@ fn main() { let slice = [1, 2, 3, 4, 5, 6, 7, 8]; // Should trigger lint - literal constant - let mut it = slice.as_chunks::<4>().0.iter(); + let result = slice.as_chunks::<4>(); //~^ chunks_exact_with_const_size - for chunk in it {} // Should trigger lint - const value const CHUNK_SIZE: usize = 4; - let mut it = slice.as_chunks::().0.iter(); + let result = slice.as_chunks::(); //~^ chunks_exact_with_const_size - for chunk in it {} // Should NOT trigger - runtime value let size = 4; @@ -21,13 +19,11 @@ fn main() { for chunk in it {} // Should trigger lint - simple iteration - let mut it = slice.as_chunks::<3>().0.iter(); + let result = slice.as_chunks::<3>(); //~^ chunks_exact_with_const_size - for chunk in it {} // Should trigger - mutable variant let mut arr = [1, 2, 3, 4, 5, 6, 7, 8]; - let mut it = arr.as_chunks_mut::<4>().0.iter(); + let result = arr.as_chunks_mut::<4>(); //~^ chunks_exact_with_const_size - for chunk in it {} } diff --git a/tests/ui/chunks_exact_with_const_size.rs b/tests/ui/chunks_exact_with_const_size.rs index 48585b84a5b7..bb29af973af7 100644 --- a/tests/ui/chunks_exact_with_const_size.rs +++ b/tests/ui/chunks_exact_with_const_size.rs @@ -5,15 +5,13 @@ fn main() { let slice = [1, 2, 3, 4, 5, 6, 7, 8]; // Should trigger lint - literal constant - let mut it = slice.chunks_exact(4); + let result = slice.chunks_exact(4); //~^ chunks_exact_with_const_size - for chunk in it {} // Should trigger lint - const value const CHUNK_SIZE: usize = 4; - let mut it = slice.chunks_exact(CHUNK_SIZE); + let result = slice.chunks_exact(CHUNK_SIZE); //~^ chunks_exact_with_const_size - for chunk in it {} // Should NOT trigger - runtime value let size = 4; @@ -21,13 +19,11 @@ fn main() { for chunk in it {} // Should trigger lint - simple iteration - let mut it = slice.chunks_exact(3); + let result = slice.chunks_exact(3); //~^ chunks_exact_with_const_size - for chunk in it {} // Should trigger - mutable variant let mut arr = [1, 2, 3, 4, 5, 6, 7, 8]; - let mut it = arr.chunks_exact_mut(4); + let result = arr.chunks_exact_mut(4); //~^ chunks_exact_with_const_size - for chunk in it {} } diff --git a/tests/ui/chunks_exact_with_const_size.stderr b/tests/ui/chunks_exact_with_const_size.stderr index 7bccc0bcaf2d..36f4f03e816f 100644 --- a/tests/ui/chunks_exact_with_const_size.stderr +++ b/tests/ui/chunks_exact_with_const_size.stderr @@ -1,29 +1,37 @@ error: using `chunks_exact` with a constant chunk size - --> tests/ui/chunks_exact_with_const_size.rs:8:18 + --> tests/ui/chunks_exact_with_const_size.rs:8:24 | -LL | let mut it = slice.chunks_exact(4); - | ^^^^^^^^^^^^^^^^^^^^^ help: consider using `as_chunks` instead: `slice.as_chunks::<4>().0.iter()` +LL | let result = slice.chunks_exact(4); + | ------^^^^^^^^^^^^^^^ + | | + | help: consider using `as_chunks` instead: `slice.as_chunks::<4>()` | = note: `-D clippy::chunks-exact-with-const-size` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::chunks_exact_with_const_size)]` error: using `chunks_exact` with a constant chunk size - --> tests/ui/chunks_exact_with_const_size.rs:14:18 + --> tests/ui/chunks_exact_with_const_size.rs:13:24 | -LL | let mut it = slice.chunks_exact(CHUNK_SIZE); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `as_chunks` instead: `slice.as_chunks::().0.iter()` +LL | let result = slice.chunks_exact(CHUNK_SIZE); + | ------^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | help: consider using `as_chunks` instead: `slice.as_chunks::()` error: using `chunks_exact` with a constant chunk size - --> tests/ui/chunks_exact_with_const_size.rs:24:18 + --> tests/ui/chunks_exact_with_const_size.rs:22:24 | -LL | let mut it = slice.chunks_exact(3); - | ^^^^^^^^^^^^^^^^^^^^^ help: consider using `as_chunks` instead: `slice.as_chunks::<3>().0.iter()` +LL | let result = slice.chunks_exact(3); + | ------^^^^^^^^^^^^^^^ + | | + | help: consider using `as_chunks` instead: `slice.as_chunks::<3>()` error: using `chunks_exact_mut` with a constant chunk size - --> tests/ui/chunks_exact_with_const_size.rs:30:18 + --> tests/ui/chunks_exact_with_const_size.rs:27:22 | -LL | let mut it = arr.chunks_exact_mut(4); - | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `as_chunks` instead: `arr.as_chunks_mut::<4>().0.iter()` +LL | let result = arr.chunks_exact_mut(4); + | ----^^^^^^^^^^^^^^^^^^^ + | | + | help: consider using `as_chunks` instead: `arr.as_chunks_mut::<4>()` error: aborting due to 4 previous errors From afaf92b2d93095dd7f3480e5f67638d74104864b Mon Sep 17 00:00:00 2001 From: rommeld <138243859+rommeld@users.noreply.github.com> Date: Sat, 8 Nov 2025 00:15:40 +0100 Subject: [PATCH 11/23] Moved method to lints which handle methods whose receivers and arguments may not come from expansions to reduce risk for errors --- clippy_lints/src/methods/mod.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index ae881d1dd1ec..516938253b80 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -5071,6 +5071,9 @@ impl Methods { _ => {}, } }, + (name @ (sym::chunks_exact | sym::chunks_exact_mut), [arg]) => { + chunks_exact_with_const_size::check(cx, recv, arg, expr.span, call_span, name, self.msrv); + }, (sym::and_then, [arg]) => { let biom_option_linted = bind_instead_of_map::check_and_then_some(cx, expr, recv, arg); let biom_result_linted = bind_instead_of_map::check_and_then_ok(cx, expr, recv, arg); @@ -5677,7 +5680,7 @@ impl Methods { } } // Handle method calls whose receiver and arguments may come from expansion - if let ExprKind::MethodCall(path, recv, args, call_span) = expr.kind { + if let ExprKind::MethodCall(path, recv, args, _call_span) = expr.kind { let method_span = path.ident.span; // Those methods do their own method name checking as they deal with multiple methods. @@ -5743,9 +5746,6 @@ impl Methods { unwrap_expect_used::Variant::Unwrap, ); }, - (name @ (sym::chunks_exact | sym::chunks_exact_mut), [arg]) => { - chunks_exact_with_const_size::check(cx, recv, arg, expr.span, call_span, name, self.msrv); - }, _ => {}, } } From dfd80657cf3bd8286b4e974fa4d074f7183bf3ff Mon Sep 17 00:00:00 2001 From: rommeld <138243859+rommeld@users.noreply.github.com> Date: Sat, 8 Nov 2025 00:39:42 +0100 Subject: [PATCH 12/23] Changed suggestion to return iterator instead of tuple --- .../methods/chunks_exact_with_const_size.rs | 2 +- tests/ui/chunks_exact_with_const_size.fixed | 13 +++++++--- tests/ui/chunks_exact_with_const_size.rs | 5 ++++ tests/ui/chunks_exact_with_const_size.stderr | 26 ++++++++++++------- 4 files changed, 32 insertions(+), 14 deletions(-) diff --git a/clippy_lints/src/methods/chunks_exact_with_const_size.rs b/clippy_lints/src/methods/chunks_exact_with_const_size.rs index 6fbc4a6fc349..be7ec529574a 100644 --- a/clippy_lints/src/methods/chunks_exact_with_const_size.rs +++ b/clippy_lints/src/methods/chunks_exact_with_const_size.rs @@ -39,7 +39,7 @@ pub(super) fn check( let recv_str = snippet_with_applicability(cx, recv.span, "_", &mut applicability); let arg_str = snippet_with_applicability(cx, arg.span, "_", &mut applicability); - let suggestion = format!("{recv_str}.{suggestion_method}::<{arg_str}>()"); + let suggestion = format!("{recv_str}.{suggestion_method}::<{arg_str}>().0.iter()"); span_lint_and_then( cx, diff --git a/tests/ui/chunks_exact_with_const_size.fixed b/tests/ui/chunks_exact_with_const_size.fixed index d3e46981115f..3d4e8614a522 100644 --- a/tests/ui/chunks_exact_with_const_size.fixed +++ b/tests/ui/chunks_exact_with_const_size.fixed @@ -1,16 +1,17 @@ #![warn(clippy::chunks_exact_with_const_size)] #![allow(unused)] +#![allow(clippy::iter_cloned_collect)] fn main() { let slice = [1, 2, 3, 4, 5, 6, 7, 8]; // Should trigger lint - literal constant - let result = slice.as_chunks::<4>(); + let result = slice.as_chunks::<4>().0.iter(); //~^ chunks_exact_with_const_size // Should trigger lint - const value const CHUNK_SIZE: usize = 4; - let result = slice.as_chunks::(); + let result = slice.as_chunks::().0.iter(); //~^ chunks_exact_with_const_size // Should NOT trigger - runtime value @@ -19,11 +20,15 @@ fn main() { for chunk in it {} // Should trigger lint - simple iteration - let result = slice.as_chunks::<3>(); + let result = slice.as_chunks::<3>().0.iter(); //~^ chunks_exact_with_const_size // Should trigger - mutable variant let mut arr = [1, 2, 3, 4, 5, 6, 7, 8]; - let result = arr.as_chunks_mut::<4>(); + let result = arr.as_chunks_mut::<4>().0.iter(); + //~^ chunks_exact_with_const_size + + // Should trigger - multiline expression + let result = slice.iter().copied().collect::>().as_chunks::<2>().0.iter(); //~^ chunks_exact_with_const_size } diff --git a/tests/ui/chunks_exact_with_const_size.rs b/tests/ui/chunks_exact_with_const_size.rs index bb29af973af7..97d964779df4 100644 --- a/tests/ui/chunks_exact_with_const_size.rs +++ b/tests/ui/chunks_exact_with_const_size.rs @@ -1,5 +1,6 @@ #![warn(clippy::chunks_exact_with_const_size)] #![allow(unused)] +#![allow(clippy::iter_cloned_collect)] fn main() { let slice = [1, 2, 3, 4, 5, 6, 7, 8]; @@ -26,4 +27,8 @@ fn main() { let mut arr = [1, 2, 3, 4, 5, 6, 7, 8]; let result = arr.chunks_exact_mut(4); //~^ chunks_exact_with_const_size + + // Should trigger - multiline expression + let result = slice.iter().copied().collect::>().chunks_exact(2); + //~^ chunks_exact_with_const_size } diff --git a/tests/ui/chunks_exact_with_const_size.stderr b/tests/ui/chunks_exact_with_const_size.stderr index 36f4f03e816f..d5b063721b57 100644 --- a/tests/ui/chunks_exact_with_const_size.stderr +++ b/tests/ui/chunks_exact_with_const_size.stderr @@ -1,37 +1,45 @@ error: using `chunks_exact` with a constant chunk size - --> tests/ui/chunks_exact_with_const_size.rs:8:24 + --> tests/ui/chunks_exact_with_const_size.rs:9:24 | LL | let result = slice.chunks_exact(4); | ------^^^^^^^^^^^^^^^ | | - | help: consider using `as_chunks` instead: `slice.as_chunks::<4>()` + | help: consider using `as_chunks` instead: `slice.as_chunks::<4>().0.iter()` | = note: `-D clippy::chunks-exact-with-const-size` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::chunks_exact_with_const_size)]` error: using `chunks_exact` with a constant chunk size - --> tests/ui/chunks_exact_with_const_size.rs:13:24 + --> tests/ui/chunks_exact_with_const_size.rs:14:24 | LL | let result = slice.chunks_exact(CHUNK_SIZE); | ------^^^^^^^^^^^^^^^^^^^^^^^^ | | - | help: consider using `as_chunks` instead: `slice.as_chunks::()` + | help: consider using `as_chunks` instead: `slice.as_chunks::().0.iter()` error: using `chunks_exact` with a constant chunk size - --> tests/ui/chunks_exact_with_const_size.rs:22:24 + --> tests/ui/chunks_exact_with_const_size.rs:23:24 | LL | let result = slice.chunks_exact(3); | ------^^^^^^^^^^^^^^^ | | - | help: consider using `as_chunks` instead: `slice.as_chunks::<3>()` + | help: consider using `as_chunks` instead: `slice.as_chunks::<3>().0.iter()` error: using `chunks_exact_mut` with a constant chunk size - --> tests/ui/chunks_exact_with_const_size.rs:27:22 + --> tests/ui/chunks_exact_with_const_size.rs:28:22 | LL | let result = arr.chunks_exact_mut(4); | ----^^^^^^^^^^^^^^^^^^^ | | - | help: consider using `as_chunks` instead: `arr.as_chunks_mut::<4>()` + | help: consider using `as_chunks` instead: `arr.as_chunks_mut::<4>().0.iter()` -error: aborting due to 4 previous errors +error: using `chunks_exact` with a constant chunk size + --> tests/ui/chunks_exact_with_const_size.rs:32:60 + | +LL | let result = slice.iter().copied().collect::>().chunks_exact(2); + | ------------------------------------------^^^^^^^^^^^^^^^ + | | + | help: consider using `as_chunks` instead: `slice.iter().copied().collect::>().as_chunks::<2>().0.iter()` + +error: aborting due to 5 previous errors From 3cfa99ac6e821950698217ba007149704b66b76a Mon Sep 17 00:00:00 2001 From: rommeld <138243859+rommeld@users.noreply.github.com> Date: Sat, 8 Nov 2025 00:46:54 +0100 Subject: [PATCH 13/23] Moved version check after cheaper checks is slice and constant evaluation to reduce costs --- clippy_lints/src/methods/chunks_exact_with_const_size.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/methods/chunks_exact_with_const_size.rs b/clippy_lints/src/methods/chunks_exact_with_const_size.rs index be7ec529574a..c9ec649a4b69 100644 --- a/clippy_lints/src/methods/chunks_exact_with_const_size.rs +++ b/clippy_lints/src/methods/chunks_exact_with_const_size.rs @@ -27,6 +27,11 @@ pub(super) fn check( // Check if argument is a constant let constant_eval = ConstEvalCtxt::new(cx); if let Some(Constant::Int(_)) = constant_eval.eval(arg) { + // Check for Rust version - only check after we know we would emit a lint + if !msrv.meets(cx, msrvs::AS_CHUNKS) { + return; + } + // Determine the suggested method name let suggestion_method = if method_name == sym::chunks_exact_mut { "as_chunks_mut" @@ -56,7 +61,4 @@ pub(super) fn check( }, ); } - - // Check for Rust version - if !msrv.meets(cx, msrvs::AS_CHUNKS) {} } From 94181ab24ed190f9432f96adf268c39a3e86457e Mon Sep 17 00:00:00 2001 From: rommeld <138243859+rommeld@users.noreply.github.com> Date: Sat, 8 Nov 2025 00:57:28 +0100 Subject: [PATCH 14/23] Changed suggestion to just consider method call --- .../methods/chunks_exact_with_const_size.rs | 7 +++---- clippy_lints/src/methods/mod.rs | 2 +- tests/ui/chunks_exact_with_const_size.stderr | 20 +++++-------------- 3 files changed, 9 insertions(+), 20 deletions(-) diff --git a/clippy_lints/src/methods/chunks_exact_with_const_size.rs b/clippy_lints/src/methods/chunks_exact_with_const_size.rs index c9ec649a4b69..abd53180d3d7 100644 --- a/clippy_lints/src/methods/chunks_exact_with_const_size.rs +++ b/clippy_lints/src/methods/chunks_exact_with_const_size.rs @@ -14,7 +14,6 @@ pub(super) fn check( cx: &LateContext<'_>, recv: &Expr<'_>, arg: &Expr<'_>, - expr_span: Span, call_span: Span, method_name: Symbol, msrv: Msrv, @@ -41,10 +40,10 @@ pub(super) fn check( // Build the suggestion with proper applicability tracking let mut applicability = Applicability::MachineApplicable; - let recv_str = snippet_with_applicability(cx, recv.span, "_", &mut applicability); let arg_str = snippet_with_applicability(cx, arg.span, "_", &mut applicability); - let suggestion = format!("{recv_str}.{suggestion_method}::<{arg_str}>().0.iter()"); + // Suggestion replaces just "chunks_exact(N)" with "as_chunks::().0.iter()" + let suggestion = format!("{suggestion_method}::<{arg_str}>().0.iter()"); span_lint_and_then( cx, @@ -53,7 +52,7 @@ pub(super) fn check( format!("using `{method_name}` with a constant chunk size"), |diag| { diag.span_suggestion( - expr_span, + call_span, "consider using `as_chunks` instead", suggestion, applicability, diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 516938253b80..e07632e7aa79 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -5072,7 +5072,7 @@ impl Methods { } }, (name @ (sym::chunks_exact | sym::chunks_exact_mut), [arg]) => { - chunks_exact_with_const_size::check(cx, recv, arg, expr.span, call_span, name, self.msrv); + chunks_exact_with_const_size::check(cx, recv, arg, call_span, name, self.msrv); }, (sym::and_then, [arg]) => { let biom_option_linted = bind_instead_of_map::check_and_then_some(cx, expr, recv, arg); diff --git a/tests/ui/chunks_exact_with_const_size.stderr b/tests/ui/chunks_exact_with_const_size.stderr index d5b063721b57..1bbd9b23d363 100644 --- a/tests/ui/chunks_exact_with_const_size.stderr +++ b/tests/ui/chunks_exact_with_const_size.stderr @@ -2,9 +2,7 @@ error: using `chunks_exact` with a constant chunk size --> tests/ui/chunks_exact_with_const_size.rs:9:24 | LL | let result = slice.chunks_exact(4); - | ------^^^^^^^^^^^^^^^ - | | - | help: consider using `as_chunks` instead: `slice.as_chunks::<4>().0.iter()` + | ^^^^^^^^^^^^^^^ help: consider using `as_chunks` instead: `as_chunks::<4>().0.iter()` | = note: `-D clippy::chunks-exact-with-const-size` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::chunks_exact_with_const_size)]` @@ -13,33 +11,25 @@ error: using `chunks_exact` with a constant chunk size --> tests/ui/chunks_exact_with_const_size.rs:14:24 | LL | let result = slice.chunks_exact(CHUNK_SIZE); - | ------^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | help: consider using `as_chunks` instead: `slice.as_chunks::().0.iter()` + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `as_chunks` instead: `as_chunks::().0.iter()` error: using `chunks_exact` with a constant chunk size --> tests/ui/chunks_exact_with_const_size.rs:23:24 | LL | let result = slice.chunks_exact(3); - | ------^^^^^^^^^^^^^^^ - | | - | help: consider using `as_chunks` instead: `slice.as_chunks::<3>().0.iter()` + | ^^^^^^^^^^^^^^^ help: consider using `as_chunks` instead: `as_chunks::<3>().0.iter()` error: using `chunks_exact_mut` with a constant chunk size --> tests/ui/chunks_exact_with_const_size.rs:28:22 | LL | let result = arr.chunks_exact_mut(4); - | ----^^^^^^^^^^^^^^^^^^^ - | | - | help: consider using `as_chunks` instead: `arr.as_chunks_mut::<4>().0.iter()` + | ^^^^^^^^^^^^^^^^^^^ help: consider using `as_chunks` instead: `as_chunks_mut::<4>().0.iter()` error: using `chunks_exact` with a constant chunk size --> tests/ui/chunks_exact_with_const_size.rs:32:60 | LL | let result = slice.iter().copied().collect::>().chunks_exact(2); - | ------------------------------------------^^^^^^^^^^^^^^^ - | | - | help: consider using `as_chunks` instead: `slice.iter().copied().collect::>().as_chunks::<2>().0.iter()` + | ^^^^^^^^^^^^^^^ help: consider using `as_chunks` instead: `as_chunks::<2>().0.iter()` error: aborting due to 5 previous errors From 370d0ae5fd79aba7823ea496a3e7b12f5f67db13 Mon Sep 17 00:00:00 2001 From: rommeld <138243859+rommeld@users.noreply.github.com> Date: Sat, 8 Nov 2025 01:15:02 +0100 Subject: [PATCH 15/23] Changed linting suggestion span_lint_and_then to span_lint_and_sugg --- .../src/methods/chunks_exact_with_const_size.rs | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/clippy_lints/src/methods/chunks_exact_with_const_size.rs b/clippy_lints/src/methods/chunks_exact_with_const_size.rs index abd53180d3d7..d93228119516 100644 --- a/clippy_lints/src/methods/chunks_exact_with_const_size.rs +++ b/clippy_lints/src/methods/chunks_exact_with_const_size.rs @@ -1,5 +1,5 @@ use clippy_utils::consts::{ConstEvalCtxt, Constant}; -use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_applicability; use clippy_utils::sym; @@ -45,19 +45,14 @@ pub(super) fn check( // Suggestion replaces just "chunks_exact(N)" with "as_chunks::().0.iter()" let suggestion = format!("{suggestion_method}::<{arg_str}>().0.iter()"); - span_lint_and_then( + span_lint_and_sugg( cx, CHUNKS_EXACT_WITH_CONST_SIZE, call_span, format!("using `{method_name}` with a constant chunk size"), - |diag| { - diag.span_suggestion( - call_span, - "consider using `as_chunks` instead", - suggestion, - applicability, - ); - }, + "consider using `as_chunks` instead", + suggestion, + applicability, ); } } From 24798af024efe411fd4814c9473bab8ad0053851 Mon Sep 17 00:00:00 2001 From: rommeld <138243859+rommeld@users.noreply.github.com> Date: Sat, 8 Nov 2025 13:17:02 +0100 Subject: [PATCH 16/23] Added skipping multi-line test from cargo dev fmt --- tests/ui/chunks_exact_with_const_size.fixed | 7 ++++++- tests/ui/chunks_exact_with_const_size.rs | 7 ++++++- tests/ui/chunks_exact_with_const_size.stderr | 6 +++--- 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/tests/ui/chunks_exact_with_const_size.fixed b/tests/ui/chunks_exact_with_const_size.fixed index 3d4e8614a522..80f357dcbc7f 100644 --- a/tests/ui/chunks_exact_with_const_size.fixed +++ b/tests/ui/chunks_exact_with_const_size.fixed @@ -29,6 +29,11 @@ fn main() { //~^ chunks_exact_with_const_size // Should trigger - multiline expression - let result = slice.iter().copied().collect::>().as_chunks::<2>().0.iter(); + #[rustfmt::skip] + let result = slice + .iter() + .copied() + .collect::>() + .as_chunks::<2>().0.iter(); //~^ chunks_exact_with_const_size } diff --git a/tests/ui/chunks_exact_with_const_size.rs b/tests/ui/chunks_exact_with_const_size.rs index 97d964779df4..9cd5d3c18698 100644 --- a/tests/ui/chunks_exact_with_const_size.rs +++ b/tests/ui/chunks_exact_with_const_size.rs @@ -29,6 +29,11 @@ fn main() { //~^ chunks_exact_with_const_size // Should trigger - multiline expression - let result = slice.iter().copied().collect::>().chunks_exact(2); + #[rustfmt::skip] + let result = slice + .iter() + .copied() + .collect::>() + .chunks_exact(2); //~^ chunks_exact_with_const_size } diff --git a/tests/ui/chunks_exact_with_const_size.stderr b/tests/ui/chunks_exact_with_const_size.stderr index 1bbd9b23d363..d61cf35bc54e 100644 --- a/tests/ui/chunks_exact_with_const_size.stderr +++ b/tests/ui/chunks_exact_with_const_size.stderr @@ -26,10 +26,10 @@ LL | let result = arr.chunks_exact_mut(4); | ^^^^^^^^^^^^^^^^^^^ help: consider using `as_chunks` instead: `as_chunks_mut::<4>().0.iter()` error: using `chunks_exact` with a constant chunk size - --> tests/ui/chunks_exact_with_const_size.rs:32:60 + --> tests/ui/chunks_exact_with_const_size.rs:37:10 | -LL | let result = slice.iter().copied().collect::>().chunks_exact(2); - | ^^^^^^^^^^^^^^^ help: consider using `as_chunks` instead: `as_chunks::<2>().0.iter()` +LL | .chunks_exact(2); + | ^^^^^^^^^^^^^^^ help: consider using `as_chunks` instead: `as_chunks::<2>().0.iter()` error: aborting due to 5 previous errors From 5e05b1d59dd4908dea9e3eec98812a695ff0fe28 Mon Sep 17 00:00:00 2001 From: rommeld <138243859+rommeld@users.noreply.github.com> Date: Sat, 8 Nov 2025 14:26:32 +0100 Subject: [PATCH 17/23] Improved lint by only suggesting fix when method not stored in variable If method is stored in let binding, emit a help message instead of the fix --- .../methods/chunks_exact_with_const_size.rs | 37 +++++++++++----- clippy_lints/src/methods/mod.rs | 5 ++- tests/ui/chunks_exact_with_const_size.fixed | 39 ---------------- tests/ui/chunks_exact_with_const_size.rs | 13 ++++++ tests/ui/chunks_exact_with_const_size.stderr | 44 ++++++++++++++++--- 5 files changed, 79 insertions(+), 59 deletions(-) delete mode 100644 tests/ui/chunks_exact_with_const_size.fixed diff --git a/clippy_lints/src/methods/chunks_exact_with_const_size.rs b/clippy_lints/src/methods/chunks_exact_with_const_size.rs index d93228119516..c31a963b59b7 100644 --- a/clippy_lints/src/methods/chunks_exact_with_const_size.rs +++ b/clippy_lints/src/methods/chunks_exact_with_const_size.rs @@ -1,10 +1,10 @@ use clippy_utils::consts::{ConstEvalCtxt, Constant}; -use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_applicability; use clippy_utils::sym; use rustc_errors::Applicability; -use rustc_hir::Expr; +use rustc_hir::{Expr, Node, PatKind}; use rustc_lint::LateContext; use rustc_span::{Span, Symbol}; @@ -14,6 +14,7 @@ pub(super) fn check( cx: &LateContext<'_>, recv: &Expr<'_>, arg: &Expr<'_>, + expr: &Expr<'_>, call_span: Span, method_name: Symbol, msrv: Msrv, @@ -23,36 +24,48 @@ pub(super) fn check( return; } - // Check if argument is a constant let constant_eval = ConstEvalCtxt::new(cx); if let Some(Constant::Int(_)) = constant_eval.eval(arg) { - // Check for Rust version - only check after we know we would emit a lint + // Check for Rust version if !msrv.meets(cx, msrvs::AS_CHUNKS) { return; } - // Determine the suggested method name let suggestion_method = if method_name == sym::chunks_exact_mut { "as_chunks_mut" } else { "as_chunks" }; - // Build the suggestion with proper applicability tracking let mut applicability = Applicability::MachineApplicable; let arg_str = snippet_with_applicability(cx, arg.span, "_", &mut applicability); - // Suggestion replaces just "chunks_exact(N)" with "as_chunks::().0.iter()" - let suggestion = format!("{suggestion_method}::<{arg_str}>().0.iter()"); + let as_chunks = format!("{suggestion_method}::<{arg_str}>()"); - span_lint_and_sugg( + span_lint_and_then( cx, CHUNKS_EXACT_WITH_CONST_SIZE, call_span, format!("using `{method_name}` with a constant chunk size"), - "consider using `as_chunks` instead", - suggestion, - applicability, + |diag| { + if let Node::LetStmt(let_stmt) = cx.tcx.parent_hir_node(expr.hir_id) { + diag.help(format!("consider using `{as_chunks}` instead")); + + // Try to extract the variable name to provide a more helpful note + if let PatKind::Binding(_, _, ident, _) = let_stmt.pat.kind { + diag.note(format!( + "you can access the chunks using `{ident}.0.iter()`, and the remainder using `{ident}.1`" + )); + } + } else { + diag.span_suggestion( + call_span, + "consider using `as_chunks` instead", + format!("{as_chunks}.0.iter()"), + applicability, + ); + } + }, ); } } diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index e07632e7aa79..1c7e0aff2381 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -2106,7 +2106,8 @@ declare_clippy_lint! { /// ```no_run /// let slice = [1, 2, 3, 4, 5, 6]; /// let (chunks, remainder) = slice.as_chunks::<2>(); - /// for chunk in chunks {} + /// let remainder_chunk = chunk_iter.1; + /// for chunk in chunk_iter.0.iter() { /// ``` #[clippy::version = "1.93.0"] pub CHUNKS_EXACT_WITH_CONST_SIZE, @@ -5072,7 +5073,7 @@ impl Methods { } }, (name @ (sym::chunks_exact | sym::chunks_exact_mut), [arg]) => { - chunks_exact_with_const_size::check(cx, recv, arg, call_span, name, self.msrv); + chunks_exact_with_const_size::check(cx, recv, arg, expr, call_span, name, self.msrv); }, (sym::and_then, [arg]) => { let biom_option_linted = bind_instead_of_map::check_and_then_some(cx, expr, recv, arg); diff --git a/tests/ui/chunks_exact_with_const_size.fixed b/tests/ui/chunks_exact_with_const_size.fixed deleted file mode 100644 index 80f357dcbc7f..000000000000 --- a/tests/ui/chunks_exact_with_const_size.fixed +++ /dev/null @@ -1,39 +0,0 @@ -#![warn(clippy::chunks_exact_with_const_size)] -#![allow(unused)] -#![allow(clippy::iter_cloned_collect)] - -fn main() { - let slice = [1, 2, 3, 4, 5, 6, 7, 8]; - - // Should trigger lint - literal constant - let result = slice.as_chunks::<4>().0.iter(); - //~^ chunks_exact_with_const_size - - // Should trigger lint - const value - const CHUNK_SIZE: usize = 4; - let result = slice.as_chunks::().0.iter(); - //~^ chunks_exact_with_const_size - - // Should NOT trigger - runtime value - let size = 4; - let mut it = slice.chunks_exact(size); - for chunk in it {} - - // Should trigger lint - simple iteration - let result = slice.as_chunks::<3>().0.iter(); - //~^ chunks_exact_with_const_size - - // Should trigger - mutable variant - let mut arr = [1, 2, 3, 4, 5, 6, 7, 8]; - let result = arr.as_chunks_mut::<4>().0.iter(); - //~^ chunks_exact_with_const_size - - // Should trigger - multiline expression - #[rustfmt::skip] - let result = slice - .iter() - .copied() - .collect::>() - .as_chunks::<2>().0.iter(); - //~^ chunks_exact_with_const_size -} diff --git a/tests/ui/chunks_exact_with_const_size.rs b/tests/ui/chunks_exact_with_const_size.rs index 9cd5d3c18698..e1dc47d5fd28 100644 --- a/tests/ui/chunks_exact_with_const_size.rs +++ b/tests/ui/chunks_exact_with_const_size.rs @@ -36,4 +36,17 @@ fn main() { .collect::>() .chunks_exact(2); //~^ chunks_exact_with_const_size + + // Should trigger lint with help message only (not suggestion) - stored in variable + let mut chunk_iter = slice.chunks_exact(CHUNK_SIZE); + //~^ chunks_exact_with_const_size + for chunk in chunk_iter.by_ref() {} + let _remainder = chunk_iter.remainder(); + + // Similar for mutable version - help message only + let mut arr2 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + let mut chunk_iter = arr2.chunks_exact_mut(CHUNK_SIZE); + //~^ chunks_exact_with_const_size + for chunk in chunk_iter.by_ref() {} + let _remainder = chunk_iter.into_remainder(); } diff --git a/tests/ui/chunks_exact_with_const_size.stderr b/tests/ui/chunks_exact_with_const_size.stderr index d61cf35bc54e..223481ecd2ff 100644 --- a/tests/ui/chunks_exact_with_const_size.stderr +++ b/tests/ui/chunks_exact_with_const_size.stderr @@ -2,8 +2,10 @@ error: using `chunks_exact` with a constant chunk size --> tests/ui/chunks_exact_with_const_size.rs:9:24 | LL | let result = slice.chunks_exact(4); - | ^^^^^^^^^^^^^^^ help: consider using `as_chunks` instead: `as_chunks::<4>().0.iter()` + | ^^^^^^^^^^^^^^^ | + = help: consider using `as_chunks::<4>()` instead + = note: you can access the chunks using `result.0.iter()`, and the remainder using `result.1` = note: `-D clippy::chunks-exact-with-const-size` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::chunks_exact_with_const_size)]` @@ -11,25 +13,55 @@ error: using `chunks_exact` with a constant chunk size --> tests/ui/chunks_exact_with_const_size.rs:14:24 | LL | let result = slice.chunks_exact(CHUNK_SIZE); - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `as_chunks` instead: `as_chunks::().0.iter()` + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using `as_chunks::()` instead + = note: you can access the chunks using `result.0.iter()`, and the remainder using `result.1` error: using `chunks_exact` with a constant chunk size --> tests/ui/chunks_exact_with_const_size.rs:23:24 | LL | let result = slice.chunks_exact(3); - | ^^^^^^^^^^^^^^^ help: consider using `as_chunks` instead: `as_chunks::<3>().0.iter()` + | ^^^^^^^^^^^^^^^ + | + = help: consider using `as_chunks::<3>()` instead + = note: you can access the chunks using `result.0.iter()`, and the remainder using `result.1` error: using `chunks_exact_mut` with a constant chunk size --> tests/ui/chunks_exact_with_const_size.rs:28:22 | LL | let result = arr.chunks_exact_mut(4); - | ^^^^^^^^^^^^^^^^^^^ help: consider using `as_chunks` instead: `as_chunks_mut::<4>().0.iter()` + | ^^^^^^^^^^^^^^^^^^^ + | + = help: consider using `as_chunks_mut::<4>()` instead + = note: you can access the chunks using `result.0.iter()`, and the remainder using `result.1` error: using `chunks_exact` with a constant chunk size --> tests/ui/chunks_exact_with_const_size.rs:37:10 | LL | .chunks_exact(2); - | ^^^^^^^^^^^^^^^ help: consider using `as_chunks` instead: `as_chunks::<2>().0.iter()` + | ^^^^^^^^^^^^^^^ + | + = help: consider using `as_chunks::<2>()` instead + = note: you can access the chunks using `result.0.iter()`, and the remainder using `result.1` + +error: using `chunks_exact` with a constant chunk size + --> tests/ui/chunks_exact_with_const_size.rs:41:32 + | +LL | let mut chunk_iter = slice.chunks_exact(CHUNK_SIZE); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using `as_chunks::()` instead + = note: you can access the chunks using `chunk_iter.0.iter()`, and the remainder using `chunk_iter.1` + +error: using `chunks_exact_mut` with a constant chunk size + --> tests/ui/chunks_exact_with_const_size.rs:48:31 + | +LL | let mut chunk_iter = arr2.chunks_exact_mut(CHUNK_SIZE); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using `as_chunks_mut::()` instead + = note: you can access the chunks using `chunk_iter.0.iter()`, and the remainder using `chunk_iter.1` -error: aborting due to 5 previous errors +error: aborting due to 7 previous errors From ae2cb12cd93aea023045ea1a8f95f08afbaa943e Mon Sep 17 00:00:00 2001 From: rommeld <138243859+rommeld@users.noreply.github.com> Date: Sat, 8 Nov 2025 14:35:05 +0100 Subject: [PATCH 18/23] Fixed missing curly brakets --- clippy_lints/src/methods/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 1c7e0aff2381..ab752952a8a8 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -2107,7 +2107,7 @@ declare_clippy_lint! { /// let slice = [1, 2, 3, 4, 5, 6]; /// let (chunks, remainder) = slice.as_chunks::<2>(); /// let remainder_chunk = chunk_iter.1; - /// for chunk in chunk_iter.0.iter() { + /// for chunk in chunk_iter.0.iter() {} /// ``` #[clippy::version = "1.93.0"] pub CHUNKS_EXACT_WITH_CONST_SIZE, From 43a7a722c2f0ec52e683971c1ddbba92ea9fcad1 Mon Sep 17 00:00:00 2001 From: rommeld <138243859+rommeld@users.noreply.github.com> Date: Sat, 8 Nov 2025 14:42:56 +0100 Subject: [PATCH 19/23] Deleted comment from lint declaration --- clippy_lints/src/methods/mod.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index ab752952a8a8..e8997d3943da 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -2106,7 +2106,6 @@ declare_clippy_lint! { /// ```no_run /// let slice = [1, 2, 3, 4, 5, 6]; /// let (chunks, remainder) = slice.as_chunks::<2>(); - /// let remainder_chunk = chunk_iter.1; /// for chunk in chunk_iter.0.iter() {} /// ``` #[clippy::version = "1.93.0"] From 64aae82ea5cc0614bc002dc535c85a6c9c39a18e Mon Sep 17 00:00:00 2001 From: rommeld <138243859+rommeld@users.noreply.github.com> Date: Sat, 8 Nov 2025 14:56:48 +0100 Subject: [PATCH 20/23] Moved unfixable tests to separate file because ui_test otherwise would fail --- tests/ui/chunks_exact_with_const_size.rs | 13 ----------- tests/ui/chunks_exact_with_const_size.stderr | 20 +---------------- .../chunks_exact_with_const_size_unfixable.rs | 20 +++++++++++++++++ ...nks_exact_with_const_size_unfixable.stderr | 22 +++++++++++++++++++ 4 files changed, 43 insertions(+), 32 deletions(-) create mode 100644 tests/ui/chunks_exact_with_const_size_unfixable.rs create mode 100644 tests/ui/chunks_exact_with_const_size_unfixable.stderr diff --git a/tests/ui/chunks_exact_with_const_size.rs b/tests/ui/chunks_exact_with_const_size.rs index e1dc47d5fd28..9cd5d3c18698 100644 --- a/tests/ui/chunks_exact_with_const_size.rs +++ b/tests/ui/chunks_exact_with_const_size.rs @@ -36,17 +36,4 @@ fn main() { .collect::>() .chunks_exact(2); //~^ chunks_exact_with_const_size - - // Should trigger lint with help message only (not suggestion) - stored in variable - let mut chunk_iter = slice.chunks_exact(CHUNK_SIZE); - //~^ chunks_exact_with_const_size - for chunk in chunk_iter.by_ref() {} - let _remainder = chunk_iter.remainder(); - - // Similar for mutable version - help message only - let mut arr2 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; - let mut chunk_iter = arr2.chunks_exact_mut(CHUNK_SIZE); - //~^ chunks_exact_with_const_size - for chunk in chunk_iter.by_ref() {} - let _remainder = chunk_iter.into_remainder(); } diff --git a/tests/ui/chunks_exact_with_const_size.stderr b/tests/ui/chunks_exact_with_const_size.stderr index 223481ecd2ff..8a7bfc127fe1 100644 --- a/tests/ui/chunks_exact_with_const_size.stderr +++ b/tests/ui/chunks_exact_with_const_size.stderr @@ -45,23 +45,5 @@ LL | .chunks_exact(2); = help: consider using `as_chunks::<2>()` instead = note: you can access the chunks using `result.0.iter()`, and the remainder using `result.1` -error: using `chunks_exact` with a constant chunk size - --> tests/ui/chunks_exact_with_const_size.rs:41:32 - | -LL | let mut chunk_iter = slice.chunks_exact(CHUNK_SIZE); - | ^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: consider using `as_chunks::()` instead - = note: you can access the chunks using `chunk_iter.0.iter()`, and the remainder using `chunk_iter.1` - -error: using `chunks_exact_mut` with a constant chunk size - --> tests/ui/chunks_exact_with_const_size.rs:48:31 - | -LL | let mut chunk_iter = arr2.chunks_exact_mut(CHUNK_SIZE); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: consider using `as_chunks_mut::()` instead - = note: you can access the chunks using `chunk_iter.0.iter()`, and the remainder using `chunk_iter.1` - -error: aborting due to 7 previous errors +error: aborting due to 5 previous errors diff --git a/tests/ui/chunks_exact_with_const_size_unfixable.rs b/tests/ui/chunks_exact_with_const_size_unfixable.rs new file mode 100644 index 000000000000..0e6438215cd1 --- /dev/null +++ b/tests/ui/chunks_exact_with_const_size_unfixable.rs @@ -0,0 +1,20 @@ +#![warn(clippy::chunks_exact_with_const_size)] +#![allow(unused)] + +fn main() { + let slice = [1, 2, 3, 4, 5, 6, 7, 8]; + const CHUNK_SIZE: usize = 4; + + // Should trigger lint with help message only (not suggestion) - stored in variable + let mut chunk_iter = slice.chunks_exact(CHUNK_SIZE); + //~^ chunks_exact_with_const_size + for chunk in chunk_iter.by_ref() {} + let _remainder = chunk_iter.remainder(); + + // Similar for mutable version - help message only + let mut arr2 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + let mut chunk_iter = arr2.chunks_exact_mut(CHUNK_SIZE); + //~^ chunks_exact_with_const_size + for chunk in chunk_iter.by_ref() {} + let _remainder = chunk_iter.into_remainder(); +} diff --git a/tests/ui/chunks_exact_with_const_size_unfixable.stderr b/tests/ui/chunks_exact_with_const_size_unfixable.stderr new file mode 100644 index 000000000000..66f3ffc0a074 --- /dev/null +++ b/tests/ui/chunks_exact_with_const_size_unfixable.stderr @@ -0,0 +1,22 @@ +error: using `chunks_exact` with a constant chunk size + --> tests/ui/chunks_exact_with_const_size_unfixable.rs:9:32 + | +LL | let mut chunk_iter = slice.chunks_exact(CHUNK_SIZE); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using `as_chunks::()` instead + = note: you can access the chunks using `chunk_iter.0.iter()`, and the remainder using `chunk_iter.1` + = note: `-D clippy::chunks-exact-with-const-size` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::chunks_exact_with_const_size)]` + +error: using `chunks_exact_mut` with a constant chunk size + --> tests/ui/chunks_exact_with_const_size_unfixable.rs:16:31 + | +LL | let mut chunk_iter = arr2.chunks_exact_mut(CHUNK_SIZE); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using `as_chunks_mut::()` instead + = note: you can access the chunks using `chunk_iter.0.iter()`, and the remainder using `chunk_iter.1` + +error: aborting due to 2 previous errors + From 83e0039649b844ae978c6fc78f1c9d851593c50c Mon Sep 17 00:00:00 2001 From: rommeld <138243859+rommeld@users.noreply.github.com> Date: Sat, 8 Nov 2025 15:06:55 +0100 Subject: [PATCH 21/23] Swapped plain with so help function is visually attached to method --- .../methods/chunks_exact_with_const_size.rs | 4 +-- tests/ui/chunks_exact_with_const_size.stderr | 30 +++++++++++++++---- ...nks_exact_with_const_size_unfixable.stderr | 12 ++++++-- 3 files changed, 37 insertions(+), 9 deletions(-) diff --git a/clippy_lints/src/methods/chunks_exact_with_const_size.rs b/clippy_lints/src/methods/chunks_exact_with_const_size.rs index c31a963b59b7..d28a2b3dfab4 100644 --- a/clippy_lints/src/methods/chunks_exact_with_const_size.rs +++ b/clippy_lints/src/methods/chunks_exact_with_const_size.rs @@ -40,7 +40,7 @@ pub(super) fn check( let mut applicability = Applicability::MachineApplicable; let arg_str = snippet_with_applicability(cx, arg.span, "_", &mut applicability); - let as_chunks = format!("{suggestion_method}::<{arg_str}>()"); + let as_chunks = format_args!("{suggestion_method}::<{arg_str}>()"); span_lint_and_then( cx, @@ -49,7 +49,7 @@ pub(super) fn check( format!("using `{method_name}` with a constant chunk size"), |diag| { if let Node::LetStmt(let_stmt) = cx.tcx.parent_hir_node(expr.hir_id) { - diag.help(format!("consider using `{as_chunks}` instead")); + diag.span_help(call_span, format!("consider using `{as_chunks}` instead")); // Try to extract the variable name to provide a more helpful note if let PatKind::Binding(_, _, ident, _) = let_stmt.pat.kind { diff --git a/tests/ui/chunks_exact_with_const_size.stderr b/tests/ui/chunks_exact_with_const_size.stderr index 8a7bfc127fe1..7139fffad746 100644 --- a/tests/ui/chunks_exact_with_const_size.stderr +++ b/tests/ui/chunks_exact_with_const_size.stderr @@ -4,7 +4,11 @@ error: using `chunks_exact` with a constant chunk size LL | let result = slice.chunks_exact(4); | ^^^^^^^^^^^^^^^ | - = help: consider using `as_chunks::<4>()` instead +help: consider using `as_chunks::<4>()` instead + --> tests/ui/chunks_exact_with_const_size.rs:9:24 + | +LL | let result = slice.chunks_exact(4); + | ^^^^^^^^^^^^^^^ = note: you can access the chunks using `result.0.iter()`, and the remainder using `result.1` = note: `-D clippy::chunks-exact-with-const-size` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::chunks_exact_with_const_size)]` @@ -15,7 +19,11 @@ error: using `chunks_exact` with a constant chunk size LL | let result = slice.chunks_exact(CHUNK_SIZE); | ^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: consider using `as_chunks::()` instead +help: consider using `as_chunks::()` instead + --> tests/ui/chunks_exact_with_const_size.rs:14:24 + | +LL | let result = slice.chunks_exact(CHUNK_SIZE); + | ^^^^^^^^^^^^^^^^^^^^^^^^ = note: you can access the chunks using `result.0.iter()`, and the remainder using `result.1` error: using `chunks_exact` with a constant chunk size @@ -24,7 +32,11 @@ error: using `chunks_exact` with a constant chunk size LL | let result = slice.chunks_exact(3); | ^^^^^^^^^^^^^^^ | - = help: consider using `as_chunks::<3>()` instead +help: consider using `as_chunks::<3>()` instead + --> tests/ui/chunks_exact_with_const_size.rs:23:24 + | +LL | let result = slice.chunks_exact(3); + | ^^^^^^^^^^^^^^^ = note: you can access the chunks using `result.0.iter()`, and the remainder using `result.1` error: using `chunks_exact_mut` with a constant chunk size @@ -33,7 +45,11 @@ error: using `chunks_exact_mut` with a constant chunk size LL | let result = arr.chunks_exact_mut(4); | ^^^^^^^^^^^^^^^^^^^ | - = help: consider using `as_chunks_mut::<4>()` instead +help: consider using `as_chunks_mut::<4>()` instead + --> tests/ui/chunks_exact_with_const_size.rs:28:22 + | +LL | let result = arr.chunks_exact_mut(4); + | ^^^^^^^^^^^^^^^^^^^ = note: you can access the chunks using `result.0.iter()`, and the remainder using `result.1` error: using `chunks_exact` with a constant chunk size @@ -42,7 +58,11 @@ error: using `chunks_exact` with a constant chunk size LL | .chunks_exact(2); | ^^^^^^^^^^^^^^^ | - = help: consider using `as_chunks::<2>()` instead +help: consider using `as_chunks::<2>()` instead + --> tests/ui/chunks_exact_with_const_size.rs:37:10 + | +LL | .chunks_exact(2); + | ^^^^^^^^^^^^^^^ = note: you can access the chunks using `result.0.iter()`, and the remainder using `result.1` error: aborting due to 5 previous errors diff --git a/tests/ui/chunks_exact_with_const_size_unfixable.stderr b/tests/ui/chunks_exact_with_const_size_unfixable.stderr index 66f3ffc0a074..9146bca894a2 100644 --- a/tests/ui/chunks_exact_with_const_size_unfixable.stderr +++ b/tests/ui/chunks_exact_with_const_size_unfixable.stderr @@ -4,7 +4,11 @@ error: using `chunks_exact` with a constant chunk size LL | let mut chunk_iter = slice.chunks_exact(CHUNK_SIZE); | ^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: consider using `as_chunks::()` instead +help: consider using `as_chunks::()` instead + --> tests/ui/chunks_exact_with_const_size_unfixable.rs:9:32 + | +LL | let mut chunk_iter = slice.chunks_exact(CHUNK_SIZE); + | ^^^^^^^^^^^^^^^^^^^^^^^^ = note: you can access the chunks using `chunk_iter.0.iter()`, and the remainder using `chunk_iter.1` = note: `-D clippy::chunks-exact-with-const-size` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::chunks_exact_with_const_size)]` @@ -15,7 +19,11 @@ error: using `chunks_exact_mut` with a constant chunk size LL | let mut chunk_iter = arr2.chunks_exact_mut(CHUNK_SIZE); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: consider using `as_chunks_mut::()` instead +help: consider using `as_chunks_mut::()` instead + --> tests/ui/chunks_exact_with_const_size_unfixable.rs:16:31 + | +LL | let mut chunk_iter = arr2.chunks_exact_mut(CHUNK_SIZE); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: you can access the chunks using `chunk_iter.0.iter()`, and the remainder using `chunk_iter.1` error: aborting due to 2 previous errors From 1e276d7a8b210a058b491c35d0a79ccc5ac16665 Mon Sep 17 00:00:00 2001 From: rommeld <138243859+rommeld@users.noreply.github.com> Date: Sat, 8 Nov 2025 15:18:19 +0100 Subject: [PATCH 22/23] Fixed wrongly replaced comment in lint declaration --- .../methods/chunks_exact_with_const_size.rs | 20 +++++++++++++++++++ clippy_lints/src/methods/mod.rs | 2 +- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/clippy_lints/src/methods/chunks_exact_with_const_size.rs b/clippy_lints/src/methods/chunks_exact_with_const_size.rs index d28a2b3dfab4..fdd3bef7b08a 100644 --- a/clippy_lints/src/methods/chunks_exact_with_const_size.rs +++ b/clippy_lints/src/methods/chunks_exact_with_const_size.rs @@ -49,6 +49,26 @@ pub(super) fn check( format!("using `{method_name}` with a constant chunk size"), |diag| { if let Node::LetStmt(let_stmt) = cx.tcx.parent_hir_node(expr.hir_id) { + // The `ChunksExact(Mut)` struct is stored for later -- this likely means that the user intends to + // not only use it as an iterator, but also access the remainder using + // `(into_)remainder`. For now, just give a help message in this case. + // TODO: give a suggestion that replaces this: + // ``` + // let chunk_iter = bytes.chunks_exact(CHUNK_SIZE); + // let remainder_chunk = chunk_iter.remainder(); + // for chunk in chunk_iter { + // /* ... */ + // } + // ``` + // with this: + // ``` + // let chunk_iter = bytes.as_chunks::(); + // let remainder_chunk = chunk_iter.1; + // for chunk in chunk_iter.0.iter() { + // /* ... */ + // } + // ``` + diag.span_help(call_span, format!("consider using `{as_chunks}` instead")); // Try to extract the variable name to provide a more helpful note diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index e8997d3943da..40c709f70247 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -2106,7 +2106,7 @@ declare_clippy_lint! { /// ```no_run /// let slice = [1, 2, 3, 4, 5, 6]; /// let (chunks, remainder) = slice.as_chunks::<2>(); - /// for chunk in chunk_iter.0.iter() {} + /// for chunk in chunk_iter {} /// ``` #[clippy::version = "1.93.0"] pub CHUNKS_EXACT_WITH_CONST_SIZE, From c50ccf8c8c1e1e5059ca80827d5f5e9c22fbfdde Mon Sep 17 00:00:00 2001 From: rommeld <138243859+rommeld@users.noreply.github.com> Date: Sat, 8 Nov 2025 15:27:16 +0100 Subject: [PATCH 23/23] Fixed one last typo in the lint declaration comment --- clippy_lints/src/methods/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 40c709f70247..5da1b53acf47 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -2106,7 +2106,7 @@ declare_clippy_lint! { /// ```no_run /// let slice = [1, 2, 3, 4, 5, 6]; /// let (chunks, remainder) = slice.as_chunks::<2>(); - /// for chunk in chunk_iter {} + /// for chunk in chunks {} /// ``` #[clippy::version = "1.93.0"] pub CHUNKS_EXACT_WITH_CONST_SIZE,