From f8a12667a98cf8f99e93ca7a252966f28f09180f Mon Sep 17 00:00:00 2001 From: immersum Date: Sat, 21 Jun 2025 20:45:00 +0200 Subject: [PATCH] Add new lints: `const_sized_chunks_exact`, `_mut`, and `const_sized_windows` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Suggests using (nightly) `array_chunks`, `_mut`, and `array_windows` changelog: new lint: [`const_sized_chunks_exact`] changelog: new lint: [`const_sized_chunks_exact_mut`] changelog: new lint: [`const_sized_windows`] Co-authored-by: MichaƂ Chodzikiewicz --- CHANGELOG.md | 3 + clippy_lints/src/declared_lints.rs | 3 + clippy_lints/src/loops/const_sized_chunks.rs | 60 +++++++ clippy_lints/src/loops/mod.rs | 106 ++++++++++++ clippy_utils/src/sym.rs | 5 + tests/ui/const_sized_chunks_exact.fixed | 89 ++++++++++ tests/ui/const_sized_chunks_exact.rs | 89 ++++++++++ tests/ui/const_sized_chunks_exact.stderr | 172 +++++++++++++++++++ tests/ui/const_sized_chunks_exact_mut.fixed | 89 ++++++++++ tests/ui/const_sized_chunks_exact_mut.rs | 89 ++++++++++ tests/ui/const_sized_chunks_exact_mut.stderr | 172 +++++++++++++++++++ tests/ui/const_sized_windows.fixed | 89 ++++++++++ tests/ui/const_sized_windows.rs | 89 ++++++++++ tests/ui/const_sized_windows.stderr | 172 +++++++++++++++++++ 14 files changed, 1227 insertions(+) create mode 100644 clippy_lints/src/loops/const_sized_chunks.rs create mode 100644 tests/ui/const_sized_chunks_exact.fixed create mode 100644 tests/ui/const_sized_chunks_exact.rs create mode 100644 tests/ui/const_sized_chunks_exact.stderr create mode 100644 tests/ui/const_sized_chunks_exact_mut.fixed create mode 100644 tests/ui/const_sized_chunks_exact_mut.rs create mode 100644 tests/ui/const_sized_chunks_exact_mut.stderr create mode 100644 tests/ui/const_sized_windows.fixed create mode 100644 tests/ui/const_sized_windows.rs create mode 100644 tests/ui/const_sized_windows.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index 9f15b16b5c96..efaacf2dcbe0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5696,6 +5696,9 @@ Released 2018-09-13 [`comparison_to_empty`]: https://rust-lang.github.io/rust-clippy/master/index.html#comparison_to_empty [`confusing_method_to_numeric_cast`]: https://rust-lang.github.io/rust-clippy/master/index.html#confusing_method_to_numeric_cast [`const_is_empty`]: https://rust-lang.github.io/rust-clippy/master/index.html#const_is_empty +[`const_sized_chunks_exact`]: https://rust-lang.github.io/rust-clippy/master/index.html#const_sized_chunks_exact +[`const_sized_chunks_exact_mut`]: https://rust-lang.github.io/rust-clippy/master/index.html#const_sized_chunks_exact_mut +[`const_sized_windows`]: https://rust-lang.github.io/rust-clippy/master/index.html#const_sized_windows [`const_static_lifetime`]: https://rust-lang.github.io/rust-clippy/master/index.html#const_static_lifetime [`copy_iterator`]: https://rust-lang.github.io/rust-clippy/master/index.html#copy_iterator [`crate_in_macro_def`]: https://rust-lang.github.io/rust-clippy/master/index.html#crate_in_macro_def diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index aac30d29a908..6027d373dafb 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -266,6 +266,9 @@ pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[ crate::literal_representation::UNUSUAL_BYTE_GROUPINGS_INFO, crate::literal_string_with_formatting_args::LITERAL_STRING_WITH_FORMATTING_ARGS_INFO, crate::loops::CHAR_INDICES_AS_BYTE_INDICES_INFO, + crate::loops::CONST_SIZED_CHUNKS_EXACT_INFO, + crate::loops::CONST_SIZED_CHUNKS_EXACT_MUT_INFO, + crate::loops::CONST_SIZED_WINDOWS_INFO, crate::loops::EMPTY_LOOP_INFO, crate::loops::EXPLICIT_COUNTER_LOOP_INFO, crate::loops::EXPLICIT_INTO_ITER_LOOP_INFO, diff --git a/clippy_lints/src/loops/const_sized_chunks.rs b/clippy_lints/src/loops/const_sized_chunks.rs new file mode 100644 index 000000000000..576717f14129 --- /dev/null +++ b/clippy_lints/src/loops/const_sized_chunks.rs @@ -0,0 +1,60 @@ +use clippy_utils::consts::{ConstEvalCtxt, Constant}; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::expr_or_init; +use clippy_utils::source::snippet; +use clippy_utils::ty::is_slice_like; +use itertools::Itertools; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind, Pat, PatKind}; +use rustc_lint::LateContext; + +use super::{CONST_SIZED_CHUNKS_EXACT, CONST_SIZED_CHUNKS_EXACT_MUT, CONST_SIZED_WINDOWS}; + +/// Checks for the `/CONST_SIZED(_CHUNKS_EXACT(_MUT)?|_WINDOWS)/` lint. +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>, arg: &'tcx Expr<'_>) { + if !arg.span.from_expansion() + // The `for` loop pattern should be a binding. + && let PatKind::Binding(..) = pat.kind + // The `for` loop argument expression must be a method call. + && let ExprKind::MethodCall(method, self_arg, [arg], span) = arg.kind + // The receiver of the method call must be slice-like. + && is_slice_like(cx, cx.typeck_results().expr_ty(self_arg).peel_refs()) + // The parameter to the method call must be a constant. + && let Some(Constant::Int(n)) = ConstEvalCtxt::new(cx).eval(expr_or_init(cx, arg)) + // The number of elements should be limited. + && let Ok(n) = n.try_into() && n >= 1 && n <= 1 + 'z' as usize - 'a' as usize + { + let method = method.ident.name; + let new_method; + + let lint = match method { + clippy_utils::sym::chunks_exact => { + new_method = clippy_utils::sym::array_chunks; + CONST_SIZED_CHUNKS_EXACT + }, + clippy_utils::sym::chunks_exact_mut => { + new_method = clippy_utils::sym::array_chunks_mut; + CONST_SIZED_CHUNKS_EXACT_MUT + }, + rustc_span::sym::windows => { + new_method = clippy_utils::sym::array_windows; + CONST_SIZED_WINDOWS + }, + _ => return, + }; + + let bindings = ('a'..).take(n).join(", "); + let self_arg = snippet(cx, self_arg.span, ".."); + let arg = snippet(cx, arg.span, "_"); + let msg = format!("iterating over `{method}()` with constant parameter `{arg}`"); + + span_lint_and_then(cx, lint, span, msg, |diag| { + diag.span_suggestion_verbose( + span.with_lo(pat.span.lo()), + format!("use `{new_method}::<{n}>()` instead"), + format!("[{bindings}] in {self_arg}.{new_method}()"), + Applicability::Unspecified, + ); + }); + } +} diff --git a/clippy_lints/src/loops/mod.rs b/clippy_lints/src/loops/mod.rs index 01c36b8cb12f..1e4689f0b070 100644 --- a/clippy_lints/src/loops/mod.rs +++ b/clippy_lints/src/loops/mod.rs @@ -1,4 +1,5 @@ mod char_indices_as_byte_indices; +mod const_sized_chunks; mod empty_loop; mod explicit_counter_loop; mod explicit_into_iter_loop; @@ -784,6 +785,107 @@ declare_clippy_lint! { "using the character position yielded by `.chars().enumerate()` in a context where a byte index is expected" } +declare_clippy_lint! { + /// ### What it does + /// Checks for usage of `.chunks_exact()` on slices where the `chunk_size` is a constant and suggests + /// replacing it with its const generic equivalent, `.array_chunks()`, in a way that the value of the + /// const parameter `N` can be inferred. + /// + /// Specifically, in a for-loop, consuming the iterator over the (non-overlapping) chunks, the lint + /// suggests destructuring the chunks to allow for `N`, the number of elements in a chunk, to be inferred. + /// + /// ### Why is this bad? + /// When `.chunks_exact()` is used, a bounds check is required before an element can be accessed. + /// + /// ### Example + /// ```no_run + /// let numbers = Vec::from_iter(0..10); + /// for chunk in numbers.chunks_exact(2) { + /// println!("{n} is an odd number", n = chunk[1]); + /// } + /// ``` + /// Use instead: + /// ```no_run + /// #![feature(array_chunks)] + /// let numbers = Vec::from_iter(0..10); + /// for [_, n] in numbers.array_chunks() { + /// println!("{n} is an odd number"); + /// } + /// ``` + #[clippy::version = "1.89.0"] + pub CONST_SIZED_CHUNKS_EXACT, + nursery, + "calling `.chunks_exact()` with a constant `chunk_size` where `.array_chunks()` could be used instead" +} + +declare_clippy_lint! { + /// ### What it does + /// Checks for usage of `.chunks_exact_mut()` on slices where the `chunk_size` is a constant and suggests + /// replacing it with its const generic equivalent, `.array_chunks_mut()`, in a way that the value of the + /// const parameter `N` can be inferred. + /// + /// Specifically, in a for-loop, consuming the iterator over the (non-overlapping) chunks, the lint + /// suggests destructuring the chunks to allow for `N`, the number of elements in a chunk, to be inferred. + /// + /// ### Why is this bad? + /// When `.chunks_exact_mut()` is used, a bounds check is required before an element can be accessed. + /// + /// ### Example + /// ```no_run + /// let mut numbers = Vec::from_iter(0..10); + /// for chunk in numbers.chunks_exact_mut(2) { + /// chunk[1] += chunk[0]; + /// println!("{n} is an odd number", n = chunk[1]); + /// } + /// ``` + /// Use instead: + /// ```no_run + /// #![feature(array_chunks)] + /// let mut numbers = Vec::from_iter(0..10); + /// for [m, n] in numbers.array_chunks_mut() { + /// *n += *m; + /// println!("{n} is an odd number"); + /// } + /// ``` + #[clippy::version = "1.89.0"] + pub CONST_SIZED_CHUNKS_EXACT_MUT, + nursery, + "calling `.chunks_exact_mut()` with a constant `chunk_size` where `.array_chunks_mut()` could be used instead" +} + +declare_clippy_lint! { + /// ### What it does + /// Checks for usage of `.windows()` on slices where the `size` is a constant and suggests replacing it with + /// its const generic equivalent, `.array_windows()`, in a way that the value of the const parameter `N` can + /// be inferred. + /// + /// Specifically, in a for-loop, consuming the windowed iterator over the overlapping chunks, the lint + /// suggests destructuring the chunks to allow for `N`, the number of elements in a chunk, to be inferred. + /// + /// ### Why is this bad? + /// When `.windows()` is used, a bounds check is required before an element can be accessed. + /// + /// ### Example + /// ```no_run + /// let numbers = Vec::from_iter(0..10); + /// for chunk in numbers.windows(2) { + /// println!("{n} is an odd number", n = chunk[0] + chunk[1]); + /// } + /// ``` + /// Use instead: + /// ```no_run + /// #![feature(array_windows)] + /// let numbers = Vec::from_iter(0..10); + /// for [m, n] in numbers.array_windows() { + /// println!("{n} is an odd number", n = m + n); + /// } + /// ``` + #[clippy::version = "1.89.0"] + pub CONST_SIZED_WINDOWS, + nursery, + "calling `.windows()` with a constant `size` where `.array_windows()` could be used instead" +} + pub struct Loops { msrv: Msrv, enforce_iter_loop_reborrow: bool, @@ -822,6 +924,9 @@ impl_lint_pass!(Loops => [ INFINITE_LOOP, MANUAL_SLICE_FILL, CHAR_INDICES_AS_BYTE_INDICES, + CONST_SIZED_CHUNKS_EXACT, + CONST_SIZED_CHUNKS_EXACT_MUT, + CONST_SIZED_WINDOWS, ]); impl<'tcx> LateLintPass<'tcx> for Loops { @@ -906,6 +1011,7 @@ impl Loops { manual_find::check(cx, pat, arg, body, span, expr); unused_enumerate_index::check(cx, pat, arg, body); char_indices_as_byte_indices::check(cx, pat, arg, body); + const_sized_chunks::check(cx, pat, arg); } fn check_for_loop_arg(&self, cx: &LateContext<'_>, _: &Pat<'_>, arg: &Expr<'_>) { diff --git a/clippy_utils/src/sym.rs b/clippy_utils/src/sym.rs index a544954931ba..e1d03dc2b081 100644 --- a/clippy_utils/src/sym.rs +++ b/clippy_utils/src/sym.rs @@ -80,6 +80,9 @@ generate! { ambiguous_glob_reexports, append, arg, + array_chunks, + array_chunks_mut, + array_windows, as_bytes, as_deref, as_deref_mut, @@ -108,6 +111,8 @@ generate! { checked_pow, checked_rem_euclid, checked_sub, + chunks_exact, + chunks_exact_mut, clamp, clippy_utils, clone_into, diff --git a/tests/ui/const_sized_chunks_exact.fixed b/tests/ui/const_sized_chunks_exact.fixed new file mode 100644 index 000000000000..a97f8e74903b --- /dev/null +++ b/tests/ui/const_sized_chunks_exact.fixed @@ -0,0 +1,89 @@ +#![warn(clippy::const_sized_chunks_exact)] +#![feature(array_chunks)] +#![allow(unused_variables)] +#![allow(dead_code)] + +fn test_binding() { + let numbers = [0, 1, 2, 3, 4]; + + #[allow(clippy::needless_borrow)] + for [a, b] in numbers.array_chunks() { + //~^ const_sized_chunks_exact + } + + #[allow(unused_mut)] + for [a, b] in numbers.array_chunks() { + //~^ const_sized_chunks_exact + } + + for [a, b] in numbers.array_chunks() { + //~^ const_sized_chunks_exact + } +} + +fn test_slice_like() { + let numbers = [2; 5]; + for [a, b] in numbers.array_chunks() { + //~^ const_sized_chunks_exact + } + + let numbers = [0, 1, 2, 3, 4]; + for [a, b] in numbers.array_chunks() { + //~^ const_sized_chunks_exact + } + + let numbers = &[0, 1, 2, 3, 4]; + for [a, b] in numbers.array_chunks() { + //~^ const_sized_chunks_exact + } + + let numbers = &&[0, 1, 2, 3, 4]; + for [a, b] in numbers.array_chunks() { + //~^ const_sized_chunks_exact + } + + let numbers = &&&[0, 1, 2, 3, 4]; + for [a, b] in numbers.array_chunks() { + //~^ const_sized_chunks_exact + } + + let numbers = Vec::from_iter(0..5); + for [a, b] in numbers.array_chunks() { + //~^ const_sized_chunks_exact + } + + let numbers = &Vec::from_iter(0..5); + for [a, b] in numbers.array_chunks() { + //~^ const_sized_chunks_exact + } +} + +fn test_const_eval() { + const N: usize = 2; + + let numbers = [2; 5]; + for [a, b] in numbers.array_chunks() { + //~^ const_sized_chunks_exact + } + + for [a, b, c] in numbers.array_chunks() { + //~^ const_sized_chunks_exact + } +} + +fn test_chunk_size() { + let numbers = Vec::from_iter(0..5); + for chunk in numbers.chunks_exact(0) {} + + for [a] in numbers.array_chunks() { + //~^ const_sized_chunks_exact + } + + for [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z] in numbers.array_chunks() { + //~^ const_sized_chunks_exact + } + + for chunk in numbers.chunks_exact(27) {} +} + +fn main() {} diff --git a/tests/ui/const_sized_chunks_exact.rs b/tests/ui/const_sized_chunks_exact.rs new file mode 100644 index 000000000000..6ac6db683728 --- /dev/null +++ b/tests/ui/const_sized_chunks_exact.rs @@ -0,0 +1,89 @@ +#![warn(clippy::const_sized_chunks_exact)] +#![feature(array_chunks)] +#![allow(unused_variables)] +#![allow(dead_code)] + +fn test_binding() { + let numbers = [0, 1, 2, 3, 4]; + + #[allow(clippy::needless_borrow)] + for ref chunk in numbers.chunks_exact(2) { + //~^ const_sized_chunks_exact + } + + #[allow(unused_mut)] + for mut chunk in numbers.chunks_exact(2) { + //~^ const_sized_chunks_exact + } + + for ref mut chunk in numbers.chunks_exact(2) { + //~^ const_sized_chunks_exact + } +} + +fn test_slice_like() { + let numbers = [2; 5]; + for chunk in numbers.chunks_exact(2) { + //~^ const_sized_chunks_exact + } + + let numbers = [0, 1, 2, 3, 4]; + for chunk in numbers.chunks_exact(2) { + //~^ const_sized_chunks_exact + } + + let numbers = &[0, 1, 2, 3, 4]; + for chunk in numbers.chunks_exact(2) { + //~^ const_sized_chunks_exact + } + + let numbers = &&[0, 1, 2, 3, 4]; + for chunk in numbers.chunks_exact(2) { + //~^ const_sized_chunks_exact + } + + let numbers = &&&[0, 1, 2, 3, 4]; + for chunk in numbers.chunks_exact(2) { + //~^ const_sized_chunks_exact + } + + let numbers = Vec::from_iter(0..5); + for chunk in numbers.chunks_exact(2) { + //~^ const_sized_chunks_exact + } + + let numbers = &Vec::from_iter(0..5); + for chunk in numbers.chunks_exact(2) { + //~^ const_sized_chunks_exact + } +} + +fn test_const_eval() { + const N: usize = 2; + + let numbers = [2; 5]; + for chunk in numbers.chunks_exact(N) { + //~^ const_sized_chunks_exact + } + + for chunk in numbers.chunks_exact(N + 1) { + //~^ const_sized_chunks_exact + } +} + +fn test_chunk_size() { + let numbers = Vec::from_iter(0..5); + for chunk in numbers.chunks_exact(0) {} + + for chunk in numbers.chunks_exact(1) { + //~^ const_sized_chunks_exact + } + + for chunk in numbers.chunks_exact(26) { + //~^ const_sized_chunks_exact + } + + for chunk in numbers.chunks_exact(27) {} +} + +fn main() {} diff --git a/tests/ui/const_sized_chunks_exact.stderr b/tests/ui/const_sized_chunks_exact.stderr new file mode 100644 index 000000000000..02fe10a8e47a --- /dev/null +++ b/tests/ui/const_sized_chunks_exact.stderr @@ -0,0 +1,172 @@ +error: iterating over `chunks_exact()` with constant parameter `2` + --> tests/ui/const_sized_chunks_exact.rs:10:30 + | +LL | for ref chunk in numbers.chunks_exact(2) { + | ^^^^^^^^^^^^^^^ + | + = note: `-D clippy::const-sized-chunks-exact` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::const_sized_chunks_exact)]` +help: use `array_chunks::<2>()` instead + | +LL - for ref chunk in numbers.chunks_exact(2) { +LL + for [a, b] in numbers.array_chunks() { + | + +error: iterating over `chunks_exact()` with constant parameter `2` + --> tests/ui/const_sized_chunks_exact.rs:15:30 + | +LL | for mut chunk in numbers.chunks_exact(2) { + | ^^^^^^^^^^^^^^^ + | +help: use `array_chunks::<2>()` instead + | +LL - for mut chunk in numbers.chunks_exact(2) { +LL + for [a, b] in numbers.array_chunks() { + | + +error: iterating over `chunks_exact()` with constant parameter `2` + --> tests/ui/const_sized_chunks_exact.rs:19:34 + | +LL | for ref mut chunk in numbers.chunks_exact(2) { + | ^^^^^^^^^^^^^^^ + | +help: use `array_chunks::<2>()` instead + | +LL - for ref mut chunk in numbers.chunks_exact(2) { +LL + for [a, b] in numbers.array_chunks() { + | + +error: iterating over `chunks_exact()` with constant parameter `2` + --> tests/ui/const_sized_chunks_exact.rs:26:26 + | +LL | for chunk in numbers.chunks_exact(2) { + | ^^^^^^^^^^^^^^^ + | +help: use `array_chunks::<2>()` instead + | +LL - for chunk in numbers.chunks_exact(2) { +LL + for [a, b] in numbers.array_chunks() { + | + +error: iterating over `chunks_exact()` with constant parameter `2` + --> tests/ui/const_sized_chunks_exact.rs:31:26 + | +LL | for chunk in numbers.chunks_exact(2) { + | ^^^^^^^^^^^^^^^ + | +help: use `array_chunks::<2>()` instead + | +LL - for chunk in numbers.chunks_exact(2) { +LL + for [a, b] in numbers.array_chunks() { + | + +error: iterating over `chunks_exact()` with constant parameter `2` + --> tests/ui/const_sized_chunks_exact.rs:36:26 + | +LL | for chunk in numbers.chunks_exact(2) { + | ^^^^^^^^^^^^^^^ + | +help: use `array_chunks::<2>()` instead + | +LL - for chunk in numbers.chunks_exact(2) { +LL + for [a, b] in numbers.array_chunks() { + | + +error: iterating over `chunks_exact()` with constant parameter `2` + --> tests/ui/const_sized_chunks_exact.rs:41:26 + | +LL | for chunk in numbers.chunks_exact(2) { + | ^^^^^^^^^^^^^^^ + | +help: use `array_chunks::<2>()` instead + | +LL - for chunk in numbers.chunks_exact(2) { +LL + for [a, b] in numbers.array_chunks() { + | + +error: iterating over `chunks_exact()` with constant parameter `2` + --> tests/ui/const_sized_chunks_exact.rs:46:26 + | +LL | for chunk in numbers.chunks_exact(2) { + | ^^^^^^^^^^^^^^^ + | +help: use `array_chunks::<2>()` instead + | +LL - for chunk in numbers.chunks_exact(2) { +LL + for [a, b] in numbers.array_chunks() { + | + +error: iterating over `chunks_exact()` with constant parameter `2` + --> tests/ui/const_sized_chunks_exact.rs:51:26 + | +LL | for chunk in numbers.chunks_exact(2) { + | ^^^^^^^^^^^^^^^ + | +help: use `array_chunks::<2>()` instead + | +LL - for chunk in numbers.chunks_exact(2) { +LL + for [a, b] in numbers.array_chunks() { + | + +error: iterating over `chunks_exact()` with constant parameter `2` + --> tests/ui/const_sized_chunks_exact.rs:56:26 + | +LL | for chunk in numbers.chunks_exact(2) { + | ^^^^^^^^^^^^^^^ + | +help: use `array_chunks::<2>()` instead + | +LL - for chunk in numbers.chunks_exact(2) { +LL + for [a, b] in numbers.array_chunks() { + | + +error: iterating over `chunks_exact()` with constant parameter `N` + --> tests/ui/const_sized_chunks_exact.rs:65:26 + | +LL | for chunk in numbers.chunks_exact(N) { + | ^^^^^^^^^^^^^^^ + | +help: use `array_chunks::<2>()` instead + | +LL - for chunk in numbers.chunks_exact(N) { +LL + for [a, b] in numbers.array_chunks() { + | + +error: iterating over `chunks_exact()` with constant parameter `N + 1` + --> tests/ui/const_sized_chunks_exact.rs:69:26 + | +LL | for chunk in numbers.chunks_exact(N + 1) { + | ^^^^^^^^^^^^^^^^^^^ + | +help: use `array_chunks::<3>()` instead + | +LL - for chunk in numbers.chunks_exact(N + 1) { +LL + for [a, b, c] in numbers.array_chunks() { + | + +error: iterating over `chunks_exact()` with constant parameter `1` + --> tests/ui/const_sized_chunks_exact.rs:78:26 + | +LL | for chunk in numbers.chunks_exact(1) { + | ^^^^^^^^^^^^^^^ + | +help: use `array_chunks::<1>()` instead + | +LL - for chunk in numbers.chunks_exact(1) { +LL + for [a] in numbers.array_chunks() { + | + +error: iterating over `chunks_exact()` with constant parameter `26` + --> tests/ui/const_sized_chunks_exact.rs:82:26 + | +LL | for chunk in numbers.chunks_exact(26) { + | ^^^^^^^^^^^^^^^^ + | +help: use `array_chunks::<26>()` instead + | +LL - for chunk in numbers.chunks_exact(26) { +LL + for [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z] in numbers.array_chunks() { + | + +error: aborting due to 14 previous errors + diff --git a/tests/ui/const_sized_chunks_exact_mut.fixed b/tests/ui/const_sized_chunks_exact_mut.fixed new file mode 100644 index 000000000000..13e3f2c40512 --- /dev/null +++ b/tests/ui/const_sized_chunks_exact_mut.fixed @@ -0,0 +1,89 @@ +#![warn(clippy::const_sized_chunks_exact_mut)] +#![feature(array_chunks)] +#![allow(unused_variables)] +#![allow(dead_code)] + +fn test_binding() { + let mut numbers = [0, 1, 2, 3, 4]; + + #[allow(clippy::needless_borrow)] + for [a, b] in numbers.array_chunks_mut() { + //~^ const_sized_chunks_exact_mut + } + + #[allow(unused_mut)] + for [a, b] in numbers.array_chunks_mut() { + //~^ const_sized_chunks_exact_mut + } + + for [a, b] in numbers.array_chunks_mut() { + //~^ const_sized_chunks_exact_mut + } +} + +fn test_slice_like() { + let mut numbers = [2; 5]; + for [a, b] in numbers.array_chunks_mut() { + //~^ const_sized_chunks_exact_mut + } + + let mut numbers = [0, 1, 2, 3, 4]; + for [a, b] in numbers.array_chunks_mut() { + //~^ const_sized_chunks_exact_mut + } + + let mut numbers = &mut [0, 1, 2, 3, 4]; + for [a, b] in numbers.array_chunks_mut() { + //~^ const_sized_chunks_exact_mut + } + + let mut numbers = &mut &mut [0, 1, 2, 3, 4]; + for [a, b] in numbers.array_chunks_mut() { + //~^ const_sized_chunks_exact_mut + } + + let mut numbers = &mut &mut &mut [0, 1, 2, 3, 4]; + for [a, b] in numbers.array_chunks_mut() { + //~^ const_sized_chunks_exact_mut + } + + let mut numbers = Vec::from_iter(0..5); + for [a, b] in numbers.array_chunks_mut() { + //~^ const_sized_chunks_exact_mut + } + + let mut numbers = &mut Vec::from_iter(0..5); + for [a, b] in numbers.array_chunks_mut() { + //~^ const_sized_chunks_exact_mut + } +} + +fn test_const_eval() { + const N: usize = 2; + + let mut numbers = [2; 5]; + for [a, b] in numbers.array_chunks_mut() { + //~^ const_sized_chunks_exact_mut + } + + for [a, b, c] in numbers.array_chunks_mut() { + //~^ const_sized_chunks_exact_mut + } +} + +fn test_chunk_size() { + let mut numbers = Vec::from_iter(0..5); + for chunk in numbers.chunks_exact_mut(0) {} + + for [a] in numbers.array_chunks_mut() { + //~^ const_sized_chunks_exact_mut + } + + for [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z] in numbers.array_chunks_mut() { + //~^ const_sized_chunks_exact_mut + } + + for chunk in numbers.chunks_exact_mut(27) {} +} + +fn main() {} diff --git a/tests/ui/const_sized_chunks_exact_mut.rs b/tests/ui/const_sized_chunks_exact_mut.rs new file mode 100644 index 000000000000..9fa0d1f4b1e4 --- /dev/null +++ b/tests/ui/const_sized_chunks_exact_mut.rs @@ -0,0 +1,89 @@ +#![warn(clippy::const_sized_chunks_exact_mut)] +#![feature(array_chunks)] +#![allow(unused_variables)] +#![allow(dead_code)] + +fn test_binding() { + let mut numbers = [0, 1, 2, 3, 4]; + + #[allow(clippy::needless_borrow)] + for ref chunk in numbers.chunks_exact_mut(2) { + //~^ const_sized_chunks_exact_mut + } + + #[allow(unused_mut)] + for mut chunk in numbers.chunks_exact_mut(2) { + //~^ const_sized_chunks_exact_mut + } + + for ref mut chunk in numbers.chunks_exact_mut(2) { + //~^ const_sized_chunks_exact_mut + } +} + +fn test_slice_like() { + let mut numbers = [2; 5]; + for chunk in numbers.chunks_exact_mut(2) { + //~^ const_sized_chunks_exact_mut + } + + let mut numbers = [0, 1, 2, 3, 4]; + for chunk in numbers.chunks_exact_mut(2) { + //~^ const_sized_chunks_exact_mut + } + + let mut numbers = &mut [0, 1, 2, 3, 4]; + for chunk in numbers.chunks_exact_mut(2) { + //~^ const_sized_chunks_exact_mut + } + + let mut numbers = &mut &mut [0, 1, 2, 3, 4]; + for chunk in numbers.chunks_exact_mut(2) { + //~^ const_sized_chunks_exact_mut + } + + let mut numbers = &mut &mut &mut [0, 1, 2, 3, 4]; + for chunk in numbers.chunks_exact_mut(2) { + //~^ const_sized_chunks_exact_mut + } + + let mut numbers = Vec::from_iter(0..5); + for chunk in numbers.chunks_exact_mut(2) { + //~^ const_sized_chunks_exact_mut + } + + let mut numbers = &mut Vec::from_iter(0..5); + for chunk in numbers.chunks_exact_mut(2) { + //~^ const_sized_chunks_exact_mut + } +} + +fn test_const_eval() { + const N: usize = 2; + + let mut numbers = [2; 5]; + for chunk in numbers.chunks_exact_mut(N) { + //~^ const_sized_chunks_exact_mut + } + + for chunk in numbers.chunks_exact_mut(N + 1) { + //~^ const_sized_chunks_exact_mut + } +} + +fn test_chunk_size() { + let mut numbers = Vec::from_iter(0..5); + for chunk in numbers.chunks_exact_mut(0) {} + + for chunk in numbers.chunks_exact_mut(1) { + //~^ const_sized_chunks_exact_mut + } + + for chunk in numbers.chunks_exact_mut(26) { + //~^ const_sized_chunks_exact_mut + } + + for chunk in numbers.chunks_exact_mut(27) {} +} + +fn main() {} diff --git a/tests/ui/const_sized_chunks_exact_mut.stderr b/tests/ui/const_sized_chunks_exact_mut.stderr new file mode 100644 index 000000000000..2d6e87f45084 --- /dev/null +++ b/tests/ui/const_sized_chunks_exact_mut.stderr @@ -0,0 +1,172 @@ +error: iterating over `chunks_exact_mut()` with constant parameter `2` + --> tests/ui/const_sized_chunks_exact_mut.rs:10:30 + | +LL | for ref chunk in numbers.chunks_exact_mut(2) { + | ^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::const-sized-chunks-exact-mut` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::const_sized_chunks_exact_mut)]` +help: use `array_chunks_mut::<2>()` instead + | +LL - for ref chunk in numbers.chunks_exact_mut(2) { +LL + for [a, b] in numbers.array_chunks_mut() { + | + +error: iterating over `chunks_exact_mut()` with constant parameter `2` + --> tests/ui/const_sized_chunks_exact_mut.rs:15:30 + | +LL | for mut chunk in numbers.chunks_exact_mut(2) { + | ^^^^^^^^^^^^^^^^^^^ + | +help: use `array_chunks_mut::<2>()` instead + | +LL - for mut chunk in numbers.chunks_exact_mut(2) { +LL + for [a, b] in numbers.array_chunks_mut() { + | + +error: iterating over `chunks_exact_mut()` with constant parameter `2` + --> tests/ui/const_sized_chunks_exact_mut.rs:19:34 + | +LL | for ref mut chunk in numbers.chunks_exact_mut(2) { + | ^^^^^^^^^^^^^^^^^^^ + | +help: use `array_chunks_mut::<2>()` instead + | +LL - for ref mut chunk in numbers.chunks_exact_mut(2) { +LL + for [a, b] in numbers.array_chunks_mut() { + | + +error: iterating over `chunks_exact_mut()` with constant parameter `2` + --> tests/ui/const_sized_chunks_exact_mut.rs:26:26 + | +LL | for chunk in numbers.chunks_exact_mut(2) { + | ^^^^^^^^^^^^^^^^^^^ + | +help: use `array_chunks_mut::<2>()` instead + | +LL - for chunk in numbers.chunks_exact_mut(2) { +LL + for [a, b] in numbers.array_chunks_mut() { + | + +error: iterating over `chunks_exact_mut()` with constant parameter `2` + --> tests/ui/const_sized_chunks_exact_mut.rs:31:26 + | +LL | for chunk in numbers.chunks_exact_mut(2) { + | ^^^^^^^^^^^^^^^^^^^ + | +help: use `array_chunks_mut::<2>()` instead + | +LL - for chunk in numbers.chunks_exact_mut(2) { +LL + for [a, b] in numbers.array_chunks_mut() { + | + +error: iterating over `chunks_exact_mut()` with constant parameter `2` + --> tests/ui/const_sized_chunks_exact_mut.rs:36:26 + | +LL | for chunk in numbers.chunks_exact_mut(2) { + | ^^^^^^^^^^^^^^^^^^^ + | +help: use `array_chunks_mut::<2>()` instead + | +LL - for chunk in numbers.chunks_exact_mut(2) { +LL + for [a, b] in numbers.array_chunks_mut() { + | + +error: iterating over `chunks_exact_mut()` with constant parameter `2` + --> tests/ui/const_sized_chunks_exact_mut.rs:41:26 + | +LL | for chunk in numbers.chunks_exact_mut(2) { + | ^^^^^^^^^^^^^^^^^^^ + | +help: use `array_chunks_mut::<2>()` instead + | +LL - for chunk in numbers.chunks_exact_mut(2) { +LL + for [a, b] in numbers.array_chunks_mut() { + | + +error: iterating over `chunks_exact_mut()` with constant parameter `2` + --> tests/ui/const_sized_chunks_exact_mut.rs:46:26 + | +LL | for chunk in numbers.chunks_exact_mut(2) { + | ^^^^^^^^^^^^^^^^^^^ + | +help: use `array_chunks_mut::<2>()` instead + | +LL - for chunk in numbers.chunks_exact_mut(2) { +LL + for [a, b] in numbers.array_chunks_mut() { + | + +error: iterating over `chunks_exact_mut()` with constant parameter `2` + --> tests/ui/const_sized_chunks_exact_mut.rs:51:26 + | +LL | for chunk in numbers.chunks_exact_mut(2) { + | ^^^^^^^^^^^^^^^^^^^ + | +help: use `array_chunks_mut::<2>()` instead + | +LL - for chunk in numbers.chunks_exact_mut(2) { +LL + for [a, b] in numbers.array_chunks_mut() { + | + +error: iterating over `chunks_exact_mut()` with constant parameter `2` + --> tests/ui/const_sized_chunks_exact_mut.rs:56:26 + | +LL | for chunk in numbers.chunks_exact_mut(2) { + | ^^^^^^^^^^^^^^^^^^^ + | +help: use `array_chunks_mut::<2>()` instead + | +LL - for chunk in numbers.chunks_exact_mut(2) { +LL + for [a, b] in numbers.array_chunks_mut() { + | + +error: iterating over `chunks_exact_mut()` with constant parameter `N` + --> tests/ui/const_sized_chunks_exact_mut.rs:65:26 + | +LL | for chunk in numbers.chunks_exact_mut(N) { + | ^^^^^^^^^^^^^^^^^^^ + | +help: use `array_chunks_mut::<2>()` instead + | +LL - for chunk in numbers.chunks_exact_mut(N) { +LL + for [a, b] in numbers.array_chunks_mut() { + | + +error: iterating over `chunks_exact_mut()` with constant parameter `N + 1` + --> tests/ui/const_sized_chunks_exact_mut.rs:69:26 + | +LL | for chunk in numbers.chunks_exact_mut(N + 1) { + | ^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `array_chunks_mut::<3>()` instead + | +LL - for chunk in numbers.chunks_exact_mut(N + 1) { +LL + for [a, b, c] in numbers.array_chunks_mut() { + | + +error: iterating over `chunks_exact_mut()` with constant parameter `1` + --> tests/ui/const_sized_chunks_exact_mut.rs:78:26 + | +LL | for chunk in numbers.chunks_exact_mut(1) { + | ^^^^^^^^^^^^^^^^^^^ + | +help: use `array_chunks_mut::<1>()` instead + | +LL - for chunk in numbers.chunks_exact_mut(1) { +LL + for [a] in numbers.array_chunks_mut() { + | + +error: iterating over `chunks_exact_mut()` with constant parameter `26` + --> tests/ui/const_sized_chunks_exact_mut.rs:82:26 + | +LL | for chunk in numbers.chunks_exact_mut(26) { + | ^^^^^^^^^^^^^^^^^^^^ + | +help: use `array_chunks_mut::<26>()` instead + | +LL - for chunk in numbers.chunks_exact_mut(26) { +LL + for [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z] in numbers.array_chunks_mut() { + | + +error: aborting due to 14 previous errors + diff --git a/tests/ui/const_sized_windows.fixed b/tests/ui/const_sized_windows.fixed new file mode 100644 index 000000000000..5c2f0d65e070 --- /dev/null +++ b/tests/ui/const_sized_windows.fixed @@ -0,0 +1,89 @@ +#![warn(clippy::const_sized_windows)] +#![feature(array_windows)] +#![allow(unused_variables)] +#![allow(dead_code)] + +fn test_binding() { + let numbers = [0, 1, 2, 3, 4]; + + #[allow(clippy::needless_borrow)] + for [a, b] in numbers.array_windows() { + //~^ const_sized_windows + } + + #[allow(unused_mut)] + for [a, b] in numbers.array_windows() { + //~^ const_sized_windows + } + + for [a, b] in numbers.array_windows() { + //~^ const_sized_windows + } +} + +fn test_slice_like() { + let numbers = [2; 5]; + for [a, b] in numbers.array_windows() { + //~^ const_sized_windows + } + + let numbers = [0, 1, 2, 3, 4]; + for [a, b] in numbers.array_windows() { + //~^ const_sized_windows + } + + let numbers = &[0, 1, 2, 3, 4]; + for [a, b] in numbers.array_windows() { + //~^ const_sized_windows + } + + let numbers = &&[0, 1, 2, 3, 4]; + for [a, b] in numbers.array_windows() { + //~^ const_sized_windows + } + + let numbers = &&&[0, 1, 2, 3, 4]; + for [a, b] in numbers.array_windows() { + //~^ const_sized_windows + } + + let numbers = Vec::from_iter(0..5); + for [a, b] in numbers.array_windows() { + //~^ const_sized_windows + } + + let numbers = &Vec::from_iter(0..5); + for [a, b] in numbers.array_windows() { + //~^ const_sized_windows + } +} + +fn test_const_eval() { + const N: usize = 2; + + let numbers = [2; 5]; + for [a, b] in numbers.array_windows() { + //~^ const_sized_windows + } + + for [a, b, c] in numbers.array_windows() { + //~^ const_sized_windows + } +} + +fn test_chunk_size() { + let numbers = Vec::from_iter(0..5); + for chunk in numbers.windows(0) {} + + for [a] in numbers.array_windows() { + //~^ const_sized_windows + } + + for [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z] in numbers.array_windows() { + //~^ const_sized_windows + } + + for chunk in numbers.windows(27) {} +} + +fn main() {} diff --git a/tests/ui/const_sized_windows.rs b/tests/ui/const_sized_windows.rs new file mode 100644 index 000000000000..bfa852d398a3 --- /dev/null +++ b/tests/ui/const_sized_windows.rs @@ -0,0 +1,89 @@ +#![warn(clippy::const_sized_windows)] +#![feature(array_windows)] +#![allow(unused_variables)] +#![allow(dead_code)] + +fn test_binding() { + let numbers = [0, 1, 2, 3, 4]; + + #[allow(clippy::needless_borrow)] + for ref chunk in numbers.windows(2) { + //~^ const_sized_windows + } + + #[allow(unused_mut)] + for mut chunk in numbers.windows(2) { + //~^ const_sized_windows + } + + for ref mut chunk in numbers.windows(2) { + //~^ const_sized_windows + } +} + +fn test_slice_like() { + let numbers = [2; 5]; + for chunk in numbers.windows(2) { + //~^ const_sized_windows + } + + let numbers = [0, 1, 2, 3, 4]; + for chunk in numbers.windows(2) { + //~^ const_sized_windows + } + + let numbers = &[0, 1, 2, 3, 4]; + for chunk in numbers.windows(2) { + //~^ const_sized_windows + } + + let numbers = &&[0, 1, 2, 3, 4]; + for chunk in numbers.windows(2) { + //~^ const_sized_windows + } + + let numbers = &&&[0, 1, 2, 3, 4]; + for chunk in numbers.windows(2) { + //~^ const_sized_windows + } + + let numbers = Vec::from_iter(0..5); + for chunk in numbers.windows(2) { + //~^ const_sized_windows + } + + let numbers = &Vec::from_iter(0..5); + for chunk in numbers.windows(2) { + //~^ const_sized_windows + } +} + +fn test_const_eval() { + const N: usize = 2; + + let numbers = [2; 5]; + for chunk in numbers.windows(N) { + //~^ const_sized_windows + } + + for chunk in numbers.windows(N + 1) { + //~^ const_sized_windows + } +} + +fn test_chunk_size() { + let numbers = Vec::from_iter(0..5); + for chunk in numbers.windows(0) {} + + for chunk in numbers.windows(1) { + //~^ const_sized_windows + } + + for chunk in numbers.windows(26) { + //~^ const_sized_windows + } + + for chunk in numbers.windows(27) {} +} + +fn main() {} diff --git a/tests/ui/const_sized_windows.stderr b/tests/ui/const_sized_windows.stderr new file mode 100644 index 000000000000..b6ce19e26b89 --- /dev/null +++ b/tests/ui/const_sized_windows.stderr @@ -0,0 +1,172 @@ +error: iterating over `windows()` with constant parameter `2` + --> tests/ui/const_sized_windows.rs:10:30 + | +LL | for ref chunk in numbers.windows(2) { + | ^^^^^^^^^^ + | + = note: `-D clippy::const-sized-windows` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::const_sized_windows)]` +help: use `array_windows::<2>()` instead + | +LL - for ref chunk in numbers.windows(2) { +LL + for [a, b] in numbers.array_windows() { + | + +error: iterating over `windows()` with constant parameter `2` + --> tests/ui/const_sized_windows.rs:15:30 + | +LL | for mut chunk in numbers.windows(2) { + | ^^^^^^^^^^ + | +help: use `array_windows::<2>()` instead + | +LL - for mut chunk in numbers.windows(2) { +LL + for [a, b] in numbers.array_windows() { + | + +error: iterating over `windows()` with constant parameter `2` + --> tests/ui/const_sized_windows.rs:19:34 + | +LL | for ref mut chunk in numbers.windows(2) { + | ^^^^^^^^^^ + | +help: use `array_windows::<2>()` instead + | +LL - for ref mut chunk in numbers.windows(2) { +LL + for [a, b] in numbers.array_windows() { + | + +error: iterating over `windows()` with constant parameter `2` + --> tests/ui/const_sized_windows.rs:26:26 + | +LL | for chunk in numbers.windows(2) { + | ^^^^^^^^^^ + | +help: use `array_windows::<2>()` instead + | +LL - for chunk in numbers.windows(2) { +LL + for [a, b] in numbers.array_windows() { + | + +error: iterating over `windows()` with constant parameter `2` + --> tests/ui/const_sized_windows.rs:31:26 + | +LL | for chunk in numbers.windows(2) { + | ^^^^^^^^^^ + | +help: use `array_windows::<2>()` instead + | +LL - for chunk in numbers.windows(2) { +LL + for [a, b] in numbers.array_windows() { + | + +error: iterating over `windows()` with constant parameter `2` + --> tests/ui/const_sized_windows.rs:36:26 + | +LL | for chunk in numbers.windows(2) { + | ^^^^^^^^^^ + | +help: use `array_windows::<2>()` instead + | +LL - for chunk in numbers.windows(2) { +LL + for [a, b] in numbers.array_windows() { + | + +error: iterating over `windows()` with constant parameter `2` + --> tests/ui/const_sized_windows.rs:41:26 + | +LL | for chunk in numbers.windows(2) { + | ^^^^^^^^^^ + | +help: use `array_windows::<2>()` instead + | +LL - for chunk in numbers.windows(2) { +LL + for [a, b] in numbers.array_windows() { + | + +error: iterating over `windows()` with constant parameter `2` + --> tests/ui/const_sized_windows.rs:46:26 + | +LL | for chunk in numbers.windows(2) { + | ^^^^^^^^^^ + | +help: use `array_windows::<2>()` instead + | +LL - for chunk in numbers.windows(2) { +LL + for [a, b] in numbers.array_windows() { + | + +error: iterating over `windows()` with constant parameter `2` + --> tests/ui/const_sized_windows.rs:51:26 + | +LL | for chunk in numbers.windows(2) { + | ^^^^^^^^^^ + | +help: use `array_windows::<2>()` instead + | +LL - for chunk in numbers.windows(2) { +LL + for [a, b] in numbers.array_windows() { + | + +error: iterating over `windows()` with constant parameter `2` + --> tests/ui/const_sized_windows.rs:56:26 + | +LL | for chunk in numbers.windows(2) { + | ^^^^^^^^^^ + | +help: use `array_windows::<2>()` instead + | +LL - for chunk in numbers.windows(2) { +LL + for [a, b] in numbers.array_windows() { + | + +error: iterating over `windows()` with constant parameter `N` + --> tests/ui/const_sized_windows.rs:65:26 + | +LL | for chunk in numbers.windows(N) { + | ^^^^^^^^^^ + | +help: use `array_windows::<2>()` instead + | +LL - for chunk in numbers.windows(N) { +LL + for [a, b] in numbers.array_windows() { + | + +error: iterating over `windows()` with constant parameter `N + 1` + --> tests/ui/const_sized_windows.rs:69:26 + | +LL | for chunk in numbers.windows(N + 1) { + | ^^^^^^^^^^^^^^ + | +help: use `array_windows::<3>()` instead + | +LL - for chunk in numbers.windows(N + 1) { +LL + for [a, b, c] in numbers.array_windows() { + | + +error: iterating over `windows()` with constant parameter `1` + --> tests/ui/const_sized_windows.rs:78:26 + | +LL | for chunk in numbers.windows(1) { + | ^^^^^^^^^^ + | +help: use `array_windows::<1>()` instead + | +LL - for chunk in numbers.windows(1) { +LL + for [a] in numbers.array_windows() { + | + +error: iterating over `windows()` with constant parameter `26` + --> tests/ui/const_sized_windows.rs:82:26 + | +LL | for chunk in numbers.windows(26) { + | ^^^^^^^^^^^ + | +help: use `array_windows::<26>()` instead + | +LL - for chunk in numbers.windows(26) { +LL + for [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z] in numbers.array_windows() { + | + +error: aborting due to 14 previous errors +