diff --git a/CHANGELOG.md b/CHANGELOG.md index dc308285319f..99f7daed6fc9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6825,6 +6825,7 @@ 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_size_windows`]: https://rust-lang.github.io/rust-clippy/master/index.html#const_size_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/comparison_chain.rs b/clippy_lints/src/comparison_chain.rs index 554f1ab18685..9a56866130ea 100644 --- a/clippy_lints/src/comparison_chain.rs +++ b/clippy_lints/src/comparison_chain.rs @@ -80,9 +80,9 @@ impl<'tcx> LateLintPass<'tcx> for ComparisonChain { return; } - for cond in conds.windows(2) { + for [left, right] in conds.array_windows() { if let (&ExprKind::Binary(ref kind1, lhs1, rhs1), &ExprKind::Binary(ref kind2, lhs2, rhs2)) = - (&cond[0].kind, &cond[1].kind) + (&left.kind, &right.kind) { if !kind_is_cmp(kind1.node) || !kind_is_cmp(kind2.node) { return; diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index b14ee7f3de90..8a1f4ff6b3ed 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -378,6 +378,7 @@ pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[ crate::methods::CLONED_INSTEAD_OF_COPIED_INFO, crate::methods::COLLAPSIBLE_STR_REPLACE_INFO, crate::methods::CONST_IS_EMPTY_INFO, + crate::methods::CONST_SIZE_WINDOWS_INFO, crate::methods::DOUBLE_ENDED_ITERATOR_LAST_INFO, crate::methods::DRAIN_COLLECT_INFO, crate::methods::ERR_EXPECT_INFO, diff --git a/clippy_lints/src/formatting.rs b/clippy_lints/src/formatting.rs index 39106e0fcd4c..6a6917be32be 100644 --- a/clippy_lints/src/formatting.rs +++ b/clippy_lints/src/formatting.rs @@ -147,8 +147,9 @@ declare_lint_pass!(Formatting => [ impl EarlyLintPass for Formatting { fn check_block(&mut self, cx: &EarlyContext<'_>, block: &Block) { - for w in block.stmts.windows(2) { - if let (StmtKind::Expr(first), StmtKind::Expr(second) | StmtKind::Semi(second)) = (&w[0].kind, &w[1].kind) { + for [left, right] in block.stmts.array_windows() { + if let (StmtKind::Expr(first), StmtKind::Expr(second) | StmtKind::Semi(second)) = (&left.kind, &right.kind) + { check_missing_else(cx, first, second); } } diff --git a/clippy_lints/src/inconsistent_struct_constructor.rs b/clippy_lints/src/inconsistent_struct_constructor.rs index 4555af85c2d2..6fde2df4400a 100644 --- a/clippy_lints/src/inconsistent_struct_constructor.rs +++ b/clippy_lints/src/inconsistent_struct_constructor.rs @@ -155,11 +155,11 @@ fn suggestion<'tcx>( def_order_map: &FxHashMap, ) -> String { let ws = fields - .windows(2) - .map(|w| { - let w0_span = field_with_attrs_span(cx.tcx, &w[0]); - let w1_span = field_with_attrs_span(cx.tcx, &w[1]); - let span = w0_span.between(w1_span); + .array_windows() + .map(|[left, right]| { + let left_span = field_with_attrs_span(cx.tcx, left); + let right_span = field_with_attrs_span(cx.tcx, right); + let span = left_span.between(right_span); snippet(cx, span, " ") }) .collect::>(); diff --git a/clippy_lints/src/matches/single_match.rs b/clippy_lints/src/matches/single_match.rs index 4a1e2090224d..c25c893accbf 100644 --- a/clippy_lints/src/matches/single_match.rs +++ b/clippy_lints/src/matches/single_match.rs @@ -22,7 +22,9 @@ use super::{MATCH_BOOL, SINGLE_MATCH, SINGLE_MATCH_ELSE}; /// span, e.g. a string literal `"//"`, but we know that this isn't the case for empty /// match arms. fn empty_arm_has_comment(cx: &LateContext<'_>, span: Span) -> bool { - span.check_text(cx, |text| text.as_bytes().windows(2).any(|w| w == b"//" || w == b"/*")) + span.check_text(cx, |text| { + text.as_bytes().array_windows::<2>().any(|w| w == b"//" || w == b"/*") + }) } pub(crate) fn check<'tcx>( diff --git a/clippy_lints/src/methods/const_size_windows.rs b/clippy_lints/src/methods/const_size_windows.rs new file mode 100644 index 000000000000..2ee07e2c64ff --- /dev/null +++ b/clippy_lints/src/methods/const_size_windows.rs @@ -0,0 +1,295 @@ +use super::CONST_SIZE_WINDOWS; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::msrvs::Msrv; +use clippy_utils::res::{MaybeDef as _, MaybeTypeckRes as _}; +use clippy_utils::source::snippet_opt; +use clippy_utils::ty::{deref_chain, implements_trait}; +use clippy_utils::visitors::is_const_evaluatable; +use clippy_utils::{contains_name, msrvs, sym}; +use rustc_ast::LitKind; +use rustc_data_structures::packed::Pu128; +use rustc_errors::Applicability; +use rustc_hir::def_id::DefId; +use rustc_hir::{Expr, ExprKind, ImplItemKind, Item, ItemKind, Node, QPath, TraitFn, TraitItemKind, UnOp}; +use rustc_lint::LateContext; +use rustc_middle::ty::{AssocTag, EarlyBinder, Ty, Unnormalized}; +use rustc_span::{Span, Symbol}; +use std::ops::Not as _; + +const ARRAY_WINDOWS: Symbol = sym::array_windows; +const WINDOWS: Symbol = sym::windows; +const SLICE: Symbol = sym::slice; + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +struct Suggestion { + span_location: SpanLocation, + code: String, + destructuring_example: Option, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +enum SpanLocation { + MethodCall, + EntireExpression, +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +struct DestructuredArray { + array_snippet: String, + extent: DestructuringExtent, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +enum DestructuringExtent { + Full, + Partial, +} + +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'tcx>, + recv: &'tcx Expr<'tcx>, + size_arg: &'tcx Expr<'tcx>, + call_span: Span, + msrv: Msrv, +) { + // Ignore cases where entire expression originates from a macro. + if expr.span.from_expansion() { + return; + } + + // Ignore Rust versions where `slice::array_windows` has not stabilized + if !msrv.meets(cx, msrvs::ARRAY_WINDOWS) { + return; + } + + if is_const_size_window(cx, expr, size_arg) { + span_lint_and_then( + cx, + CONST_SIZE_WINDOWS, + call_span, + format!("using `{SLICE}::{WINDOWS}` with a constant size instead of `{SLICE}::{ARRAY_WINDOWS}`"), + |diag| { + if let Some(Suggestion { + span_location, + code, + destructuring_example, + }) = compute_suggestion(cx, recv, size_arg) + { + let span = match span_location { + SpanLocation::MethodCall => call_span, + SpanLocation::EntireExpression => expr.span, + }; + diag.span_suggestion(span, "use", code, Applicability::MachineApplicable); + + if let Some(example) = destructuring_example { + diag.note(format!("you may also consider array destructuring: `{example}`")); + } + } else { + diag.span_help(call_span, format!("consider using `{SLICE}::{ARRAY_WINDOWS}` here`")); + } + }, + ); + } +} + +fn is_const_size_window<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, size_arg: &'tcx Expr<'_>) -> bool { + let is_slice_method_call = cx + .ty_based_def(expr) + .opt_parent(cx) + .opt_impl_ty(cx) + .map(EarlyBinder::instantiate_identity) + .map(Unnormalized::skip_normalization) + .is_some_and(Ty::is_slice); + + is_slice_method_call && is_const_evaluatable(cx.tcx, cx.typeck_results(), size_arg) +} + +fn compute_suggestion<'tcx>( + cx: &LateContext<'tcx>, + recv: &'tcx Expr<'tcx>, + size_arg: &'tcx Expr<'tcx>, +) -> Option { + let (recv_snippet, size_arg_snippet) = Option::zip( + snippet_opt(cx, recv.span.source_callsite()), + snippet_opt(cx, size_arg.span.source_callsite()), + )?; + + let size_generic_const_arg = if expr_needs_braces_in_const_arg(size_arg) { + format!("{{ {size_arg_snippet} }}") + } else { + size_arg_snippet + }; + + let is_ucfs_required = is_array_windows_method_call_ambiguous(cx, recv); + + let (span_location, code) = if is_ucfs_required { + ( + SpanLocation::EntireExpression, + format!( + "<[_]>::{ARRAY_WINDOWS}::<{size_generic_const_arg}>({})", + normalize_expr_to_single_ref(cx, recv)? + ), + ) + } else { + ( + SpanLocation::MethodCall, + format!("{ARRAY_WINDOWS}::<{size_generic_const_arg}>()"), + ) + }; + + let destructuring_example = + build_destructured_array(cx, size_arg).and_then(|DestructuredArray { array_snippet, extent }| { + let iterator_expr_snippet = match extent { + DestructuringExtent::Full if is_ucfs_required => { + format!("<[_]>::{ARRAY_WINDOWS}({})", normalize_expr_to_single_ref(cx, recv)?) + }, + DestructuringExtent::Full => format!("{recv_snippet}.{ARRAY_WINDOWS}()"), + DestructuringExtent::Partial if is_ucfs_required => format!( + "<[_]>::{ARRAY_WINDOWS}::<{size_generic_const_arg}>({})", + normalize_expr_to_single_ref(cx, recv)? + ), + DestructuringExtent::Partial => format!("{recv_snippet}.{ARRAY_WINDOWS}::<{size_generic_const_arg}>()"), + }; + + Some(format!("for {array_snippet} in {iterator_expr_snippet}")) + }); + + Some(Suggestion { + span_location, + code, + destructuring_example, + }) +} + +fn build_destructured_array(cx: &LateContext<'_>, size_arg: &Expr<'_>) -> Option { + const MAX_HINTED_DESTRUCTURED_ARRAY_LENGTH: u128 = 5; + let containing_fn = get_containing_fn(cx, size_arg)?; + let is_unused_name = |name: &&str| !contains_name(Symbol::intern(name), containing_fn, cx); + + let destructured_array = if let ExprKind::Lit(lit) = size_arg.kind + && let LitKind::Int(Pu128(length), _) = lit.node + && length <= MAX_HINTED_DESTRUCTURED_ARRAY_LENGTH + && let length = length as usize + && !size_arg.span.from_expansion() + { + const EXACT_LEN_POTENTIAL_NAMES: &[&[&str]] = &[&["left", "right"], &["x", "y", "z"]]; + + const ANY_LEN_POTENTIAL_NAMES: &[&[&str]] = &[ + &["item_1", "item_2", "item_3", "item_4", "item_5"], + &["el_1", "el_2", "el_3", "el_4", "el_5"], + &["x1", "x2", "x3", "x4", "x5"], + ]; + + let comma_separated_variables = EXACT_LEN_POTENTIAL_NAMES + .iter() + .filter(|names| names.len() == length) + .chain(ANY_LEN_POTENTIAL_NAMES.iter().filter(|names| names.len() >= length)) + .map(|names| &names[..length]) + .find(|names| names.iter().all(is_unused_name))? + .join(", "); + + DestructuredArray { + array_snippet: format!("[{comma_separated_variables}]"), + extent: DestructuringExtent::Full, + } + } else { + const POTENTIAL_NAMES: &[&str] = &["item", "element", "el", "a", "x"]; + let name = POTENTIAL_NAMES.iter().find(|name| is_unused_name(name))?; + DestructuredArray { + array_snippet: format!("[{name}, ..]"), + extent: DestructuringExtent::Partial, + } + }; + + Some(destructured_array) +} + +fn expr_needs_braces_in_const_arg(expr: &Expr<'_>) -> bool { + expr.span.from_expansion() + || match &expr.kind { + ExprKind::Lit(_) => false, + ExprKind::Path(QPath::Resolved(None, path)) => { + path.segments.len() != 1 || path.segments[0].args.is_none().not() + }, + _ => true, + } +} + +/// We are overly careful with this check: we allow FP because our goal is never allowing FN. +/// The worst-case scenario of being overly careful is that UCFS is suggested when it isn't strictly +/// necessary. +fn is_array_windows_method_call_ambiguous(cx: &LateContext<'_>, recv: &Expr<'_>) -> bool { + let typeck_results = cx.typeck_results(); + let candidate_recv_types: Vec<_> = [typeck_results.expr_ty(recv), typeck_results.expr_ty_adjusted(recv)] + .into_iter() + .flat_map(|ty| deref_chain(cx, ty)) + .collect(); + + let recv_may_implements_trait = |trait_def_id: DefId| { + candidate_recv_types + .iter() + .any(|&ty| implements_trait(cx, ty, trait_def_id, &[])) + }; + + cx.tcx + .visible_traits() + .filter(|&trait_def_id| trait_declares_array_windows(cx, trait_def_id)) + .any(recv_may_implements_trait) +} + +fn trait_declares_array_windows(cx: &LateContext<'_>, trait_def_id: DefId) -> bool { + cx.tcx + .associated_items(trait_def_id) + .filter_by_name_unhygienic(ARRAY_WINDOWS) + .any(|item| item.tag() == AssocTag::Fn) +} + +fn get_containing_fn<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> Option<&'tcx Expr<'tcx>> { + let parent_item = cx.tcx.hir_get_parent_item(expr.hir_id); + + let body_id = match cx.tcx.hir_node_by_def_id(parent_item.def_id) { + Node::Item(Item { + kind: ItemKind::Fn { body, .. }, + .. + }) + | Node::ImplItem(rustc_hir::ImplItem { + kind: ImplItemKind::Fn(_, body), + .. + }) + | Node::TraitItem(rustc_hir::TraitItem { + kind: TraitItemKind::Fn(_, TraitFn::Provided(body)), + .. + }) => Some(*body), + _ => None, + }; + + Some(cx.tcx.hir_body(body_id?).value) +} + +/// Attempt to produce a snippet of type &T by removing/adding `&` and `*` operators. +/// If this is not possible, return `None`. +/// Stops at macro expansion. +/// +/// Examples: +/// if `expr` is of type `T` -> `&expr` +/// if `expr` is of type `&T` -> `expr` +/// if `expr` is of type `&&T` -> `*expr` +fn normalize_expr_to_single_ref(cx: &LateContext<'_>, recv: &Expr<'_>) -> Option { + // Peel & and * until we reach macro expansion or core referent + let mut referent = recv; + while !referent.span.from_expansion() + && let ExprKind::AddrOf(_, _, inner) | ExprKind::Unary(UnOp::Deref, inner) = referent.kind + { + referent = inner; + } + + let referent_snippet = snippet_opt(cx, referent.span.source_callsite())?; + let snippet = if cx.typeck_results().expr_ty(referent).is_ref() { + referent_snippet + } else { + format!("&{referent_snippet}") + }; + + Some(snippet) +} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 53bcd319bc86..3f2b57544642 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -16,6 +16,7 @@ mod clone_on_copy; mod clone_on_ref_ptr; mod cloned_instead_of_copied; mod collapsible_str_replace; +mod const_size_windows; mod double_ended_iterator_last; mod drain_collect; mod err_expect; @@ -540,6 +541,38 @@ declare_clippy_lint! { "is_empty() called on strings known at compile time" } +declare_clippy_lint! { + /// ### What it does + /// Checks for usage of `slice::windows` with a constant window size that can be replaced + /// with `slice::array_windows`. + /// + /// ### Why is this bad? + /// `slice::windows` yields `&[T]` slices, whose length is only known at runtime. + /// `slice::array_windows` yields fixed-size `&[T; N]` arrays instead, so the + /// length is known at compile time and each window can be destructured directly. + /// + /// ### Example + /// ```no_run + /// fn foo(values: &[u8]) { + /// for pair in values.windows(2) { + /// println!("{} {}", pair[0], pair[1]); + /// } + /// } + /// ``` + /// Use instead: + /// ```no_run + /// fn foo(values: &[u8]) { + /// for [left, right] in values.array_windows() { + /// println!("{left} {right}"); + /// } + /// } + /// ``` + #[clippy::version = "1.99.0"] + pub CONST_SIZE_WINDOWS, + style, + "using `slice::windows` with a constant size instead of `slice::array_windows`" +} + declare_clippy_lint! { /// ### What it does /// @@ -4936,6 +4969,7 @@ impl_lint_pass!(Methods => [ CLONE_ON_REF_PTR, COLLAPSIBLE_STR_REPLACE, CONST_IS_EMPTY, + CONST_SIZE_WINDOWS, DOUBLE_ENDED_ITERATOR_LAST, DRAIN_COLLECT, ERR_EXPECT, @@ -5997,6 +6031,9 @@ impl Methods { unwrap_expect_used::Variant::Unwrap, ); }, + (sym::windows, [size_arg]) => { + const_size_windows::check(cx, expr, recv, size_arg, call_span, self.msrv); + }, _ => {}, } } diff --git a/clippy_lints/src/redundant_closure_call.rs b/clippy_lints/src/redundant_closure_call.rs index 49d09c0e7c66..ae819b16b0b5 100644 --- a/clippy_lints/src/redundant_closure_call.rs +++ b/clippy_lints/src/redundant_closure_call.rs @@ -270,12 +270,12 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall { closure_usage_count.count } - for w in block.stmts.windows(2) { - if let hir::StmtKind::Let(local) = w[0].kind + for [left, right] in block.stmts.array_windows() { + if let hir::StmtKind::Let(local) = left.kind && let Some(t) = local.init && let ExprKind::Closure { .. } = t.kind && let hir::PatKind::Binding(_, _, ident, _) = local.pat.kind - && let hir::StmtKind::Semi(second) = w[1].kind + && let hir::StmtKind::Semi(second) = right.kind && let ExprKind::Assign(_, call, _) = second.kind && let ExprKind::Call(closure, _) = call.kind && let ExprKind::Path(hir::QPath::Resolved(_, path)) = closure.kind diff --git a/clippy_lints_internal/src/repeated_is_diagnostic_item.rs b/clippy_lints_internal/src/repeated_is_diagnostic_item.rs index a7599ae21350..1e1b005ebd74 100644 --- a/clippy_lints_internal/src/repeated_is_diagnostic_item.rs +++ b/clippy_lints_internal/src/repeated_is_diagnostic_item.rs @@ -125,10 +125,9 @@ impl<'tcx> LateLintPass<'tcx> for RepeatedIsDiagnosticItem { fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'_>) { for [(cond1, stmt1_span), (cond2, stmt2_span)] in block .stmts - .windows(2) - .filter_map(|pair| { - if let [if1, if2] = pair - && let StmtKind::Expr(e1) | StmtKind::Semi(e1) = if1.kind + .array_windows() + .filter_map(|[if1, if2]| { + if let StmtKind::Expr(e1) | StmtKind::Semi(e1) = if1.kind && let ExprKind::If(cond1, ..) = e1.kind && let StmtKind::Expr(e2) | StmtKind::Semi(e2) = if2.kind && let ExprKind::If(cond2, ..) = e2.kind diff --git a/clippy_utils/src/msrvs.rs b/clippy_utils/src/msrvs.rs index 9c325032b16f..3857affd0a4f 100644 --- a/clippy_utils/src/msrvs.rs +++ b/clippy_utils/src/msrvs.rs @@ -26,7 +26,7 @@ macro_rules! msrv_aliases { // names may refer to stabilized feature flags or library items msrv_aliases! { 1,97,0 { ISOLATE_LOWEST_ONE, BIT_WIDTH } - 1,94,0 { EULER_GAMMA, GOLDEN_RATIO } + 1,94,0 { EULER_GAMMA, GOLDEN_RATIO, ARRAY_WINDOWS } 1,93,0 { VEC_DEQUE_POP_BACK_IF, VEC_DEQUE_POP_FRONT_IF } 1,91,0 { DURATION_FROM_MINUTES_HOURS } 1,88,0 { LET_CHAINS, AS_CHUNKS } diff --git a/clippy_utils/src/str_utils.rs b/clippy_utils/src/str_utils.rs index f0f82c8dddcf..3c8acda839f0 100644 --- a/clippy_utils/src/str_utils.rs +++ b/clippy_utils/src/str_utils.rs @@ -162,7 +162,7 @@ pub fn camel_case_split(s: &str) -> Vec<&str> { offsets.insert(0, 0); } - offsets.windows(2).map(|w| &s[w[0]..w[1]]).collect() + offsets.array_windows().map(|[left, right]| &s[*left..*right]).collect() } /// Dealing with string comparison can be complicated, this struct ensures that both the diff --git a/clippy_utils/src/sym.rs b/clippy_utils/src/sym.rs index 5da94bfda5e6..2961301e6d9f 100644 --- a/clippy_utils/src/sym.rs +++ b/clippy_utils/src/sym.rs @@ -134,6 +134,7 @@ generate! { append, applicability, arg, + array_windows, as_bytes, as_deref, as_deref_mut, diff --git a/tests/ui/const_size_windows/true_negatives.rs b/tests/ui/const_size_windows/true_negatives.rs new file mode 100644 index 000000000000..5c09cb12f10d --- /dev/null +++ b/tests/ui/const_size_windows/true_negatives.rs @@ -0,0 +1,106 @@ +//@check-pass +#![warn(clippy::const_size_windows)] + +macro_rules! number { + () => { + (0..100).count() + }; +} + +macro_rules! as_window_pairs { + ($slice:expr) => {{ + let s: &[_] = $slice; + s.windows(2) + }}; +} + +fn get_number() -> usize { + (0..100).filter(|num| num % 2 == 0).count() +} + +fn slice_windows_variable_size(slice: &[u8], size: usize) { + for window in slice.windows(size) { + let window: &[u8] = window; + println!("{}", window[0]); + } +} + +fn slice_windows_fn_variable_size(slice: &[u8]) { + for window in slice.windows(get_number()) { + let window: &[u8] = window; + println!("{}", window[0]); + } +} + +fn slice_windows_macro_variable_size(slice: &[u8]) { + for window in slice.windows(number!()) { + let window: &[u8] = window; + println!("{}", window[0]); + } +} + +fn vec_windows_variable_size(vector: Vec, size: usize) { + for window in vector.windows(size) { + let window: &[u8] = window; + println!("{}", window[0]); + } +} + +fn array_windows_variable_size(array: [u8; 3], size: usize) { + for window in array.windows(size) { + let window: &[u8] = window; + println!("{}", window[0]); + } +} + +fn array_generic_length_windows_variable_size(array: [u8; LENGTH], size: usize) { + for window in array.windows(size) { + let window: &[u8] = window; + println!("{}", window[0]); + } +} + +fn inline_vec_windows_variable_size(size: usize) { + #[expect(clippy::useless_vec)] + for window in vec![1, 2, 3].windows(size) { + let window: &[u8] = window; + println!("{}", window[0]); + } +} + +fn inline_array_windows_variable_size(size: usize) { + for window in [1, 2, 3].windows(size) { + let window: &[i32] = window; + println!("{}", window[0]); + } +} + +fn inline_slice_windows_variable_size(size: usize) { + for window in [1, 2, 3, 4, 5][..=2].windows(size) { + let window: &[i32] = window; + println!("{}", window[0]); + } +} + +fn into_slice_windows_variable_size<'a>(into_slice: impl Into<&'a [u8]>, size: usize) { + for window in into_slice.into().windows(size) { + let window: &[u8] = window; + println!("{}", window[0]); + } +} + +fn deref_slice_windows_variable_size(deref_slice: impl std::ops::Deref, size: usize) { + for window in (*deref_slice).windows(size) { + let window: &[u8] = window; + println!("{}", window[0]); + } +} + +fn macro_containing_slice_windows_literal_size(slice: &[u8]) { + for pair in as_window_pairs!(slice) { + let pair: &[u8] = pair; + println!("{} {}", pair[0], pair[1]); + } +} + +fn main() {} diff --git a/tests/ui/const_size_windows/true_positives.fixed b/tests/ui/const_size_windows/true_positives.fixed new file mode 100644 index 000000000000..381c9dcadadf --- /dev/null +++ b/tests/ui/const_size_windows/true_positives.fixed @@ -0,0 +1,145 @@ +#![warn(clippy::const_size_windows)] + +macro_rules! two { + () => { + 2usize + }; +} + +const fn get_two() -> usize { + 2 +} + +fn slice_windows_literal_size(slice: &[u8]) { + for pair in slice.array_windows::<2>() { + //~^ const_size_windows + let pair: &[u8] = pair; + println!("{} {}", pair[0], pair[1]); + } +} + +fn slice_windows_literal_size_three(slice: &[u8]) { + for triplet in slice.array_windows::<3>() { + //~^ const_size_windows + let triplet: &[u8] = triplet; + println!("{} {} {}", triplet[0], triplet[1], triplet[2]); + } +} + +fn slice_windows_const_size(slice: &[u8]) { + const TWO: usize = 2; + for pair in slice.array_windows::() { + //~^ const_size_windows + let pair: &[u8] = pair; + println!("{} {}", pair[0], pair[1]); + } +} + +fn slice_windows_param_const_size(slice: &[u8]) { + for window in slice.array_windows::() { + //~^ const_size_windows + let window: &[u8] = window; + println!("{}", window[0]); + } +} + +fn slice_windows_const_fn_size(slice: &[u8]) { + for pair in slice.array_windows::<{ get_two() }>() { + //~^ const_size_windows + let pair: &[u8] = pair; + println!("{} {}", pair[0], pair[1]); + } +} + +fn slice_windows_inline_const_macro_size(slice: &[u8]) { + for pair in slice.array_windows::<{ two!() }>() { + //~^ const_size_windows + let pair: &[u8] = pair; + println!("{} {}", pair[0], pair[1]); + } +} + +fn vec_windows_literal_size(vector: Vec) { + for pair in vector.array_windows::<2>() { + //~^ const_size_windows + let pair: &[u8] = pair; + println!("{} {}", pair[0], pair[1]); + } +} + +fn array_windows_literal_size(array: [u8; 3]) { + for pair in array.array_windows::<2>() { + //~^ const_size_windows + let pair: &[u8] = pair; + println!("{} {}", pair[0], pair[1]); + } +} + +fn array_generic_length_windows_literal_size(array: [u8; LENGTH]) { + for pair in array.array_windows::<2>() { + //~^ const_size_windows + let pair: &[u8] = pair; + println!("{} {}", pair[0], pair[1]); + } +} + +fn inline_vec_windows_literal_size() { + #[expect(clippy::useless_vec)] + for pair in vec![1, 2, 3].array_windows::<2>() { + //~^ const_size_windows + let pair: &[u8] = pair; + println!("{} {}", pair[0], pair[1]); + } +} + +fn inline_array_windows_literal_size() { + for pair in [1, 2, 3].array_windows::<2>() { + //~^ const_size_windows + let pair: &[u8] = pair; + println!("{} {}", pair[0], pair[1]); + } +} + +fn inline_slice_windows_literal_size() { + for pair in [1, 2, 3, 4, 5][..=2].array_windows::<2>() { + //~^ const_size_windows + let pair: &[u8] = pair; + println!("{} {}", pair[0], pair[1]); + } +} + +fn into_slice_windows_literal_size<'a>(into_slice: impl Into<&'a [u8]>) { + for pair in into_slice.into().array_windows::<2>() { + //~^ const_size_windows + let pair: &[u8] = pair; + println!("{} {}", pair[0], pair[1]); + } +} + +fn deref_slice_windows_literal_size(deref_slice: impl std::ops::Deref) { + for pair in (*deref_slice).array_windows::<2>() { + //~^ const_size_windows + let pair: &[u8] = pair; + println!("{} {}", pair[0], pair[1]); + } +} + +fn deref_coerced_slice_windows_literal_size(deref_slice: impl std::ops::Deref) { + for pair in deref_slice.array_windows::<2>() { + //~^ const_size_windows + let pair: &[u8] = pair; + println!("{} {}", pair[0], pair[1]); + } +} + +fn shadowed_destruct_variables() { + let vec: Vec = vec![1, 2, 3]; + let (left, right) = (0, 1); + let (x, y) = (0, 1); + + for pair in vec.array_windows::<2>() { + //~^ const_size_windows + let pair: &[u8] = pair; + println!("{} {}", pair[0], pair[1]); + } +} diff --git a/tests/ui/const_size_windows/true_positives.rs b/tests/ui/const_size_windows/true_positives.rs new file mode 100644 index 000000000000..e9f9562e82d4 --- /dev/null +++ b/tests/ui/const_size_windows/true_positives.rs @@ -0,0 +1,145 @@ +#![warn(clippy::const_size_windows)] + +macro_rules! two { + () => { + 2usize + }; +} + +const fn get_two() -> usize { + 2 +} + +fn slice_windows_literal_size(slice: &[u8]) { + for pair in slice.windows(2) { + //~^ const_size_windows + let pair: &[u8] = pair; + println!("{} {}", pair[0], pair[1]); + } +} + +fn slice_windows_literal_size_three(slice: &[u8]) { + for triplet in slice.windows(3) { + //~^ const_size_windows + let triplet: &[u8] = triplet; + println!("{} {} {}", triplet[0], triplet[1], triplet[2]); + } +} + +fn slice_windows_const_size(slice: &[u8]) { + const TWO: usize = 2; + for pair in slice.windows(TWO) { + //~^ const_size_windows + let pair: &[u8] = pair; + println!("{} {}", pair[0], pair[1]); + } +} + +fn slice_windows_param_const_size(slice: &[u8]) { + for window in slice.windows(SIZE) { + //~^ const_size_windows + let window: &[u8] = window; + println!("{}", window[0]); + } +} + +fn slice_windows_const_fn_size(slice: &[u8]) { + for pair in slice.windows(get_two()) { + //~^ const_size_windows + let pair: &[u8] = pair; + println!("{} {}", pair[0], pair[1]); + } +} + +fn slice_windows_inline_const_macro_size(slice: &[u8]) { + for pair in slice.windows(two!()) { + //~^ const_size_windows + let pair: &[u8] = pair; + println!("{} {}", pair[0], pair[1]); + } +} + +fn vec_windows_literal_size(vector: Vec) { + for pair in vector.windows(2) { + //~^ const_size_windows + let pair: &[u8] = pair; + println!("{} {}", pair[0], pair[1]); + } +} + +fn array_windows_literal_size(array: [u8; 3]) { + for pair in array.windows(2) { + //~^ const_size_windows + let pair: &[u8] = pair; + println!("{} {}", pair[0], pair[1]); + } +} + +fn array_generic_length_windows_literal_size(array: [u8; LENGTH]) { + for pair in array.windows(2) { + //~^ const_size_windows + let pair: &[u8] = pair; + println!("{} {}", pair[0], pair[1]); + } +} + +fn inline_vec_windows_literal_size() { + #[expect(clippy::useless_vec)] + for pair in vec![1, 2, 3].windows(2) { + //~^ const_size_windows + let pair: &[u8] = pair; + println!("{} {}", pair[0], pair[1]); + } +} + +fn inline_array_windows_literal_size() { + for pair in [1, 2, 3].windows(2) { + //~^ const_size_windows + let pair: &[u8] = pair; + println!("{} {}", pair[0], pair[1]); + } +} + +fn inline_slice_windows_literal_size() { + for pair in [1, 2, 3, 4, 5][..=2].windows(2) { + //~^ const_size_windows + let pair: &[u8] = pair; + println!("{} {}", pair[0], pair[1]); + } +} + +fn into_slice_windows_literal_size<'a>(into_slice: impl Into<&'a [u8]>) { + for pair in into_slice.into().windows(2) { + //~^ const_size_windows + let pair: &[u8] = pair; + println!("{} {}", pair[0], pair[1]); + } +} + +fn deref_slice_windows_literal_size(deref_slice: impl std::ops::Deref) { + for pair in (*deref_slice).windows(2) { + //~^ const_size_windows + let pair: &[u8] = pair; + println!("{} {}", pair[0], pair[1]); + } +} + +fn deref_coerced_slice_windows_literal_size(deref_slice: impl std::ops::Deref) { + for pair in deref_slice.windows(2) { + //~^ const_size_windows + let pair: &[u8] = pair; + println!("{} {}", pair[0], pair[1]); + } +} + +fn shadowed_destruct_variables() { + let vec: Vec = vec![1, 2, 3]; + let (left, right) = (0, 1); + let (x, y) = (0, 1); + + for pair in vec.windows(2) { + //~^ const_size_windows + let pair: &[u8] = pair; + println!("{} {}", pair[0], pair[1]); + } +} diff --git a/tests/ui/const_size_windows/true_positives.stderr b/tests/ui/const_size_windows/true_positives.stderr new file mode 100644 index 000000000000..be30cda1cb2b --- /dev/null +++ b/tests/ui/const_size_windows/true_positives.stderr @@ -0,0 +1,132 @@ +error: using `slice::windows` with a constant size instead of `slice::array_windows` + --> tests/ui/const_size_windows/true_positives.rs:14:23 + | +LL | for pair in slice.windows(2) { + | ^^^^^^^^^^ help: use: `array_windows::<2>()` + | + = note: you may also consider array destructuring: `for [left, right] in slice.array_windows()` + = note: `-D clippy::const-size-windows` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::const_size_windows)]` + +error: using `slice::windows` with a constant size instead of `slice::array_windows` + --> tests/ui/const_size_windows/true_positives.rs:22:26 + | +LL | for triplet in slice.windows(3) { + | ^^^^^^^^^^ help: use: `array_windows::<3>()` + | + = note: you may also consider array destructuring: `for [x, y, z] in slice.array_windows()` + +error: using `slice::windows` with a constant size instead of `slice::array_windows` + --> tests/ui/const_size_windows/true_positives.rs:31:23 + | +LL | for pair in slice.windows(TWO) { + | ^^^^^^^^^^^^ help: use: `array_windows::()` + | + = note: you may also consider array destructuring: `for [item, ..] in slice.array_windows::()` + +error: using `slice::windows` with a constant size instead of `slice::array_windows` + --> tests/ui/const_size_windows/true_positives.rs:39:25 + | +LL | for window in slice.windows(SIZE) { + | ^^^^^^^^^^^^^ help: use: `array_windows::()` + | + = note: you may also consider array destructuring: `for [item, ..] in slice.array_windows::()` + +error: using `slice::windows` with a constant size instead of `slice::array_windows` + --> tests/ui/const_size_windows/true_positives.rs:47:23 + | +LL | for pair in slice.windows(get_two()) { + | ^^^^^^^^^^^^^^^^^^ help: use: `array_windows::<{ get_two() }>()` + | + = note: you may also consider array destructuring: `for [item, ..] in slice.array_windows::<{ get_two() }>()` + +error: using `slice::windows` with a constant size instead of `slice::array_windows` + --> tests/ui/const_size_windows/true_positives.rs:55:23 + | +LL | for pair in slice.windows(two!()) { + | ^^^^^^^^^^^^^^^ help: use: `array_windows::<{ two!() }>()` + | + = note: you may also consider array destructuring: `for [item, ..] in slice.array_windows::<{ two!() }>()` + +error: using `slice::windows` with a constant size instead of `slice::array_windows` + --> tests/ui/const_size_windows/true_positives.rs:63:24 + | +LL | for pair in vector.windows(2) { + | ^^^^^^^^^^ help: use: `array_windows::<2>()` + | + = note: you may also consider array destructuring: `for [left, right] in vector.array_windows()` + +error: using `slice::windows` with a constant size instead of `slice::array_windows` + --> tests/ui/const_size_windows/true_positives.rs:71:23 + | +LL | for pair in array.windows(2) { + | ^^^^^^^^^^ help: use: `array_windows::<2>()` + | + = note: you may also consider array destructuring: `for [left, right] in array.array_windows()` + +error: using `slice::windows` with a constant size instead of `slice::array_windows` + --> tests/ui/const_size_windows/true_positives.rs:79:23 + | +LL | for pair in array.windows(2) { + | ^^^^^^^^^^ help: use: `array_windows::<2>()` + | + = note: you may also consider array destructuring: `for [left, right] in array.array_windows()` + +error: using `slice::windows` with a constant size instead of `slice::array_windows` + --> tests/ui/const_size_windows/true_positives.rs:88:31 + | +LL | for pair in vec![1, 2, 3].windows(2) { + | ^^^^^^^^^^ help: use: `array_windows::<2>()` + | + = note: you may also consider array destructuring: `for [left, right] in vec![1, 2, 3].array_windows()` + +error: using `slice::windows` with a constant size instead of `slice::array_windows` + --> tests/ui/const_size_windows/true_positives.rs:96:27 + | +LL | for pair in [1, 2, 3].windows(2) { + | ^^^^^^^^^^ help: use: `array_windows::<2>()` + | + = note: you may also consider array destructuring: `for [left, right] in [1, 2, 3].array_windows()` + +error: using `slice::windows` with a constant size instead of `slice::array_windows` + --> tests/ui/const_size_windows/true_positives.rs:104:39 + | +LL | for pair in [1, 2, 3, 4, 5][..=2].windows(2) { + | ^^^^^^^^^^ help: use: `array_windows::<2>()` + | + = note: you may also consider array destructuring: `for [left, right] in [1, 2, 3, 4, 5][..=2].array_windows()` + +error: using `slice::windows` with a constant size instead of `slice::array_windows` + --> tests/ui/const_size_windows/true_positives.rs:112:35 + | +LL | for pair in into_slice.into().windows(2) { + | ^^^^^^^^^^ help: use: `array_windows::<2>()` + | + = note: you may also consider array destructuring: `for [left, right] in into_slice.into().array_windows()` + +error: using `slice::windows` with a constant size instead of `slice::array_windows` + --> tests/ui/const_size_windows/true_positives.rs:120:32 + | +LL | for pair in (*deref_slice).windows(2) { + | ^^^^^^^^^^ help: use: `array_windows::<2>()` + | + = note: you may also consider array destructuring: `for [left, right] in (*deref_slice).array_windows()` + +error: using `slice::windows` with a constant size instead of `slice::array_windows` + --> tests/ui/const_size_windows/true_positives.rs:128:29 + | +LL | for pair in deref_slice.windows(2) { + | ^^^^^^^^^^ help: use: `array_windows::<2>()` + | + = note: you may also consider array destructuring: `for [left, right] in deref_slice.array_windows()` + +error: using `slice::windows` with a constant size instead of `slice::array_windows` + --> tests/ui/const_size_windows/true_positives.rs:140:21 + | +LL | for pair in vec.windows(2) { + | ^^^^^^^^^^ help: use: `array_windows::<2>()` + | + = note: you may also consider array destructuring: `for [item_1, item_2] in vec.array_windows()` + +error: aborting due to 16 previous errors + diff --git a/tests/ui/const_size_windows/with_array_windows_impl.fixed b/tests/ui/const_size_windows/with_array_windows_impl.fixed new file mode 100644 index 000000000000..4ad19f6b96a9 --- /dev/null +++ b/tests/ui/const_size_windows/with_array_windows_impl.fixed @@ -0,0 +1,156 @@ +#![warn(clippy::const_size_windows)] + +trait DefinesArrayWindows { + fn array_windows(&self) -> [char; LENGTH] { + ['🪟'; LENGTH] + } +} + +#[derive(Debug)] +struct ArrayWindowsStub; + +impl DefinesArrayWindows for Vec {} + +mod array_methods_mod { + trait InnerDefinesArrayWindows { + fn array_windows(&self) -> [char; LENGTH] { + ['🪟'; LENGTH] + } + } + #[derive(Debug)] + pub struct ArrayWindowsStub; + impl InnerDefinesArrayWindows for Vec {} +} + +use array_methods_mod::ArrayWindowsStub as ModArrayWindowsStub; + +fn array_windows_implemented_by_public_trait(vec: Vec) { + for pair in <[_]>::array_windows::<2>(&vec) { + //~^ const_size_windows + let pair: &[ArrayWindowsStub] = pair; + println!("{:#?} {:#?}", pair[0], pair[1]); + } +} + +fn array_windows_implemented_by_trait_in_mod(vec: Vec) { + for pair in <[_]>::array_windows::<2>(&vec) { + //~^ const_size_windows + let pair: &[ModArrayWindowsStub] = pair; + println!("{:#?} {:#?}", pair[0], pair[1]); + } +} + +fn array_windows_implemented_by_nested_trait() { + #[derive(Debug)] + struct Stub; + trait DefinesArrayWindows { + fn array_windows(&self) -> [char; LENGTH] { + ['🪟'; LENGTH] + } + } + + impl DefinesArrayWindows for Vec {} + + #[allow(clippy::useless_vec)] + let vec = vec![Stub, Stub, Stub]; + for pair in <[_]>::array_windows::<2>(&vec) { + //~^ const_size_windows + let pair: &[Stub] = pair; + println!("{:#?} {:#?}", pair[0], pair[1]); + } +} + +fn array_windows_implemented_by_public_trait_with_macro() { + #[expect(clippy::useless_vec)] + for pair in <[_]>::array_windows::<2>(&vec![ArrayWindowsStub, ArrayWindowsStub, ArrayWindowsStub]) { + //~^ const_size_windows + let pair: &[ArrayWindowsStub] = pair; + println!("{:#?} {:#?}", pair[0], pair[1]); + } +} + +fn array_windows_implemented_by_trait_borrowed(#[expect(clippy::ptr_arg)] vec: &Vec) { + for pair in <[_]>::array_windows::<2>(vec) { + //~^ const_size_windows + let pair: &[ArrayWindowsStub] = pair; + println!("{:#?} {:#?}", pair[0], pair[1]); + } +} + +fn array_windows_implemented_by_trait_dereferenced(#[allow(clippy::ptr_arg)] vec: &Vec) { + for pair in <[_]>::array_windows::<2>(vec) { + //~^ const_size_windows + let pair: &[ArrayWindowsStub] = pair; + println!("{:#?} {:#?}", pair[0], pair[1]); + } +} + +fn array_windows_implemented_by_trait_with_ref() { + #[derive(Debug)] + struct Stub; + impl DefinesArrayWindows for &Vec {} + + let vec = vec![Stub, Stub, Stub]; + #[allow(clippy::needless_borrow)] + for pair in <[_]>::array_windows::<2>(&vec) { + //~^ const_size_windows + let pair: &[Stub] = pair; + println!("{:#?} {:#?}", pair[0], pair[1]); + } +} + +fn array_windows_implemented_by_trait_with_deref( + derefs_into_vec_stub: impl std::ops::Deref>, +) { + for pair in <[_]>::array_windows::<2>(&derefs_into_vec_stub) { + //~^ const_size_windows + let pair: &[ArrayWindowsStub] = pair; + println!("{:#?} {:#?}", pair[0], pair[1]); + } +} + +fn array_windows_implemented_by_trait_with_deref_coercion( + derefs_into_vec_stub: impl std::ops::Deref>, +) { + for pair in <[_]>::array_windows::<2>(&derefs_into_vec_stub) { + //~^ const_size_windows + let pair: &[ArrayWindowsStub] = pair; + println!("{:#?} {:#?}", pair[0], pair[1]); + } +} + +fn array_windows_not_implemented_by_trait(vec: Vec) { + #[derive(Debug)] + struct Stub; + impl DefinesArrayWindows for Vec {} + + for pair in vec.array_windows::<2>() { + //~^ const_size_windows + let pair: &[String] = pair; + println!("{:#?} {:#?}", pair[0], pair[1]); + } +} + +fn array_windows_implemented_with_double_borrowed_vec_macro() { + macro_rules! double_borrowed_vec { + ($($x:expr),* $(,)?) => { + &&vec![$($x),*] + }; + } + + #[derive(Debug)] + struct Stub; + trait DefinesArrayWindows { + fn array_windows(&self) -> [char; LENGTH] { + ['🪟'; LENGTH] + } + } + + impl DefinesArrayWindows for &&Vec {} + + for pair in <[_]>::array_windows::<2>(double_borrowed_vec![Stub, Stub, Stub]) { + //~^ const_size_windows + let pair: &[Stub] = pair; + println!("{:#?} {:#?}", pair[0], pair[1]); + } +} diff --git a/tests/ui/const_size_windows/with_array_windows_impl.rs b/tests/ui/const_size_windows/with_array_windows_impl.rs new file mode 100644 index 000000000000..c4ee90cb41f3 --- /dev/null +++ b/tests/ui/const_size_windows/with_array_windows_impl.rs @@ -0,0 +1,156 @@ +#![warn(clippy::const_size_windows)] + +trait DefinesArrayWindows { + fn array_windows(&self) -> [char; LENGTH] { + ['🪟'; LENGTH] + } +} + +#[derive(Debug)] +struct ArrayWindowsStub; + +impl DefinesArrayWindows for Vec {} + +mod array_methods_mod { + trait InnerDefinesArrayWindows { + fn array_windows(&self) -> [char; LENGTH] { + ['🪟'; LENGTH] + } + } + #[derive(Debug)] + pub struct ArrayWindowsStub; + impl InnerDefinesArrayWindows for Vec {} +} + +use array_methods_mod::ArrayWindowsStub as ModArrayWindowsStub; + +fn array_windows_implemented_by_public_trait(vec: Vec) { + for pair in vec.windows(2) { + //~^ const_size_windows + let pair: &[ArrayWindowsStub] = pair; + println!("{:#?} {:#?}", pair[0], pair[1]); + } +} + +fn array_windows_implemented_by_trait_in_mod(vec: Vec) { + for pair in vec.windows(2) { + //~^ const_size_windows + let pair: &[ModArrayWindowsStub] = pair; + println!("{:#?} {:#?}", pair[0], pair[1]); + } +} + +fn array_windows_implemented_by_nested_trait() { + #[derive(Debug)] + struct Stub; + trait DefinesArrayWindows { + fn array_windows(&self) -> [char; LENGTH] { + ['🪟'; LENGTH] + } + } + + impl DefinesArrayWindows for Vec {} + + #[allow(clippy::useless_vec)] + let vec = vec![Stub, Stub, Stub]; + for pair in vec.windows(2) { + //~^ const_size_windows + let pair: &[Stub] = pair; + println!("{:#?} {:#?}", pair[0], pair[1]); + } +} + +fn array_windows_implemented_by_public_trait_with_macro() { + #[expect(clippy::useless_vec)] + for pair in vec![ArrayWindowsStub, ArrayWindowsStub, ArrayWindowsStub].windows(2) { + //~^ const_size_windows + let pair: &[ArrayWindowsStub] = pair; + println!("{:#?} {:#?}", pair[0], pair[1]); + } +} + +fn array_windows_implemented_by_trait_borrowed(#[expect(clippy::ptr_arg)] vec: &Vec) { + for pair in vec.windows(2) { + //~^ const_size_windows + let pair: &[ArrayWindowsStub] = pair; + println!("{:#?} {:#?}", pair[0], pair[1]); + } +} + +fn array_windows_implemented_by_trait_dereferenced(#[allow(clippy::ptr_arg)] vec: &Vec) { + for pair in (*vec).windows(2) { + //~^ const_size_windows + let pair: &[ArrayWindowsStub] = pair; + println!("{:#?} {:#?}", pair[0], pair[1]); + } +} + +fn array_windows_implemented_by_trait_with_ref() { + #[derive(Debug)] + struct Stub; + impl DefinesArrayWindows for &Vec {} + + let vec = vec![Stub, Stub, Stub]; + #[allow(clippy::needless_borrow)] + for pair in (&vec).windows(2) { + //~^ const_size_windows + let pair: &[Stub] = pair; + println!("{:#?} {:#?}", pair[0], pair[1]); + } +} + +fn array_windows_implemented_by_trait_with_deref( + derefs_into_vec_stub: impl std::ops::Deref>, +) { + for pair in (*derefs_into_vec_stub).windows(2) { + //~^ const_size_windows + let pair: &[ArrayWindowsStub] = pair; + println!("{:#?} {:#?}", pair[0], pair[1]); + } +} + +fn array_windows_implemented_by_trait_with_deref_coercion( + derefs_into_vec_stub: impl std::ops::Deref>, +) { + for pair in derefs_into_vec_stub.windows(2) { + //~^ const_size_windows + let pair: &[ArrayWindowsStub] = pair; + println!("{:#?} {:#?}", pair[0], pair[1]); + } +} + +fn array_windows_not_implemented_by_trait(vec: Vec) { + #[derive(Debug)] + struct Stub; + impl DefinesArrayWindows for Vec {} + + for pair in vec.windows(2) { + //~^ const_size_windows + let pair: &[String] = pair; + println!("{:#?} {:#?}", pair[0], pair[1]); + } +} + +fn array_windows_implemented_with_double_borrowed_vec_macro() { + macro_rules! double_borrowed_vec { + ($($x:expr),* $(,)?) => { + &&vec![$($x),*] + }; + } + + #[derive(Debug)] + struct Stub; + trait DefinesArrayWindows { + fn array_windows(&self) -> [char; LENGTH] { + ['🪟'; LENGTH] + } + } + + impl DefinesArrayWindows for &&Vec {} + + for pair in double_borrowed_vec![Stub, Stub, Stub].windows(2) { + //~^ const_size_windows + let pair: &[Stub] = pair; + println!("{:#?} {:#?}", pair[0], pair[1]); + } +} diff --git a/tests/ui/const_size_windows/with_array_windows_impl.stderr b/tests/ui/const_size_windows/with_array_windows_impl.stderr new file mode 100644 index 000000000000..2530dc4d1f96 --- /dev/null +++ b/tests/ui/const_size_windows/with_array_windows_impl.stderr @@ -0,0 +1,112 @@ +error: using `slice::windows` with a constant size instead of `slice::array_windows` + --> tests/ui/const_size_windows/with_array_windows_impl.rs:28:21 + | +LL | for pair in vec.windows(2) { + | ----^^^^^^^^^^ + | | + | help: use: `<[_]>::array_windows::<2>(&vec)` + | + = note: you may also consider array destructuring: `for [left, right] in <[_]>::array_windows(&vec)` + = note: `-D clippy::const-size-windows` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::const_size_windows)]` + +error: using `slice::windows` with a constant size instead of `slice::array_windows` + --> tests/ui/const_size_windows/with_array_windows_impl.rs:36:21 + | +LL | for pair in vec.windows(2) { + | ----^^^^^^^^^^ + | | + | help: use: `<[_]>::array_windows::<2>(&vec)` + | + = note: you may also consider array destructuring: `for [left, right] in <[_]>::array_windows(&vec)` + +error: using `slice::windows` with a constant size instead of `slice::array_windows` + --> tests/ui/const_size_windows/with_array_windows_impl.rs:56:21 + | +LL | for pair in vec.windows(2) { + | ----^^^^^^^^^^ + | | + | help: use: `<[_]>::array_windows::<2>(&vec)` + | + = note: you may also consider array destructuring: `for [left, right] in <[_]>::array_windows(&vec)` + +error: using `slice::windows` with a constant size instead of `slice::array_windows` + --> tests/ui/const_size_windows/with_array_windows_impl.rs:65:76 + | +LL | for pair in vec![ArrayWindowsStub, ArrayWindowsStub, ArrayWindowsStub].windows(2) { + | -----------------------------------------------------------^^^^^^^^^^ + | | + | help: use: `<[_]>::array_windows::<2>(&vec![ArrayWindowsStub, ArrayWindowsStub, ArrayWindowsStub])` + | + = note: you may also consider array destructuring: `for [left, right] in <[_]>::array_windows(&vec![ArrayWindowsStub, ArrayWindowsStub, ArrayWindowsStub])` + +error: using `slice::windows` with a constant size instead of `slice::array_windows` + --> tests/ui/const_size_windows/with_array_windows_impl.rs:73:21 + | +LL | for pair in vec.windows(2) { + | ----^^^^^^^^^^ + | | + | help: use: `<[_]>::array_windows::<2>(vec)` + | + = note: you may also consider array destructuring: `for [left, right] in <[_]>::array_windows(vec)` + +error: using `slice::windows` with a constant size instead of `slice::array_windows` + --> tests/ui/const_size_windows/with_array_windows_impl.rs:81:24 + | +LL | for pair in (*vec).windows(2) { + | -------^^^^^^^^^^ + | | + | help: use: `<[_]>::array_windows::<2>(vec)` + | + = note: you may also consider array destructuring: `for [left, right] in <[_]>::array_windows(vec)` + +error: using `slice::windows` with a constant size instead of `slice::array_windows` + --> tests/ui/const_size_windows/with_array_windows_impl.rs:95:24 + | +LL | for pair in (&vec).windows(2) { + | -------^^^^^^^^^^ + | | + | help: use: `<[_]>::array_windows::<2>(&vec)` + | + = note: you may also consider array destructuring: `for [left, right] in <[_]>::array_windows(&vec)` + +error: using `slice::windows` with a constant size instead of `slice::array_windows` + --> tests/ui/const_size_windows/with_array_windows_impl.rs:105:41 + | +LL | for pair in (*derefs_into_vec_stub).windows(2) { + | ------------------------^^^^^^^^^^ + | | + | help: use: `<[_]>::array_windows::<2>(&derefs_into_vec_stub)` + | + = note: you may also consider array destructuring: `for [left, right] in <[_]>::array_windows(&derefs_into_vec_stub)` + +error: using `slice::windows` with a constant size instead of `slice::array_windows` + --> tests/ui/const_size_windows/with_array_windows_impl.rs:115:38 + | +LL | for pair in derefs_into_vec_stub.windows(2) { + | ---------------------^^^^^^^^^^ + | | + | help: use: `<[_]>::array_windows::<2>(&derefs_into_vec_stub)` + | + = note: you may also consider array destructuring: `for [left, right] in <[_]>::array_windows(&derefs_into_vec_stub)` + +error: using `slice::windows` with a constant size instead of `slice::array_windows` + --> tests/ui/const_size_windows/with_array_windows_impl.rs:127:21 + | +LL | for pair in vec.windows(2) { + | ^^^^^^^^^^ help: use: `array_windows::<2>()` + | + = note: you may also consider array destructuring: `for [left, right] in vec.array_windows()` + +error: using `slice::windows` with a constant size instead of `slice::array_windows` + --> tests/ui/const_size_windows/with_array_windows_impl.rs:151:56 + | +LL | for pair in double_borrowed_vec![Stub, Stub, Stub].windows(2) { + | ---------------------------------------^^^^^^^^^^ + | | + | help: use: `<[_]>::array_windows::<2>(double_borrowed_vec![Stub, Stub, Stub])` + | + = note: you may also consider array destructuring: `for [left, right] in <[_]>::array_windows(double_borrowed_vec![Stub, Stub, Stub])` + +error: aborting due to 11 previous errors + diff --git a/tests/ui/const_size_windows/with_windows_impl.fixed b/tests/ui/const_size_windows/with_windows_impl.fixed new file mode 100644 index 000000000000..8c42fdad0577 --- /dev/null +++ b/tests/ui/const_size_windows/with_windows_impl.fixed @@ -0,0 +1,110 @@ +#![warn(clippy::const_size_windows)] + +trait DefinesWindows { + fn windows(&self, size: usize) -> impl Iterator { + std::iter::repeat_n('🪟', size) + } +} + +#[derive(Debug)] +struct WindowsStub; + +impl DefinesWindows for Vec {} + +mod array_methods_mod { + trait InnerDefinesWindows { + fn windows(&self, size: usize) -> impl Iterator { + std::iter::repeat_n('🪟', size) + } + } + #[derive(Debug)] + pub struct WindowsStub; + impl InnerDefinesWindows for Vec {} +} + +use array_methods_mod::WindowsStub as ModWindowsStub; + +fn windows_implemented_by_public_trait(vec: Vec) { + for window in vec.array_windows::<2>() { + //~^ const_size_windows + let window: &[ModWindowsStub] = window; + println!("{:#?} {:#?}", window[0], window[1]); + } +} + +fn windows_implemented_by_trait_in_mod(vec: Vec) { + for window in vec.array_windows::<2>() { + //~^ const_size_windows + let window: &[ModWindowsStub] = window; + println!("{:#?} {:#?}", window[0], window[1]); + } +} + +fn windows_implemented_by_nested_trait() { + #[derive(Debug)] + struct Stub; + trait DefinesWindows { + fn windows(&self, size: usize) -> impl Iterator { + std::iter::repeat_n('🪟', size) + } + } + + impl DefinesWindows for Vec {} + + let vec = vec![Stub, Stub, Stub]; + for emoji in vec.windows(2) { + let emoji: char = emoji; + println!("{emoji:#?}"); + } +} + +fn windows_implemented_by_public_trait_with_macro() { + for emoji in vec![WindowsStub, WindowsStub, WindowsStub].windows(2) { + let emoji: char = emoji; + println!("{emoji:#?}"); + } +} + +fn windows_implemented_by_trait_borrowed(vec: &Vec) { + for emoji in vec.windows(2) { + let emoji: char = emoji; + println!("{emoji:#?}"); + } +} + +fn windows_implemented_by_trait_dereferenced(vec: &Vec) { + for emoji in (*vec).windows(2) { + let emoji: char = emoji; + println!("{emoji:#?}"); + } +} + +fn windows_implemented_by_trait_with_ref() { + #[derive(Debug)] + struct Stub; + impl DefinesWindows for &Vec {} + + let vec = vec![Stub, Stub, Stub]; + for emoji in (&vec).windows(2) { + let emoji: char = emoji; + println!("{emoji:#?}"); + } +} + +fn windows_implemented_by_trait_with_deref(derefs_into_windows_impl: impl std::ops::Deref>) { + for emoji in (*derefs_into_windows_impl).windows(2) { + let emoji: char = emoji; + println!("{emoji:#?}"); + } +} + +fn windows_implemented_by_trait_with_deref_coercion( + derefs_into_windows_impl: impl std::ops::Deref>, +) { + for emoji in derefs_into_windows_impl.windows(2) { + let emoji: char = emoji; + println!("{emoji:#?}"); + } +} + +fn main() {} diff --git a/tests/ui/const_size_windows/with_windows_impl.rs b/tests/ui/const_size_windows/with_windows_impl.rs new file mode 100644 index 000000000000..f2fab33c5b51 --- /dev/null +++ b/tests/ui/const_size_windows/with_windows_impl.rs @@ -0,0 +1,110 @@ +#![warn(clippy::const_size_windows)] + +trait DefinesWindows { + fn windows(&self, size: usize) -> impl Iterator { + std::iter::repeat_n('🪟', size) + } +} + +#[derive(Debug)] +struct WindowsStub; + +impl DefinesWindows for Vec {} + +mod array_methods_mod { + trait InnerDefinesWindows { + fn windows(&self, size: usize) -> impl Iterator { + std::iter::repeat_n('🪟', size) + } + } + #[derive(Debug)] + pub struct WindowsStub; + impl InnerDefinesWindows for Vec {} +} + +use array_methods_mod::WindowsStub as ModWindowsStub; + +fn windows_implemented_by_public_trait(vec: Vec) { + for window in vec.windows(2) { + //~^ const_size_windows + let window: &[ModWindowsStub] = window; + println!("{:#?} {:#?}", window[0], window[1]); + } +} + +fn windows_implemented_by_trait_in_mod(vec: Vec) { + for window in vec.windows(2) { + //~^ const_size_windows + let window: &[ModWindowsStub] = window; + println!("{:#?} {:#?}", window[0], window[1]); + } +} + +fn windows_implemented_by_nested_trait() { + #[derive(Debug)] + struct Stub; + trait DefinesWindows { + fn windows(&self, size: usize) -> impl Iterator { + std::iter::repeat_n('🪟', size) + } + } + + impl DefinesWindows for Vec {} + + let vec = vec![Stub, Stub, Stub]; + for emoji in vec.windows(2) { + let emoji: char = emoji; + println!("{emoji:#?}"); + } +} + +fn windows_implemented_by_public_trait_with_macro() { + for emoji in vec![WindowsStub, WindowsStub, WindowsStub].windows(2) { + let emoji: char = emoji; + println!("{emoji:#?}"); + } +} + +fn windows_implemented_by_trait_borrowed(vec: &Vec) { + for emoji in vec.windows(2) { + let emoji: char = emoji; + println!("{emoji:#?}"); + } +} + +fn windows_implemented_by_trait_dereferenced(vec: &Vec) { + for emoji in (*vec).windows(2) { + let emoji: char = emoji; + println!("{emoji:#?}"); + } +} + +fn windows_implemented_by_trait_with_ref() { + #[derive(Debug)] + struct Stub; + impl DefinesWindows for &Vec {} + + let vec = vec![Stub, Stub, Stub]; + for emoji in (&vec).windows(2) { + let emoji: char = emoji; + println!("{emoji:#?}"); + } +} + +fn windows_implemented_by_trait_with_deref(derefs_into_windows_impl: impl std::ops::Deref>) { + for emoji in (*derefs_into_windows_impl).windows(2) { + let emoji: char = emoji; + println!("{emoji:#?}"); + } +} + +fn windows_implemented_by_trait_with_deref_coercion( + derefs_into_windows_impl: impl std::ops::Deref>, +) { + for emoji in derefs_into_windows_impl.windows(2) { + let emoji: char = emoji; + println!("{emoji:#?}"); + } +} + +fn main() {} diff --git a/tests/ui/const_size_windows/with_windows_impl.stderr b/tests/ui/const_size_windows/with_windows_impl.stderr new file mode 100644 index 000000000000..35dd6f8f0baf --- /dev/null +++ b/tests/ui/const_size_windows/with_windows_impl.stderr @@ -0,0 +1,20 @@ +error: using `slice::windows` with a constant size instead of `slice::array_windows` + --> tests/ui/const_size_windows/with_windows_impl.rs:28:23 + | +LL | for window in vec.windows(2) { + | ^^^^^^^^^^ help: use: `array_windows::<2>()` + | + = note: you may also consider array destructuring: `for [left, right] in vec.array_windows()` + = note: `-D clippy::const-size-windows` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::const_size_windows)]` + +error: using `slice::windows` with a constant size instead of `slice::array_windows` + --> tests/ui/const_size_windows/with_windows_impl.rs:36:23 + | +LL | for window in vec.windows(2) { + | ^^^^^^^^^^ help: use: `array_windows::<2>()` + | + = note: you may also consider array destructuring: `for [left, right] in vec.array_windows()` + +error: aborting due to 2 previous errors + diff --git a/tests/ui/missing_asserts_for_indexing_unfixable.rs b/tests/ui/missing_asserts_for_indexing_unfixable.rs index b8cdb71bd30a..fbfe97588f07 100644 --- a/tests/ui/missing_asserts_for_indexing_unfixable.rs +++ b/tests/ui/missing_asserts_for_indexing_unfixable.rs @@ -1,4 +1,5 @@ #![warn(clippy::missing_asserts_for_indexing)] +#![allow(clippy::const_size_windows)] fn sum(v: &[u8]) -> u8 { v[0] + v[1] + v[2] + v[3] + v[4] diff --git a/tests/ui/missing_asserts_for_indexing_unfixable.stderr b/tests/ui/missing_asserts_for_indexing_unfixable.stderr index fe929aa36dba..2929646494a4 100644 --- a/tests/ui/missing_asserts_for_indexing_unfixable.stderr +++ b/tests/ui/missing_asserts_for_indexing_unfixable.stderr @@ -1,5 +1,5 @@ error: indexing into a slice multiple times without an `assert` - --> tests/ui/missing_asserts_for_indexing_unfixable.rs:4:5 + --> tests/ui/missing_asserts_for_indexing_unfixable.rs:5:5 | LL | v[0] + v[1] + v[2] + v[3] + v[4] | ^^^^ ^^^^ ^^^^ ^^^^ ^^^^ @@ -10,7 +10,7 @@ LL | v[0] + v[1] + v[2] + v[3] + v[4] = help: to override `-D warnings` add `#[allow(clippy::missing_asserts_for_indexing)]` error: indexing into a slice multiple times without an `assert` - --> tests/ui/missing_asserts_for_indexing_unfixable.rs:9:13 + --> tests/ui/missing_asserts_for_indexing_unfixable.rs:10:13 | LL | let _ = v[0]; | ^^^^ @@ -21,7 +21,7 @@ LL | let _ = v[1..4]; = help: consider asserting the length before indexing: `assert!(v.len() > 3);` error: indexing into a slice multiple times without an `assert` - --> tests/ui/missing_asserts_for_indexing_unfixable.rs:16:13 + --> tests/ui/missing_asserts_for_indexing_unfixable.rs:17:13 | LL | let a = v[0]; | ^^^^ @@ -34,7 +34,7 @@ LL | let c = v[2]; = help: consider asserting the length before indexing: `assert!(v.len() > 2);` error: indexing into a slice multiple times without an `assert` - --> tests/ui/missing_asserts_for_indexing_unfixable.rs:25:13 + --> tests/ui/missing_asserts_for_indexing_unfixable.rs:26:13 | LL | let _ = v1[0] + v1[12]; | ^^^^^ ^^^^^^ @@ -42,7 +42,7 @@ LL | let _ = v1[0] + v1[12]; = help: consider asserting the length before indexing: `assert!(v1.len() > 12);` error: indexing into a slice multiple times without an `assert` - --> tests/ui/missing_asserts_for_indexing_unfixable.rs:27:13 + --> tests/ui/missing_asserts_for_indexing_unfixable.rs:28:13 | LL | let _ = v2[5] + v2[15]; | ^^^^^ ^^^^^^ @@ -50,7 +50,7 @@ LL | let _ = v2[5] + v2[15]; = help: consider asserting the length before indexing: `assert!(v2.len() > 15);` error: indexing into a slice multiple times without an `assert` - --> tests/ui/missing_asserts_for_indexing_unfixable.rs:34:13 + --> tests/ui/missing_asserts_for_indexing_unfixable.rs:35:13 | LL | let _ = v2[5] + v2[15]; | ^^^^^ ^^^^^^ @@ -58,7 +58,7 @@ LL | let _ = v2[5] + v2[15]; = help: consider asserting the length before indexing: `assert!(v2.len() > 15);` error: indexing into a slice multiple times without an `assert` - --> tests/ui/missing_asserts_for_indexing_unfixable.rs:44:13 + --> tests/ui/missing_asserts_for_indexing_unfixable.rs:45:13 | LL | let _ = f.v[0] + f.v[1]; | ^^^^^^ ^^^^^^ @@ -66,7 +66,7 @@ LL | let _ = f.v[0] + f.v[1]; = help: consider asserting the length before indexing: `assert!(f.v.len() > 1);` error: indexing into a slice multiple times without an `assert` - --> tests/ui/missing_asserts_for_indexing_unfixable.rs:58:13 + --> tests/ui/missing_asserts_for_indexing_unfixable.rs:59:13 | LL | let _ = x[0] + x[1]; | ^^^^ ^^^^ @@ -74,7 +74,7 @@ LL | let _ = x[0] + x[1]; = help: consider asserting the length before indexing: `assert!(x.len() > 1);` error: indexing into a slice multiple times without an `assert` - --> tests/ui/missing_asserts_for_indexing_unfixable.rs:76:13 + --> tests/ui/missing_asserts_for_indexing_unfixable.rs:77:13 | LL | let _ = v1[1] + v1[2]; | ^^^^^ ^^^^^ @@ -82,7 +82,7 @@ LL | let _ = v1[1] + v1[2]; = help: consider asserting the length before indexing: `assert!(v1.len() > 2);` error: indexing into a slice multiple times without an `assert` - --> tests/ui/missing_asserts_for_indexing_unfixable.rs:84:13 + --> tests/ui/missing_asserts_for_indexing_unfixable.rs:85:13 | LL | let _ = v1[0] + v1[1] + v1[2]; | ^^^^^ ^^^^^ ^^^^^ diff --git a/tests/ui/while_let_on_iterator.fixed b/tests/ui/while_let_on_iterator.fixed index 0d3b446af43f..6cdfc8b74b7b 100644 --- a/tests/ui/while_let_on_iterator.fixed +++ b/tests/ui/while_let_on_iterator.fixed @@ -7,7 +7,8 @@ clippy::redundant_closure_call, clippy::single_range_in_vec_init, clippy::uninlined_format_args, - clippy::useless_vec + clippy::useless_vec, + clippy::const_size_windows )] fn base() { diff --git a/tests/ui/while_let_on_iterator.rs b/tests/ui/while_let_on_iterator.rs index e1d9e9081e45..384d9ae55b4f 100644 --- a/tests/ui/while_let_on_iterator.rs +++ b/tests/ui/while_let_on_iterator.rs @@ -7,7 +7,8 @@ clippy::redundant_closure_call, clippy::single_range_in_vec_init, clippy::uninlined_format_args, - clippy::useless_vec + clippy::useless_vec, + clippy::const_size_windows )] fn base() { diff --git a/tests/ui/while_let_on_iterator.stderr b/tests/ui/while_let_on_iterator.stderr index cd43d3c17800..50b155a021f2 100644 --- a/tests/ui/while_let_on_iterator.stderr +++ b/tests/ui/while_let_on_iterator.stderr @@ -1,5 +1,5 @@ error: this loop could be written as a `for` loop - --> tests/ui/while_let_on_iterator.rs:15:5 + --> tests/ui/while_let_on_iterator.rs:16:5 | LL | while let Option::Some(x) = iter.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in iter` @@ -8,193 +8,193 @@ LL | while let Option::Some(x) = iter.next() { = help: to override `-D warnings` add `#[allow(clippy::while_let_on_iterator)]` error: this loop could be written as a `for` loop - --> tests/ui/while_let_on_iterator.rs:21:5 + --> tests/ui/while_let_on_iterator.rs:22:5 | LL | while let Some(x) = iter.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in iter` error: this loop could be written as a `for` loop - --> tests/ui/while_let_on_iterator.rs:27:5 + --> tests/ui/while_let_on_iterator.rs:28:5 | LL | while let Some(_) = iter.next() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for _ in iter` error: this loop could be written as a `for` loop - --> tests/ui/while_let_on_iterator.rs:104:9 + --> tests/ui/while_let_on_iterator.rs:105:9 | LL | while let Some([..]) = it.next() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for [..] in it` error: this loop could be written as a `for` loop - --> tests/ui/while_let_on_iterator.rs:112:9 + --> tests/ui/while_let_on_iterator.rs:113:9 | LL | while let Some([_x]) = it.next() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for [_x] in it` error: this loop could be written as a `for` loop - --> tests/ui/while_let_on_iterator.rs:126:9 + --> tests/ui/while_let_on_iterator.rs:127:9 | LL | while let Some(x @ [_]) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x @ [_] in it` error: this loop could be written as a `for` loop - --> tests/ui/while_let_on_iterator.rs:147:9 + --> tests/ui/while_let_on_iterator.rs:148:9 | LL | while let Some(_) = y.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for _ in y` error: this loop could be written as a `for` loop - --> tests/ui/while_let_on_iterator.rs:205:9 + --> tests/ui/while_let_on_iterator.rs:206:9 | LL | while let Some(m) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for m in it.by_ref()` error: this loop could be written as a `for` loop - --> tests/ui/while_let_on_iterator.rs:217:5 + --> tests/ui/while_let_on_iterator.rs:218:5 | LL | while let Some(n) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for n in it` error: this loop could be written as a `for` loop - --> tests/ui/while_let_on_iterator.rs:220:9 + --> tests/ui/while_let_on_iterator.rs:221:9 | LL | while let Some(m) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for m in it` error: this loop could be written as a `for` loop - --> tests/ui/while_let_on_iterator.rs:230:9 + --> tests/ui/while_let_on_iterator.rs:231:9 | LL | while let Some(m) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for m in it` error: this loop could be written as a `for` loop - --> tests/ui/while_let_on_iterator.rs:240:9 + --> tests/ui/while_let_on_iterator.rs:241:9 | LL | while let Some(m) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for m in it.by_ref()` error: this loop could be written as a `for` loop - --> tests/ui/while_let_on_iterator.rs:258:9 + --> tests/ui/while_let_on_iterator.rs:259:9 | LL | while let Some(m) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for m in it.by_ref()` error: this loop could be written as a `for` loop - --> tests/ui/while_let_on_iterator.rs:274:13 + --> tests/ui/while_let_on_iterator.rs:275:13 | LL | while let Some(i) = self.0.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for i in self.0.by_ref()` error: this loop could be written as a `for` loop - --> tests/ui/while_let_on_iterator.rs:307:13 + --> tests/ui/while_let_on_iterator.rs:308:13 | LL | while let Some(i) = self.0.0.0.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for i in self.0.0.0.by_ref()` error: this loop could be written as a `for` loop - --> tests/ui/while_let_on_iterator.rs:337:5 + --> tests/ui/while_let_on_iterator.rs:338:5 | LL | while let Some(n) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for n in it.by_ref()` error: this loop could be written as a `for` loop - --> tests/ui/while_let_on_iterator.rs:350:9 + --> tests/ui/while_let_on_iterator.rs:351:9 | LL | while let Some(x) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in it.by_ref()` error: this loop could be written as a `for` loop - --> tests/ui/while_let_on_iterator.rs:365:5 + --> tests/ui/while_let_on_iterator.rs:366:5 | LL | while let Some(x) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in it.by_ref()` error: this loop could be written as a `for` loop - --> tests/ui/while_let_on_iterator.rs:377:5 + --> tests/ui/while_let_on_iterator.rs:378:5 | LL | while let Some(x) = it.0.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in it.0.by_ref()` error: this loop could be written as a `for` loop - --> tests/ui/while_let_on_iterator.rs:413:5 + --> tests/ui/while_let_on_iterator.rs:414:5 | LL | while let Some(x) = s.x.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in s.x.by_ref()` error: this loop could be written as a `for` loop - --> tests/ui/while_let_on_iterator.rs:421:5 + --> tests/ui/while_let_on_iterator.rs:422:5 | LL | while let Some(x) = x[0].next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in x[0].by_ref()` error: this loop could be written as a `for` loop - --> tests/ui/while_let_on_iterator.rs:430:9 + --> tests/ui/while_let_on_iterator.rs:431:9 | LL | while let Some(x) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in it.by_ref()` error: this loop could be written as a `for` loop - --> tests/ui/while_let_on_iterator.rs:441:9 + --> tests/ui/while_let_on_iterator.rs:442:9 | LL | while let Some(x) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in it` error: this loop could be written as a `for` loop - --> tests/ui/while_let_on_iterator.rs:452:9 + --> tests/ui/while_let_on_iterator.rs:453:9 | LL | while let Some(x) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in it.by_ref()` error: this loop could be written as a `for` loop - --> tests/ui/while_let_on_iterator.rs:463:9 + --> tests/ui/while_let_on_iterator.rs:464:9 | LL | while let Some(x) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in it` error: this loop could be written as a `for` loop - --> tests/ui/while_let_on_iterator.rs:476:9 + --> tests/ui/while_let_on_iterator.rs:477:9 | LL | while let Some(x) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in it` error: this loop could be written as a `for` loop - --> tests/ui/while_let_on_iterator.rs:487:5 + --> tests/ui/while_let_on_iterator.rs:488:5 | LL | 'label: while let Some(n) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `'label: for n in it` error: this loop could be written as a `for` loop - --> tests/ui/while_let_on_iterator.rs:499:13 + --> tests/ui/while_let_on_iterator.rs:500:13 | LL | while let Some(r) = self.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for r in &mut *self` error: this loop could be written as a `for` loop - --> tests/ui/while_let_on_iterator.rs:515:13 + --> tests/ui/while_let_on_iterator.rs:516:13 | LL | while let Some(r) = self.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for r in self.by_ref()` error: this loop could be written as a `for` loop - --> tests/ui/while_let_on_iterator.rs:541:9 + --> tests/ui/while_let_on_iterator.rs:542:9 | LL | while let Some(_) = x.next() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for _ in &mut ***x` error: this loop could be written as a `for` loop - --> tests/ui/while_let_on_iterator.rs:563:9 + --> tests/ui/while_let_on_iterator.rs:564:9 | LL | while let Some(_) = x.next() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for _ in &mut **x` error: this loop could be written as a `for` loop - --> tests/ui/while_let_on_iterator.rs:594:9 + --> tests/ui/while_let_on_iterator.rs:595:9 | LL | while let Some(_) = x.next() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for _ in x.by_ref()` error: this loop could be written as a `for` loop - --> tests/ui/while_let_on_iterator.rs:601:5 + --> tests/ui/while_let_on_iterator.rs:602:5 | LL | while let Some(..) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for _ in it`