From 8ec8389fe42c0df711f3f297c9497c506fabb9cb Mon Sep 17 00:00:00 2001 From: laffed Date: Thu, 16 Apr 2026 14:01:01 -0500 Subject: [PATCH 01/77] fix(unnecessary_sort_by): use first closure param name in reverse sort suggestion MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When suggesting `sort_by_key` for a reversed comparator like `|a, b| b.foo.cmp(&a.foo)`, the lint was picking `left_expr` (the receiver of `.cmp()`, which references `b`) and `r_pat` as the closure arg, producing `|b| Reverse(b.foo)`. Both sides consistently named `b`, but `b` is the second parameter — confusing and inconsistent with the forward-sort suggestion style. Fix by using `right_expr` (the `.cmp()` argument, which references `a`) as the key body and `l_pat` as the closure parameter, peeling the single `&` that `.cmp(&rhs)` introduces so the suggestion doesn't contain a spurious borrow. --- clippy_lints/src/methods/unnecessary_sort_by.rs | 10 +++++++++- tests/ui/unnecessary_sort_by.fixed | 8 ++++---- tests/ui/unnecessary_sort_by.stderr | 8 ++++---- tests/ui/unnecessary_sort_by_no_std.fixed | 4 ++-- tests/ui/unnecessary_sort_by_no_std.rs | 2 +- tests/ui/unnecessary_sort_by_no_std.stderr | 2 +- 6 files changed, 21 insertions(+), 13 deletions(-) diff --git a/clippy_lints/src/methods/unnecessary_sort_by.rs b/clippy_lints/src/methods/unnecessary_sort_by.rs index 3f81a6ecd2f8c..c8cfcaaa5aaee 100644 --- a/clippy_lints/src/methods/unnecessary_sort_by.rs +++ b/clippy_lints/src/methods/unnecessary_sort_by.rs @@ -257,7 +257,15 @@ fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>) -> Option< if mirrored_exprs(left_expr, right_expr, &binding_map, BindingSource::Left) { (left_expr, l_pat.span, false) } else if mirrored_exprs(left_expr, right_expr, &binding_map, BindingSource::Right) { - (left_expr, r_pat.span, true) + // Use the right-hand expr (the `a` side) as the key body, peeling any `&` + // introduced by the `.cmp(&rhs)` call so the suggestion doesn't contain a + // spurious borrow. + let right_body = if let ExprKind::AddrOf(_, _, inner) = right_expr.kind { + inner + } else { + right_expr + }; + (right_body, l_pat.span, true) } else { return None; }; diff --git a/tests/ui/unnecessary_sort_by.fixed b/tests/ui/unnecessary_sort_by.fixed index 317140eacc785..db31b339a08b0 100644 --- a/tests/ui/unnecessary_sort_by.fixed +++ b/tests/ui/unnecessary_sort_by.fixed @@ -19,9 +19,9 @@ fn unnecessary_sort_by() { //~^ unnecessary_sort_by // Reverse examples vec.sort_by(|a, b| b.cmp(a)); // not linted to avoid suggesting `Reverse(b)` which would borrow - vec.sort_by_key(|b| std::cmp::Reverse((b + 5).abs())); + vec.sort_by_key(|a| std::cmp::Reverse((a + 5).abs())); //~^ unnecessary_sort_by - vec.sort_unstable_by_key(|b| std::cmp::Reverse(id(-b))); + vec.sort_unstable_by_key(|a| std::cmp::Reverse(id(-a))); //~^ unnecessary_sort_by // Negative examples (shouldn't be changed) let c = &7; @@ -99,9 +99,9 @@ mod issue_6001 { args.sort_unstable_by_key(|a| a.name()); //~^ unnecessary_sort_by // Reverse - args.sort_by_key(|b| std::cmp::Reverse(b.name())); + args.sort_by_key(|a| std::cmp::Reverse(a.name())); //~^ unnecessary_sort_by - args.sort_unstable_by_key(|b| std::cmp::Reverse(b.name())); + args.sort_unstable_by_key(|a| std::cmp::Reverse(a.name())); //~^ unnecessary_sort_by } } diff --git a/tests/ui/unnecessary_sort_by.stderr b/tests/ui/unnecessary_sort_by.stderr index 56d4831eb70aa..868f7895fc069 100644 --- a/tests/ui/unnecessary_sort_by.stderr +++ b/tests/ui/unnecessary_sort_by.stderr @@ -57,7 +57,7 @@ LL | vec.sort_by(|a, b| (b + 5).abs().cmp(&(a + 5).abs())); help: try | LL - vec.sort_by(|a, b| (b + 5).abs().cmp(&(a + 5).abs())); -LL + vec.sort_by_key(|b| std::cmp::Reverse((b + 5).abs())); +LL + vec.sort_by_key(|a| std::cmp::Reverse((a + 5).abs())); | error: consider using `sort_unstable_by_key` @@ -69,7 +69,7 @@ LL | vec.sort_unstable_by(|a, b| id(-b).cmp(&id(-a))); help: try | LL - vec.sort_unstable_by(|a, b| id(-b).cmp(&id(-a))); -LL + vec.sort_unstable_by_key(|b| std::cmp::Reverse(id(-b))); +LL + vec.sort_unstable_by_key(|a| std::cmp::Reverse(id(-a))); | error: consider using `sort_by_key` @@ -129,7 +129,7 @@ LL | args.sort_by(|a, b| b.name().cmp(&a.name())); help: try | LL - args.sort_by(|a, b| b.name().cmp(&a.name())); -LL + args.sort_by_key(|b| std::cmp::Reverse(b.name())); +LL + args.sort_by_key(|a| std::cmp::Reverse(a.name())); | error: consider using `sort_unstable_by_key` @@ -141,7 +141,7 @@ LL | args.sort_unstable_by(|a, b| b.name().cmp(&a.name())); help: try | LL - args.sort_unstable_by(|a, b| b.name().cmp(&a.name())); -LL + args.sort_unstable_by_key(|b| std::cmp::Reverse(b.name())); +LL + args.sort_unstable_by_key(|a| std::cmp::Reverse(a.name())); | error: consider using `sort_by_key` diff --git a/tests/ui/unnecessary_sort_by_no_std.fixed b/tests/ui/unnecessary_sort_by_no_std.fixed index 40e6aecd1b6d0..6fd740d87757a 100644 --- a/tests/ui/unnecessary_sort_by_no_std.fixed +++ b/tests/ui/unnecessary_sort_by_no_std.fixed @@ -15,8 +15,8 @@ fn issue_11524() -> Vec { fn issue_11524_2() -> Vec { let mut vec = vec![1, 2, 3]; - // Should lint and suggest `vec.sort_by_key(|b| core::cmp::Reverse(b + 1));` - vec.sort_by_key(|b| core::cmp::Reverse(b + 1)); + // Should lint and suggest `vec.sort_by_key(|a| core::cmp::Reverse(a + 1));` + vec.sort_by_key(|a| core::cmp::Reverse(a + 1)); //~^ unnecessary_sort_by vec } diff --git a/tests/ui/unnecessary_sort_by_no_std.rs b/tests/ui/unnecessary_sort_by_no_std.rs index 184c90d959eb5..266553e7ace6b 100644 --- a/tests/ui/unnecessary_sort_by_no_std.rs +++ b/tests/ui/unnecessary_sort_by_no_std.rs @@ -15,7 +15,7 @@ fn issue_11524() -> Vec { fn issue_11524_2() -> Vec { let mut vec = vec![1, 2, 3]; - // Should lint and suggest `vec.sort_by_key(|b| core::cmp::Reverse(b + 1));` + // Should lint and suggest `vec.sort_by_key(|a| core::cmp::Reverse(a + 1));` vec.sort_by(|a, b| (b + 1).cmp(&(a + 1))); //~^ unnecessary_sort_by vec diff --git a/tests/ui/unnecessary_sort_by_no_std.stderr b/tests/ui/unnecessary_sort_by_no_std.stderr index b4dd6a6dbdc52..26a8ad38fcd32 100644 --- a/tests/ui/unnecessary_sort_by_no_std.stderr +++ b/tests/ui/unnecessary_sort_by_no_std.stderr @@ -21,7 +21,7 @@ LL | vec.sort_by(|a, b| (b + 1).cmp(&(a + 1))); help: try | LL - vec.sort_by(|a, b| (b + 1).cmp(&(a + 1))); -LL + vec.sort_by_key(|b| core::cmp::Reverse(b + 1)); +LL + vec.sort_by_key(|a| core::cmp::Reverse(a + 1)); | error: aborting due to 2 previous errors From f6a921c1bd028fa3c463f5bd1ce4b069286c7d7c Mon Sep 17 00:00:00 2001 From: Gri-ffin Date: Tue, 28 Apr 2026 20:46:35 +0100 Subject: [PATCH 02/77] fix: [manual_slice_fill] detect for in loops over &mut [T; n] slices --- clippy_lints/src/loops/manual_slice_fill.rs | 19 ++++++++++ tests/ui/manual_slice_fill.fixed | 32 ++++++++++++++++ tests/ui/manual_slice_fill.rs | 41 +++++++++++++++++++++ tests/ui/manual_slice_fill.stderr | 29 ++++++++++++++- 4 files changed, 120 insertions(+), 1 deletion(-) diff --git a/clippy_lints/src/loops/manual_slice_fill.rs b/clippy_lints/src/loops/manual_slice_fill.rs index ffc6f7186922a..ceaf681088399 100644 --- a/clippy_lints/src/loops/manual_slice_fill.rs +++ b/clippy_lints/src/loops/manual_slice_fill.rs @@ -13,6 +13,7 @@ use rustc_hir::QPath::Resolved; use rustc_hir::def::Res; use rustc_hir::{Expr, ExprKind, Pat}; use rustc_lint::LateContext; +use rustc_middle::ty; use rustc_span::{Spanned, sym}; use super::MANUAL_SLICE_FILL; @@ -84,6 +85,24 @@ pub(super) fn check<'tcx>( { sugg(cx, body, expr, recv_path.span, assignval.span); } + // `for slot in s { *slot = value; }` where `s` is already `&mut [T; N]` + else if let ExprKind::Assign(assignee, assignval, _) = peel_blocks_with_stmt(body).kind + && let ExprKind::Unary(UnOp::Deref, slice_iter) = assignee.kind + && let ExprKind::Path(Resolved(_, slice_path)) = slice_iter.kind + && let Res::Local(local) = slice_path.res + && local == pat.hir_id + && !assignval.span.from_expansion() + && switch_to_eager_eval(cx, assignval) + && !is_local_used(cx, assignval, local) + && let arg_ty = cx.typeck_results().expr_ty(arg) + && let ty::Ref(_, inner_ty, rustc_ast::Mutability::Mut) = arg_ty.kind() + && is_slice_like(cx, *inner_ty) + && let Some(clone_trait) = cx.tcx.lang_items().clone_trait() + && implements_trait(cx, *inner_ty, clone_trait, &[]) + && msrv.meets(cx, msrvs::SLICE_FILL) + { + sugg(cx, body, expr, arg.span, assignval.span); + } } fn sugg<'tcx>( diff --git a/tests/ui/manual_slice_fill.fixed b/tests/ui/manual_slice_fill.fixed index d07d1d60e2c16..15e8e57655701 100644 --- a/tests/ui/manual_slice_fill.fixed +++ b/tests/ui/manual_slice_fill.fixed @@ -34,6 +34,38 @@ fn should_lint() { some_slice.fill(0); } +fn should_lint_direct_mutref_array(s: &mut [u8; 1]) { + s.fill(0); +} + +fn should_lint_direct_mutref_array_non_zero(s: &mut [u8; 4]) { + s.fill(42); +} + +fn should_lint_direct_mutref_array_variable(s: &mut [i32; 3]) { + let x = 7; + s.fill(x); +} + +fn should_not_lint_direct_mutref_array_fn(s: &mut [usize; 2]) { + for slot in s { + *slot = num(); + } +} + +fn should_not_lint_direct_mutref_array_iter_used(s: &mut [u8; 3]) { + for slot in s { + *slot = !*slot; + } +} + +fn should_not_lint_direct_mutref_array_extra_stmt(s: &mut [u8; 2]) { + for slot in s { + *slot = 0; + println!("foo"); + } +} + fn should_not_lint() { let mut some_slice = [1, 2, 3, 4, 5]; diff --git a/tests/ui/manual_slice_fill.rs b/tests/ui/manual_slice_fill.rs index c74ab2225c0a4..ce5f9f0e8afac 100644 --- a/tests/ui/manual_slice_fill.rs +++ b/tests/ui/manual_slice_fill.rs @@ -47,6 +47,47 @@ fn should_lint() { } } +fn should_lint_direct_mutref_array(s: &mut [u8; 1]) { + for slot in s { + //~^ manual_slice_fill + *slot = 0; + } +} + +fn should_lint_direct_mutref_array_non_zero(s: &mut [u8; 4]) { + for slot in s { + //~^ manual_slice_fill + *slot = 42; + } +} + +fn should_lint_direct_mutref_array_variable(s: &mut [i32; 3]) { + let x = 7; + for slot in s { + //~^ manual_slice_fill + *slot = x; + } +} + +fn should_not_lint_direct_mutref_array_fn(s: &mut [usize; 2]) { + for slot in s { + *slot = num(); + } +} + +fn should_not_lint_direct_mutref_array_iter_used(s: &mut [u8; 3]) { + for slot in s { + *slot = !*slot; + } +} + +fn should_not_lint_direct_mutref_array_extra_stmt(s: &mut [u8; 2]) { + for slot in s { + *slot = 0; + println!("foo"); + } +} + fn should_not_lint() { let mut some_slice = [1, 2, 3, 4, 5]; diff --git a/tests/ui/manual_slice_fill.stderr b/tests/ui/manual_slice_fill.stderr index 38e43d5b4e06e..cd1f36f4291f8 100644 --- a/tests/ui/manual_slice_fill.stderr +++ b/tests/ui/manual_slice_fill.stderr @@ -38,5 +38,32 @@ LL | | // foo LL | | } | |_____^ help: try: `some_slice.fill(0);` -error: aborting due to 4 previous errors +error: manually filling a slice + --> tests/ui/manual_slice_fill.rs:51:5 + | +LL | / for slot in s { +LL | | +LL | | *slot = 0; +LL | | } + | |_____^ help: try: `s.fill(0);` + +error: manually filling a slice + --> tests/ui/manual_slice_fill.rs:58:5 + | +LL | / for slot in s { +LL | | +LL | | *slot = 42; +LL | | } + | |_____^ help: try: `s.fill(42);` + +error: manually filling a slice + --> tests/ui/manual_slice_fill.rs:66:5 + | +LL | / for slot in s { +LL | | +LL | | *slot = x; +LL | | } + | |_____^ help: try: `s.fill(x);` + +error: aborting due to 7 previous errors From a259d0a96fc7cdd57b3b8b5090eb46a2a0cc9ec7 Mon Sep 17 00:00:00 2001 From: Daniel Scherzer Date: Tue, 28 Apr 2026 14:05:24 -0700 Subject: [PATCH 03/77] absolute_paths.rs: change item in "What it does" example The choice of `std::env::current_dir` made me originally think this was about file and directory paths - use an item where "path" couldn't mean something else. `std::f64::consts::PI` was chosen to match the example. --- clippy_lints/src/absolute_paths.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/absolute_paths.rs b/clippy_lints/src/absolute_paths.rs index fd515939dfb8e..cf2059eecc079 100644 --- a/clippy_lints/src/absolute_paths.rs +++ b/clippy_lints/src/absolute_paths.rs @@ -12,7 +12,7 @@ use rustc_span::symbol::kw; declare_clippy_lint! { /// ### What it does - /// Checks for usage of items through absolute paths, like `std::env::current_dir`. + /// Checks for usage of items through absolute paths, like `std::f64::consts::PI`. /// /// ### Why restrict this? /// Many codebases have their own style when it comes to importing, but one that is seldom used From 9fc79b23006308b1568bb8743623189f7e0764e8 Mon Sep 17 00:00:00 2001 From: cyphercodes Date: Wed, 29 Apr 2026 02:05:32 +0300 Subject: [PATCH 04/77] Avoid map_unwrap_or fix when default is adjusted --- clippy_lints/src/methods/map_unwrap_or.rs | 9 +++++---- tests/ui/map_unwrap_or.rs | 7 +++++++ tests/ui/map_unwrap_or.stderr | 8 +++++++- 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/clippy_lints/src/methods/map_unwrap_or.rs b/clippy_lints/src/methods/map_unwrap_or.rs index ac2f991804865..a12687c63736c 100644 --- a/clippy_lints/src/methods/map_unwrap_or.rs +++ b/clippy_lints/src/methods/map_unwrap_or.rs @@ -35,6 +35,7 @@ pub(super) fn check<'tcx>( }; let unwrap_arg_ty = cx.typeck_results().expr_ty(unwrap_arg); + let unwrap_arg_ty_adjusted = cx.typeck_results().expr_ty_adjusted(unwrap_arg); if !is_copy(cx, unwrap_arg_ty) { // Replacing `.map().unwrap_or()` with `.map_or(, )` can sometimes lead to // borrowck errors, see #10579 for one such instance. @@ -128,10 +129,10 @@ pub(super) fn check<'tcx>( (SuggestedKind::AndThen, _) => "and_then", (SuggestedKind::IsVariantAnd, sym::Result) => "is_ok_and", (SuggestedKind::IsVariantAnd, sym::Option) => "is_some_and", - (SuggestedKind::Other, _) - if unwrap_arg_ty.peel_refs().is_array() - && cx.typeck_results().expr_ty_adjusted(unwrap_arg).peel_refs().is_slice() => - { + (SuggestedKind::Other, _) if unwrap_arg_ty != unwrap_arg_ty_adjusted => { + // If the `unwrap_or` argument needs an adjustment, moving it into `map_or`'s + // first argument can make type inference pick the unadjusted type and reject + // the closure return type. Keep the lint, but don't emit a rustfix. return; }, _ => "map_or", diff --git a/tests/ui/map_unwrap_or.rs b/tests/ui/map_unwrap_or.rs index 37470a50cfbef..c63e4bd2285a0 100644 --- a/tests/ui/map_unwrap_or.rs +++ b/tests/ui/map_unwrap_or.rs @@ -161,3 +161,10 @@ fn issue15752() { x.map(|y| y.0).unwrap_or(&[]); //~^ map_unwrap_or } + +fn issue16901() { + let raw = String::from("scope:value"); + let after_scope = raw.split_once(':').map(|(_, v)| v).unwrap_or(&raw); + //~^ map_unwrap_or + let _: &str = after_scope; +} diff --git a/tests/ui/map_unwrap_or.stderr b/tests/ui/map_unwrap_or.stderr index a90da4a97e0c8..cd62c17848583 100644 --- a/tests/ui/map_unwrap_or.stderr +++ b/tests/ui/map_unwrap_or.stderr @@ -238,5 +238,11 @@ error: called `map().unwrap_or()` on an `Option` value LL | x.map(|y| y.0).unwrap_or(&[]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 16 previous errors +error: called `map().unwrap_or()` on an `Option` value + --> tests/ui/map_unwrap_or.rs:167:23 + | +LL | let after_scope = raw.split_once(':').map(|(_, v)| v).unwrap_or(&raw); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 17 previous errors From fbb403696e9b5c25e545bdfdf3cbb4e13e076cab Mon Sep 17 00:00:00 2001 From: rommeld <138243859+rommeld@users.noreply.github.com> Date: Sat, 1 Nov 2025 12:00:47 +0100 Subject: [PATCH 05/77] Add new `chunks_exact_to_as_chunks` lint This lint suggests using `as_chunks` or `as_chunks_mut` instead of `chunks_exact` or `chunks_exact_mut` when called with a constant size. changelog: new lint: [`chunks_exact_to_as_chunks`] --- CHANGELOG.md | 1 + clippy_lints/src/declared_lints.rs | 1 + .../src/methods/chunks_exact_to_as_chunks.rs | 108 ++++++++++++++++++ clippy_lints/src/methods/mod.rs | 31 +++++ clippy_utils/src/msrvs.rs | 2 +- clippy_utils/src/sym.rs | 2 + tests/ui/chunks_exact_to_as_chunks.rs | 34 ++++++ tests/ui/chunks_exact_to_as_chunks.stderr | 56 +++++++++ 8 files changed, 234 insertions(+), 1 deletion(-) create mode 100644 clippy_lints/src/methods/chunks_exact_to_as_chunks.rs create mode 100644 tests/ui/chunks_exact_to_as_chunks.rs create mode 100644 tests/ui/chunks_exact_to_as_chunks.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index 24b91932567a5..01a9b87943b77 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6600,6 +6600,7 @@ Released 2018-09-13 [`chars_last_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#chars_last_cmp [`chars_next_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#chars_next_cmp [`checked_conversions`]: https://rust-lang.github.io/rust-clippy/master/index.html#checked_conversions +[`chunks_exact_to_as_chunks`]: https://rust-lang.github.io/rust-clippy/master/index.html#chunks_exact_to_as_chunks [`clear_with_drain`]: https://rust-lang.github.io/rust-clippy/master/index.html#clear_with_drain [`clone_double_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#clone_double_ref [`clone_on_copy`]: https://rust-lang.github.io/rust-clippy/master/index.html#clone_on_copy diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 79ed199147f1d..468c015e6f99e 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -364,6 +364,7 @@ pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[ crate::methods::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS_INFO, crate::methods::CHARS_LAST_CMP_INFO, crate::methods::CHARS_NEXT_CMP_INFO, + crate::methods::CHUNKS_EXACT_TO_AS_CHUNKS_INFO, crate::methods::CLEAR_WITH_DRAIN_INFO, crate::methods::CLONE_ON_COPY_INFO, crate::methods::CLONE_ON_REF_PTR_INFO, diff --git a/clippy_lints/src/methods/chunks_exact_to_as_chunks.rs b/clippy_lints/src/methods/chunks_exact_to_as_chunks.rs new file mode 100644 index 0000000000000..af50cf455ed96 --- /dev/null +++ b/clippy_lints/src/methods/chunks_exact_to_as_chunks.rs @@ -0,0 +1,108 @@ +use super::CHUNKS_EXACT_TO_AS_CHUNKS; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::msrvs::{self, Msrv}; +use clippy_utils::res::{MaybeDef, MaybeTypeckRes}; +use clippy_utils::source::snippet_with_context; +use clippy_utils::visitors::is_const_evaluatable; +use clippy_utils::{get_expr_use_site, sym}; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind, Node, PatKind}; +use rustc_lint::LateContext; +use rustc_middle::ty; +use rustc_span::{DesugaringKind, ExpnKind, Span, Symbol}; + +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + recv: &'tcx Expr<'tcx>, + arg: &'tcx Expr<'tcx>, + expr: &'tcx Expr<'tcx>, + call_span: Span, + method_name: Symbol, + msrv: Msrv, +) { + let recv_ty = cx.typeck_results().expr_ty_adjusted(recv); + if !matches!(recv_ty.kind(), ty::Ref(_, inner, _) if inner.is_slice()) { + return; + } + + if is_const_evaluatable(cx, arg) { + if !msrv.meets(cx, msrvs::AS_CHUNKS) { + return; + } + + let suggestion_method = if method_name == sym::chunks_exact_mut { + "as_chunks_mut" + } else { + "as_chunks" + }; + + let mut applicability = Applicability::MachineApplicable; + let arg_str = snippet_with_context(cx, arg.span, expr.span.ctxt(), "_", &mut applicability).0; + + let as_chunks = format_args!("{suggestion_method}::<{arg_str}>()"); + + span_lint_and_then( + cx, + CHUNKS_EXACT_TO_AS_CHUNKS, + call_span, + format!("using `{method_name}` with a constant chunk size"), + |diag| { + let use_ctxt = get_expr_use_site(cx.tcx, cx.typeck_results(), expr.span.ctxt(), expr); + + if use_ctxt.is_ty_unified { + diag.span_help(call_span, format!("consider using `{as_chunks}` instead")); + return; + } + + if let Node::Expr(use_expr) = use_ctxt.node { + match use_expr.kind { + ExprKind::Call(_, [recv]) | ExprKind::MethodCall(_, recv, [], _) + if recv.hir_id == use_ctxt.child_id + && matches!( + use_expr.span.ctxt().outer_expn_data().kind, + ExpnKind::Desugaring(DesugaringKind::ForLoop), + ) => + { + // Suggest `.0` + diag.span_suggestion( + call_span, + "consider using `as_chunks` instead", + format!("{as_chunks}.0"), + applicability, + ); + return; + }, + ExprKind::MethodCall(_, recv, ..) + if recv.hir_id == use_ctxt.child_id + && cx + .ty_based_def(use_expr) + .assoc_fn_parent(cx) + .is_diag_item(cx, sym::Iterator) => + { + // Suggest `.0.iter()` + diag.span_suggestion( + call_span, + "consider using `as_chunks` instead", + format!("{as_chunks}.0.iter()"), + applicability, + ); + return; + }, + _ => {}, + } + } + + // Fallback suggestion + diag.span_help(call_span, format!("consider using `{as_chunks}` instead")); + + if let Node::LetStmt(let_stmt) = use_ctxt.node + && let PatKind::Binding(_, _, ident, _) = let_stmt.pat.kind + { + diag.note(format!( + "you can access the chunks using `{ident}.0.iter()`, and the remainder using `{ident}.1`" + )); + } + }, + ); + } +} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 3dc5767438ae7..1dcb611953310 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -9,6 +9,7 @@ mod chars_last_cmp; mod chars_last_cmp_with_unwrap; mod chars_next_cmp; mod chars_next_cmp_with_unwrap; +mod chunks_exact_to_as_chunks; mod clear_with_drain; mod clone_on_copy; mod clone_on_ref_ptr; @@ -327,6 +328,32 @@ declare_clippy_lint! { "using `.chars().next()` to check if a string starts with a char" } +declare_clippy_lint! { + /// ### What it does + /// Checks for usage of `chunks_exact` or `chunks_exact_mut` with a constant chunk size. + /// + /// ### Why is this bad? + /// `as_chunks` provides better ergonomics and type safety by returning arrays instead of slices. + /// It was stabilized in Rust 1.88. + /// + /// ### Example + /// ```no_run + /// let slice = [1, 2, 3, 4, 5, 6]; + /// let mut it = slice.chunks_exact(2); + /// for chunk in it {} + /// ``` + /// Use instead: + /// ```no_run + /// let slice = [1, 2, 3, 4, 5, 6]; + /// let (chunks, remainder) = slice.as_chunks::<2>(); + /// for chunk in chunks {} + /// ``` + #[clippy::version = "1.93.0"] + pub CHUNKS_EXACT_TO_AS_CHUNKS, + style, + "using `chunks_exact` with constant when `as_chunks` is more ergonomic" +} + declare_clippy_lint! { /// ### What it does /// Checks for usage of `.drain(..)` for the sole purpose of clearing a container. @@ -4790,6 +4817,7 @@ impl_lint_pass!(Methods => [ CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS, CHARS_LAST_CMP, CHARS_NEXT_CMP, + CHUNKS_EXACT_TO_AS_CHUNKS, CLEAR_WITH_DRAIN, CLONED_INSTEAD_OF_COPIED, CLONE_ON_COPY, @@ -5148,6 +5176,9 @@ impl Methods { _ => {}, } }, + (name @ (sym::chunks_exact | sym::chunks_exact_mut), [arg]) => { + chunks_exact_to_as_chunks::check(cx, recv, arg, expr, call_span, name, self.msrv); + }, (sym::and_then, [arg]) => { manual_option_zip::check(cx, expr, recv, arg, self.msrv); let biom_option_linted = bind_instead_of_map::check_and_then_some(cx, expr, recv, arg); diff --git a/clippy_utils/src/msrvs.rs b/clippy_utils/src/msrvs.rs index a56e729c70bbb..b7cec1ddb6f15 100644 --- a/clippy_utils/src/msrvs.rs +++ b/clippy_utils/src/msrvs.rs @@ -25,7 +25,7 @@ macro_rules! msrv_aliases { msrv_aliases! { 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 } + 1,88,0 { LET_CHAINS, AS_CHUNKS } 1,87,0 { OS_STR_DISPLAY, INT_MIDPOINT, CONST_CHAR_IS_DIGIT, UNSIGNED_IS_MULTIPLE_OF, INTEGER_SIGN_CAST } 1,86,0 { VEC_POP_IF } 1,85,0 { UINT_FLOAT_MIDPOINT, CONST_SIZE_OF_VAL, WAKER_NOOP } diff --git a/clippy_utils/src/sym.rs b/clippy_utils/src/sym.rs index 4eaeafe127078..f58df7db65839 100644 --- a/clippy_utils/src/sym.rs +++ b/clippy_utils/src/sym.rs @@ -174,6 +174,8 @@ generate! { checked_sub, child_id, child_kill, + chunks_exact, + chunks_exact_mut, clamp, clippy_utils, clone_into, diff --git a/tests/ui/chunks_exact_to_as_chunks.rs b/tests/ui/chunks_exact_to_as_chunks.rs new file mode 100644 index 0000000000000..a1422437ccccb --- /dev/null +++ b/tests/ui/chunks_exact_to_as_chunks.rs @@ -0,0 +1,34 @@ +#![warn(clippy::chunks_exact_to_as_chunks)] +#![allow(unused)] + +fn main() { + let slice = [1, 2, 3, 4, 5, 6, 7, 8]; + + // Should trigger lint - literal constant + let mut it = slice.chunks_exact(4); + //~^ ERROR: using `chunks_exact` with a constant chunk size + for chunk in it {} + + // Should trigger lint - const value + const CHUNK_SIZE: usize = 4; + let mut it = slice.chunks_exact(CHUNK_SIZE); + //~^ ERROR: using `chunks_exact` with a constant chunk size + for chunk in it {} + + // Should NOT trigger - runtime value + let size = 4; + let mut it = slice.chunks_exact(size); + for chunk in it {} + + // Should trigger lint - with remainder + let mut it = slice.chunks_exact(3); + //~^ ERROR: using `chunks_exact` with a constant chunk size + for chunk in &mut it {} + for e in it.remainder() {} + + // Should trigger - mutable variant + let mut arr = [1, 2, 3, 4, 5, 6, 7, 8]; + let mut it = arr.chunks_exact_mut(4); + //~^ ERROR: using `chunks_exact_mut` with a constant chunk size + for chunk in it {} +} diff --git a/tests/ui/chunks_exact_to_as_chunks.stderr b/tests/ui/chunks_exact_to_as_chunks.stderr new file mode 100644 index 0000000000000..628752f9bae71 --- /dev/null +++ b/tests/ui/chunks_exact_to_as_chunks.stderr @@ -0,0 +1,56 @@ +error: using `chunks_exact` with a constant chunk size + --> tests/ui/chunks_exact_to_as_chunks.rs:8:24 + | +LL | let mut it = slice.chunks_exact(4); + | ^^^^^^^^^^^^^^^ + | +help: consider using `as_chunks::<4>()` instead + --> tests/ui/chunks_exact_to_as_chunks.rs:8:24 + | +LL | let mut it = slice.chunks_exact(4); + | ^^^^^^^^^^^^^^^ + = note: you can access the chunks using `it.0.iter()`, and the remainder using `it.1` + = note: `-D clippy::chunks-exact-to-as-chunks` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::chunks_exact_to_as_chunks)]` + +error: using `chunks_exact` with a constant chunk size + --> tests/ui/chunks_exact_to_as_chunks.rs:14:24 + | +LL | let mut it = slice.chunks_exact(CHUNK_SIZE); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `as_chunks::()` instead + --> tests/ui/chunks_exact_to_as_chunks.rs:14:24 + | +LL | let mut it = slice.chunks_exact(CHUNK_SIZE); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + = note: you can access the chunks using `it.0.iter()`, and the remainder using `it.1` + +error: using `chunks_exact` with a constant chunk size + --> tests/ui/chunks_exact_to_as_chunks.rs:24:24 + | +LL | let mut it = slice.chunks_exact(3); + | ^^^^^^^^^^^^^^^ + | +help: consider using `as_chunks::<3>()` instead + --> tests/ui/chunks_exact_to_as_chunks.rs:24:24 + | +LL | let mut it = slice.chunks_exact(3); + | ^^^^^^^^^^^^^^^ + = note: you can access the chunks using `it.0.iter()`, and the remainder using `it.1` + +error: using `chunks_exact_mut` with a constant chunk size + --> tests/ui/chunks_exact_to_as_chunks.rs:31:22 + | +LL | let mut it = arr.chunks_exact_mut(4); + | ^^^^^^^^^^^^^^^^^^^ + | +help: consider using `as_chunks_mut::<4>()` instead + --> tests/ui/chunks_exact_to_as_chunks.rs:31:22 + | +LL | let mut it = arr.chunks_exact_mut(4); + | ^^^^^^^^^^^^^^^^^^^ + = note: you can access the chunks using `it.0.iter()`, and the remainder using `it.1` + +error: aborting due to 4 previous errors + From 871036832a1c03b5054c8c98365d95afbb52758c Mon Sep 17 00:00:00 2001 From: rommeld Date: Mon, 12 Jan 2026 20:20:56 +0100 Subject: [PATCH 06/77] add skip lint when is_ty_unified is true. update test comments --- .../src/methods/chunks_exact_to_as_chunks.rs | 12 ++++-------- tests/ui/chunks_exact_to_as_chunks.rs | 17 +++++++++++++---- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/clippy_lints/src/methods/chunks_exact_to_as_chunks.rs b/clippy_lints/src/methods/chunks_exact_to_as_chunks.rs index af50cf455ed96..dc6b50e4f8132 100644 --- a/clippy_lints/src/methods/chunks_exact_to_as_chunks.rs +++ b/clippy_lints/src/methods/chunks_exact_to_as_chunks.rs @@ -30,6 +30,10 @@ pub(super) fn check<'tcx>( return; } + if expr_use_ctxt(cx, expr).is_ty_unified { + return; + } + let suggestion_method = if method_name == sym::chunks_exact_mut { "as_chunks_mut" } else { @@ -49,11 +53,6 @@ pub(super) fn check<'tcx>( |diag| { let use_ctxt = get_expr_use_site(cx.tcx, cx.typeck_results(), expr.span.ctxt(), expr); - if use_ctxt.is_ty_unified { - diag.span_help(call_span, format!("consider using `{as_chunks}` instead")); - return; - } - if let Node::Expr(use_expr) = use_ctxt.node { match use_expr.kind { ExprKind::Call(_, [recv]) | ExprKind::MethodCall(_, recv, [], _) @@ -63,7 +62,6 @@ pub(super) fn check<'tcx>( ExpnKind::Desugaring(DesugaringKind::ForLoop), ) => { - // Suggest `.0` diag.span_suggestion( call_span, "consider using `as_chunks` instead", @@ -79,7 +77,6 @@ pub(super) fn check<'tcx>( .assoc_fn_parent(cx) .is_diag_item(cx, sym::Iterator) => { - // Suggest `.0.iter()` diag.span_suggestion( call_span, "consider using `as_chunks` instead", @@ -92,7 +89,6 @@ pub(super) fn check<'tcx>( } } - // Fallback suggestion diag.span_help(call_span, format!("consider using `{as_chunks}` instead")); if let Node::LetStmt(let_stmt) = use_ctxt.node diff --git a/tests/ui/chunks_exact_to_as_chunks.rs b/tests/ui/chunks_exact_to_as_chunks.rs index a1422437ccccb..0d5f4d06043d1 100644 --- a/tests/ui/chunks_exact_to_as_chunks.rs +++ b/tests/ui/chunks_exact_to_as_chunks.rs @@ -6,13 +6,13 @@ fn main() { // Should trigger lint - literal constant let mut it = slice.chunks_exact(4); - //~^ ERROR: using `chunks_exact` with a constant chunk size + //~^ chunks_exact_to_as_chunks for chunk in it {} // Should trigger lint - const value const CHUNK_SIZE: usize = 4; let mut it = slice.chunks_exact(CHUNK_SIZE); - //~^ ERROR: using `chunks_exact` with a constant chunk size + //~^ chunks_exact_to_as_chunks for chunk in it {} // Should NOT trigger - runtime value @@ -22,13 +22,22 @@ fn main() { // Should trigger lint - with remainder let mut it = slice.chunks_exact(3); - //~^ ERROR: using `chunks_exact` with a constant chunk size + //~^ chunks_exact_to_as_chunks for chunk in &mut it {} for e in it.remainder() {} // Should trigger - mutable variant let mut arr = [1, 2, 3, 4, 5, 6, 7, 8]; let mut it = arr.chunks_exact_mut(4); - //~^ ERROR: using `chunks_exact_mut` with a constant chunk size + //~^ chunks_exact_to_as_chunks for chunk in it {} + + // Should NOT trigger - type must unify with another branch + let condition = true; + let y = 3; + let _ = if condition { + slice.chunks_exact(5) + } else { + slice.chunks_exact(y) + }; } From 74ad9b63fd0ad1c7455a5fb15b55f06d16ced546 Mon Sep 17 00:00:00 2001 From: mtotbagi Date: Wed, 29 Apr 2026 13:57:53 +0200 Subject: [PATCH 07/77] remove multiple calls to expr_use_ctxt --- clippy_lints/src/methods/chunks_exact_to_as_chunks.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/methods/chunks_exact_to_as_chunks.rs b/clippy_lints/src/methods/chunks_exact_to_as_chunks.rs index dc6b50e4f8132..235df80e46985 100644 --- a/clippy_lints/src/methods/chunks_exact_to_as_chunks.rs +++ b/clippy_lints/src/methods/chunks_exact_to_as_chunks.rs @@ -30,7 +30,9 @@ pub(super) fn check<'tcx>( return; } - if expr_use_ctxt(cx, expr).is_ty_unified { + let use_ctxt = get_expr_use_site(cx.tcx, cx.typeck_results(), expr.span.ctxt(), expr); + + if use_ctxt.is_ty_unified { return; } @@ -51,8 +53,6 @@ pub(super) fn check<'tcx>( call_span, format!("using `{method_name}` with a constant chunk size"), |diag| { - let use_ctxt = get_expr_use_site(cx.tcx, cx.typeck_results(), expr.span.ctxt(), expr); - if let Node::Expr(use_expr) = use_ctxt.node { match use_expr.kind { ExprKind::Call(_, [recv]) | ExprKind::MethodCall(_, recv, [], _) From f0577192e3f874f18a68a6bc4d1d1febd1a72b3b Mon Sep 17 00:00:00 2001 From: ChrisJr404 Date: Tue, 12 May 2026 09:38:00 -0400 Subject: [PATCH 08/77] let_underscore_future: skip when type is annotated An explicit type annotation on the LHS (`let _: T = expr`) signals an intentional discard, mirroring the rationale for `let_underscore_untyped`. Without this gate, typed bindings such as `let _: Pin>> = foo();` trigger the lint despite the author explicitly opting in. changelog: [`let_underscore_future`]: no longer triggers when the binding has an explicit type annotation Signed-off-by: ChrisJr404 --- clippy_lints/src/let_underscore.rs | 3 ++- tests/ui/let_underscore_future.rs | 8 ++++++++ tests/ui/let_underscore_future.stderr | 6 +++--- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/clippy_lints/src/let_underscore.rs b/clippy_lints/src/let_underscore.rs index 984574c221fb6..3f8bd2223876f 100644 --- a/clippy_lints/src/let_underscore.rs +++ b/clippy_lints/src/let_underscore.rs @@ -162,7 +162,8 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { ); }, ); - } else if let Some(future_trait_def_id) = cx.tcx.lang_items().future_trait() + } else if local.ty.is_none() + && let Some(future_trait_def_id) = cx.tcx.lang_items().future_trait() && implements_trait(cx, cx.typeck_results().expr_ty(init), future_trait_def_id, &[]) { #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")] diff --git a/tests/ui/let_underscore_future.rs b/tests/ui/let_underscore_future.rs index eb1a985a91172..17c73876302dd 100644 --- a/tests/ui/let_underscore_future.rs +++ b/tests/ui/let_underscore_future.rs @@ -1,4 +1,5 @@ use std::future::Future; +use std::pin::Pin; async fn some_async_fn() {} @@ -10,6 +11,10 @@ fn custom() -> impl Future { fn do_something_to_future(future: &mut impl Future) {} +fn boxed() -> Pin>> { + Box::pin(async {}) +} + fn main() { let _ = some_async_fn(); //~^ let_underscore_future @@ -21,4 +26,7 @@ fn main() { do_something_to_future(&mut future); let _ = future; //~^ let_underscore_future + + // Typed bindings are an intentional discard, see also `let_underscore_untyped`. + let _: Pin>> = boxed(); } diff --git a/tests/ui/let_underscore_future.stderr b/tests/ui/let_underscore_future.stderr index baa489551d4a3..12cbfff133e9c 100644 --- a/tests/ui/let_underscore_future.stderr +++ b/tests/ui/let_underscore_future.stderr @@ -1,5 +1,5 @@ error: non-binding `let` on a future - --> tests/ui/let_underscore_future.rs:14:5 + --> tests/ui/let_underscore_future.rs:19:5 | LL | let _ = some_async_fn(); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -9,7 +9,7 @@ LL | let _ = some_async_fn(); = help: to override `-D warnings` add `#[allow(clippy::let_underscore_future)]` error: non-binding `let` on a future - --> tests/ui/let_underscore_future.rs:17:5 + --> tests/ui/let_underscore_future.rs:22:5 | LL | let _ = custom(); | ^^^^^^^^^^^^^^^^^ @@ -17,7 +17,7 @@ LL | let _ = custom(); = help: consider awaiting the future or dropping explicitly with `std::mem::drop` error: non-binding `let` on a future - --> tests/ui/let_underscore_future.rs:22:5 + --> tests/ui/let_underscore_future.rs:27:5 | LL | let _ = future; | ^^^^^^^^^^^^^^^ From 029b8d2e4e68243acbf1cd0b27b8d36860761e90 Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Thu, 21 May 2026 19:06:48 +0200 Subject: [PATCH 09/77] Attributes cleanup in tests [12/20] --- tests/ui/methods.rs | 22 +------- tests/ui/methods.stderr | 6 +-- tests/ui/methods_fixable.fixed | 2 +- tests/ui/methods_fixable.rs | 2 +- tests/ui/min_ident_chars.rs | 4 +- tests/ui/min_max.rs | 3 +- tests/ui/min_max.stderr | 29 +++++------ tests/ui/min_rust_version_attr.rs | 1 - tests/ui/min_rust_version_attr.stderr | 12 ++--- tests/ui/mismatching_type_param_order.rs | 1 - tests/ui/mismatching_type_param_order.stderr | 20 ++++---- tests/ui/misnamed_getters.fixed | 3 +- tests/ui/misnamed_getters.rs | 3 +- tests/ui/misnamed_getters.stderr | 36 ++++++------- tests/ui/misnamed_getters_2021.fixed | 2 - tests/ui/misnamed_getters_2021.rs | 2 - tests/ui/misnamed_getters_2021.stderr | 2 +- tests/ui/misrefactored_assign_op.1.fixed | 3 +- tests/ui/misrefactored_assign_op.2.fixed | 3 +- tests/ui/misrefactored_assign_op.rs | 3 +- tests/ui/misrefactored_assign_op.stderr | 18 +++---- .../missing_asserts_for_indexing_unfixable.rs | 1 - ...sing_asserts_for_indexing_unfixable.stderr | 20 ++++---- .../missing_const_for_fn/could_be_const.fixed | 2 +- .../ui/missing_const_for_fn/could_be_const.rs | 2 +- tests/ui/missing_fields_in_debug.rs | 1 - tests/ui/missing_fields_in_debug.stderr | 16 +++--- tests/ui/missing_inline.rs | 2 +- tests/ui/missing_panics_doc.rs | 2 +- tests/ui/missing_spin_loop.fixed | 3 +- tests/ui/missing_spin_loop.rs | 3 +- tests/ui/missing_spin_loop.stderr | 12 ++--- tests/ui/missing_trait_methods.rs | 2 +- tests/ui/missing_transmute_annotations.fixed | 2 +- tests/ui/missing_transmute_annotations.rs | 2 +- tests/ui/mistyped_literal_suffix.fixed | 6 +-- tests/ui/mistyped_literal_suffix.rs | 6 +-- tests/ui/mistyped_literal_suffix.stderr | 35 ++++++------- tests/ui/module_name_repetitions.rs | 1 - tests/ui/module_name_repetitions.stderr | 12 ++--- tests/ui/modulo_arithmetic_float.rs | 2 +- tests/ui/modulo_arithmetic_integral.rs | 2 +- tests/ui/modulo_arithmetic_integral_const.rs | 7 +-- .../modulo_arithmetic_integral_const.stderr | 34 ++++++------- tests/ui/modulo_one.rs | 3 +- tests/ui/modulo_one.stderr | 12 ++--- .../ui/msrv_attributes_without_early_lints.rs | 1 - tests/ui/multiple_unsafe_ops_per_block.rs | 6 +-- tests/ui/must_use_candidates.fixed | 6 --- tests/ui/must_use_candidates.rs | 6 --- tests/ui/must_use_candidates.stderr | 14 +++--- tests/ui/must_use_unit.fixed | 2 +- tests/ui/must_use_unit.rs | 2 +- tests/ui/mut_from_ref.rs | 9 ++-- tests/ui/mut_from_ref.stderr | 32 ++++++------ tests/ui/mut_mut.fixed | 8 --- tests/ui/mut_mut.rs | 8 --- tests/ui/mut_mut.stderr | 14 +++--- tests/ui/mut_mut_unfixable.rs | 1 - tests/ui/mut_mut_unfixable.stderr | 12 ++--- tests/ui/mut_mutex_lock.fixed | 1 - tests/ui/mut_mutex_lock.rs | 1 - tests/ui/mut_mutex_lock.stderr | 4 +- tests/ui/mut_range_bound.rs | 2 +- tests/ui/mutex_atomic.fixed | 5 +- tests/ui/mutex_atomic.rs | 5 +- tests/ui/mutex_atomic.stderr | 30 +++++------ tests/ui/needless_arbitrary_self_type.fixed | 2 +- tests/ui/needless_arbitrary_self_type.rs | 2 +- tests/ui/needless_bitwise_bool.fixed | 2 +- tests/ui/needless_bitwise_bool.rs | 2 +- tests/ui/needless_bool/fixable.fixed | 14 +----- tests/ui/needless_bool/fixable.rs | 14 +----- tests/ui/needless_bool/fixable.stderr | 50 +++++++++---------- tests/ui/needless_bool/simple.rs | 9 +--- tests/ui/needless_bool/simple.stderr | 8 +-- tests/ui/needless_bool_assign.fixed | 1 - tests/ui/needless_bool_assign.rs | 1 - tests/ui/needless_bool_assign.stderr | 14 +++--- 79 files changed, 278 insertions(+), 377 deletions(-) diff --git a/tests/ui/methods.rs b/tests/ui/methods.rs index f73ec563dceb1..b45b7dcd56a43 100644 --- a/tests/ui/methods.rs +++ b/tests/ui/methods.rs @@ -1,25 +1,7 @@ //@aux-build:option_helpers.rs -#![allow( - clippy::disallowed_names, - clippy::default_trait_access, - clippy::let_underscore_untyped, - clippy::missing_docs_in_private_items, - clippy::missing_safety_doc, - clippy::non_ascii_literal, - clippy::new_without_default, - clippy::needless_pass_by_value, - clippy::needless_lifetimes, - clippy::elidable_lifetime_names, - clippy::print_stdout, - clippy::must_use_candidate, - clippy::use_self, - clippy::useless_format, - clippy::wrong_self_convention, - clippy::unused_async, - clippy::unused_self, - clippy::useless_vec -)] +#![warn(clippy::filter_next, clippy::new_ret_no_self)] +#![expect(clippy::disallowed_names, clippy::useless_vec)] #[macro_use] extern crate option_helpers; diff --git a/tests/ui/methods.stderr b/tests/ui/methods.stderr index 45efea4ee01cd..a637818cee48c 100644 --- a/tests/ui/methods.stderr +++ b/tests/ui/methods.stderr @@ -1,5 +1,5 @@ error: methods called `new` usually return `Self` - --> tests/ui/methods.rs:102:5 + --> tests/ui/methods.rs:84:5 | LL | / fn new() -> i32 { LL | | @@ -11,7 +11,7 @@ LL | | } = help: to override `-D warnings` add `#[allow(clippy::new_ret_no_self)]` error: called `filter(..).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(..)` instead - --> tests/ui/methods.rs:124:13 + --> tests/ui/methods.rs:106:13 | LL | let _ = v.iter().filter(|&x| { | _____________^ @@ -25,7 +25,7 @@ LL | | ).next(); = help: to override `-D warnings` add `#[allow(clippy::filter_next)]` error: called `filter(..).next_back()` on an `DoubleEndedIterator`. This is more succinctly expressed by calling `.rfind(..)` instead - --> tests/ui/methods.rs:143:13 + --> tests/ui/methods.rs:125:13 | LL | let _ = v.iter().filter(|&x| { | _____________^ diff --git a/tests/ui/methods_fixable.fixed b/tests/ui/methods_fixable.fixed index 287d8d881ec28..17a751eb79457 100644 --- a/tests/ui/methods_fixable.fixed +++ b/tests/ui/methods_fixable.fixed @@ -1,5 +1,5 @@ #![warn(clippy::filter_next)] -#![allow(clippy::useless_vec)] +#![expect(clippy::useless_vec)] /// Checks implementation of `FILTER_NEXT` lint. fn main() { diff --git a/tests/ui/methods_fixable.rs b/tests/ui/methods_fixable.rs index 11ce1b63560db..b2520acc36385 100644 --- a/tests/ui/methods_fixable.rs +++ b/tests/ui/methods_fixable.rs @@ -1,5 +1,5 @@ #![warn(clippy::filter_next)] -#![allow(clippy::useless_vec)] +#![expect(clippy::useless_vec)] /// Checks implementation of `FILTER_NEXT` lint. fn main() { diff --git a/tests/ui/min_ident_chars.rs b/tests/ui/min_ident_chars.rs index e2f82e2a182f6..298798be7a1e6 100644 --- a/tests/ui/min_ident_chars.rs +++ b/tests/ui/min_ident_chars.rs @@ -1,7 +1,7 @@ //@aux-build:proc_macros.rs -#![allow(irrefutable_let_patterns, nonstandard_style, unused)] -#![allow(clippy::struct_field_names)] #![warn(clippy::min_ident_chars)] +#![expect(irrefutable_let_patterns, nonstandard_style)] +#![allow(clippy::struct_field_names)] extern crate proc_macros; use proc_macros::{external, with_span}; diff --git a/tests/ui/min_max.rs b/tests/ui/min_max.rs index ee19d3ff71421..cc97e496514bc 100644 --- a/tests/ui/min_max.rs +++ b/tests/ui/min_max.rs @@ -1,4 +1,5 @@ -#![allow(clippy::manual_clamp)] +#![warn(clippy::min_max)] +#![expect(clippy::manual_clamp)] use std::cmp::{max as my_max, max, min as my_min, min}; diff --git a/tests/ui/min_max.stderr b/tests/ui/min_max.stderr index 87510a465a08b..84b4d37545529 100644 --- a/tests/ui/min_max.stderr +++ b/tests/ui/min_max.stderr @@ -1,79 +1,80 @@ error: this `min`/`max` combination leads to constant result - --> tests/ui/min_max.rs:21:5 + --> tests/ui/min_max.rs:22:5 | LL | min(1, max(3, x)); | ^^^^^^^^^^^^^^^^^ | - = note: `#[deny(clippy::min_max)]` on by default + = note: `-D clippy::min-max` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::min_max)]` error: this `min`/`max` combination leads to constant result - --> tests/ui/min_max.rs:24:5 + --> tests/ui/min_max.rs:25:5 | LL | min(max(3, x), 1); | ^^^^^^^^^^^^^^^^^ error: this `min`/`max` combination leads to constant result - --> tests/ui/min_max.rs:27:5 + --> tests/ui/min_max.rs:28:5 | LL | max(min(x, 1), 3); | ^^^^^^^^^^^^^^^^^ error: this `min`/`max` combination leads to constant result - --> tests/ui/min_max.rs:30:5 + --> tests/ui/min_max.rs:31:5 | LL | max(3, min(x, 1)); | ^^^^^^^^^^^^^^^^^ error: this `min`/`max` combination leads to constant result - --> tests/ui/min_max.rs:33:5 + --> tests/ui/min_max.rs:34:5 | LL | my_max(3, my_min(x, 1)); | ^^^^^^^^^^^^^^^^^^^^^^^ error: this `min`/`max` combination leads to constant result - --> tests/ui/min_max.rs:44:5 + --> tests/ui/min_max.rs:45:5 | LL | min("Apple", max("Zoo", s)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this `min`/`max` combination leads to constant result - --> tests/ui/min_max.rs:47:5 + --> tests/ui/min_max.rs:48:5 | LL | max(min(s, "Apple"), "Zoo"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this `min`/`max` combination leads to constant result - --> tests/ui/min_max.rs:53:5 + --> tests/ui/min_max.rs:54:5 | LL | x.min(1).max(3); | ^^^^^^^^^^^^^^^ error: this `min`/`max` combination leads to constant result - --> tests/ui/min_max.rs:56:5 + --> tests/ui/min_max.rs:57:5 | LL | x.max(3).min(1); | ^^^^^^^^^^^^^^^ error: this `min`/`max` combination leads to constant result - --> tests/ui/min_max.rs:59:5 + --> tests/ui/min_max.rs:60:5 | LL | f.max(3f32).min(1f32); | ^^^^^^^^^^^^^^^^^^^^^ error: this `min`/`max` combination leads to constant result - --> tests/ui/min_max.rs:66:5 + --> tests/ui/min_max.rs:67:5 | LL | max(x.min(1), 3); | ^^^^^^^^^^^^^^^^ error: this `min`/`max` combination leads to constant result - --> tests/ui/min_max.rs:71:5 + --> tests/ui/min_max.rs:72:5 | LL | s.max("Zoo").min("Apple"); | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: this `min`/`max` combination leads to constant result - --> tests/ui/min_max.rs:74:5 + --> tests/ui/min_max.rs:75:5 | LL | s.min("Apple").max("Zoo"); | ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/min_rust_version_attr.rs b/tests/ui/min_rust_version_attr.rs index 4627bef28a29b..c624774a8a9cf 100644 --- a/tests/ui/min_rust_version_attr.rs +++ b/tests/ui/min_rust_version_attr.rs @@ -1,4 +1,3 @@ -#![allow(clippy::redundant_clone)] #![feature(custom_inner_attributes)] fn main() {} diff --git a/tests/ui/min_rust_version_attr.stderr b/tests/ui/min_rust_version_attr.stderr index 809b1cfe73bf0..842bd5c238618 100644 --- a/tests/ui/min_rust_version_attr.stderr +++ b/tests/ui/min_rust_version_attr.stderr @@ -1,5 +1,5 @@ error: approximate value of `f{32, 64}::consts::LOG2_10` found - --> tests/ui/min_rust_version_attr.rs:13:19 + --> tests/ui/min_rust_version_attr.rs:12:19 | LL | let log2_10 = 3.321928094887362; | ^^^^^^^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | let log2_10 = 3.321928094887362; = note: `#[deny(clippy::approx_constant)]` on by default error: approximate value of `f{32, 64}::consts::LOG2_10` found - --> tests/ui/min_rust_version_attr.rs:19:19 + --> tests/ui/min_rust_version_attr.rs:18:19 | LL | let log2_10 = 3.321928094887362; | ^^^^^^^^^^^^^^^^^ @@ -16,7 +16,7 @@ LL | let log2_10 = 3.321928094887362; = help: consider using the constant directly error: approximate value of `f{32, 64}::consts::LOG2_10` found - --> tests/ui/min_rust_version_attr.rs:30:19 + --> tests/ui/min_rust_version_attr.rs:29:19 | LL | let log2_10 = 3.321928094887362; | ^^^^^^^^^^^^^^^^^ @@ -24,7 +24,7 @@ LL | let log2_10 = 3.321928094887362; = help: consider using the constant directly error: approximate value of `f{32, 64}::consts::LOG2_10` found - --> tests/ui/min_rust_version_attr.rs:41:19 + --> tests/ui/min_rust_version_attr.rs:40:19 | LL | let log2_10 = 3.321928094887362; | ^^^^^^^^^^^^^^^^^ @@ -32,7 +32,7 @@ LL | let log2_10 = 3.321928094887362; = help: consider using the constant directly error: approximate value of `f{32, 64}::consts::LOG2_10` found - --> tests/ui/min_rust_version_attr.rs:52:19 + --> tests/ui/min_rust_version_attr.rs:51:19 | LL | let log2_10 = 3.321928094887362; | ^^^^^^^^^^^^^^^^^ @@ -40,7 +40,7 @@ LL | let log2_10 = 3.321928094887362; = help: consider using the constant directly error: approximate value of `f{32, 64}::consts::LOG2_10` found - --> tests/ui/min_rust_version_attr.rs:60:27 + --> tests/ui/min_rust_version_attr.rs:59:27 | LL | let log2_10 = 3.321928094887362; | ^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/mismatching_type_param_order.rs b/tests/ui/mismatching_type_param_order.rs index 11ff865b583bf..49d7031441066 100644 --- a/tests/ui/mismatching_type_param_order.rs +++ b/tests/ui/mismatching_type_param_order.rs @@ -1,5 +1,4 @@ #![warn(clippy::mismatching_type_param_order)] -#![allow(clippy::disallowed_names, clippy::needless_lifetimes)] fn main() { struct Foo { diff --git a/tests/ui/mismatching_type_param_order.stderr b/tests/ui/mismatching_type_param_order.stderr index 214d9d734d1bb..a1b5ca7ec26c7 100644 --- a/tests/ui/mismatching_type_param_order.stderr +++ b/tests/ui/mismatching_type_param_order.stderr @@ -1,5 +1,5 @@ error: `Foo` has a similarly named generic type parameter `B` in its declaration, but in a different order - --> tests/ui/mismatching_type_param_order.rs:11:20 + --> tests/ui/mismatching_type_param_order.rs:10:20 | LL | impl Foo {} | ^ @@ -9,7 +9,7 @@ LL | impl Foo {} = help: to override `-D warnings` add `#[allow(clippy::mismatching_type_param_order)]` error: `Foo` has a similarly named generic type parameter `A` in its declaration, but in a different order - --> tests/ui/mismatching_type_param_order.rs:11:23 + --> tests/ui/mismatching_type_param_order.rs:10:23 | LL | impl Foo {} | ^ @@ -17,7 +17,7 @@ LL | impl Foo {} = help: try `B`, or a name that does not conflict with `Foo`'s generic params error: `Foo` has a similarly named generic type parameter `A` in its declaration, but in a different order - --> tests/ui/mismatching_type_param_order.rs:16:23 + --> tests/ui/mismatching_type_param_order.rs:15:23 | LL | impl Foo {} | ^ @@ -25,7 +25,7 @@ LL | impl Foo {} = help: try `B`, or a name that does not conflict with `Foo`'s generic params error: `FooLifetime` has a similarly named generic type parameter `B` in its declaration, but in a different order - --> tests/ui/mismatching_type_param_order.rs:28:44 + --> tests/ui/mismatching_type_param_order.rs:27:44 | LL | impl<'m, 'l, B, A> FooLifetime<'m, 'l, B, A> {} | ^ @@ -33,7 +33,7 @@ LL | impl<'m, 'l, B, A> FooLifetime<'m, 'l, B, A> {} = help: try `A`, or a name that does not conflict with `FooLifetime`'s generic params error: `FooLifetime` has a similarly named generic type parameter `A` in its declaration, but in a different order - --> tests/ui/mismatching_type_param_order.rs:28:47 + --> tests/ui/mismatching_type_param_order.rs:27:47 | LL | impl<'m, 'l, B, A> FooLifetime<'m, 'l, B, A> {} | ^ @@ -41,7 +41,7 @@ LL | impl<'m, 'l, B, A> FooLifetime<'m, 'l, B, A> {} = help: try `B`, or a name that does not conflict with `FooLifetime`'s generic params error: `FooEnum` has a similarly named generic type parameter `C` in its declaration, but in a different order - --> tests/ui/mismatching_type_param_order.rs:46:27 + --> tests/ui/mismatching_type_param_order.rs:45:27 | LL | impl FooEnum {} | ^ @@ -49,7 +49,7 @@ LL | impl FooEnum {} = help: try `A`, or a name that does not conflict with `FooEnum`'s generic params error: `FooEnum` has a similarly named generic type parameter `A` in its declaration, but in a different order - --> tests/ui/mismatching_type_param_order.rs:46:30 + --> tests/ui/mismatching_type_param_order.rs:45:30 | LL | impl FooEnum {} | ^ @@ -57,7 +57,7 @@ LL | impl FooEnum {} = help: try `B`, or a name that does not conflict with `FooEnum`'s generic params error: `FooEnum` has a similarly named generic type parameter `B` in its declaration, but in a different order - --> tests/ui/mismatching_type_param_order.rs:46:33 + --> tests/ui/mismatching_type_param_order.rs:45:33 | LL | impl FooEnum {} | ^ @@ -65,7 +65,7 @@ LL | impl FooEnum {} = help: try `C`, or a name that does not conflict with `FooEnum`'s generic params error: `FooUnion` has a similarly named generic type parameter `B` in its declaration, but in a different order - --> tests/ui/mismatching_type_param_order.rs:60:31 + --> tests/ui/mismatching_type_param_order.rs:59:31 | LL | impl FooUnion where A: Copy {} | ^ @@ -73,7 +73,7 @@ LL | impl FooUnion where A: Copy {} = help: try `A`, or a name that does not conflict with `FooUnion`'s generic params error: `FooUnion` has a similarly named generic type parameter `A` in its declaration, but in a different order - --> tests/ui/mismatching_type_param_order.rs:60:34 + --> tests/ui/mismatching_type_param_order.rs:59:34 | LL | impl FooUnion where A: Copy {} | ^ diff --git a/tests/ui/misnamed_getters.fixed b/tests/ui/misnamed_getters.fixed index bc123d1a40ba2..479d5f91492d5 100644 --- a/tests/ui/misnamed_getters.fixed +++ b/tests/ui/misnamed_getters.fixed @@ -1,6 +1,5 @@ -#![allow(unused)] -#![allow(clippy::struct_field_names)] #![warn(clippy::misnamed_getters)] +#![expect(clippy::struct_field_names)] struct A { a: u8, diff --git a/tests/ui/misnamed_getters.rs b/tests/ui/misnamed_getters.rs index 6590101157c3f..985c273c59ed7 100644 --- a/tests/ui/misnamed_getters.rs +++ b/tests/ui/misnamed_getters.rs @@ -1,6 +1,5 @@ -#![allow(unused)] -#![allow(clippy::struct_field_names)] #![warn(clippy::misnamed_getters)] +#![expect(clippy::struct_field_names)] struct A { a: u8, diff --git a/tests/ui/misnamed_getters.stderr b/tests/ui/misnamed_getters.stderr index aaf21cecb9255..37f57d7f79e55 100644 --- a/tests/ui/misnamed_getters.stderr +++ b/tests/ui/misnamed_getters.stderr @@ -1,5 +1,5 @@ error: getter function appears to return the wrong field - --> tests/ui/misnamed_getters.rs:12:5 + --> tests/ui/misnamed_getters.rs:11:5 | LL | / fn a(&self) -> &u8 { LL | | @@ -13,7 +13,7 @@ LL | | } = help: to override `-D warnings` add `#[allow(clippy::misnamed_getters)]` error: getter function appears to return the wrong field - --> tests/ui/misnamed_getters.rs:17:5 + --> tests/ui/misnamed_getters.rs:16:5 | LL | / fn a_mut(&mut self) -> &mut u8 { LL | | @@ -24,7 +24,7 @@ LL | | } | |_____^ error: getter function appears to return the wrong field - --> tests/ui/misnamed_getters.rs:23:5 + --> tests/ui/misnamed_getters.rs:22:5 | LL | / fn b(self) -> u8 { LL | | @@ -35,7 +35,7 @@ LL | | } | |_____^ error: getter function appears to return the wrong field - --> tests/ui/misnamed_getters.rs:29:5 + --> tests/ui/misnamed_getters.rs:28:5 | LL | / fn b_mut(&mut self) -> &mut u8 { LL | | @@ -46,7 +46,7 @@ LL | | } | |_____^ error: getter function appears to return the wrong field - --> tests/ui/misnamed_getters.rs:35:5 + --> tests/ui/misnamed_getters.rs:34:5 | LL | / fn c(&self) -> &u8 { LL | | @@ -57,7 +57,7 @@ LL | | } | |_____^ error: getter function appears to return the wrong field - --> tests/ui/misnamed_getters.rs:41:5 + --> tests/ui/misnamed_getters.rs:40:5 | LL | / fn c_mut(&mut self) -> &mut u8 { LL | | @@ -68,7 +68,7 @@ LL | | } | |_____^ error: getter function appears to return the wrong field - --> tests/ui/misnamed_getters.rs:54:5 + --> tests/ui/misnamed_getters.rs:53:5 | LL | / unsafe fn a(&self) -> &u8 { LL | | @@ -79,7 +79,7 @@ LL | | } | |_____^ error: getter function appears to return the wrong field - --> tests/ui/misnamed_getters.rs:59:5 + --> tests/ui/misnamed_getters.rs:58:5 | LL | / unsafe fn a_mut(&mut self) -> &mut u8 { LL | | @@ -90,7 +90,7 @@ LL | | } | |_____^ error: getter function appears to return the wrong field - --> tests/ui/misnamed_getters.rs:65:5 + --> tests/ui/misnamed_getters.rs:64:5 | LL | / unsafe fn b(self) -> u8 { LL | | @@ -101,7 +101,7 @@ LL | | } | |_____^ error: getter function appears to return the wrong field - --> tests/ui/misnamed_getters.rs:71:5 + --> tests/ui/misnamed_getters.rs:70:5 | LL | / unsafe fn b_mut(&mut self) -> &mut u8 { LL | | @@ -112,7 +112,7 @@ LL | | } | |_____^ error: getter function appears to return the wrong field - --> tests/ui/misnamed_getters.rs:85:5 + --> tests/ui/misnamed_getters.rs:84:5 | LL | / unsafe fn a_unchecked(&self) -> &u8 { LL | | @@ -123,7 +123,7 @@ LL | | } | |_____^ error: getter function appears to return the wrong field - --> tests/ui/misnamed_getters.rs:90:5 + --> tests/ui/misnamed_getters.rs:89:5 | LL | / unsafe fn a_unchecked_mut(&mut self) -> &mut u8 { LL | | @@ -134,7 +134,7 @@ LL | | } | |_____^ error: getter function appears to return the wrong field - --> tests/ui/misnamed_getters.rs:96:5 + --> tests/ui/misnamed_getters.rs:95:5 | LL | / unsafe fn b_unchecked(self) -> u8 { LL | | @@ -145,7 +145,7 @@ LL | | } | |_____^ error: getter function appears to return the wrong field - --> tests/ui/misnamed_getters.rs:102:5 + --> tests/ui/misnamed_getters.rs:101:5 | LL | / unsafe fn b_unchecked_mut(&mut self) -> &mut u8 { LL | | @@ -156,7 +156,7 @@ LL | | } | |_____^ error: getter function appears to return the wrong field - --> tests/ui/misnamed_getters.rs:136:5 + --> tests/ui/misnamed_getters.rs:135:5 | LL | / fn a(&self) -> &u8 { LL | | @@ -167,7 +167,7 @@ LL | | } | |_____^ error: getter function appears to return the wrong field - --> tests/ui/misnamed_getters.rs:141:5 + --> tests/ui/misnamed_getters.rs:140:5 | LL | / fn a_mut(&mut self) -> &mut u8 { LL | | @@ -178,7 +178,7 @@ LL | | } | |_____^ error: getter function appears to return the wrong field - --> tests/ui/misnamed_getters.rs:147:5 + --> tests/ui/misnamed_getters.rs:146:5 | LL | / fn d(&self) -> &u8 { LL | | @@ -189,7 +189,7 @@ LL | | } | |_____^ error: getter function appears to return the wrong field - --> tests/ui/misnamed_getters.rs:152:5 + --> tests/ui/misnamed_getters.rs:151:5 | LL | / fn d_mut(&mut self) -> &mut u8 { LL | | diff --git a/tests/ui/misnamed_getters_2021.fixed b/tests/ui/misnamed_getters_2021.fixed index 7112719a9f284..a923da1962fbe 100644 --- a/tests/ui/misnamed_getters_2021.fixed +++ b/tests/ui/misnamed_getters_2021.fixed @@ -1,6 +1,4 @@ //@edition: 2021 -#![allow(unused)] -#![allow(clippy::struct_field_names)] #![warn(clippy::misnamed_getters)] // Edition 2021 specific check, where `unsafe` blocks are not required diff --git a/tests/ui/misnamed_getters_2021.rs b/tests/ui/misnamed_getters_2021.rs index 19b5d086041f4..bdb011939da64 100644 --- a/tests/ui/misnamed_getters_2021.rs +++ b/tests/ui/misnamed_getters_2021.rs @@ -1,6 +1,4 @@ //@edition: 2021 -#![allow(unused)] -#![allow(clippy::struct_field_names)] #![warn(clippy::misnamed_getters)] // Edition 2021 specific check, where `unsafe` blocks are not required diff --git a/tests/ui/misnamed_getters_2021.stderr b/tests/ui/misnamed_getters_2021.stderr index 5495e2e3733f0..9771d2d8b119f 100644 --- a/tests/ui/misnamed_getters_2021.stderr +++ b/tests/ui/misnamed_getters_2021.stderr @@ -1,5 +1,5 @@ error: getter function appears to return the wrong field - --> tests/ui/misnamed_getters_2021.rs:15:5 + --> tests/ui/misnamed_getters_2021.rs:13:5 | LL | / unsafe fn a(&self) -> &u8 { LL | | diff --git a/tests/ui/misrefactored_assign_op.1.fixed b/tests/ui/misrefactored_assign_op.1.fixed index 882ff6bf8944a..c5628f2486b0a 100644 --- a/tests/ui/misrefactored_assign_op.1.fixed +++ b/tests/ui/misrefactored_assign_op.1.fixed @@ -1,5 +1,6 @@ +#![warn(clippy::misrefactored_assign_op)] +#![deny(clippy::assign_op_pattern)] #![allow(clippy::eq_op)] -#![warn(clippy::misrefactored_assign_op, clippy::assign_op_pattern)] fn main() { let mut a = 5; diff --git a/tests/ui/misrefactored_assign_op.2.fixed b/tests/ui/misrefactored_assign_op.2.fixed index de3a0f1710d24..02c4383f45ab7 100644 --- a/tests/ui/misrefactored_assign_op.2.fixed +++ b/tests/ui/misrefactored_assign_op.2.fixed @@ -1,5 +1,6 @@ +#![warn(clippy::misrefactored_assign_op)] +#![deny(clippy::assign_op_pattern)] #![allow(clippy::eq_op)] -#![warn(clippy::misrefactored_assign_op, clippy::assign_op_pattern)] fn main() { let mut a = 5; diff --git a/tests/ui/misrefactored_assign_op.rs b/tests/ui/misrefactored_assign_op.rs index 62d83d1619c1e..dcb284574ce43 100644 --- a/tests/ui/misrefactored_assign_op.rs +++ b/tests/ui/misrefactored_assign_op.rs @@ -1,5 +1,6 @@ +#![warn(clippy::misrefactored_assign_op)] +#![deny(clippy::assign_op_pattern)] #![allow(clippy::eq_op)] -#![warn(clippy::misrefactored_assign_op, clippy::assign_op_pattern)] fn main() { let mut a = 5; diff --git a/tests/ui/misrefactored_assign_op.stderr b/tests/ui/misrefactored_assign_op.stderr index 63f3a3e28f12c..50547a91dedc1 100644 --- a/tests/ui/misrefactored_assign_op.stderr +++ b/tests/ui/misrefactored_assign_op.stderr @@ -1,5 +1,5 @@ error: variable appears on both sides of an assignment operation - --> tests/ui/misrefactored_assign_op.rs:6:5 + --> tests/ui/misrefactored_assign_op.rs:7:5 | LL | a += a + 1; | ^^^^^^^^^^ @@ -18,7 +18,7 @@ LL + a = a + a + 1; | error: variable appears on both sides of an assignment operation - --> tests/ui/misrefactored_assign_op.rs:9:5 + --> tests/ui/misrefactored_assign_op.rs:10:5 | LL | a += 1 + a; | ^^^^^^^^^^ @@ -35,7 +35,7 @@ LL + a = a + 1 + a; | error: variable appears on both sides of an assignment operation - --> tests/ui/misrefactored_assign_op.rs:12:5 + --> tests/ui/misrefactored_assign_op.rs:13:5 | LL | a -= a - 1; | ^^^^^^^^^^ @@ -52,7 +52,7 @@ LL + a = a - (a - 1); | error: variable appears on both sides of an assignment operation - --> tests/ui/misrefactored_assign_op.rs:15:5 + --> tests/ui/misrefactored_assign_op.rs:16:5 | LL | a *= a * 99; | ^^^^^^^^^^^ @@ -69,7 +69,7 @@ LL + a = a * a * 99; | error: variable appears on both sides of an assignment operation - --> tests/ui/misrefactored_assign_op.rs:18:5 + --> tests/ui/misrefactored_assign_op.rs:19:5 | LL | a *= 42 * a; | ^^^^^^^^^^^ @@ -86,7 +86,7 @@ LL + a = a * 42 * a; | error: variable appears on both sides of an assignment operation - --> tests/ui/misrefactored_assign_op.rs:21:5 + --> tests/ui/misrefactored_assign_op.rs:22:5 | LL | a /= a / 2; | ^^^^^^^^^^ @@ -103,7 +103,7 @@ LL + a = a / (a / 2); | error: variable appears on both sides of an assignment operation - --> tests/ui/misrefactored_assign_op.rs:24:5 + --> tests/ui/misrefactored_assign_op.rs:25:5 | LL | a %= a % 5; | ^^^^^^^^^^ @@ -120,7 +120,7 @@ LL + a = a % (a % 5); | error: variable appears on both sides of an assignment operation - --> tests/ui/misrefactored_assign_op.rs:27:5 + --> tests/ui/misrefactored_assign_op.rs:28:5 | LL | a &= a & 1; | ^^^^^^^^^^ @@ -137,7 +137,7 @@ LL + a = a & a & 1; | error: variable appears on both sides of an assignment operation - --> tests/ui/misrefactored_assign_op.rs:30:5 + --> tests/ui/misrefactored_assign_op.rs:31:5 | LL | a *= a * a; | ^^^^^^^^^^ diff --git a/tests/ui/missing_asserts_for_indexing_unfixable.rs b/tests/ui/missing_asserts_for_indexing_unfixable.rs index eb98969efa47f..b8cdb71bd30a9 100644 --- a/tests/ui/missing_asserts_for_indexing_unfixable.rs +++ b/tests/ui/missing_asserts_for_indexing_unfixable.rs @@ -1,4 +1,3 @@ -#![allow(unused)] #![warn(clippy::missing_asserts_for_indexing)] fn sum(v: &[u8]) -> u8 { diff --git a/tests/ui/missing_asserts_for_indexing_unfixable.stderr b/tests/ui/missing_asserts_for_indexing_unfixable.stderr index 2929646494a41..fe929aa36dbad 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:5:5 + --> tests/ui/missing_asserts_for_indexing_unfixable.rs:4: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:10:13 + --> tests/ui/missing_asserts_for_indexing_unfixable.rs:9: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:17:13 + --> tests/ui/missing_asserts_for_indexing_unfixable.rs:16: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:26:13 + --> tests/ui/missing_asserts_for_indexing_unfixable.rs:25: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:28:13 + --> tests/ui/missing_asserts_for_indexing_unfixable.rs:27: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:35:13 + --> tests/ui/missing_asserts_for_indexing_unfixable.rs:34: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:45:13 + --> tests/ui/missing_asserts_for_indexing_unfixable.rs:44: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:59:13 + --> tests/ui/missing_asserts_for_indexing_unfixable.rs:58: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:77:13 + --> tests/ui/missing_asserts_for_indexing_unfixable.rs:76: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:85:13 + --> tests/ui/missing_asserts_for_indexing_unfixable.rs:84:13 | LL | let _ = v1[0] + v1[1] + v1[2]; | ^^^^^ ^^^^^ ^^^^^ diff --git a/tests/ui/missing_const_for_fn/could_be_const.fixed b/tests/ui/missing_const_for_fn/could_be_const.fixed index 46a7f79ac16ce..bc2d5b9d1c7b4 100644 --- a/tests/ui/missing_const_for_fn/could_be_const.fixed +++ b/tests/ui/missing_const_for_fn/could_be_const.fixed @@ -1,5 +1,5 @@ #![warn(clippy::missing_const_for_fn)] -#![allow(incomplete_features, clippy::let_and_return, clippy::missing_transmute_annotations)] +#![expect(clippy::let_and_return)] #![feature(const_trait_impl)] use std::mem::transmute; diff --git a/tests/ui/missing_const_for_fn/could_be_const.rs b/tests/ui/missing_const_for_fn/could_be_const.rs index 78e1939a85973..26baebfc535e2 100644 --- a/tests/ui/missing_const_for_fn/could_be_const.rs +++ b/tests/ui/missing_const_for_fn/could_be_const.rs @@ -1,5 +1,5 @@ #![warn(clippy::missing_const_for_fn)] -#![allow(incomplete_features, clippy::let_and_return, clippy::missing_transmute_annotations)] +#![expect(clippy::let_and_return)] #![feature(const_trait_impl)] use std::mem::transmute; diff --git a/tests/ui/missing_fields_in_debug.rs b/tests/ui/missing_fields_in_debug.rs index 14803b5485a11..e52630408f039 100644 --- a/tests/ui/missing_fields_in_debug.rs +++ b/tests/ui/missing_fields_in_debug.rs @@ -1,4 +1,3 @@ -#![allow(unused)] #![warn(clippy::missing_fields_in_debug)] use std::fmt; diff --git a/tests/ui/missing_fields_in_debug.stderr b/tests/ui/missing_fields_in_debug.stderr index 75b551e1f5c7e..4ea837e47836d 100644 --- a/tests/ui/missing_fields_in_debug.stderr +++ b/tests/ui/missing_fields_in_debug.stderr @@ -1,5 +1,5 @@ error: manual `Debug` impl does not include all fields - --> tests/ui/missing_fields_in_debug.rs:14:1 + --> tests/ui/missing_fields_in_debug.rs:13:1 | LL | / impl fmt::Debug for NamedStruct1Ignored { ... | @@ -7,7 +7,7 @@ LL | | } | |_^ | note: this field is unused - --> tests/ui/missing_fields_in_debug.rs:11:5 + --> tests/ui/missing_fields_in_debug.rs:10:5 | LL | hidden: u32, | ^^^^^^^^^^^ @@ -17,7 +17,7 @@ LL | hidden: u32, = help: to override `-D warnings` add `#[allow(clippy::missing_fields_in_debug)]` error: manual `Debug` impl does not include all fields - --> tests/ui/missing_fields_in_debug.rs:34:1 + --> tests/ui/missing_fields_in_debug.rs:33:1 | LL | / impl fmt::Debug for NamedStructMultipleIgnored { ... | @@ -25,17 +25,17 @@ LL | | } | |_^ | note: this field is unused - --> tests/ui/missing_fields_in_debug.rs:28:5 + --> tests/ui/missing_fields_in_debug.rs:27:5 | LL | hidden: u32, | ^^^^^^^^^^^ note: this field is unused - --> tests/ui/missing_fields_in_debug.rs:29:5 + --> tests/ui/missing_fields_in_debug.rs:28:5 | LL | hidden2: String, | ^^^^^^^^^^^^^^^ note: this field is unused - --> tests/ui/missing_fields_in_debug.rs:31:5 + --> tests/ui/missing_fields_in_debug.rs:30:5 | LL | hidden4: ((((u8), u16), u32), u64), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -43,7 +43,7 @@ LL | hidden4: ((((u8), u16), u32), u64), = help: consider calling `.finish_non_exhaustive()` if you intend to ignore fields error: manual `Debug` impl does not include all fields - --> tests/ui/missing_fields_in_debug.rs:97:1 + --> tests/ui/missing_fields_in_debug.rs:96:1 | LL | / impl fmt::Debug for MultiExprDebugImpl { LL | | @@ -54,7 +54,7 @@ LL | | } | |_^ | note: this field is unused - --> tests/ui/missing_fields_in_debug.rs:93:5 + --> tests/ui/missing_fields_in_debug.rs:92:5 | LL | b: String, | ^^^^^^^^^ diff --git a/tests/ui/missing_inline.rs b/tests/ui/missing_inline.rs index 8e937d609512a..0adaeaa9cab8a 100644 --- a/tests/ui/missing_inline.rs +++ b/tests/ui/missing_inline.rs @@ -2,7 +2,7 @@ #![crate_type = "dylib"] // When denying at the crate level, be sure to not get random warnings from the // injected intrinsics by the compiler. -#![allow(dead_code, non_snake_case)] +#![expect(non_snake_case)] type Typedef = String; pub type PubTypedef = String; diff --git a/tests/ui/missing_panics_doc.rs b/tests/ui/missing_panics_doc.rs index d016e099e303b..63e84ffaab634 100644 --- a/tests/ui/missing_panics_doc.rs +++ b/tests/ui/missing_panics_doc.rs @@ -1,6 +1,6 @@ //@aux-build:macro_rules.rs #![warn(clippy::missing_panics_doc)] -#![allow(clippy::option_map_unit_fn, clippy::unnecessary_literal_unwrap)] +#![expect(clippy::option_map_unit_fn, clippy::unnecessary_literal_unwrap)] #[macro_use] extern crate macro_rules; diff --git a/tests/ui/missing_spin_loop.fixed b/tests/ui/missing_spin_loop.fixed index 03fbf8ccc8a37..7876a0c47d5e7 100644 --- a/tests/ui/missing_spin_loop.fixed +++ b/tests/ui/missing_spin_loop.fixed @@ -1,6 +1,5 @@ #![warn(clippy::missing_spin_loop)] -#![allow(clippy::bool_comparison)] -#![allow(unused_braces)] +#![expect(clippy::bool_comparison)] use core::sync::atomic::{AtomicBool, Ordering}; diff --git a/tests/ui/missing_spin_loop.rs b/tests/ui/missing_spin_loop.rs index bf18590b9408e..06bfe8eeaab80 100644 --- a/tests/ui/missing_spin_loop.rs +++ b/tests/ui/missing_spin_loop.rs @@ -1,6 +1,5 @@ #![warn(clippy::missing_spin_loop)] -#![allow(clippy::bool_comparison)] -#![allow(unused_braces)] +#![expect(clippy::bool_comparison)] use core::sync::atomic::{AtomicBool, Ordering}; diff --git a/tests/ui/missing_spin_loop.stderr b/tests/ui/missing_spin_loop.stderr index 98c32d0423469..d4a93bb2d75b7 100644 --- a/tests/ui/missing_spin_loop.stderr +++ b/tests/ui/missing_spin_loop.stderr @@ -1,5 +1,5 @@ error: busy-waiting loop should at least have a spin loop hint - --> tests/ui/missing_spin_loop.rs:10:37 + --> tests/ui/missing_spin_loop.rs:9:37 | LL | while b.load(Ordering::Acquire) {} | ^^ help: try: `{ std::hint::spin_loop() }` @@ -8,31 +8,31 @@ LL | while b.load(Ordering::Acquire) {} = help: to override `-D warnings` add `#[allow(clippy::missing_spin_loop)]` error: busy-waiting loop should at least have a spin loop hint - --> tests/ui/missing_spin_loop.rs:13:37 + --> tests/ui/missing_spin_loop.rs:12:37 | LL | while !b.load(Ordering::SeqCst) {} | ^^ help: try: `{ std::hint::spin_loop() }` error: busy-waiting loop should at least have a spin loop hint - --> tests/ui/missing_spin_loop.rs:16:46 + --> tests/ui/missing_spin_loop.rs:15:46 | LL | while b.load(Ordering::Acquire) == false {} | ^^ help: try: `{ std::hint::spin_loop() }` error: busy-waiting loop should at least have a spin loop hint - --> tests/ui/missing_spin_loop.rs:19:49 + --> tests/ui/missing_spin_loop.rs:18:49 | LL | while { true == b.load(Ordering::Acquire) } {} | ^^ help: try: `{ std::hint::spin_loop() }` error: busy-waiting loop should at least have a spin loop hint - --> tests/ui/missing_spin_loop.rs:22:93 + --> tests/ui/missing_spin_loop.rs:21:93 | LL | while b.compare_exchange(true, false, Ordering::Acquire, Ordering::Relaxed) != Ok(true) {} | ^^ help: try: `{ std::hint::spin_loop() }` error: busy-waiting loop should at least have a spin loop hint - --> tests/ui/missing_spin_loop.rs:25:94 + --> tests/ui/missing_spin_loop.rs:24:94 | LL | while Ok(false) != b.compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed) {} | ^^ help: try: `{ std::hint::spin_loop() }` diff --git a/tests/ui/missing_trait_methods.rs b/tests/ui/missing_trait_methods.rs index 67070a2999510..90349a0de101f 100644 --- a/tests/ui/missing_trait_methods.rs +++ b/tests/ui/missing_trait_methods.rs @@ -1,5 +1,5 @@ -#![allow(unused, clippy::needless_lifetimes)] #![warn(clippy::missing_trait_methods)] +#![expect(clippy::needless_lifetimes)] trait A { fn provided() {} diff --git a/tests/ui/missing_transmute_annotations.fixed b/tests/ui/missing_transmute_annotations.fixed index 58faeaee09d46..2602a2fda5135 100644 --- a/tests/ui/missing_transmute_annotations.fixed +++ b/tests/ui/missing_transmute_annotations.fixed @@ -1,7 +1,7 @@ //@aux-build:macro_rules.rs #![warn(clippy::missing_transmute_annotations)] -#![allow(clippy::let_with_type_underscore)] +#![expect(clippy::let_with_type_underscore)] #[macro_use] extern crate macro_rules; diff --git a/tests/ui/missing_transmute_annotations.rs b/tests/ui/missing_transmute_annotations.rs index c9a4c5fa83b2b..fe7b7238d33fe 100644 --- a/tests/ui/missing_transmute_annotations.rs +++ b/tests/ui/missing_transmute_annotations.rs @@ -1,7 +1,7 @@ //@aux-build:macro_rules.rs #![warn(clippy::missing_transmute_annotations)] -#![allow(clippy::let_with_type_underscore)] +#![expect(clippy::let_with_type_underscore)] #[macro_use] extern crate macro_rules; diff --git a/tests/ui/mistyped_literal_suffix.fixed b/tests/ui/mistyped_literal_suffix.fixed index a0190acc5d4b3..3a7d714375a77 100644 --- a/tests/ui/mistyped_literal_suffix.fixed +++ b/tests/ui/mistyped_literal_suffix.fixed @@ -1,10 +1,8 @@ //@aux-build: proc_macros.rs -#![allow( - dead_code, - unused_variables, +#![warn(clippy::mistyped_literal_suffixes)] +#![expect( overflowing_literals, - clippy::excessive_precision, clippy::inconsistent_digit_grouping, clippy::unusual_byte_groupings )] diff --git a/tests/ui/mistyped_literal_suffix.rs b/tests/ui/mistyped_literal_suffix.rs index 12a26204e7557..02e76a468d210 100644 --- a/tests/ui/mistyped_literal_suffix.rs +++ b/tests/ui/mistyped_literal_suffix.rs @@ -1,10 +1,8 @@ //@aux-build: proc_macros.rs -#![allow( - dead_code, - unused_variables, +#![warn(clippy::mistyped_literal_suffixes)] +#![expect( overflowing_literals, - clippy::excessive_precision, clippy::inconsistent_digit_grouping, clippy::unusual_byte_groupings )] diff --git a/tests/ui/mistyped_literal_suffix.stderr b/tests/ui/mistyped_literal_suffix.stderr index 9c6b2fab21c31..a986bc0e69ec0 100644 --- a/tests/ui/mistyped_literal_suffix.stderr +++ b/tests/ui/mistyped_literal_suffix.stderr @@ -1,97 +1,98 @@ error: mistyped literal suffix - --> tests/ui/mistyped_literal_suffix.rs:16:18 + --> tests/ui/mistyped_literal_suffix.rs:14:18 | LL | let fail14 = 2_32; | ^^^^ help: did you mean to write: `2_i32` | - = note: `#[deny(clippy::mistyped_literal_suffixes)]` on by default + = note: `-D clippy::mistyped-literal-suffixes` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::mistyped_literal_suffixes)]` error: mistyped literal suffix - --> tests/ui/mistyped_literal_suffix.rs:18:18 + --> tests/ui/mistyped_literal_suffix.rs:16:18 | LL | let fail15 = 4_64; | ^^^^ help: did you mean to write: `4_i64` error: mistyped literal suffix - --> tests/ui/mistyped_literal_suffix.rs:20:18 + --> tests/ui/mistyped_literal_suffix.rs:18:18 | LL | let fail16 = 7_8; // | ^^^ help: did you mean to write: `7_i8` error: mistyped literal suffix - --> tests/ui/mistyped_literal_suffix.rs:23:18 + --> tests/ui/mistyped_literal_suffix.rs:21:18 | LL | let fail17 = 23_16; // | ^^^^^ help: did you mean to write: `23_i16` error: mistyped literal suffix - --> tests/ui/mistyped_literal_suffix.rs:28:18 + --> tests/ui/mistyped_literal_suffix.rs:26:18 | LL | let fail20 = 2__8; // | ^^^^ help: did you mean to write: `2_i8` error: mistyped literal suffix - --> tests/ui/mistyped_literal_suffix.rs:31:18 + --> tests/ui/mistyped_literal_suffix.rs:29:18 | LL | let fail21 = 4___16; // | ^^^^^^ help: did you mean to write: `4_i16` error: mistyped literal suffix - --> tests/ui/mistyped_literal_suffix.rs:36:18 + --> tests/ui/mistyped_literal_suffix.rs:34:18 | LL | let fail25 = 1E2_32; | ^^^^^^ help: did you mean to write: `1E2_f32` error: mistyped literal suffix - --> tests/ui/mistyped_literal_suffix.rs:38:18 + --> tests/ui/mistyped_literal_suffix.rs:36:18 | LL | let fail26 = 43E7_64; | ^^^^^^^ help: did you mean to write: `43E7_f64` error: mistyped literal suffix - --> tests/ui/mistyped_literal_suffix.rs:40:18 + --> tests/ui/mistyped_literal_suffix.rs:38:18 | LL | let fail27 = 243E17_32; | ^^^^^^^^^ help: did you mean to write: `243E17_f32` error: mistyped literal suffix - --> tests/ui/mistyped_literal_suffix.rs:42:18 + --> tests/ui/mistyped_literal_suffix.rs:40:18 | LL | let fail28 = 241251235E723_64; | ^^^^^^^^^^^^^^^^ help: did you mean to write: `241_251_235E723_f64` error: mistyped literal suffix - --> tests/ui/mistyped_literal_suffix.rs:47:18 + --> tests/ui/mistyped_literal_suffix.rs:45:18 | LL | let fail30 = 127_8; // should be i8 | ^^^^^ help: did you mean to write: `127_i8` error: mistyped literal suffix - --> tests/ui/mistyped_literal_suffix.rs:50:18 + --> tests/ui/mistyped_literal_suffix.rs:48:18 | LL | let fail31 = 240_8; // should be u8 | ^^^^^ help: did you mean to write: `240_u8` error: mistyped literal suffix - --> tests/ui/mistyped_literal_suffix.rs:54:18 + --> tests/ui/mistyped_literal_suffix.rs:52:18 | LL | let fail33 = 0x1234_16; | ^^^^^^^^^ help: did you mean to write: `0x1234_i16` error: mistyped literal suffix - --> tests/ui/mistyped_literal_suffix.rs:56:18 + --> tests/ui/mistyped_literal_suffix.rs:54:18 | LL | let fail34 = 0xABCD_16; | ^^^^^^^^^ help: did you mean to write: `0xABCD_u16` error: mistyped literal suffix - --> tests/ui/mistyped_literal_suffix.rs:59:18 + --> tests/ui/mistyped_literal_suffix.rs:57:18 | LL | let fail36 = 0xFFFF_FFFF_FFFF_FFFF_64; // u64 | ^^^^^^^^^^^^^^^^^^^^^^^^ help: did you mean to write: `0xFFFF_FFFF_FFFF_FFFF_u64` error: mistyped literal suffix - --> tests/ui/mistyped_literal_suffix.rs:67:13 + --> tests/ui/mistyped_literal_suffix.rs:65:13 | LL | let _ = 1.12345E1_32; | ^^^^^^^^^^^^ help: did you mean to write: `1.123_45E1_f32` diff --git a/tests/ui/module_name_repetitions.rs b/tests/ui/module_name_repetitions.rs index 5d16858bf85ec..8fdce71d05528 100644 --- a/tests/ui/module_name_repetitions.rs +++ b/tests/ui/module_name_repetitions.rs @@ -1,7 +1,6 @@ //@compile-flags: --test #![warn(clippy::module_name_repetitions)] -#![allow(dead_code)] pub mod foo { pub fn foo() {} diff --git a/tests/ui/module_name_repetitions.stderr b/tests/ui/module_name_repetitions.stderr index 9000c44a3902e..e4c3daacdbead 100644 --- a/tests/ui/module_name_repetitions.stderr +++ b/tests/ui/module_name_repetitions.stderr @@ -1,5 +1,5 @@ error: item name starts with its containing module's name - --> tests/ui/module_name_repetitions.rs:8:12 + --> tests/ui/module_name_repetitions.rs:7:12 | LL | pub fn foo_bar() {} | ^^^^^^^ @@ -8,31 +8,31 @@ LL | pub fn foo_bar() {} = help: to override `-D warnings` add `#[allow(clippy::module_name_repetitions)]` error: item name ends with its containing module's name - --> tests/ui/module_name_repetitions.rs:11:12 + --> tests/ui/module_name_repetitions.rs:10:12 | LL | pub fn bar_foo() {} | ^^^^^^^ error: item name starts with its containing module's name - --> tests/ui/module_name_repetitions.rs:14:16 + --> tests/ui/module_name_repetitions.rs:13:16 | LL | pub struct FooCake; | ^^^^^^^ error: item name ends with its containing module's name - --> tests/ui/module_name_repetitions.rs:17:14 + --> tests/ui/module_name_repetitions.rs:16:14 | LL | pub enum CakeFoo {} | ^^^^^^^ error: item name starts with its containing module's name - --> tests/ui/module_name_repetitions.rs:20:16 + --> tests/ui/module_name_repetitions.rs:19:16 | LL | pub struct Foo7Bar; | ^^^^^^^ error: item name starts with its containing module's name - --> tests/ui/module_name_repetitions.rs:33:20 + --> tests/ui/module_name_repetitions.rs:32:20 | LL | pub use error::FooError; | ^^^^^^^^ diff --git a/tests/ui/modulo_arithmetic_float.rs b/tests/ui/modulo_arithmetic_float.rs index 0e08174f686eb..46d554616f8df 100644 --- a/tests/ui/modulo_arithmetic_float.rs +++ b/tests/ui/modulo_arithmetic_float.rs @@ -1,7 +1,7 @@ #![feature(f128)] #![feature(f16)] #![warn(clippy::modulo_arithmetic)] -#![allow(clippy::no_effect, clippy::unnecessary_operation, clippy::modulo_one)] +#![expect(clippy::no_effect)] fn main() { // Lint when both sides are const and of the opposite sign diff --git a/tests/ui/modulo_arithmetic_integral.rs b/tests/ui/modulo_arithmetic_integral.rs index d7cd910e43cb7..583637dbc2855 100644 --- a/tests/ui/modulo_arithmetic_integral.rs +++ b/tests/ui/modulo_arithmetic_integral.rs @@ -1,5 +1,5 @@ #![warn(clippy::modulo_arithmetic)] -#![allow(clippy::no_effect, clippy::unnecessary_operation, clippy::modulo_one)] +#![expect(clippy::no_effect)] fn main() { // Lint on signed integral numbers diff --git a/tests/ui/modulo_arithmetic_integral_const.rs b/tests/ui/modulo_arithmetic_integral_const.rs index 9f5fb697df0ea..160bc86629247 100644 --- a/tests/ui/modulo_arithmetic_integral_const.rs +++ b/tests/ui/modulo_arithmetic_integral_const.rs @@ -1,10 +1,5 @@ #![warn(clippy::modulo_arithmetic)] -#![allow( - clippy::no_effect, - clippy::unnecessary_operation, - clippy::modulo_one, - clippy::identity_op -)] +#![expect(clippy::identity_op, clippy::modulo_one, clippy::no_effect)] fn main() { // Lint when both sides are const and of the opposite sign diff --git a/tests/ui/modulo_arithmetic_integral_const.stderr b/tests/ui/modulo_arithmetic_integral_const.stderr index 12edee8cf4255..e09673213f79a 100644 --- a/tests/ui/modulo_arithmetic_integral_const.stderr +++ b/tests/ui/modulo_arithmetic_integral_const.stderr @@ -1,5 +1,5 @@ error: you are using modulo operator on constants with different signs: `-1 % 2` - --> tests/ui/modulo_arithmetic_integral_const.rs:11:5 + --> tests/ui/modulo_arithmetic_integral_const.rs:6:5 | LL | -1 % 2; | ^^^^^^ @@ -10,7 +10,7 @@ LL | -1 % 2; = help: to override `-D warnings` add `#[allow(clippy::modulo_arithmetic)]` error: you are using modulo operator on constants with different signs: `1 % -2` - --> tests/ui/modulo_arithmetic_integral_const.rs:14:5 + --> tests/ui/modulo_arithmetic_integral_const.rs:9:5 | LL | 1 % -2; | ^^^^^^ @@ -19,7 +19,7 @@ LL | 1 % -2; = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on constants with different signs: `-1 % 3` - --> tests/ui/modulo_arithmetic_integral_const.rs:17:5 + --> tests/ui/modulo_arithmetic_integral_const.rs:12:5 | LL | (1 - 2) % (1 + 2); | ^^^^^^^^^^^^^^^^^ @@ -28,7 +28,7 @@ LL | (1 - 2) % (1 + 2); = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on constants with different signs: `3 % -1` - --> tests/ui/modulo_arithmetic_integral_const.rs:20:5 + --> tests/ui/modulo_arithmetic_integral_const.rs:15:5 | LL | (1 + 2) % (1 - 2); | ^^^^^^^^^^^^^^^^^ @@ -37,7 +37,7 @@ LL | (1 + 2) % (1 - 2); = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on constants with different signs: `-35 % 300000` - --> tests/ui/modulo_arithmetic_integral_const.rs:23:5 + --> tests/ui/modulo_arithmetic_integral_const.rs:18:5 | LL | 35 * (7 - 4 * 2) % (-500 * -600); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -46,7 +46,7 @@ LL | 35 * (7 - 4 * 2) % (-500 * -600); = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on constants with different signs: `-1 % 2` - --> tests/ui/modulo_arithmetic_integral_const.rs:26:5 + --> tests/ui/modulo_arithmetic_integral_const.rs:21:5 | LL | -1i8 % 2i8; | ^^^^^^^^^^ @@ -55,7 +55,7 @@ LL | -1i8 % 2i8; = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on constants with different signs: `1 % -2` - --> tests/ui/modulo_arithmetic_integral_const.rs:29:5 + --> tests/ui/modulo_arithmetic_integral_const.rs:24:5 | LL | 1i8 % -2i8; | ^^^^^^^^^^ @@ -64,7 +64,7 @@ LL | 1i8 % -2i8; = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on constants with different signs: `-1 % 2` - --> tests/ui/modulo_arithmetic_integral_const.rs:32:5 + --> tests/ui/modulo_arithmetic_integral_const.rs:27:5 | LL | -1i16 % 2i16; | ^^^^^^^^^^^^ @@ -73,7 +73,7 @@ LL | -1i16 % 2i16; = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on constants with different signs: `1 % -2` - --> tests/ui/modulo_arithmetic_integral_const.rs:35:5 + --> tests/ui/modulo_arithmetic_integral_const.rs:30:5 | LL | 1i16 % -2i16; | ^^^^^^^^^^^^ @@ -82,7 +82,7 @@ LL | 1i16 % -2i16; = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on constants with different signs: `-1 % 2` - --> tests/ui/modulo_arithmetic_integral_const.rs:38:5 + --> tests/ui/modulo_arithmetic_integral_const.rs:33:5 | LL | -1i32 % 2i32; | ^^^^^^^^^^^^ @@ -91,7 +91,7 @@ LL | -1i32 % 2i32; = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on constants with different signs: `1 % -2` - --> tests/ui/modulo_arithmetic_integral_const.rs:41:5 + --> tests/ui/modulo_arithmetic_integral_const.rs:36:5 | LL | 1i32 % -2i32; | ^^^^^^^^^^^^ @@ -100,7 +100,7 @@ LL | 1i32 % -2i32; = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on constants with different signs: `-1 % 2` - --> tests/ui/modulo_arithmetic_integral_const.rs:44:5 + --> tests/ui/modulo_arithmetic_integral_const.rs:39:5 | LL | -1i64 % 2i64; | ^^^^^^^^^^^^ @@ -109,7 +109,7 @@ LL | -1i64 % 2i64; = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on constants with different signs: `1 % -2` - --> tests/ui/modulo_arithmetic_integral_const.rs:47:5 + --> tests/ui/modulo_arithmetic_integral_const.rs:42:5 | LL | 1i64 % -2i64; | ^^^^^^^^^^^^ @@ -118,7 +118,7 @@ LL | 1i64 % -2i64; = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on constants with different signs: `-1 % 2` - --> tests/ui/modulo_arithmetic_integral_const.rs:50:5 + --> tests/ui/modulo_arithmetic_integral_const.rs:45:5 | LL | -1i128 % 2i128; | ^^^^^^^^^^^^^^ @@ -127,7 +127,7 @@ LL | -1i128 % 2i128; = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on constants with different signs: `1 % -2` - --> tests/ui/modulo_arithmetic_integral_const.rs:53:5 + --> tests/ui/modulo_arithmetic_integral_const.rs:48:5 | LL | 1i128 % -2i128; | ^^^^^^^^^^^^^^ @@ -136,7 +136,7 @@ LL | 1i128 % -2i128; = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on constants with different signs: `-1 % 2` - --> tests/ui/modulo_arithmetic_integral_const.rs:56:5 + --> tests/ui/modulo_arithmetic_integral_const.rs:51:5 | LL | -1isize % 2isize; | ^^^^^^^^^^^^^^^^ @@ -145,7 +145,7 @@ LL | -1isize % 2isize; = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on constants with different signs: `1 % -2` - --> tests/ui/modulo_arithmetic_integral_const.rs:59:5 + --> tests/ui/modulo_arithmetic_integral_const.rs:54:5 | LL | 1isize % -2isize; | ^^^^^^^^^^^^^^^^ diff --git a/tests/ui/modulo_one.rs b/tests/ui/modulo_one.rs index 63ae61059cb86..730c37d0e368e 100644 --- a/tests/ui/modulo_one.rs +++ b/tests/ui/modulo_one.rs @@ -1,6 +1,5 @@ #![warn(clippy::modulo_one)] -#![allow(unconditional_panic)] -#![allow(clippy::no_effect, clippy::unnecessary_operation, clippy::identity_op)] +#![expect(clippy::identity_op, clippy::no_effect)] static STATIC_ONE: usize = 2 - 1; static STATIC_NEG_ONE: i64 = 1 - 2; diff --git a/tests/ui/modulo_one.stderr b/tests/ui/modulo_one.stderr index 1c9c79d1c6214..f841ac18bbc3d 100644 --- a/tests/ui/modulo_one.stderr +++ b/tests/ui/modulo_one.stderr @@ -1,5 +1,5 @@ error: any number modulo 1 will be 0 - --> tests/ui/modulo_one.rs:9:5 + --> tests/ui/modulo_one.rs:8:5 | LL | 10 % 1; | ^^^^^^ @@ -8,31 +8,31 @@ LL | 10 % 1; = help: to override `-D warnings` add `#[allow(clippy::modulo_one)]` error: any number modulo -1 will panic/overflow or result in 0 - --> tests/ui/modulo_one.rs:12:5 + --> tests/ui/modulo_one.rs:11:5 | LL | 10 % -1; | ^^^^^^^ error: any number modulo -1 will panic/overflow or result in 0 - --> tests/ui/modulo_one.rs:17:5 + --> tests/ui/modulo_one.rs:16:5 | LL | i32::MIN % (-1); | ^^^^^^^^^^^^^^^ error: any number modulo 1 will be 0 - --> tests/ui/modulo_one.rs:24:5 + --> tests/ui/modulo_one.rs:23:5 | LL | 2 % ONE; | ^^^^^^^ error: any number modulo -1 will panic/overflow or result in 0 - --> tests/ui/modulo_one.rs:29:5 + --> tests/ui/modulo_one.rs:28:5 | LL | 2 % NEG_ONE; | ^^^^^^^^^^^ error: any number modulo -1 will panic/overflow or result in 0 - --> tests/ui/modulo_one.rs:35:5 + --> tests/ui/modulo_one.rs:34:5 | LL | INT_MIN % NEG_ONE; | ^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/msrv_attributes_without_early_lints.rs b/tests/ui/msrv_attributes_without_early_lints.rs index dcef1a485fceb..fe83023aaeb79 100644 --- a/tests/ui/msrv_attributes_without_early_lints.rs +++ b/tests/ui/msrv_attributes_without_early_lints.rs @@ -1,6 +1,5 @@ //@check-pass -#![allow(clippy::all, clippy::pedantic, clippy::restriction, clippy::nursery)] #![forbid(clippy::ptr_as_ptr)] /// MSRV checking in late passes skips checking the parent nodes if no early pass sees a diff --git a/tests/ui/multiple_unsafe_ops_per_block.rs b/tests/ui/multiple_unsafe_ops_per_block.rs index 0ff881472cbb9..5d51c47eeed91 100644 --- a/tests/ui/multiple_unsafe_ops_per_block.rs +++ b/tests/ui/multiple_unsafe_ops_per_block.rs @@ -1,11 +1,11 @@ //@needs-asm-support //@aux-build:proc_macros.rs +#![warn(clippy::multiple_unsafe_ops_per_block)] #![expect( dropping_copy_types, - clippy::unnecessary_operation, - clippy::unnecessary_literal_unwrap + clippy::unnecessary_literal_unwrap, + clippy::unnecessary_operation )] -#![warn(clippy::multiple_unsafe_ops_per_block)] extern crate proc_macros; use proc_macros::external; diff --git a/tests/ui/must_use_candidates.fixed b/tests/ui/must_use_candidates.fixed index 17569884658b1..226fafccddced 100644 --- a/tests/ui/must_use_candidates.fixed +++ b/tests/ui/must_use_candidates.fixed @@ -1,10 +1,4 @@ #![feature(never_type)] -#![allow( - unused_mut, - clippy::redundant_allocation, - clippy::needless_pass_by_ref_mut, - static_mut_refs -)] #![warn(clippy::must_use_candidate)] use std::rc::Rc; use std::sync::Arc; diff --git a/tests/ui/must_use_candidates.rs b/tests/ui/must_use_candidates.rs index 8b898533d01b7..f9b6c2986504c 100644 --- a/tests/ui/must_use_candidates.rs +++ b/tests/ui/must_use_candidates.rs @@ -1,10 +1,4 @@ #![feature(never_type)] -#![allow( - unused_mut, - clippy::redundant_allocation, - clippy::needless_pass_by_ref_mut, - static_mut_refs -)] #![warn(clippy::must_use_candidate)] use std::rc::Rc; use std::sync::Arc; diff --git a/tests/ui/must_use_candidates.stderr b/tests/ui/must_use_candidates.stderr index 38c7334322503..24fda87cd16aa 100644 --- a/tests/ui/must_use_candidates.stderr +++ b/tests/ui/must_use_candidates.stderr @@ -1,5 +1,5 @@ error: this function could have a `#[must_use]` attribute - --> tests/ui/must_use_candidates.rs:16:8 + --> tests/ui/must_use_candidates.rs:10:8 | LL | pub fn pure(i: u8) -> u8 { | ^^^^ @@ -13,7 +13,7 @@ LL | pub fn pure(i: u8) -> u8 { | error: this method could have a `#[must_use]` attribute - --> tests/ui/must_use_candidates.rs:22:12 + --> tests/ui/must_use_candidates.rs:16:12 | LL | pub fn inherent_pure(&self) -> u8 { | ^^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL ~ pub fn inherent_pure(&self) -> u8 { | error: this function could have a `#[must_use]` attribute - --> tests/ui/must_use_candidates.rs:54:8 + --> tests/ui/must_use_candidates.rs:48:8 | LL | pub fn with_marker(_d: std::marker::PhantomData<&mut u32>) -> bool { | ^^^^^^^^^^^ @@ -37,7 +37,7 @@ LL | pub fn with_marker(_d: std::marker::PhantomData<&mut u32>) -> bool { | error: this function could have a `#[must_use]` attribute - --> tests/ui/must_use_candidates.rs:67:8 + --> tests/ui/must_use_candidates.rs:61:8 | LL | pub fn rcd(_x: Rc) -> bool { | ^^^ @@ -49,7 +49,7 @@ LL | pub fn rcd(_x: Rc) -> bool { | error: this function could have a `#[must_use]` attribute - --> tests/ui/must_use_candidates.rs:76:8 + --> tests/ui/must_use_candidates.rs:70:8 | LL | pub fn arcd(_x: Arc) -> bool { | ^^^^ @@ -61,7 +61,7 @@ LL | pub fn arcd(_x: Arc) -> bool { | error: this function could have a `#[must_use]` attribute - --> tests/ui/must_use_candidates.rs:108:8 + --> tests/ui/must_use_candidates.rs:102:8 | LL | pub fn result_uninhabited() -> Result { | ^^^^^^^^^^^^^^^^^^ @@ -74,7 +74,7 @@ LL | pub fn result_uninhabited() -> Result { | error: this function could have a `#[must_use]` attribute - --> tests/ui/must_use_candidates.rs:113:8 + --> tests/ui/must_use_candidates.rs:107:8 | LL | pub fn controlflow_uninhabited() -> std::ops::ControlFlow { | ^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/must_use_unit.fixed b/tests/ui/must_use_unit.fixed index b9871991b16f0..5c1993f6575a2 100644 --- a/tests/ui/must_use_unit.fixed +++ b/tests/ui/must_use_unit.fixed @@ -1,7 +1,7 @@ //@aux-build:proc_macros.rs #![warn(clippy::must_use_unit)] -#![allow(clippy::unused_unit)] +#![expect(clippy::unused_unit)] extern crate proc_macros; use proc_macros::external; diff --git a/tests/ui/must_use_unit.rs b/tests/ui/must_use_unit.rs index a5865681c8a8e..86b4380a477aa 100644 --- a/tests/ui/must_use_unit.rs +++ b/tests/ui/must_use_unit.rs @@ -1,7 +1,7 @@ //@aux-build:proc_macros.rs #![warn(clippy::must_use_unit)] -#![allow(clippy::unused_unit)] +#![expect(clippy::unused_unit)] extern crate proc_macros; use proc_macros::external; diff --git a/tests/ui/mut_from_ref.rs b/tests/ui/mut_from_ref.rs index 1b0b351518cbb..f91e2992406b7 100644 --- a/tests/ui/mut_from_ref.rs +++ b/tests/ui/mut_from_ref.rs @@ -1,11 +1,10 @@ -#![allow( - unused, +#![warn(clippy::mut_from_ref)] +#![expect( + clippy::boxed_local, clippy::needless_lifetimes, clippy::needless_pass_by_ref_mut, - clippy::redundant_allocation, - clippy::boxed_local + clippy::redundant_allocation )] -#![warn(clippy::mut_from_ref)] struct Foo; diff --git a/tests/ui/mut_from_ref.stderr b/tests/ui/mut_from_ref.stderr index 0974268734653..92165eb9ae735 100644 --- a/tests/ui/mut_from_ref.stderr +++ b/tests/ui/mut_from_ref.stderr @@ -1,11 +1,11 @@ error: mutable borrow from immutable input(s) - --> tests/ui/mut_from_ref.rs:13:39 + --> tests/ui/mut_from_ref.rs:12:39 | LL | fn this_wont_hurt_a_bit(&self) -> &mut Foo { | ^^^^^^^^ | note: immutable borrow here - --> tests/ui/mut_from_ref.rs:13:29 + --> tests/ui/mut_from_ref.rs:12:29 | LL | fn this_wont_hurt_a_bit(&self) -> &mut Foo { | ^^^^^ @@ -13,85 +13,85 @@ LL | fn this_wont_hurt_a_bit(&self) -> &mut Foo { = help: to override `-D warnings` add `#[allow(clippy::mut_from_ref)]` error: mutable borrow from immutable input(s) - --> tests/ui/mut_from_ref.rs:21:25 + --> tests/ui/mut_from_ref.rs:20:25 | LL | fn ouch(x: &Foo) -> &mut Foo; | ^^^^^^^^ | note: immutable borrow here - --> tests/ui/mut_from_ref.rs:21:16 + --> tests/ui/mut_from_ref.rs:20:16 | LL | fn ouch(x: &Foo) -> &mut Foo; | ^^^^ error: mutable borrow from immutable input(s) - --> tests/ui/mut_from_ref.rs:31:21 + --> tests/ui/mut_from_ref.rs:30:21 | LL | fn fail(x: &u32) -> &mut u16 { | ^^^^^^^^ | note: immutable borrow here - --> tests/ui/mut_from_ref.rs:31:12 + --> tests/ui/mut_from_ref.rs:30:12 | LL | fn fail(x: &u32) -> &mut u16 { | ^^^^ error: mutable borrow from immutable input(s) - --> tests/ui/mut_from_ref.rs:37:50 + --> tests/ui/mut_from_ref.rs:36:50 | LL | fn fail_lifetime<'a>(x: &'a u32, y: &mut u32) -> &'a mut u32 { | ^^^^^^^^^^^ | note: immutable borrow here - --> tests/ui/mut_from_ref.rs:37:25 + --> tests/ui/mut_from_ref.rs:36:25 | LL | fn fail_lifetime<'a>(x: &'a u32, y: &mut u32) -> &'a mut u32 { | ^^^^^^^ error: mutable borrow from immutable input(s) - --> tests/ui/mut_from_ref.rs:43:67 + --> tests/ui/mut_from_ref.rs:42:67 | LL | fn fail_double<'a, 'b>(x: &'a u32, y: &'a u32, z: &'b mut u32) -> &'a mut u32 { | ^^^^^^^^^^^ | note: immutable borrow here - --> tests/ui/mut_from_ref.rs:43:27 + --> tests/ui/mut_from_ref.rs:42:27 | LL | fn fail_double<'a, 'b>(x: &'a u32, y: &'a u32, z: &'b mut u32) -> &'a mut u32 { | ^^^^^^^ ^^^^^^^ error: mutable borrow from immutable input(s) - --> tests/ui/mut_from_ref.rs:49:46 + --> tests/ui/mut_from_ref.rs:48:46 | LL | fn fail_tuples<'a>(x: (&'a u32, &'a u32)) -> &'a mut u32 { | ^^^^^^^^^^^ | note: immutable borrow here - --> tests/ui/mut_from_ref.rs:49:24 + --> tests/ui/mut_from_ref.rs:48:24 | LL | fn fail_tuples<'a>(x: (&'a u32, &'a u32)) -> &'a mut u32 { | ^^^^^^^ ^^^^^^^ error: mutable borrow from immutable input(s) - --> tests/ui/mut_from_ref.rs:55:37 + --> tests/ui/mut_from_ref.rs:54:37 | LL | fn fail_box<'a>(x: Box<&'a u32>) -> &'a mut u32 { | ^^^^^^^^^^^ | note: immutable borrow here - --> tests/ui/mut_from_ref.rs:55:24 + --> tests/ui/mut_from_ref.rs:54:24 | LL | fn fail_box<'a>(x: Box<&'a u32>) -> &'a mut u32 { | ^^^^^^^ error: mutable borrow from immutable input(s) - --> tests/ui/mut_from_ref.rs:85:35 + --> tests/ui/mut_from_ref.rs:84:35 | LL | unsafe fn also_broken(x: &u32) -> &mut u32 { | ^^^^^^^^ | note: immutable borrow here - --> tests/ui/mut_from_ref.rs:85:26 + --> tests/ui/mut_from_ref.rs:84:26 | LL | unsafe fn also_broken(x: &u32) -> &mut u32 { | ^^^^ diff --git a/tests/ui/mut_mut.fixed b/tests/ui/mut_mut.fixed index f9a7f5dcb5a15..c34f605e3da6e 100644 --- a/tests/ui/mut_mut.fixed +++ b/tests/ui/mut_mut.fixed @@ -1,13 +1,6 @@ //@aux-build:proc_macros.rs #![warn(clippy::mut_mut)] -#![allow(unused)] -#![allow( - clippy::no_effect, - clippy::uninlined_format_args, - clippy::unnecessary_operation, - clippy::needless_pass_by_ref_mut -)] extern crate proc_macros; use proc_macros::{external, inline_macros}; @@ -26,7 +19,6 @@ macro_rules! mut_ptr { }; } -#[allow(unused_mut, unused_variables)] #[inline_macros] fn main() { let mut x = &mut 1u32; diff --git a/tests/ui/mut_mut.rs b/tests/ui/mut_mut.rs index bbec48011a17e..d17394dfe3f69 100644 --- a/tests/ui/mut_mut.rs +++ b/tests/ui/mut_mut.rs @@ -1,13 +1,6 @@ //@aux-build:proc_macros.rs #![warn(clippy::mut_mut)] -#![allow(unused)] -#![allow( - clippy::no_effect, - clippy::uninlined_format_args, - clippy::unnecessary_operation, - clippy::needless_pass_by_ref_mut -)] extern crate proc_macros; use proc_macros::{external, inline_macros}; @@ -26,7 +19,6 @@ macro_rules! mut_ptr { }; } -#[allow(unused_mut, unused_variables)] #[inline_macros] fn main() { let mut x = &mut &mut 1u32; diff --git a/tests/ui/mut_mut.stderr b/tests/ui/mut_mut.stderr index 85e9c5649b89a..0a7a923e0f48f 100644 --- a/tests/ui/mut_mut.stderr +++ b/tests/ui/mut_mut.stderr @@ -1,5 +1,5 @@ error: a type of form `&mut &mut _` - --> tests/ui/mut_mut.rs:15:11 + --> tests/ui/mut_mut.rs:8:11 | LL | fn fun(x: &mut &mut u32) { | ^^^^^^^^^^^^^ help: remove the extra `&mut`: `&mut u32` @@ -8,37 +8,37 @@ LL | fn fun(x: &mut &mut u32) { = help: to override `-D warnings` add `#[allow(clippy::mut_mut)]` error: an expression of form `&mut &mut _` - --> tests/ui/mut_mut.rs:32:17 + --> tests/ui/mut_mut.rs:24:17 | LL | let mut x = &mut &mut 1u32; | ^^^^^^^^^^^^^^ help: remove the extra `&mut`: `&mut 1u32` error: this expression mutably borrows a mutable reference - --> tests/ui/mut_mut.rs:35:21 + --> tests/ui/mut_mut.rs:27:21 | LL | let mut y = &mut x; | ^^^^^^ help: reborrow instead: `&mut *x` error: an expression of form `&mut &mut _` - --> tests/ui/mut_mut.rs:40:32 + --> tests/ui/mut_mut.rs:32:32 | LL | let y: &mut &mut u32 = &mut &mut 2; | ^^^^^^^^^^^ help: remove the extra `&mut`: `&mut 2` error: a type of form `&mut &mut _` - --> tests/ui/mut_mut.rs:40:16 + --> tests/ui/mut_mut.rs:32:16 | LL | let y: &mut &mut u32 = &mut &mut 2; | ^^^^^^^^^^^^^ help: remove the extra `&mut`: `&mut u32` error: an expression of form `&mut &mut _` - --> tests/ui/mut_mut.rs:46:37 + --> tests/ui/mut_mut.rs:38:37 | LL | let y: &mut &mut &mut u32 = &mut &mut &mut 2; | ^^^^^^^^^^^^^^^^ help: remove the extra `&mut`s: `&mut 2` error: a type of form `&mut &mut _` - --> tests/ui/mut_mut.rs:46:16 + --> tests/ui/mut_mut.rs:38:16 | LL | let y: &mut &mut &mut u32 = &mut &mut &mut 2; | ^^^^^^^^^^^^^^^^^^ help: remove the extra `&mut`s: `&mut u32` diff --git a/tests/ui/mut_mut_unfixable.rs b/tests/ui/mut_mut_unfixable.rs index 271cb7b968898..0c6444fd9fa35 100644 --- a/tests/ui/mut_mut_unfixable.rs +++ b/tests/ui/mut_mut_unfixable.rs @@ -1,7 +1,6 @@ //@no-rustfix #![warn(clippy::mut_mut)] -#![allow(unused)] #![expect(clippy::no_effect)] //! removing the extra `&mut`s will break the derefs diff --git a/tests/ui/mut_mut_unfixable.stderr b/tests/ui/mut_mut_unfixable.stderr index cf66eb2ed1eca..7e7fb801ce1e7 100644 --- a/tests/ui/mut_mut_unfixable.stderr +++ b/tests/ui/mut_mut_unfixable.stderr @@ -1,5 +1,5 @@ error: a type of form `&mut &mut _` - --> tests/ui/mut_mut_unfixable.rs:9:11 + --> tests/ui/mut_mut_unfixable.rs:8:11 | LL | fn fun(x: &mut &mut u32) -> bool { | ^^^^^^^^^^^^^ help: remove the extra `&mut`: `&mut u32` @@ -8,31 +8,31 @@ LL | fn fun(x: &mut &mut u32) -> bool { = help: to override `-D warnings` add `#[allow(clippy::mut_mut)]` error: an expression of form `&mut &mut _` - --> tests/ui/mut_mut_unfixable.rs:15:17 + --> tests/ui/mut_mut_unfixable.rs:14:17 | LL | let mut x = &mut &mut 1u32; | ^^^^^^^^^^^^^^ help: remove the extra `&mut`: `&mut 1u32` error: this expression mutably borrows a mutable reference - --> tests/ui/mut_mut_unfixable.rs:18:21 + --> tests/ui/mut_mut_unfixable.rs:17:21 | LL | let mut y = &mut x; | ^^^^^^ help: reborrow instead: `&mut *x` error: an expression of form `&mut &mut _` - --> tests/ui/mut_mut_unfixable.rs:24:17 + --> tests/ui/mut_mut_unfixable.rs:23:17 | LL | let y = &mut &mut 2; | ^^^^^^^^^^^ help: remove the extra `&mut`: `&mut 2` error: an expression of form `&mut &mut _` - --> tests/ui/mut_mut_unfixable.rs:30:17 + --> tests/ui/mut_mut_unfixable.rs:29:17 | LL | let y = &mut &mut &mut 2; | ^^^^^^^^^^^^^^^^ help: remove the extra `&mut`s: `&mut 2` error: an expression of form `&mut &mut _` - --> tests/ui/mut_mut_unfixable.rs:39:17 + --> tests/ui/mut_mut_unfixable.rs:38:17 | LL | let y = &mut &mut x; | ^^^^^^^^^^^ help: remove the extra `&mut`: `&mut x` diff --git a/tests/ui/mut_mutex_lock.fixed b/tests/ui/mut_mutex_lock.fixed index 5790ee8c1b022..44587b89ec836 100644 --- a/tests/ui/mut_mutex_lock.fixed +++ b/tests/ui/mut_mutex_lock.fixed @@ -1,4 +1,3 @@ -#![allow(dead_code, unused_mut)] #![warn(clippy::mut_mutex_lock)] use std::sync::{Arc, Mutex}; diff --git a/tests/ui/mut_mutex_lock.rs b/tests/ui/mut_mutex_lock.rs index 7286afac823b7..eef4f26c09595 100644 --- a/tests/ui/mut_mutex_lock.rs +++ b/tests/ui/mut_mutex_lock.rs @@ -1,4 +1,3 @@ -#![allow(dead_code, unused_mut)] #![warn(clippy::mut_mutex_lock)] use std::sync::{Arc, Mutex}; diff --git a/tests/ui/mut_mutex_lock.stderr b/tests/ui/mut_mutex_lock.stderr index 67543c73c6eef..587405449523c 100644 --- a/tests/ui/mut_mutex_lock.stderr +++ b/tests/ui/mut_mutex_lock.stderr @@ -1,5 +1,5 @@ error: calling `&mut Mutex::lock` unnecessarily locks an exclusive (mutable) reference - --> tests/ui/mut_mutex_lock.rs:10:33 + --> tests/ui/mut_mutex_lock.rs:9:33 | LL | let mut value = value_mutex.lock().unwrap(); | ^^^^ help: change this to: `get_mut` @@ -8,7 +8,7 @@ LL | let mut value = value_mutex.lock().unwrap(); = help: to override `-D warnings` add `#[allow(clippy::mut_mutex_lock)]` error: calling `&mut Mutex::lock` unnecessarily locks an exclusive (mutable) reference - --> tests/ui/mut_mutex_lock.rs:16:43 + --> tests/ui/mut_mutex_lock.rs:15:43 | LL | let mut value = mut_ref_mut_ref_mutex.lock().unwrap(); | ^^^^ help: change this to: `get_mut` diff --git a/tests/ui/mut_range_bound.rs b/tests/ui/mut_range_bound.rs index 107a6229b86d8..4e1192a86c2c1 100644 --- a/tests/ui/mut_range_bound.rs +++ b/tests/ui/mut_range_bound.rs @@ -1,4 +1,4 @@ -#![allow(unused)] +#![warn(clippy::mut_range_bound)] fn main() {} diff --git a/tests/ui/mutex_atomic.fixed b/tests/ui/mutex_atomic.fixed index dc05d8a2c61fe..711aba8da37b6 100644 --- a/tests/ui/mutex_atomic.fixed +++ b/tests/ui/mutex_atomic.fixed @@ -1,6 +1,5 @@ -#![warn(clippy::mutex_integer)] -#![warn(clippy::mutex_atomic)] -#![allow(clippy::borrow_as_ptr)] +#![warn(clippy::mutex_atomic, clippy::mutex_integer)] +#![expect(clippy::borrow_as_ptr)] use std::sync::Mutex; diff --git a/tests/ui/mutex_atomic.rs b/tests/ui/mutex_atomic.rs index 33745f8fc5e13..f0ca75458d100 100644 --- a/tests/ui/mutex_atomic.rs +++ b/tests/ui/mutex_atomic.rs @@ -1,6 +1,5 @@ -#![warn(clippy::mutex_integer)] -#![warn(clippy::mutex_atomic)] -#![allow(clippy::borrow_as_ptr)] +#![warn(clippy::mutex_atomic, clippy::mutex_integer)] +#![expect(clippy::borrow_as_ptr)] use std::sync::Mutex; diff --git a/tests/ui/mutex_atomic.stderr b/tests/ui/mutex_atomic.stderr index c1391e0111c8d..85c1829f44121 100644 --- a/tests/ui/mutex_atomic.stderr +++ b/tests/ui/mutex_atomic.stderr @@ -1,5 +1,5 @@ error: using a `Mutex` where an atomic would do - --> tests/ui/mutex_atomic.rs:8:13 + --> tests/ui/mutex_atomic.rs:7:13 | LL | let _ = Mutex::new(true); | ^^^^^^^^^^^^^^^^ @@ -14,7 +14,7 @@ LL + let _ = std::sync::atomic::AtomicBool::new(true); | error: using a `Mutex` where an atomic would do - --> tests/ui/mutex_atomic.rs:11:13 + --> tests/ui/mutex_atomic.rs:10:13 | LL | let _ = Mutex::new(5usize); | ^^^^^^^^^^^^^^^^^^ @@ -27,7 +27,7 @@ LL + let _ = std::sync::atomic::AtomicUsize::new(5usize); | error: using a `Mutex` where an atomic would do - --> tests/ui/mutex_atomic.rs:14:13 + --> tests/ui/mutex_atomic.rs:13:13 | LL | let _ = Mutex::new(9isize); | ^^^^^^^^^^^^^^^^^^ @@ -40,7 +40,7 @@ LL + let _ = std::sync::atomic::AtomicIsize::new(9isize); | error: using a `Mutex` where an atomic would do - --> tests/ui/mutex_atomic.rs:21:13 + --> tests/ui/mutex_atomic.rs:20:13 | LL | let _ = Mutex::new(&mut x as *mut u32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -53,7 +53,7 @@ LL + let _ = std::sync::atomic::AtomicPtr::new(&mut x as *mut u32); | error: using a `Mutex` where an atomic would do - --> tests/ui/mutex_atomic.rs:24:13 + --> tests/ui/mutex_atomic.rs:23:13 | LL | let _ = Mutex::new(0u32); | ^^^^^^^^^^^^^^^^ @@ -68,7 +68,7 @@ LL + let _ = std::sync::atomic::AtomicU32::new(0u32); | error: using a `Mutex` where an atomic would do - --> tests/ui/mutex_atomic.rs:27:13 + --> tests/ui/mutex_atomic.rs:26:13 | LL | let _ = Mutex::new(0i32); | ^^^^^^^^^^^^^^^^ @@ -81,7 +81,7 @@ LL + let _ = std::sync::atomic::AtomicI32::new(0i32); | error: using a `Mutex` where an atomic would do - --> tests/ui/mutex_atomic.rs:31:13 + --> tests/ui/mutex_atomic.rs:30:13 | LL | let _ = Mutex::new(0u8); | ^^^^^^^^^^^^^^^ @@ -94,7 +94,7 @@ LL + let _ = std::sync::atomic::AtomicU8::new(0u8); | error: using a `Mutex` where an atomic would do - --> tests/ui/mutex_atomic.rs:34:13 + --> tests/ui/mutex_atomic.rs:33:13 | LL | let _ = Mutex::new(0i16); | ^^^^^^^^^^^^^^^^ @@ -107,7 +107,7 @@ LL + let _ = std::sync::atomic::AtomicI16::new(0i16); | error: using a `Mutex` where an atomic would do - --> tests/ui/mutex_atomic.rs:37:25 + --> tests/ui/mutex_atomic.rs:36:25 | LL | let _x: Mutex = Mutex::new(0); | ^^^^^^^^^^^^^ @@ -120,7 +120,7 @@ LL + let _x = std::sync::atomic::AtomicI8::new(0); | error: using a `Mutex` where an atomic would do - --> tests/ui/mutex_atomic.rs:41:13 + --> tests/ui/mutex_atomic.rs:40:13 | LL | let _ = Mutex::new(X); | ^^^^^^^^^^^^^ @@ -133,7 +133,7 @@ LL + let _ = std::sync::atomic::AtomicI64::new(X); | error: using a `Mutex` where an atomic would do - --> tests/ui/mutex_atomic.rs:53:30 + --> tests/ui/mutex_atomic.rs:52:30 | LL | static MTX: Mutex = Mutex::new(0); | ^^^^^^^^^^^^^ @@ -146,7 +146,7 @@ LL + static MTX: std::sync::atomic::AtomicU32 = std::sync::atomic::AtomicU32 | error: using a `Mutex` where an atomic would do - --> tests/ui/mutex_atomic.rs:56:15 + --> tests/ui/mutex_atomic.rs:55:15 | LL | let mtx = Mutex::new(0); | ^^^^^^^^^^^^^ @@ -159,7 +159,7 @@ LL + let mtx = std::sync::atomic::AtomicI32::new(0); | error: using a `Mutex` where an atomic would do - --> tests/ui/mutex_atomic.rs:60:22 + --> tests/ui/mutex_atomic.rs:59:22 | LL | let reassigned = mtx; | ^^^ @@ -168,7 +168,7 @@ LL | let reassigned = mtx; = help: if you just want the locking behavior and not the internal type, consider using `Mutex<()>` error: using a `Mutex` where an atomic would do - --> tests/ui/mutex_atomic.rs:65:35 + --> tests/ui/mutex_atomic.rs:64:35 | LL | let (funky_mtx): Mutex = Mutex::new(0); | ^^^^^^^^^^^^^ @@ -181,7 +181,7 @@ LL + let (funky_mtx) = std::sync::atomic::AtomicU64::new(0); | error: using a `Mutex` where an atomic would do - --> tests/ui/mutex_atomic.rs:76:13 + --> tests/ui/mutex_atomic.rs:75:13 | LL | let _ = Mutex::new(test_expr!(1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/needless_arbitrary_self_type.fixed b/tests/ui/needless_arbitrary_self_type.fixed index adb9096c9f242..0eef094895dd8 100644 --- a/tests/ui/needless_arbitrary_self_type.fixed +++ b/tests/ui/needless_arbitrary_self_type.fixed @@ -1,5 +1,5 @@ #![warn(clippy::needless_arbitrary_self_type)] -#![allow(unused_mut, clippy::needless_lifetimes)] +#![expect(clippy::needless_lifetimes)] pub enum ValType { A, diff --git a/tests/ui/needless_arbitrary_self_type.rs b/tests/ui/needless_arbitrary_self_type.rs index 550546ed24fd7..0ea16ce89946b 100644 --- a/tests/ui/needless_arbitrary_self_type.rs +++ b/tests/ui/needless_arbitrary_self_type.rs @@ -1,5 +1,5 @@ #![warn(clippy::needless_arbitrary_self_type)] -#![allow(unused_mut, clippy::needless_lifetimes)] +#![expect(clippy::needless_lifetimes)] pub enum ValType { A, diff --git a/tests/ui/needless_bitwise_bool.fixed b/tests/ui/needless_bitwise_bool.fixed index eedeecd8a8cbc..a5c34939a5c9d 100644 --- a/tests/ui/needless_bitwise_bool.fixed +++ b/tests/ui/needless_bitwise_bool.fixed @@ -1,5 +1,5 @@ #![warn(clippy::needless_bitwise_bool)] -#![allow(clippy::const_is_empty)] +#![expect(clippy::const_is_empty)] fn returns_bool() -> bool { true diff --git a/tests/ui/needless_bitwise_bool.rs b/tests/ui/needless_bitwise_bool.rs index 5c0a4ccf266c3..ca03d888f3650 100644 --- a/tests/ui/needless_bitwise_bool.rs +++ b/tests/ui/needless_bitwise_bool.rs @@ -1,5 +1,5 @@ #![warn(clippy::needless_bitwise_bool)] -#![allow(clippy::const_is_empty)] +#![expect(clippy::const_is_empty)] fn returns_bool() -> bool { true diff --git a/tests/ui/needless_bool/fixable.fixed b/tests/ui/needless_bool/fixable.fixed index 0af4f87bec677..c3eed4e3fd717 100644 --- a/tests/ui/needless_bool/fixable.fixed +++ b/tests/ui/needless_bool/fixable.fixed @@ -1,15 +1,6 @@ #![warn(clippy::needless_bool)] -#![allow( - unused, - dead_code, - clippy::no_effect, - clippy::if_same_then_else, - clippy::equatable_if_let, - clippy::needless_ifs, - clippy::needless_return, - clippy::self_named_constructors, - clippy::struct_field_names -)] +#![allow(clippy::no_effect)] +#![expect(clippy::needless_return)] use std::cell::Cell; @@ -21,7 +12,6 @@ macro_rules! bool_comparison_trigger { $($i: (Cell, bool, bool)),+ } - #[allow(dead_code)] impl Trigger { pub fn trigger(&self, key: &str) -> bool { $( diff --git a/tests/ui/needless_bool/fixable.rs b/tests/ui/needless_bool/fixable.rs index 2e8719bd041e0..4571628be20ea 100644 --- a/tests/ui/needless_bool/fixable.rs +++ b/tests/ui/needless_bool/fixable.rs @@ -1,15 +1,6 @@ #![warn(clippy::needless_bool)] -#![allow( - unused, - dead_code, - clippy::no_effect, - clippy::if_same_then_else, - clippy::equatable_if_let, - clippy::needless_ifs, - clippy::needless_return, - clippy::self_named_constructors, - clippy::struct_field_names -)] +#![allow(clippy::no_effect)] +#![expect(clippy::needless_return)] use std::cell::Cell; @@ -21,7 +12,6 @@ macro_rules! bool_comparison_trigger { $($i: (Cell, bool, bool)),+ } - #[allow(dead_code)] impl Trigger { pub fn trigger(&self, key: &str) -> bool { $( diff --git a/tests/ui/needless_bool/fixable.stderr b/tests/ui/needless_bool/fixable.stderr index e15260242f4dd..f8cad52c2bbf2 100644 --- a/tests/ui/needless_bool/fixable.stderr +++ b/tests/ui/needless_bool/fixable.stderr @@ -1,5 +1,5 @@ error: this if-then-else expression returns a bool literal - --> tests/ui/needless_bool/fixable.rs:41:5 + --> tests/ui/needless_bool/fixable.rs:31:5 | LL | / if x { LL | | true @@ -12,7 +12,7 @@ LL | | }; = help: to override `-D warnings` add `#[allow(clippy::needless_bool)]` error: this if-then-else expression returns a bool literal - --> tests/ui/needless_bool/fixable.rs:47:5 + --> tests/ui/needless_bool/fixable.rs:37:5 | LL | / if x { LL | | false @@ -22,7 +22,7 @@ LL | | }; | |_____^ help: you can reduce it to: `!x` error: this if-then-else expression returns a bool literal - --> tests/ui/needless_bool/fixable.rs:53:5 + --> tests/ui/needless_bool/fixable.rs:43:5 | LL | / if x && y { LL | | false @@ -32,7 +32,7 @@ LL | | }; | |_____^ help: you can reduce it to: `!(x && y)` error: this if-then-else expression returns a bool literal - --> tests/ui/needless_bool/fixable.rs:62:5 + --> tests/ui/needless_bool/fixable.rs:52:5 | LL | / if a == b { LL | | false @@ -42,7 +42,7 @@ LL | | }; | |_____^ help: you can reduce it to: `a != b` error: this if-then-else expression returns a bool literal - --> tests/ui/needless_bool/fixable.rs:68:5 + --> tests/ui/needless_bool/fixable.rs:58:5 | LL | / if a != b { LL | | false @@ -52,7 +52,7 @@ LL | | }; | |_____^ help: you can reduce it to: `a == b` error: this if-then-else expression returns a bool literal - --> tests/ui/needless_bool/fixable.rs:74:5 + --> tests/ui/needless_bool/fixable.rs:64:5 | LL | / if a < b { LL | | false @@ -62,7 +62,7 @@ LL | | }; | |_____^ help: you can reduce it to: `a >= b` error: this if-then-else expression returns a bool literal - --> tests/ui/needless_bool/fixable.rs:80:5 + --> tests/ui/needless_bool/fixable.rs:70:5 | LL | / if a <= b { LL | | false @@ -72,7 +72,7 @@ LL | | }; | |_____^ help: you can reduce it to: `a > b` error: this if-then-else expression returns a bool literal - --> tests/ui/needless_bool/fixable.rs:86:5 + --> tests/ui/needless_bool/fixable.rs:76:5 | LL | / if a > b { LL | | false @@ -82,7 +82,7 @@ LL | | }; | |_____^ help: you can reduce it to: `a <= b` error: this if-then-else expression returns a bool literal - --> tests/ui/needless_bool/fixable.rs:92:5 + --> tests/ui/needless_bool/fixable.rs:82:5 | LL | / if a >= b { LL | | false @@ -92,7 +92,7 @@ LL | | }; | |_____^ help: you can reduce it to: `a < b` error: this if-then-else expression returns a bool literal - --> tests/ui/needless_bool/fixable.rs:121:5 + --> tests/ui/needless_bool/fixable.rs:111:5 | LL | / if x { LL | | return true; @@ -102,7 +102,7 @@ LL | | }; | |_____^ help: you can reduce it to: `return x` error: this if-then-else expression returns a bool literal - --> tests/ui/needless_bool/fixable.rs:130:5 + --> tests/ui/needless_bool/fixable.rs:120:5 | LL | / if x { LL | | return false; @@ -112,7 +112,7 @@ LL | | }; | |_____^ help: you can reduce it to: `return !x` error: this if-then-else expression returns a bool literal - --> tests/ui/needless_bool/fixable.rs:139:5 + --> tests/ui/needless_bool/fixable.rs:129:5 | LL | / if x && y { LL | | return true; @@ -122,7 +122,7 @@ LL | | }; | |_____^ help: you can reduce it to: `return x && y` error: this if-then-else expression returns a bool literal - --> tests/ui/needless_bool/fixable.rs:148:5 + --> tests/ui/needless_bool/fixable.rs:138:5 | LL | / if x && y { LL | | return false; @@ -132,7 +132,7 @@ LL | | }; | |_____^ help: you can reduce it to: `return !(x && y)` error: equality checks against true are unnecessary - --> tests/ui/needless_bool/fixable.rs:157:8 + --> tests/ui/needless_bool/fixable.rs:147:8 | LL | if x == true {}; | ^^^^^^^^^ help: try: `x` @@ -141,25 +141,25 @@ LL | if x == true {}; = help: to override `-D warnings` add `#[allow(clippy::bool_comparison)]` error: equality checks against false can be replaced by a negation - --> tests/ui/needless_bool/fixable.rs:162:8 + --> tests/ui/needless_bool/fixable.rs:152:8 | LL | if x == false {}; | ^^^^^^^^^^ help: try: `!x` error: equality checks against true are unnecessary - --> tests/ui/needless_bool/fixable.rs:173:8 + --> tests/ui/needless_bool/fixable.rs:163:8 | LL | if x == true {}; | ^^^^^^^^^ help: try: `x` error: equality checks against false can be replaced by a negation - --> tests/ui/needless_bool/fixable.rs:175:8 + --> tests/ui/needless_bool/fixable.rs:165:8 | LL | if x == false {}; | ^^^^^^^^^^ help: try: `!x` error: this if-then-else expression returns a bool literal - --> tests/ui/needless_bool/fixable.rs:185:12 + --> tests/ui/needless_bool/fixable.rs:175:12 | LL | } else if returns_bool() { | ____________^ @@ -170,7 +170,7 @@ LL | | }; | |_____^ help: you can reduce it to: `{ !returns_bool() }` error: this if-then-else expression returns a bool literal - --> tests/ui/needless_bool/fixable.rs:199:5 + --> tests/ui/needless_bool/fixable.rs:189:5 | LL | / if unsafe { no(4) } & 1 != 0 { LL | | true @@ -180,37 +180,37 @@ LL | | }; | |_____^ help: you can reduce it to: `(unsafe { no(4) } & 1 != 0)` error: this if-then-else expression returns a bool literal - --> tests/ui/needless_bool/fixable.rs:205:30 + --> tests/ui/needless_bool/fixable.rs:195:30 | LL | let _brackets_unneeded = if unsafe { no(4) } & 1 != 0 { true } else { false }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `unsafe { no(4) } & 1 != 0` error: this if-then-else expression returns a bool literal - --> tests/ui/needless_bool/fixable.rs:209:9 + --> tests/ui/needless_bool/fixable.rs:199:9 | LL | if unsafe { no(4) } & 1 != 0 { true } else { false } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `(unsafe { no(4) } & 1 != 0)` error: this if-then-else expression returns a bool literal - --> tests/ui/needless_bool/fixable.rs:221:14 + --> tests/ui/needless_bool/fixable.rs:211:14 | LL | let _x = if a && b { true } else { false }.then(|| todo!()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `(a && b)` error: this if-then-else expression returns a bool literal - --> tests/ui/needless_bool/fixable.rs:223:14 + --> tests/ui/needless_bool/fixable.rs:213:14 | LL | let _x = if a && b { true } else { false } as u8; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `(a && b)` error: this if-then-else expression returns a bool literal - --> tests/ui/needless_bool/fixable.rs:227:14 + --> tests/ui/needless_bool/fixable.rs:217:14 | LL | let _x = if a { true } else { false }.then(|| todo!()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `a` error: this if-then-else expression returns a bool literal - --> tests/ui/needless_bool/fixable.rs:239:5 + --> tests/ui/needless_bool/fixable.rs:229:5 | LL | / if test_expr!(x) { LL | | true diff --git a/tests/ui/needless_bool/simple.rs b/tests/ui/needless_bool/simple.rs index 40ffeae6c56fa..c5d2ef51fade5 100644 --- a/tests/ui/needless_bool/simple.rs +++ b/tests/ui/needless_bool/simple.rs @@ -1,12 +1,5 @@ #![warn(clippy::needless_bool)] -#![allow( - unused, - dead_code, - clippy::no_effect, - clippy::if_same_then_else, - clippy::needless_return, - clippy::branches_sharing_code -)] +#![expect(clippy::if_same_then_else, clippy::needless_return)] fn main() { let x = true; diff --git a/tests/ui/needless_bool/simple.stderr b/tests/ui/needless_bool/simple.stderr index 077e9b5df47cf..07711b9234cdd 100644 --- a/tests/ui/needless_bool/simple.stderr +++ b/tests/ui/needless_bool/simple.stderr @@ -1,5 +1,5 @@ error: this if-then-else expression will always return true - --> tests/ui/needless_bool/simple.rs:14:5 + --> tests/ui/needless_bool/simple.rs:7:5 | LL | / if x { LL | | true @@ -12,7 +12,7 @@ LL | | }; = help: to override `-D warnings` add `#[allow(clippy::needless_bool)]` error: this if-then-else expression will always return false - --> tests/ui/needless_bool/simple.rs:20:5 + --> tests/ui/needless_bool/simple.rs:13:5 | LL | / if x { LL | | false @@ -22,7 +22,7 @@ LL | | }; | |_____^ error: this if-then-else expression will always return true - --> tests/ui/needless_bool/simple.rs:36:5 + --> tests/ui/needless_bool/simple.rs:29:5 | LL | / if x { LL | | return true; @@ -32,7 +32,7 @@ LL | | }; | |_____^ error: this if-then-else expression will always return false - --> tests/ui/needless_bool/simple.rs:45:5 + --> tests/ui/needless_bool/simple.rs:38:5 | LL | / if x { LL | | return false; diff --git a/tests/ui/needless_bool_assign.fixed b/tests/ui/needless_bool_assign.fixed index 8fd5720381404..3bd592b471e4b 100644 --- a/tests/ui/needless_bool_assign.fixed +++ b/tests/ui/needless_bool_assign.fixed @@ -1,4 +1,3 @@ -#![allow(unused)] #![warn(clippy::needless_bool_assign)] fn random() -> bool { diff --git a/tests/ui/needless_bool_assign.rs b/tests/ui/needless_bool_assign.rs index 4721ab433b327..1279176cb20a2 100644 --- a/tests/ui/needless_bool_assign.rs +++ b/tests/ui/needless_bool_assign.rs @@ -1,4 +1,3 @@ -#![allow(unused)] #![warn(clippy::needless_bool_assign)] fn random() -> bool { diff --git a/tests/ui/needless_bool_assign.stderr b/tests/ui/needless_bool_assign.stderr index 34ff782f34a35..3dfea7cd1af99 100644 --- a/tests/ui/needless_bool_assign.stderr +++ b/tests/ui/needless_bool_assign.stderr @@ -1,5 +1,5 @@ error: this if-then-else expression assigns a bool literal - --> tests/ui/needless_bool_assign.rs:13:5 + --> tests/ui/needless_bool_assign.rs:12:5 | LL | / if random() && random() { LL | | a.field = true; @@ -12,7 +12,7 @@ LL | | } = help: to override `-D warnings` add `#[allow(clippy::needless_bool_assign)]` error: this if-then-else expression assigns a bool literal - --> tests/ui/needless_bool_assign.rs:19:5 + --> tests/ui/needless_bool_assign.rs:18:5 | LL | / if random() && random() { LL | | a.field = false; @@ -22,7 +22,7 @@ LL | | } | |_____^ help: you can reduce it to: `a.field = !(random() && random());` error: this if-then-else expression assigns a bool literal - --> tests/ui/needless_bool_assign.rs:34:5 + --> tests/ui/needless_bool_assign.rs:33:5 | LL | / if random() { LL | | a.field = true; @@ -32,7 +32,7 @@ LL | | } | |_____^ help: you can reduce it to: `random(); a.field = true;` error: this `if` has identical blocks - --> tests/ui/needless_bool_assign.rs:34:17 + --> tests/ui/needless_bool_assign.rs:33:17 | LL | if random() { | _________________^ @@ -41,7 +41,7 @@ LL | | } else { | |_____^ | note: same as this - --> tests/ui/needless_bool_assign.rs:36:12 + --> tests/ui/needless_bool_assign.rs:35:12 | LL | } else { | ____________^ @@ -52,7 +52,7 @@ LL | | } = help: to override `-D warnings` add `#[allow(clippy::if_same_then_else)]` error: this if-then-else expression assigns a bool literal - --> tests/ui/needless_bool_assign.rs:54:12 + --> tests/ui/needless_bool_assign.rs:53:12 | LL | } else if x || y { | ____________^ @@ -63,7 +63,7 @@ LL | | } | |_____^ help: you can reduce it to: `{ z = x || y; }` error: this if-then-else expression assigns a bool literal - --> tests/ui/needless_bool_assign.rs:77:5 + --> tests/ui/needless_bool_assign.rs:76:5 | LL | / if invoke!(must_keep, x, y) { LL | | dot_0!(skip) = false; From 6c8aae7088feb3ab530ab9694481fa367fa4226a Mon Sep 17 00:00:00 2001 From: Jose Torres Date: Tue, 9 Jun 2026 22:22:55 -0400 Subject: [PATCH 10/77] refactor TypeRelativePath::AssocItem to use AliasTerm, remove alias_ty_kind_from_def_id and new_from_def_id --- clippy_utils/src/ty/mod.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/clippy_utils/src/ty/mod.rs b/clippy_utils/src/ty/mod.rs index 056eb818c1ac3..a944e91db0c0e 100644 --- a/clippy_utils/src/ty/mod.rs +++ b/clippy_utils/src/ty/mod.rs @@ -1050,11 +1050,13 @@ pub fn make_projection<'tcx>( #[cfg(debug_assertions)] assert_generic_args_match(tcx, assoc_item.def_id, args); - Some(AliasTy::new_from_args( - tcx, - ty::AliasTyKind::new_from_def_id(tcx, assoc_item.def_id), - args, - )) + let kind = if let DefKind::Impl { of_trait: false } = tcx.def_kind(tcx.parent(assoc_item.def_id)) { + ty::AliasTyKind::Inherent { def_id: assoc_item.def_id } + } else { + ty::AliasTyKind::Projection { def_id: assoc_item.def_id } + }; + + Some(AliasTy::new_from_args(tcx, kind, args)) } helper( tcx, From c60910b5eb230a741b3dc636f2f4be53caf0629d Mon Sep 17 00:00:00 2001 From: Jose Torres Date: Tue, 9 Jun 2026 22:40:38 -0400 Subject: [PATCH 11/77] Remove unused is_type_const from hir::TraitItemKind --- clippy_lints/src/non_copy_const.rs | 4 ++-- clippy_lints/src/types/mod.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/non_copy_const.rs b/clippy_lints/src/non_copy_const.rs index fabc1f5c74ee0..22d7d83d730d9 100644 --- a/clippy_lints/src/non_copy_const.rs +++ b/clippy_lints/src/non_copy_const.rs @@ -757,7 +757,7 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst<'tcx> { } fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) { - if let TraitItemKind::Const(_, ct_rhs_opt, _) = item.kind + if let TraitItemKind::Const(_, ct_rhs_opt) = item.kind && let ty = cx.tcx.type_of(item.owner_id).instantiate_identity().skip_norm_wip() && match self.is_ty_freeze(cx.tcx, cx.typing_env(), ty) { IsFreeze::No => true, @@ -958,7 +958,7 @@ fn get_const_hir_value<'tcx>( { match tcx.hir_node(tcx.local_def_id_to_hir_id(did)) { Node::ImplItem(item) if let ImplItemKind::Const(.., ct_rhs) = item.kind => (did, ct_rhs), - Node::TraitItem(item) if let TraitItemKind::Const(_, Some(ct_rhs), _) = item.kind => (did, ct_rhs), + Node::TraitItem(item) if let TraitItemKind::Const(_, Some(ct_rhs)) = item.kind => (did, ct_rhs), _ => return None, } }, diff --git a/clippy_lints/src/types/mod.rs b/clippy_lints/src/types/mod.rs index 17f1adf6960f0..f6c6e3848a4c4 100644 --- a/clippy_lints/src/types/mod.rs +++ b/clippy_lints/src/types/mod.rs @@ -514,7 +514,7 @@ impl<'tcx> LateLintPass<'tcx> for Types { }; match item.kind { - TraitItemKind::Const(ty, _, _) | TraitItemKind::Type(_, Some(ty)) => { + TraitItemKind::Const(ty, _) | TraitItemKind::Type(_, Some(ty)) => { self.check_ty(cx, ty, context); }, TraitItemKind::Fn(ref sig, trait_method) => { From 2ae17355e34cb079ab4ef3b9054dbf50d79db293 Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Wed, 20 May 2026 15:03:26 +0200 Subject: [PATCH 12/77] New `by_ref_peekable_peek` lint --- CHANGELOG.md | 1 + clippy_lints/src/declared_lints.rs | 1 + .../src/methods/by_ref_peekable_peek.rs | 84 +++++++++++++++ clippy_lints/src/methods/mod.rs | 38 +++++++ tests/ui/by_ref_peekable_peek.1.fixed | 55 ++++++++++ tests/ui/by_ref_peekable_peek.2.fixed | 55 ++++++++++ tests/ui/by_ref_peekable_peek.3.fixed | 55 ++++++++++ tests/ui/by_ref_peekable_peek.rs | 55 ++++++++++ tests/ui/by_ref_peekable_peek.stderr | 101 ++++++++++++++++++ 9 files changed, 445 insertions(+) create mode 100644 clippy_lints/src/methods/by_ref_peekable_peek.rs create mode 100644 tests/ui/by_ref_peekable_peek.1.fixed create mode 100644 tests/ui/by_ref_peekable_peek.2.fixed create mode 100644 tests/ui/by_ref_peekable_peek.3.fixed create mode 100644 tests/ui/by_ref_peekable_peek.rs create mode 100644 tests/ui/by_ref_peekable_peek.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index f53143e564b6c..5de08fbbdf03a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6576,6 +6576,7 @@ Released 2018-09-13 [`boxed_local`]: https://rust-lang.github.io/rust-clippy/master/index.html#boxed_local [`branches_sharing_code`]: https://rust-lang.github.io/rust-clippy/master/index.html#branches_sharing_code [`builtin_type_shadow`]: https://rust-lang.github.io/rust-clippy/master/index.html#builtin_type_shadow +[`by_ref_peekable_peek`]: https://rust-lang.github.io/rust-clippy/master/index.html#by_ref_peekable_peek [`byte_char_slices`]: https://rust-lang.github.io/rust-clippy/master/index.html#byte_char_slices [`bytes_count_to_len`]: https://rust-lang.github.io/rust-clippy/master/index.html#bytes_count_to_len [`bytes_nth`]: https://rust-lang.github.io/rust-clippy/master/index.html#bytes_nth diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 4218d1fdc2901..6c73e2501dabe 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -360,6 +360,7 @@ pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[ crate::mem_replace::MEM_REPLACE_WITH_DEFAULT_INFO, crate::mem_replace::MEM_REPLACE_WITH_UNINIT_INFO, crate::methods::BIND_INSTEAD_OF_MAP_INFO, + crate::methods::BY_REF_PEEKABLE_PEEK_INFO, crate::methods::BYTES_COUNT_TO_LEN_INFO, crate::methods::BYTES_NTH_INFO, crate::methods::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS_INFO, diff --git a/clippy_lints/src/methods/by_ref_peekable_peek.rs b/clippy_lints/src/methods/by_ref_peekable_peek.rs new file mode 100644 index 0000000000000..1faaf2c9c8e43 --- /dev/null +++ b/clippy_lints/src/methods/by_ref_peekable_peek.rs @@ -0,0 +1,84 @@ +use crate::clippy_utils::res::MaybeTypeckRes; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::res::{MaybeDef, MaybeResPath as _}; +use clippy_utils::sugg::Sugg; +use clippy_utils::sym; +use clippy_utils::ty::implements_trait; +use rustc_ast::BindingMode; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind, LetStmt, Node, PatKind}; +use rustc_lint::LateContext; +use rustc_middle::ty; + +use super::BY_REF_PEEKABLE_PEEK; + +pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>) { + if let ExprKind::MethodCall(maybe_peekable, peekable_recv, [], _) = recv.kind + && maybe_peekable.ident.name == sym::peekable + && !peekable_recv.span.from_expansion() + && let ExprKind::MethodCall(maybe_by_ref, by_ref_recv, [], _) = peekable_recv.kind + && maybe_by_ref.ident.name == sym::by_ref + && !by_ref_recv.span.from_expansion() + && [peekable_recv, recv] + .into_iter() + .all(|e| cx.ty_based_def(e).opt_parent(cx).is_diag_item(cx, sym::Iterator)) + { + span_lint_and_then( + cx, + BY_REF_PEEKABLE_PEEK, + expr.span, + "calling `.by_ref().peekable().peek()` will advance the underlying iterator and consume its first output", + |diag| { + let span = by_ref_recv.span.shrink_to_hi().with_hi(expr.span.hi()); + if let ty::Ref(_, iter_ty, _) = cx.typeck_results().expr_ty_adjusted(by_ref_recv).kind() + && let Some(clone_trait) = cx.tcx.lang_items().clone_trait() + && implements_trait(cx, *iter_ty, clone_trait, &[]) + { + diag.span_suggestion_verbose( + span, + "to peek the first item without advancing the underlying iterator, use", + ".clone().next().as_ref()", + Applicability::MaybeIncorrect, + ); + } + diag.span_suggestion_verbose( + span, + "to advance the underlying iterator, use", + ".next().as_ref()", + Applicability::MaybeIncorrect, + ); + // If the iterator is a local variable, initialized through a simple binding with an inferred + // initialization expression, suggest making the initialization expression peekable. + if let Some(iter_local_id) = by_ref_recv.res_local_id() + && let Node::LetStmt(LetStmt { + pat: let_pat, + ty: None, + init: Some(init_expr), + els: None, + span: let_stmt_span, + .. + }) = cx.tcx.parent_hir_node(iter_local_id) + && let PatKind::Binding(BindingMode::MUT, _, _, None) = let_pat.kind + && !let_stmt_span.from_expansion() + // Changing the type of the iterator may prevent the code from compiling + && let mut app = Applicability::MaybeIncorrect + && let sugg = + Sugg::hir_with_context(cx, init_expr, let_stmt_span.ctxt(), "_", &mut app).maybe_paren() + { + diag.multipart_suggestion( + "to make the iterator peekable, use", + vec![ + (init_expr.span.source_callsite(), format!("{sugg}.peekable()")), + (recv.span.with_lo(by_ref_recv.span.hi()), String::new()), + ], + app, + ); + } else { + diag.help( + "you might want to transform the iterator itself using `.peekable()` without using `.by_ref()`", + ); + } + }, + ); + } +} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index a8a2fc55c9019..6b271a4a6371a 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1,4 +1,5 @@ mod bind_instead_of_map; +mod by_ref_peekable_peek; mod bytecount; mod bytes_count_to_len; mod bytes_nth; @@ -201,6 +202,39 @@ declare_clippy_lint! { "using `Option.and_then(|x| Some(y))`, which is more succinctly expressed as `map(|x| y)`" } +declare_clippy_lint! { + /// ### What it does + /// Checks for usages of `Iterator::by_ref().peekable().peek()`. + /// + /// ### Why is this bad? + /// While it might look like this will allow peeking on the first + /// element of an iterator without consuming it and without consuming + /// the iterator itself, it will in practice consume the first element. + /// + /// The implementation of `Peekable::peek()` produces the first element + /// of the underlying iterator, and stores it internally so that it can + /// be later produced. As a consequence, it advances the underlying + /// iterator, whose `.next()` method will now produce its second element. + /// + /// ### Example + /// ```no_run + /// let mut iter = [1, 2, 3].into_iter(); + /// let x = iter.by_ref().peekable().peek(); // 1 + /// let y = iter.by_ref().peekable().peek(); // 2 + /// ``` + /// If this does what you intended, use the following instead, which is + /// shorter and clearer: + /// ```no_run + /// let mut iter = [1, 2, 3].into_iter(); + /// let x = iter.next().as_ref(); // 1 + /// let y = iter.next().as_ref(); // 2 + /// ``` + #[clippy::version = "1.98.0"] + pub BY_REF_PEEKABLE_PEEK, + suspicious, + "Using `.by_ref().peekable().peek()` on an iterator" +} + declare_clippy_lint! { /// ### What it does /// It checks for `str::bytes().count()` and suggests replacing it with @@ -4837,6 +4871,7 @@ impl_lint_pass!(Methods => [ BIND_INSTEAD_OF_MAP, BYTES_COUNT_TO_LEN, BYTES_NTH, + BY_REF_PEEKABLE_PEEK, CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS, CHARS_LAST_CMP, CHARS_NEXT_CMP, @@ -5606,6 +5641,9 @@ impl Methods { unnecessary_lazy_eval::check(cx, expr, recv, arg, "or"); } }, + (sym::peek, []) => { + by_ref_peekable_peek::check(cx, expr, recv); + }, (sym::push, [arg]) => { path_buf_push_overwrite::check(cx, expr, arg); }, diff --git a/tests/ui/by_ref_peekable_peek.1.fixed b/tests/ui/by_ref_peekable_peek.1.fixed new file mode 100644 index 0000000000000..e40b745245568 --- /dev/null +++ b/tests/ui/by_ref_peekable_peek.1.fixed @@ -0,0 +1,55 @@ +#![warn(clippy::by_ref_peekable_peek)] + +struct S; + +impl S { + fn by_ref(&mut self) -> impl Iterator { + std::iter::empty() + } +} + +macro_rules! mac { + ($x:expr) => { + $x.by_ref().peekable().peek() + }; +} + +fn with_non_clone_parameter(i: &mut impl Iterator) { + // This won't suggest `.clone().next().as_ref()` as `i` is not `Clone` + let _: Option<&i32> = i.next().as_ref(); + //~^ by_ref_peekable_peek +} + +fn with_cloneable_local_iterator(a: Vec) { + let mut i = a.into_iter(); + let _: Option<&i32> = i.clone().next().as_ref(); + //~^ by_ref_peekable_peek +} + +fn with_cloneable_local_iterator_from_macro() { + macro_rules! mac { + () => { + [1, 2, 3].into_iter() + }; + } + let mut i = mac!(); + let _: Option<&i32> = i.clone().next().as_ref(); + //~^ by_ref_peekable_peek +} + +fn main() { + let mut iter = [1, 2, 3].into_iter(); + let _: Option<&i32> = iter.clone().next().as_ref(); + //~^ by_ref_peekable_peek + #[expect(clippy::needless_borrow)] + #[allow(clippy::unnecessary_mut_passed)] // For the `.clone().next().as_ref()` suggestion + let _: Option<&i32> = (&mut iter).clone().next().as_ref(); + //~^ by_ref_peekable_peek + + // Do not lint if `by_ref()` is not the one on `Iterator` + let _: Option<&i32> = S.by_ref().peekable().peek(); + + // Do not lint if coming from a macro, as we cannot ensure + // that all uses of `.by_ref()` will be `Iterator::by_ref()`. + let _: Option<&i32> = mac!(iter); +} diff --git a/tests/ui/by_ref_peekable_peek.2.fixed b/tests/ui/by_ref_peekable_peek.2.fixed new file mode 100644 index 0000000000000..b9b7cdeaf5922 --- /dev/null +++ b/tests/ui/by_ref_peekable_peek.2.fixed @@ -0,0 +1,55 @@ +#![warn(clippy::by_ref_peekable_peek)] + +struct S; + +impl S { + fn by_ref(&mut self) -> impl Iterator { + std::iter::empty() + } +} + +macro_rules! mac { + ($x:expr) => { + $x.by_ref().peekable().peek() + }; +} + +fn with_non_clone_parameter(i: &mut impl Iterator) { + // This won't suggest `.clone().next().as_ref()` as `i` is not `Clone` + let _: Option<&i32> = i.next().as_ref(); + //~^ by_ref_peekable_peek +} + +fn with_cloneable_local_iterator(a: Vec) { + let mut i = a.into_iter(); + let _: Option<&i32> = i.next().as_ref(); + //~^ by_ref_peekable_peek +} + +fn with_cloneable_local_iterator_from_macro() { + macro_rules! mac { + () => { + [1, 2, 3].into_iter() + }; + } + let mut i = mac!(); + let _: Option<&i32> = i.next().as_ref(); + //~^ by_ref_peekable_peek +} + +fn main() { + let mut iter = [1, 2, 3].into_iter(); + let _: Option<&i32> = iter.next().as_ref(); + //~^ by_ref_peekable_peek + #[expect(clippy::needless_borrow)] + #[allow(clippy::unnecessary_mut_passed)] // For the `.clone().next().as_ref()` suggestion + let _: Option<&i32> = (&mut iter).next().as_ref(); + //~^ by_ref_peekable_peek + + // Do not lint if `by_ref()` is not the one on `Iterator` + let _: Option<&i32> = S.by_ref().peekable().peek(); + + // Do not lint if coming from a macro, as we cannot ensure + // that all uses of `.by_ref()` will be `Iterator::by_ref()`. + let _: Option<&i32> = mac!(iter); +} diff --git a/tests/ui/by_ref_peekable_peek.3.fixed b/tests/ui/by_ref_peekable_peek.3.fixed new file mode 100644 index 0000000000000..67256fc86887c --- /dev/null +++ b/tests/ui/by_ref_peekable_peek.3.fixed @@ -0,0 +1,55 @@ +#![warn(clippy::by_ref_peekable_peek)] + +struct S; + +impl S { + fn by_ref(&mut self) -> impl Iterator { + std::iter::empty() + } +} + +macro_rules! mac { + ($x:expr) => { + $x.by_ref().peekable().peek() + }; +} + +fn with_non_clone_parameter(i: &mut impl Iterator) { + // This won't suggest `.clone().next().as_ref()` as `i` is not `Clone` + let _: Option<&i32> = i.next().as_ref(); + //~^ by_ref_peekable_peek +} + +fn with_cloneable_local_iterator(a: Vec) { + let mut i = a.into_iter().peekable(); + let _: Option<&i32> = i.peek(); + //~^ by_ref_peekable_peek +} + +fn with_cloneable_local_iterator_from_macro() { + macro_rules! mac { + () => { + [1, 2, 3].into_iter() + }; + } + let mut i = mac!().peekable(); + let _: Option<&i32> = i.peek(); + //~^ by_ref_peekable_peek +} + +fn main() { + let mut iter = [1, 2, 3].into_iter().peekable(); + let _: Option<&i32> = iter.peek(); + //~^ by_ref_peekable_peek + #[expect(clippy::needless_borrow)] + #[allow(clippy::unnecessary_mut_passed)] // For the `.clone().next().as_ref()` suggestion + let _: Option<&i32> = (&mut iter).clone().next().as_ref(); + //~^ by_ref_peekable_peek + + // Do not lint if `by_ref()` is not the one on `Iterator` + let _: Option<&i32> = S.by_ref().peekable().peek(); + + // Do not lint if coming from a macro, as we cannot ensure + // that all uses of `.by_ref()` will be `Iterator::by_ref()`. + let _: Option<&i32> = mac!(iter); +} diff --git a/tests/ui/by_ref_peekable_peek.rs b/tests/ui/by_ref_peekable_peek.rs new file mode 100644 index 0000000000000..d8ccb8b74fb64 --- /dev/null +++ b/tests/ui/by_ref_peekable_peek.rs @@ -0,0 +1,55 @@ +#![warn(clippy::by_ref_peekable_peek)] + +struct S; + +impl S { + fn by_ref(&mut self) -> impl Iterator { + std::iter::empty() + } +} + +macro_rules! mac { + ($x:expr) => { + $x.by_ref().peekable().peek() + }; +} + +fn with_non_clone_parameter(i: &mut impl Iterator) { + // This won't suggest `.clone().next().as_ref()` as `i` is not `Clone` + let _: Option<&i32> = i.by_ref().peekable().peek(); + //~^ by_ref_peekable_peek +} + +fn with_cloneable_local_iterator(a: Vec) { + let mut i = a.into_iter(); + let _: Option<&i32> = i.by_ref().peekable().peek(); + //~^ by_ref_peekable_peek +} + +fn with_cloneable_local_iterator_from_macro() { + macro_rules! mac { + () => { + [1, 2, 3].into_iter() + }; + } + let mut i = mac!(); + let _: Option<&i32> = i.by_ref().peekable().peek(); + //~^ by_ref_peekable_peek +} + +fn main() { + let mut iter = [1, 2, 3].into_iter(); + let _: Option<&i32> = iter.by_ref().peekable().peek(); + //~^ by_ref_peekable_peek + #[expect(clippy::needless_borrow)] + #[allow(clippy::unnecessary_mut_passed)] // For the `.clone().next().as_ref()` suggestion + let _: Option<&i32> = (&mut iter).by_ref().peekable().peek(); + //~^ by_ref_peekable_peek + + // Do not lint if `by_ref()` is not the one on `Iterator` + let _: Option<&i32> = S.by_ref().peekable().peek(); + + // Do not lint if coming from a macro, as we cannot ensure + // that all uses of `.by_ref()` will be `Iterator::by_ref()`. + let _: Option<&i32> = mac!(iter); +} diff --git a/tests/ui/by_ref_peekable_peek.stderr b/tests/ui/by_ref_peekable_peek.stderr new file mode 100644 index 0000000000000..5a284775e04f3 --- /dev/null +++ b/tests/ui/by_ref_peekable_peek.stderr @@ -0,0 +1,101 @@ +error: calling `.by_ref().peekable().peek()` will advance the underlying iterator and consume its first output + --> tests/ui/by_ref_peekable_peek.rs:19:27 + | +LL | let _: Option<&i32> = i.by_ref().peekable().peek(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: you might want to transform the iterator itself using `.peekable()` without using `.by_ref()` + = note: `-D clippy::by-ref-peekable-peek` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::by_ref_peekable_peek)]` +help: to advance the underlying iterator, use + | +LL - let _: Option<&i32> = i.by_ref().peekable().peek(); +LL + let _: Option<&i32> = i.next().as_ref(); + | + +error: calling `.by_ref().peekable().peek()` will advance the underlying iterator and consume its first output + --> tests/ui/by_ref_peekable_peek.rs:25:27 + | +LL | let _: Option<&i32> = i.by_ref().peekable().peek(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: to peek the first item without advancing the underlying iterator, use + | +LL - let _: Option<&i32> = i.by_ref().peekable().peek(); +LL + let _: Option<&i32> = i.clone().next().as_ref(); + | +help: to advance the underlying iterator, use + | +LL - let _: Option<&i32> = i.by_ref().peekable().peek(); +LL + let _: Option<&i32> = i.next().as_ref(); + | +help: to make the iterator peekable, use + | +LL ~ let mut i = a.into_iter().peekable(); +LL ~ let _: Option<&i32> = i.peek(); + | + +error: calling `.by_ref().peekable().peek()` will advance the underlying iterator and consume its first output + --> tests/ui/by_ref_peekable_peek.rs:36:27 + | +LL | let _: Option<&i32> = i.by_ref().peekable().peek(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: to peek the first item without advancing the underlying iterator, use + | +LL - let _: Option<&i32> = i.by_ref().peekable().peek(); +LL + let _: Option<&i32> = i.clone().next().as_ref(); + | +help: to advance the underlying iterator, use + | +LL - let _: Option<&i32> = i.by_ref().peekable().peek(); +LL + let _: Option<&i32> = i.next().as_ref(); + | +help: to make the iterator peekable, use + | +LL ~ let mut i = mac!().peekable(); +LL ~ let _: Option<&i32> = i.peek(); + | + +error: calling `.by_ref().peekable().peek()` will advance the underlying iterator and consume its first output + --> tests/ui/by_ref_peekable_peek.rs:42:27 + | +LL | let _: Option<&i32> = iter.by_ref().peekable().peek(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: to peek the first item without advancing the underlying iterator, use + | +LL - let _: Option<&i32> = iter.by_ref().peekable().peek(); +LL + let _: Option<&i32> = iter.clone().next().as_ref(); + | +help: to advance the underlying iterator, use + | +LL - let _: Option<&i32> = iter.by_ref().peekable().peek(); +LL + let _: Option<&i32> = iter.next().as_ref(); + | +help: to make the iterator peekable, use + | +LL ~ let mut iter = [1, 2, 3].into_iter().peekable(); +LL ~ let _: Option<&i32> = iter.peek(); + | + +error: calling `.by_ref().peekable().peek()` will advance the underlying iterator and consume its first output + --> tests/ui/by_ref_peekable_peek.rs:46:27 + | +LL | let _: Option<&i32> = (&mut iter).by_ref().peekable().peek(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: you might want to transform the iterator itself using `.peekable()` without using `.by_ref()` +help: to peek the first item without advancing the underlying iterator, use + | +LL - let _: Option<&i32> = (&mut iter).by_ref().peekable().peek(); +LL + let _: Option<&i32> = (&mut iter).clone().next().as_ref(); + | +help: to advance the underlying iterator, use + | +LL - let _: Option<&i32> = (&mut iter).by_ref().peekable().peek(); +LL + let _: Option<&i32> = (&mut iter).next().as_ref(); + | + +error: aborting due to 5 previous errors + From 85daf6e7d0ea3a811f5caffc3b8bd12129b365c8 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Thu, 11 Jun 2026 18:14:56 +0200 Subject: [PATCH 13/77] Merge commit '5f29bd0df789f92cd494061f9223dbb5d96e8e16' into clippy-subtree-update --- CHANGELOG.md | 100 ++- CONTRIBUTING.md | 34 +- Cargo.toml | 2 +- book/src/configuration.md | 2 +- book/src/development/adding_lints.md | 15 +- book/src/development/defining_lints.md | 11 +- book/src/lint_configuration.md | 28 +- book/src/lints.md | 7 +- build.rs | 2 - clippy_config/src/conf.rs | 216 ++++- clippy_config/src/types.rs | 9 + clippy_dev/src/new_lint.rs | 27 +- clippy_dummy/Cargo.toml | 4 +- clippy_lints/src/attrs/inline_always.rs | 9 +- clippy_lints/src/attrs/mod.rs | 32 +- clippy_lints/src/attrs/utils.rs | 47 +- clippy_lints/src/combined_early_pass.rs | 92 ++ clippy_lints/src/combined_late_pass.rs | 106 +++ clippy_lints/src/declared_lints.rs | 4 +- clippy_lints/src/default_numeric_fallback.rs | 6 +- clippy_lints/src/deprecated_lints.rs | 2 + clippy_lints/src/dereference.rs | 55 +- clippy_lints/src/disallowed_methods.rs | 125 ++- clippy_lints/src/disallowed_types.rs | 167 +++- clippy_lints/src/doc/mod.rs | 48 +- clippy_lints/src/empty_line_after.rs | 128 +-- clippy_lints/src/escape.rs | 113 ++- clippy_lints/src/excessive_bools.rs | 48 +- clippy_lints/src/functions/must_use.rs | 60 +- clippy_lints/src/functions/result.rs | 34 +- clippy_lints/src/inline_trait_bounds.rs | 33 +- clippy_lints/src/large_const_arrays.rs | 36 +- clippy_lints/src/large_futures.rs | 4 +- clippy_lints/src/lib.rs | 828 +++++++++--------- clippy_lints/src/lifetimes.rs | 50 +- .../src/loops/explicit_counter_loop.rs | 6 +- clippy_lints/src/loops/for_unbounded_range.rs | 42 + clippy_lints/src/loops/infinite_loop.rs | 32 +- clippy_lints/src/loops/mod.rs | 32 + clippy_lints/src/loops/needless_range_loop.rs | 4 +- clippy_lints/src/loops/never_loop.rs | 90 +- clippy_lints/src/loops/utils.rs | 15 +- clippy_lints/src/manual_non_exhaustive.rs | 22 +- clippy_lints/src/manual_option_as_slice.rs | 2 +- clippy_lints/src/manual_pop_if.rs | 2 +- clippy_lints/src/matches/collapsible_match.rs | 36 +- .../matches/infallible_destructuring_match.rs | 28 +- .../src/matches/redundant_pattern_match.rs | 161 ++-- .../matches/significant_drop_in_scrutinee.rs | 3 +- clippy_lints/src/mem_replace.rs | 27 +- .../methods/from_iter_instead_of_collect.rs | 81 -- .../src/methods/iter_cloned_collect.rs | 38 +- clippy_lints/src/methods/iter_next_slice.rs | 31 +- .../src/methods/manual_is_variant_and.rs | 32 +- clippy_lints/src/methods/mod.rs | 68 +- .../src/methods/range_zip_with_len.rs | 4 +- .../operators/manual_isolate_lowest_one.rs | 167 ++++ clippy_lints/src/operators/mod.rs | 27 + clippy_lints/src/operators/modulo_one.rs | 23 +- clippy_lints/src/ranges.rs | 18 +- clippy_lints/src/redundant_closure_call.rs | 120 +-- .../src/significant_drop_tightening.rs | 3 +- clippy_lints/src/single_range_in_vec_init.rs | 150 ++-- .../src/transmute/transmuting_null.rs | 8 +- clippy_lints/src/types/borrowed_box.rs | 85 +- clippy_lints/src/unused_async.rs | 35 +- clippy_lints/src/utils/author.rs | 4 +- clippy_lints/src/utils/dump_hir.rs | 4 +- clippy_lints/src/with_capacity_zero.rs | 78 ++ clippy_utils/README.md | 2 +- clippy_utils/src/attrs.rs | 84 +- clippy_utils/src/consts.rs | 25 + clippy_utils/src/disallowed_profiles.rs | 180 ++++ clippy_utils/src/lib.rs | 24 +- clippy_utils/src/macros.rs | 28 + clippy_utils/src/msrvs.rs | 1 + clippy_utils/src/qualify_min_const_fn.rs | 10 +- clippy_utils/src/sym.rs | 4 +- rust-toolchain.toml | 2 +- src/driver.rs | 81 +- tests/integration.rs | 12 +- .../disallowed_profiles_methods/clippy.toml | 13 + .../disallowed_profiles_methods/main.rs | 78 ++ .../disallowed_profiles_methods/main.stderr | 72 ++ .../disallowed_profiles_types/clippy.toml | 13 + .../ui-toml/disallowed_profiles_types/main.rs | 61 ++ .../disallowed_profiles_types/main.stderr | 78 ++ ...ub_underscore_fields.all_pub_fields.stderr | 14 +- .../pub_underscore_fields.exported.stderr | 2 +- .../pub_underscore_fields.rs | 1 - tests/ui-toml/ref_option/ref_option.all.fixed | 2 +- .../ref_option/ref_option.private.fixed | 2 +- tests/ui-toml/ref_option/ref_option.rs | 2 +- .../renamed_function_params.default.stderr | 12 +- .../renamed_function_params.extend.stderr | 8 +- .../renamed_function_params.rs | 1 - tests/ui-toml/semicolon_block/both.fixed | 10 +- tests/ui-toml/semicolon_block/both.rs | 10 +- tests/ui-toml/semicolon_block/both.stderr | 8 +- .../semicolon_inside_block.fixed | 7 +- .../semicolon_block/semicolon_inside_block.rs | 7 +- .../semicolon_inside_block.stderr | 2 +- .../semicolon_outside_block.fixed | 7 +- .../semicolon_outside_block.rs | 7 +- .../semicolon_outside_block.stderr | 6 +- tests/ui-toml/suppress_lint_in_const/test.rs | 14 +- .../suppress_lint_in_const/test.stderr | 12 +- .../conf_french_disallowed_name.rs | 2 - .../conf_french_disallowed_name.stderr | 14 +- .../conf_disallowed_methods.rs | 3 +- .../conf_disallowed_methods.stderr | 34 +- ...conf_inconsistent_struct_constructor.fixed | 4 +- .../conf_inconsistent_struct_constructor.rs | 4 +- ...onf_inconsistent_struct_constructor.stderr | 10 +- .../toml_unknown_key/conf_unknown_key.stderr | 3 + tests/ui-toml/unwrap_used/unwrap_used.fixed | 10 +- tests/ui-toml/unwrap_used/unwrap_used.rs | 10 +- tests/ui-toml/unwrap_used/unwrap_used.stderr | 56 +- .../unwrap_used_allowed.rs | 1 - .../unwrap_used_allowed.stderr | 4 +- tests/ui-toml/useless_vec/useless_vec.fixed | 2 +- tests/ui-toml/useless_vec/useless_vec.rs | 2 +- tests/ui/absurd-extreme-comparisons.rs | 8 +- tests/ui/absurd-extreme-comparisons.stderr | 36 +- tests/ui/allow_attributes.fixed | 1 - tests/ui/allow_attributes.rs | 1 - tests/ui/allow_attributes.stderr | 8 +- tests/ui/almost_complete_range.fixed | 5 +- tests/ui/almost_complete_range.rs | 5 +- tests/ui/almost_complete_range.stderr | 54 +- tests/ui/arc_with_non_send_sync.rs | 1 - tests/ui/arc_with_non_send_sync.stderr | 6 +- tests/ui/arithmetic_side_effects.rs | 6 +- tests/ui/arithmetic_side_effects.stderr | 262 +++--- tests/ui/as_conversions.rs | 2 +- tests/ui/as_ptr_cast_mut.fixed | 3 +- tests/ui/as_ptr_cast_mut.rs | 3 +- tests/ui/as_ptr_cast_mut.stderr | 2 +- tests/ui/as_ptr_cast_mut_unfixable.rs | 1 - tests/ui/as_ptr_cast_mut_unfixable.stderr | 2 +- tests/ui/assertions_on_constants.rs | 3 +- tests/ui/assertions_on_constants.stderr | 34 +- tests/ui/assertions_on_result_states.fixed | 2 +- tests/ui/assertions_on_result_states.rs | 2 +- tests/ui/assign_ops.fixed | 2 +- tests/ui/assign_ops.rs | 2 +- tests/ui/assigning_clones.fixed | 6 +- tests/ui/assigning_clones.rs | 6 +- tests/ui/assigning_clones.stderr | 60 +- tests/ui/attrs.rs | 4 +- tests/ui/author/blocks.rs | 2 +- tests/ui/author/if.rs | 1 + tests/ui/author/issue_3849.rs | 4 +- tests/ui/author/loop.rs | 6 +- tests/ui/author/macro_in_closure.rs | 2 +- tests/ui/author/macro_in_loop.rs | 2 +- tests/ui/author/matches.rs | 2 +- tests/ui/author/struct.rs | 7 +- tests/ui/auxiliary/extern_fake_libc.rs | 3 +- tests/ui/auxiliary/macro_rules.rs | 2 - tests/ui/auxiliary/option_helpers.rs | 2 +- tests/ui/auxiliary/proc_macro_attr.rs | 2 +- tests/ui/auxiliary/proc_macro_derive.rs | 8 +- tests/ui/auxiliary/proc_macros.rs | 2 +- tests/ui/await_holding_lock.rs | 2 +- tests/ui/bind_instead_of_map.fixed | 2 +- tests/ui/bind_instead_of_map.rs | 2 +- tests/ui/bind_instead_of_map_multipart.fixed | 2 +- tests/ui/bind_instead_of_map_multipart.rs | 2 +- tests/ui/blocks_in_conditions.fixed | 11 +- tests/ui/blocks_in_conditions.rs | 9 +- tests/ui/blocks_in_conditions.stderr | 20 +- tests/ui/blocks_in_conditions_2021.fixed | 2 +- tests/ui/blocks_in_conditions_2021.rs | 2 +- tests/ui/bool_assert_comparison.fixed | 3 +- tests/ui/bool_assert_comparison.rs | 3 +- tests/ui/bool_assert_comparison.stderr | 78 +- tests/ui/bool_comparison.fixed | 3 +- tests/ui/bool_comparison.rs | 3 +- tests/ui/bool_comparison.stderr | 46 +- tests/ui/bool_to_int_with_if.fixed | 1 - tests/ui/bool_to_int_with_if.rs | 1 - tests/ui/bool_to_int_with_if.stderr | 22 +- tests/ui/borrow_and_ref_as_ptr.fixed | 3 +- tests/ui/borrow_and_ref_as_ptr.rs | 3 +- tests/ui/borrow_and_ref_as_ptr.stderr | 4 +- tests/ui/borrow_as_ptr.fixed | 2 +- tests/ui/borrow_as_ptr.rs | 2 +- tests/ui/borrow_as_ptr_raw_ref.fixed | 2 +- tests/ui/borrow_as_ptr_raw_ref.rs | 2 +- tests/ui/borrow_box.stderr | 68 -- tests/ui/borrow_deref_ref.fixed | 2 - tests/ui/borrow_deref_ref.rs | 2 - tests/ui/borrow_deref_ref.stderr | 18 +- tests/ui/borrow_deref_ref_unfixable.rs | 1 - tests/ui/borrow_deref_ref_unfixable.stderr | 2 +- tests/ui/borrow_interior_mutable_const.rs | 7 +- tests/ui/borrow_interior_mutable_const.stderr | 58 +- .../{borrow_box.fixed => borrowed_box.fixed} | 17 +- tests/ui/{borrow_box.rs => borrowed_box.rs} | 17 +- tests/ui/borrowed_box.stderr | 68 ++ tests/ui/box_collection.rs | 7 +- tests/ui/box_collection.stderr | 18 +- tests/ui/box_default.fixed | 2 +- tests/ui/box_default.rs | 2 +- tests/ui/boxed_local.rs | 8 +- .../branches_sharing_code/false_positives.rs | 3 +- .../branches_sharing_code/shared_at_bottom.rs | 7 +- .../shared_at_bottom.stderr | 38 +- .../ui/branches_sharing_code/shared_at_top.rs | 2 - .../shared_at_top.stderr | 18 +- .../shared_at_top_and_bottom.rs | 1 - .../shared_at_top_and_bottom.stderr | 24 +- .../branches_sharing_code/valid_if_blocks.rs | 7 +- .../valid_if_blocks.stderr | 20 +- tests/ui/builtin_type_shadow.rs | 2 +- tests/ui/byte_char_slices.fixed | 2 +- tests/ui/byte_char_slices.rs | 2 +- tests/ui/bytecount.rs | 2 +- tests/ui/bytes_nth.fixed | 2 - tests/ui/bytes_nth.rs | 2 - tests/ui/bytes_nth.stderr | 6 +- tests/ui/cast.rs | 14 +- tests/ui/cast_abs_to_unsigned.fixed | 1 - tests/ui/cast_abs_to_unsigned.rs | 1 - tests/ui/cast_abs_to_unsigned.stderr | 36 +- tests/ui/cast_alignment.rs | 7 +- tests/ui/cast_alignment.stderr | 8 +- tests/ui/cast_enum_constructor.rs | 2 +- tests/ui/cast_lossless_bool.fixed | 1 - tests/ui/cast_lossless_bool.rs | 1 - tests/ui/cast_lossless_bool.stderr | 30 +- tests/ui/cast_lossless_float.fixed | 1 - tests/ui/cast_lossless_float.rs | 1 - tests/ui/cast_lossless_float.stderr | 26 +- tests/ui/cast_lossless_integer.fixed | 2 +- tests/ui/cast_lossless_integer.rs | 2 +- tests/ui/cast_nan_to_int.rs | 2 +- tests/ui/cast_size.rs | 8 +- tests/ui/cast_slice_different_sizes.rs | 2 +- tests/ui/cfg_attr_cargo_clippy.fixed | 2 +- tests/ui/cfg_attr_cargo_clippy.rs | 2 +- tests/ui/cfg_attr_rustfmt.fixed | 2 +- tests/ui/cfg_attr_rustfmt.rs | 2 +- tests/ui/cfg_not_test.rs | 1 - tests/ui/cfg_not_test.stderr | 10 +- tests/ui/checked_conversions.fixed | 8 +- tests/ui/checked_conversions.rs | 8 +- tests/ui/checked_conversions.stderr | 36 +- .../ui/checked_unwrap/simple_conditionals.rs | 6 +- tests/ui/clear_with_drain.fixed | 1 - tests/ui/clear_with_drain.rs | 1 - tests/ui/clear_with_drain.stderr | 42 +- tests/ui/clone_on_copy.fixed | 7 +- tests/ui/clone_on_copy.rs | 7 +- tests/ui/clone_on_copy.stderr | 20 +- tests/ui/clone_on_copy_impl.rs | 2 +- tests/ui/cloned_instead_of_copied.fixed | 3 +- tests/ui/cloned_instead_of_copied.rs | 3 +- tests/ui/cloned_instead_of_copied.stderr | 16 +- tests/ui/cloned_ref_to_slice_refs.fixed | 1 - tests/ui/cloned_ref_to_slice_refs.rs | 1 - tests/ui/cloned_ref_to_slice_refs.stderr | 22 +- tests/ui/cmp_null.fixed | 1 - tests/ui/cmp_null.rs | 1 - tests/ui/cmp_null.stderr | 14 +- .../ui/cmp_owned/asymmetric_partial_eq.fixed | 7 +- tests/ui/cmp_owned/asymmetric_partial_eq.rs | 7 +- .../ui/cmp_owned/asymmetric_partial_eq.stderr | 12 +- tests/ui/cmp_owned/without_suggestion.rs | 3 - tests/ui/cmp_owned/without_suggestion.stderr | 6 +- tests/ui/cognitive_complexity.rs | 2 +- tests/ui/cognitive_complexity_attr_used.rs | 3 +- .../ui/cognitive_complexity_attr_used.stderr | 2 +- tests/ui/collapsible_else_if.fixed | 1 - tests/ui/collapsible_else_if.rs | 1 - tests/ui/collapsible_else_if.stderr | 24 +- tests/ui/collapsible_if.fixed | 10 +- tests/ui/collapsible_if.rs | 10 +- tests/ui/collapsible_if.stderr | 24 +- tests/ui/collapsible_match.rs | 7 +- tests/ui/collapsible_match.stderr | 68 +- tests/ui/collapsible_match2.rs | 7 +- tests/ui/collapsible_match2.stderr | 20 +- tests/ui/collapsible_match_fixable.fixed | 34 +- tests/ui/collapsible_match_fixable.rs | 34 +- tests/ui/collapsible_match_fixable.stderr | 50 +- tests/ui/collapsible_str_replace.fixed | 1 - tests/ui/collapsible_str_replace.rs | 1 - tests/ui/collapsible_str_replace.stderr | 28 +- tests/ui/collection_is_never_read.rs | 2 +- tests/ui/comparison_chain.rs | 1 - tests/ui/comparison_chain.stderr | 12 +- tests/ui/comparison_to_empty.fixed | 3 +- tests/ui/comparison_to_empty.rs | 3 +- tests/ui/comparison_to_empty.stderr | 26 +- tests/ui/const_comparisons.rs | 3 +- tests/ui/const_comparisons.stderr | 62 +- tests/ui/const_is_empty.rs | 2 +- tests/ui/copy_iterator.rs | 2 +- .../elidable_lifetime_names_impl_trait.fixed | 1 - .../elidable_lifetime_names_impl_trait.rs | 1 - .../elidable_lifetime_names_impl_trait.stderr | 4 +- tests/ui/crashes/ice-11230.fixed | 3 +- tests/ui/crashes/ice-11230.rs | 3 +- tests/ui/crashes/ice-11230.stderr | 2 +- tests/ui/crashes/ice-11939.rs | 2 +- tests/ui/crashes/ice-12585.rs | 2 +- tests/ui/crashes/ice-12616.fixed | 2 +- tests/ui/crashes/ice-12616.rs | 2 +- tests/ui/crashes/ice-13544-reduced.rs | 2 +- tests/ui/crashes/ice-14325.rs | 2 +- tests/ui/crashes/ice-1782.rs | 4 +- tests/ui/crashes/ice-2499.rs | 2 +- tests/ui/crashes/ice-2594.rs | 2 - tests/ui/crashes/ice-2760.rs | 7 +- tests/ui/crashes/ice-2865.rs | 2 +- tests/ui/crashes/ice-3969.rs | 1 - tests/ui/crashes/ice-3969.stderr | 10 +- tests/ui/crashes/ice-4579.rs | 2 +- tests/ui/crashes/ice-4760.rs | 2 - tests/ui/crashes/ice-4775.rs | 2 - tests/ui/crashes/ice-4968.rs | 2 +- tests/ui/crashes/ice-5389.rs | 2 +- tests/ui/crashes/ice-5497.rs | 2 +- tests/ui/crashes/ice-5579.rs | 2 +- tests/ui/crashes/ice-5944.rs | 2 +- tests/ui/crashes/ice-6179.rs | 2 +- tests/ui/crashes/ice-6254.rs | 2 +- tests/ui/crashes/ice-6256.rs | 2 +- tests/ui/crashes/ice-6840.rs | 1 - tests/ui/crashes/ice-7169.fixed | 2 - tests/ui/crashes/ice-7169.rs | 2 - tests/ui/crashes/ice-7169.stderr | 11 +- tests/ui/crashes/ice-7231.rs | 2 +- tests/ui/crashes/ice-7272.rs | 2 +- tests/ui/crashes/ice-7340.rs | 2 +- tests/ui/crashes/ice-7410.rs | 4 +- tests/ui/crashes/ice-7868.rs | 1 - tests/ui/crashes/ice-7934.rs | 1 - tests/ui/crashes/ice-9238.rs | 2 +- tests/ui/crashes/ice-9405.rs | 1 - tests/ui/crashes/ice-9405.stderr | 2 +- tests/ui/crashes/ice-rust-107877.rs | 2 - tests/ui/crashes/issue-825.rs | 2 +- tests/ui/crashes/issues_loop_mut_cond.rs | 2 - tests/ui/crashes/mgca-16691.rs | 2 +- tests/ui/crashes/regressions.rs | 2 - tests/ui/crashes/trivial_bounds.rs | 2 +- tests/ui/create_dir.fixed | 1 - tests/ui/create_dir.rs | 1 - tests/ui/create_dir.stderr | 10 +- tests/ui/dbg_macro/dbg_macro.fixed | 7 +- tests/ui/dbg_macro/dbg_macro.rs | 7 +- tests/ui/dbg_macro/dbg_macro.stderr | 40 +- tests/ui/debug_assert_with_mut_call.rs | 2 +- tests/ui/decimal_bitwise_operands.rs | 6 +- tests/ui/declare_interior_mutable_const.rs | 2 +- tests/ui/def_id_nocore.rs | 2 +- .../ui/default_constructed_unit_structs.fixed | 1 - tests/ui/default_constructed_unit_structs.rs | 1 - .../default_constructed_unit_structs.stderr | 14 +- tests/ui/default_instead_of_iter_empty.fixed | 1 - tests/ui/default_instead_of_iter_empty.rs | 1 - tests/ui/default_instead_of_iter_empty.stderr | 6 +- ...default_instead_of_iter_empty_no_std.fixed | 1 - .../default_instead_of_iter_empty_no_std.rs | 1 - ...efault_instead_of_iter_empty_no_std.stderr | 4 +- tests/ui/default_numeric_fallback_f64.fixed | 12 +- tests/ui/default_numeric_fallback_f64.rs | 12 +- tests/ui/default_numeric_fallback_f64.stderr | 46 +- tests/ui/default_numeric_fallback_i32.fixed | 10 +- tests/ui/default_numeric_fallback_i32.rs | 10 +- tests/ui/default_numeric_fallback_i32.stderr | 56 +- tests/ui/default_trait_access.fixed | 1 - tests/ui/default_trait_access.rs | 1 - tests/ui/default_trait_access.stderr | 16 +- tests/ui/default_union_representation.rs | 2 +- tests/ui/deprecated.rs | 1 + tests/ui/deprecated.stderr | 36 +- tests/ui/deref_addrof.fixed | 8 +- tests/ui/deref_addrof.rs | 8 +- tests/ui/deref_addrof.stderr | 36 +- tests/ui/deref_by_slicing.fixed | 1 - tests/ui/deref_by_slicing.rs | 1 - tests/ui/deref_by_slicing.stderr | 20 +- tests/ui/derivable_impls.fixed | 1 - tests/ui/derivable_impls.rs | 1 - tests/ui/derivable_impls.stderr | 24 +- tests/ui/derivable_impls_derive_const.fixed | 1 - tests/ui/derivable_impls_derive_const.rs | 1 - tests/ui/derivable_impls_derive_const.stderr | 4 +- tests/ui/derive.rs | 12 +- tests/ui/derive.stderr | 12 +- tests/ui/derive_ord_xor_partial_ord.rs | 3 +- tests/ui/derive_ord_xor_partial_ord.stderr | 16 +- tests/ui/derive_partial_eq_without_eq.fixed | 1 - tests/ui/derive_partial_eq_without_eq.rs | 1 - tests/ui/derive_partial_eq_without_eq.stderr | 26 +- tests/ui/derived_hash_with_manual_eq.rs | 2 - tests/ui/derived_hash_with_manual_eq.stderr | 8 +- tests/ui/disallowed_names.rs | 10 +- tests/ui/disallowed_names.stderr | 28 +- tests/ui/disallowed_script_idents.rs | 1 - tests/ui/disallowed_script_idents.stderr | 4 +- tests/ui/diverging_sub_expression.rs | 7 +- tests/ui/diverging_sub_expression.stderr | 4 +- tests/ui/doc/doc-fixable.fixed | 3 +- tests/ui/doc/doc-fixable.rs | 3 +- tests/ui/doc/doc-fixable.stderr | 44 +- .../doc_comment_double_space_linebreaks.fixed | 2 +- .../doc_comment_double_space_linebreaks.rs | 2 +- tests/ui/doc/doc_lazy_list.fixed | 2 +- tests/ui/doc/doc_lazy_list.rs | 2 +- tests/ui/doc/doc_markdown-issue_13097.fixed | 2 +- tests/ui/doc/doc_markdown-issue_13097.rs | 2 +- tests/ui/doc/unbalanced_ticks.rs | 1 - tests/ui/doc/unbalanced_ticks.stderr | 22 +- tests/ui/doc_errors.rs | 2 +- tests/ui/doc_suspicious_footnotes.fixed | 2 +- tests/ui/doc_suspicious_footnotes.rs | 2 +- tests/ui/doc_unsafe.rs | 1 - tests/ui/doc_unsafe.stderr | 26 +- tests/ui/double_comparison.fixed | 2 - tests/ui/double_comparison.rs | 2 - tests/ui/double_comparison.stderr | 24 +- tests/ui/double_must_use.fixed | 65 ++ tests/ui/double_must_use.rs | 2 +- tests/ui/double_must_use.stderr | 24 +- tests/ui/double_must_use_unfixable.rs | 17 + tests/ui/double_must_use_unfixable.stderr | 30 + tests/ui/drain_collect.fixed | 1 - tests/ui/drain_collect.rs | 1 - tests/ui/drain_collect.stderr | 20 +- tests/ui/duration_subsec.fixed | 2 +- tests/ui/duration_subsec.rs | 2 +- tests/ui/eager_transmute.fixed | 2 +- tests/ui/eager_transmute.rs | 2 +- tests/ui/elidable_lifetime_names.fixed | 3 +- tests/ui/elidable_lifetime_names.rs | 3 +- tests/ui/elidable_lifetime_names.stderr | 48 +- tests/ui/else_if_without_else.rs | 2 +- tests/ui/empty_docs.rs | 3 +- tests/ui/empty_docs.stderr | 18 +- tests/ui/empty_drop.fixed | 1 - tests/ui/empty_drop.rs | 1 - tests/ui/empty_drop.stderr | 4 +- .../empty_enum_variants_with_brackets.fixed | 1 - tests/ui/empty_enum_variants_with_brackets.rs | 1 - .../empty_enum_variants_with_brackets.stderr | 22 +- .../ui/empty_line_after/doc_comments.1.fixed | 3 +- .../ui/empty_line_after/doc_comments.2.fixed | 3 +- tests/ui/empty_line_after/doc_comments.rs | 3 +- tests/ui/empty_line_after/doc_comments.stderr | 24 +- .../empty_line_after/outer_attribute.1.fixed | 3 +- .../empty_line_after/outer_attribute.2.fixed | 3 +- tests/ui/empty_line_after/outer_attribute.rs | 3 +- .../empty_line_after/outer_attribute.stderr | 20 +- tests/ui/empty_structs_with_brackets.fixed | 1 - tests/ui/empty_structs_with_brackets.rs | 1 - tests/ui/empty_structs_with_brackets.stderr | 6 +- tests/ui/endian_bytes.rs | 3 +- tests/ui/endian_bytes.stderr | 172 ++-- tests/ui/entry.fixed | 1 - tests/ui/entry.rs | 1 - tests/ui/entry.stderr | 24 +- tests/ui/entry_btree.fixed | 1 - tests/ui/entry_btree.rs | 1 - tests/ui/entry_btree.stderr | 2 +- tests/ui/entry_unfixable.rs | 1 - tests/ui/entry_unfixable.stderr | 6 +- tests/ui/entry_with_else.fixed | 1 - tests/ui/entry_with_else.rs | 1 - tests/ui/entry_with_else.stderr | 14 +- tests/ui/enum_clike_unportable_variant.rs | 2 +- tests/ui/enum_glob_use.fixed | 5 +- tests/ui/enum_glob_use.rs | 5 +- tests/ui/enum_glob_use.stderr | 6 +- tests/ui/enum_variants.rs | 2 +- tests/ui/eprint_with_newline.fixed | 2 +- tests/ui/eprint_with_newline.rs | 2 +- tests/ui/eq_op.rs | 2 +- tests/ui/eq_op_macros.rs | 2 +- tests/ui/equatable_if_let.fixed | 2 +- tests/ui/equatable_if_let.rs | 2 +- tests/ui/equatable_if_let_const_cmp.fixed | 1 - tests/ui/equatable_if_let_const_cmp.rs | 1 - tests/ui/equatable_if_let_const_cmp.stderr | 4 +- tests/ui/err_expect.fixed | 2 +- tests/ui/err_expect.rs | 2 +- tests/ui/error_impl_error.rs | 1 - tests/ui/error_impl_error.stderr | 14 +- tests/ui/eta.fixed | 12 +- tests/ui/eta.rs | 12 +- tests/ui/eta.stderr | 88 +- tests/ui/excessive_precision.fixed | 9 +- tests/ui/excessive_precision.rs | 9 +- tests/ui/excessive_precision.stderr | 44 +- tests/ui/exhaustive_items.fixed | 3 +- tests/ui/exhaustive_items.rs | 3 +- tests/ui/exhaustive_items.stderr | 20 +- tests/ui/expect.rs | 2 +- tests/ui/expect_fun_call.fixed | 6 +- tests/ui/expect_fun_call.rs | 6 +- tests/ui/expect_fun_call.stderr | 36 +- tests/ui/expect_tool_lint_rfc_2383.rs | 1 - tests/ui/expect_tool_lint_rfc_2383.stderr | 14 +- tests/ui/explicit_auto_deref.fixed | 15 +- tests/ui/explicit_auto_deref.rs | 15 +- tests/ui/explicit_auto_deref.stderr | 92 +- tests/ui/explicit_counter_loop.rs | 23 +- tests/ui/explicit_counter_loop.stderr | 8 +- tests/ui/explicit_deref_methods.fixed | 12 +- tests/ui/explicit_deref_methods.rs | 12 +- tests/ui/explicit_deref_methods.stderr | 26 +- tests/ui/explicit_into_iter_loop.fixed | 1 - tests/ui/explicit_into_iter_loop.rs | 1 - tests/ui/explicit_into_iter_loop.stderr | 14 +- tests/ui/explicit_iter_loop.fixed | 12 +- tests/ui/explicit_iter_loop.rs | 12 +- tests/ui/explicit_iter_loop.stderr | 45 +- tests/ui/explicit_write.fixed | 1 - tests/ui/explicit_write.rs | 1 - tests/ui/explicit_write.stderr | 26 +- tests/ui/extend_with_drain.fixed | 1 - tests/ui/extend_with_drain.rs | 1 - tests/ui/extend_with_drain.stderr | 8 +- tests/ui/extra_unused_lifetimes.rs | 41 +- tests/ui/extra_unused_lifetimes.stderr | 46 +- tests/ui/extra_unused_type_parameters.fixed | 2 +- tests/ui/extra_unused_type_parameters.rs | 2 +- tests/ui/field_reassign_with_default.rs | 2 +- tests/ui/filetype_is_file.rs | 1 - tests/ui/filetype_is_file.stderr | 6 +- tests/ui/filter_map_bool_then.fixed | 7 +- tests/ui/filter_map_bool_then.rs | 7 +- tests/ui/filter_map_bool_then.stderr | 22 +- tests/ui/filter_map_bool_then_unfixable.rs | 2 +- tests/ui/filter_map_identity.fixed | 2 +- tests/ui/filter_map_identity.rs | 2 +- tests/ui/find_map.rs | 35 - tests/ui/flat_map_identity.fixed | 2 +- tests/ui/flat_map_identity.rs | 2 +- tests/ui/flat_map_option.fixed | 1 - tests/ui/flat_map_option.rs | 1 - tests/ui/flat_map_option.stderr | 4 +- tests/ui/float_arithmetic.rs | 12 +- tests/ui/float_arithmetic.stderr | 34 +- tests/ui/float_cmp.rs | 7 +- tests/ui/float_cmp.stderr | 12 +- tests/ui/float_cmp_const.rs | 4 +- tests/ui/floating_point_arithmetic_nostd.rs | 3 +- tests/ui/floating_point_exp.fixed | 2 +- tests/ui/floating_point_exp.rs | 2 +- tests/ui/floating_point_log.fixed | 4 +- tests/ui/floating_point_log.rs | 4 +- tests/ui/floating_point_logbase.fixed | 2 +- tests/ui/floating_point_logbase.rs | 2 +- tests/ui/floating_point_powf.fixed | 4 +- tests/ui/floating_point_powf.rs | 4 +- tests/ui/floating_point_powi.fixed | 2 +- tests/ui/floating_point_powi.rs | 2 +- tests/ui/fn_params_excessive_bools.rs | 2 +- tests/ui/fn_to_numeric_cast.rs | 2 +- tests/ui/fn_to_numeric_cast_any.rs | 2 +- tests/ui/for_kv_map.fixed | 2 +- tests/ui/for_kv_map.rs | 2 +- tests/ui/for_unbounded_range.fixed | 35 + tests/ui/for_unbounded_range.rs | 35 + tests/ui/for_unbounded_range.stderr | 32 + tests/ui/format.fixed | 12 +- tests/ui/format.rs | 12 +- tests/ui/format.stderr | 38 +- tests/ui/format_args.fixed | 12 +- tests/ui/format_args.rs | 12 +- tests/ui/format_args.stderr | 52 +- tests/ui/format_collect.rs | 1 - tests/ui/format_collect.stderr | 18 +- ....rs => format_in_format_args_unfixable.rs} | 5 +- ...=> format_in_format_args_unfixable.stderr} | 50 +- tests/ui/formatting.rs | 4 +- tests/ui/formatting.stderr | 12 +- tests/ui/four_forward_slashes.fixed | 3 - tests/ui/four_forward_slashes.rs | 3 - tests/ui/four_forward_slashes.stderr | 12 +- tests/ui/from_iter_instead_of_collect.fixed | 118 --- tests/ui/from_iter_instead_of_collect.rs | 118 --- tests/ui/from_iter_instead_of_collect.stderr | 149 ---- tests/ui/from_over_into.fixed | 2 - tests/ui/from_over_into.rs | 2 - tests/ui/from_over_into.stderr | 16 +- tests/ui/from_raw_with_void_ptr.rs | 2 +- tests/ui/functions.rs | 2 +- tests/ui/functions_maxlines.rs | 2 +- tests/ui/get_first.fixed | 2 +- tests/ui/get_first.rs | 2 +- tests/ui/get_last_with_len.fixed | 2 +- tests/ui/get_last_with_len.rs | 2 +- tests/ui/get_unwrap.fixed | 11 +- tests/ui/get_unwrap.rs | 11 +- tests/ui/get_unwrap.stderr | 62 +- tests/ui/identity_op.fixed | 15 +- tests/ui/identity_op.rs | 15 +- tests/ui/identity_op.stderr | 140 +-- tests/ui/if_let_mutex.rs | 2 +- tests/ui/if_same_then_else.rs | 8 +- tests/ui/if_same_then_else.stderr | 92 +- tests/ui/if_same_then_else2.rs | 12 +- tests/ui/if_same_then_else2.stderr | 24 +- tests/ui/if_then_some_else_none.fixed | 7 +- tests/ui/if_then_some_else_none.rs | 7 +- tests/ui/if_then_some_else_none.stderr | 28 +- tests/ui/if_then_some_else_none_unfixable.rs | 2 +- tests/ui/ifs_same_cond.rs | 6 +- tests/ui/ifs_same_cond.stderr | 10 +- tests/ui/ignored_unit_patterns.fixed | 9 +- tests/ui/ignored_unit_patterns.rs | 9 +- tests/ui/ignored_unit_patterns.stderr | 18 +- tests/ui/impl.rs | 2 +- tests/ui/impl_trait_in_params.rs | 1 - tests/ui/impl_trait_in_params.stderr | 8 +- tests/ui/implicit_clone.fixed | 2 +- tests/ui/implicit_clone.rs | 2 +- tests/ui/implicit_return.fixed | 2 +- tests/ui/implicit_return.rs | 2 +- tests/ui/implicit_saturating_add.fixed | 1 - tests/ui/implicit_saturating_add.rs | 1 - tests/ui/implicit_saturating_add.stderr | 48 +- tests/ui/implicit_saturating_sub.fixed | 2 +- tests/ui/implicit_saturating_sub.rs | 2 +- tests/ui/implied_bounds_in_impls.fixed | 1 - tests/ui/implied_bounds_in_impls.rs | 1 - tests/ui/implied_bounds_in_impls.stderr | 46 +- tests/ui/incompatible_msrv.rs | 4 +- .../ui/inconsistent_struct_constructor.fixed | 5 +- tests/ui/inconsistent_struct_constructor.rs | 5 +- .../ui/inconsistent_struct_constructor.stderr | 4 +- .../if_let_slice_binding.fixed | 4 +- .../if_let_slice_binding.rs | 4 +- .../if_let_slice_binding.stderr | 7 +- tests/ui/indexing_slicing_index.rs | 12 +- tests/ui/indexing_slicing_index.stderr | 35 +- tests/ui/indexing_slicing_slice.rs | 14 +- tests/ui/indexing_slicing_slice.stderr | 45 +- tests/ui/infallible_destructuring_match.fixed | 3 +- tests/ui/infallible_destructuring_match.rs | 3 +- .../ui/infallible_destructuring_match.stderr | 24 +- tests/ui/infinite_iter.rs | 2 - tests/ui/infinite_iter.stderr | 32 +- tests/ui/infinite_loops.rs | 2 +- tests/ui/inherent_to_string.rs | 2 +- tests/ui/inline_fn_without_body.fixed | 1 - tests/ui/inline_fn_without_body.rs | 1 - tests/ui/inline_fn_without_body.stderr | 6 +- tests/ui/inline_trait_bounds.fixed | 36 + tests/ui/inline_trait_bounds.rs | 36 + tests/ui/inline_trait_bounds.stderr | 14 +- tests/ui/integer_division_remainder_used.rs | 3 +- .../ui/integer_division_remainder_used.stderr | 18 +- tests/ui/into_iter_on_ref.fixed | 2 +- tests/ui/into_iter_on_ref.rs | 2 +- tests/ui/invalid_upcast_comparisons.rs | 8 +- tests/ui/invalid_upcast_comparisons.stderr | 56 +- tests/ui/ip_constant.fixed | 3 +- tests/ui/ip_constant.rs | 3 +- tests/ui/ip_constant.stderr | 42 +- tests/ui/issue-111399.rs | 2 +- tests/ui/issue_2356.fixed | 3 +- tests/ui/issue_2356.rs | 3 +- tests/ui/issue_2356.stderr | 9 +- tests/ui/issue_4266.rs | 2 - tests/ui/issue_4266.stderr | 6 +- tests/ui/items_after_statement.rs | 2 +- .../imported_module.rs | 1 - tests/ui/iter_cloned_collect.fixed | 3 +- tests/ui/iter_cloned_collect.rs | 3 +- tests/ui/iter_cloned_collect.stderr | 75 +- tests/ui/iter_count.fixed | 11 +- tests/ui/iter_count.rs | 11 +- tests/ui/iter_count.stderr | 50 +- tests/ui/iter_filter_is_ok.fixed | 8 +- tests/ui/iter_filter_is_ok.rs | 8 +- tests/ui/iter_filter_is_ok.stderr | 24 +- tests/ui/iter_filter_is_some.fixed | 10 +- tests/ui/iter_filter_is_some.rs | 10 +- tests/ui/iter_filter_is_some.stderr | 20 +- tests/ui/iter_kv_map.fixed | 9 +- tests/ui/iter_kv_map.rs | 9 +- tests/ui/iter_kv_map.stderr | 102 +-- tests/ui/iter_next_loop.rs | 2 +- tests/ui/iter_next_slice.fixed | 11 +- tests/ui/iter_next_slice.rs | 11 +- tests/ui/iter_next_slice.stderr | 22 +- tests/ui/iter_nth.fixed | 2 +- tests/ui/iter_nth.rs | 2 +- tests/ui/iter_on_empty_collections.fixed | 3 +- tests/ui/iter_on_empty_collections.rs | 3 +- tests/ui/iter_on_single_items.fixed | 3 +- tests/ui/iter_on_single_items.rs | 3 +- tests/ui/iter_out_of_bounds.rs | 4 +- tests/ui/iter_out_of_bounds.stderr | 7 +- tests/ui/iter_overeager_cloned.fixed | 11 +- tests/ui/iter_overeager_cloned.rs | 11 +- tests/ui/iter_overeager_cloned.stderr | 42 +- tests/ui/iter_skip_next.fixed | 7 +- tests/ui/iter_skip_next.rs | 7 +- tests/ui/iter_skip_next.stderr | 14 +- tests/ui/iter_skip_next_unfixable.rs | 1 - tests/ui/iter_skip_next_unfixable.stderr | 12 +- tests/ui/iter_skip_zero.fixed | 2 +- tests/ui/iter_skip_zero.rs | 2 +- tests/ui/iter_with_drain.fixed | 6 +- tests/ui/iter_with_drain.rs | 6 +- tests/ui/iter_with_drain.stderr | 12 +- tests/ui/iter_without_into_iter.rs | 1 - tests/ui/iter_without_into_iter.stderr | 16 +- tests/ui/iterator_step_by_zero.rs | 2 +- tests/ui/join_absolute_paths.1.fixed | 2 +- tests/ui/join_absolute_paths.2.fixed | 2 +- tests/ui/join_absolute_paths.rs | 2 +- tests/ui/large_const_arrays.fixed | 15 +- tests/ui/large_const_arrays.rs | 15 +- tests/ui/large_const_arrays.stderr | 50 +- tests/ui/large_enum_variant.r32bit.stderr | 48 +- tests/ui/large_enum_variant.r64bit.stderr | 52 +- tests/ui/large_enum_variant.rs | 2 - tests/ui/large_futures.fixed | 7 +- tests/ui/large_futures.rs | 7 +- tests/ui/large_futures.stderr | 16 +- tests/ui/large_stack_arrays.rs | 2 +- tests/ui/large_stack_frames.rs | 1 - tests/ui/large_stack_frames.stderr | 8 +- tests/ui/legacy_numeric_constants.fixed | 83 +- tests/ui/legacy_numeric_constants.rs | 83 +- tests/ui/legacy_numeric_constants.stderr | 44 +- .../ui/legacy_numeric_constants_unfixable.rs | 1 - .../legacy_numeric_constants_unfixable.stderr | 18 +- tests/ui/len_without_is_empty.rs | 3 +- tests/ui/len_without_is_empty.stderr | 40 +- tests/ui/len_without_is_empty_expect.rs | 2 +- tests/ui/len_zero.fixed | 9 +- tests/ui/len_zero.rs | 9 +- tests/ui/len_zero.stderr | 54 +- tests/ui/len_zero_ranges.fixed | 1 - tests/ui/len_zero_ranges.rs | 1 - tests/ui/len_zero_ranges.stderr | 4 +- tests/ui/let_and_return.edition2021.fixed | 1 - tests/ui/let_and_return.edition2021.stderr | 22 +- tests/ui/let_and_return.edition2024.fixed | 1 - tests/ui/let_and_return.edition2024.stderr | 32 +- tests/ui/let_and_return.rs | 1 - tests/ui/let_if_seq.rs | 9 +- tests/ui/let_if_seq.stderr | 12 +- tests/ui/let_underscore_must_use.rs | 2 +- tests/ui/let_underscore_untyped.rs | 1 - tests/ui/let_underscore_untyped.stderr | 20 +- tests/ui/let_unit.fixed | 7 +- tests/ui/let_unit.rs | 7 +- tests/ui/let_unit.stderr | 18 +- tests/ui/let_with_type_underscore.fixed | 3 +- tests/ui/let_with_type_underscore.rs | 3 +- tests/ui/let_with_type_underscore.stderr | 18 +- tests/ui/lines_filter_map_ok.fixed | 2 +- tests/ui/lines_filter_map_ok.rs | 2 +- tests/ui/linkedlist.rs | 2 +- .../ui/literal_string_with_formatting_arg.rs | 2 +- tests/ui/literals.rs | 12 +- tests/ui/literals.stderr | 44 +- tests/ui/lossy_float_literal.fixed | 2 +- tests/ui/lossy_float_literal.rs | 2 +- tests/ui/macro_use_imports.fixed | 3 +- tests/ui/macro_use_imports.rs | 3 +- tests/ui/macro_use_imports.stderr | 8 +- tests/ui/macro_use_imports_expect.rs | 3 +- tests/ui/manual_arithmetic_check-2.rs | 1 - tests/ui/manual_arithmetic_check-2.stderr | 36 +- tests/ui/manual_arithmetic_check.fixed | 2 +- tests/ui/manual_arithmetic_check.rs | 2 +- tests/ui/manual_assert.edition2018.fixed | 3 +- tests/ui/manual_assert.edition2018.stderr | 22 +- tests/ui/manual_assert.edition2021.fixed | 3 +- tests/ui/manual_assert.edition2021.stderr | 22 +- tests/ui/manual_assert.rs | 3 +- tests/ui/manual_assert_eq.fixed | 3 +- tests/ui/manual_assert_eq.rs | 3 +- tests/ui/manual_assert_eq.stderr | 14 +- tests/ui/manual_async_fn.fixed | 2 +- tests/ui/manual_async_fn.rs | 2 +- tests/ui/manual_bits.fixed | 10 +- tests/ui/manual_bits.rs | 10 +- tests/ui/manual_bits.stderr | 58 +- tests/ui/manual_clamp.fixed | 9 +- tests/ui/manual_clamp.rs | 9 +- tests/ui/manual_clamp.stderr | 70 +- tests/ui/manual_contains.fixed | 2 +- tests/ui/manual_contains.rs | 2 +- tests/ui/manual_filter.fixed | 8 +- tests/ui/manual_filter.rs | 8 +- tests/ui/manual_filter.stderr | 40 +- tests/ui/manual_filter_map.fixed | 6 +- tests/ui/manual_filter_map.rs | 6 +- tests/ui/manual_filter_map.stderr | 76 +- tests/ui/manual_find.rs | 1 - tests/ui/manual_find.stderr | 4 +- tests/ui/manual_find_fixable.fixed | 3 +- tests/ui/manual_find_fixable.rs | 3 +- tests/ui/manual_find_fixable.stderr | 28 +- tests/ui/manual_find_map.fixed | 6 +- tests/ui/manual_find_map.rs | 6 +- tests/ui/manual_find_map.stderr | 78 +- tests/ui/manual_flatten.fixed | 2 +- tests/ui/manual_flatten.rs | 2 +- tests/ui/manual_float_methods.1.fixed | 67 ++ tests/ui/manual_float_methods.2.fixed | 67 ++ tests/ui/manual_float_methods.3.fixed | 67 ++ tests/ui/manual_float_methods.rs | 5 +- tests/ui/manual_float_methods.stderr | 10 +- tests/ui/manual_ignore_case_cmp.fixed | 2 +- tests/ui/manual_ignore_case_cmp.rs | 2 +- tests/ui/manual_ilog2.fixed | 2 +- tests/ui/manual_ilog2.rs | 2 +- tests/ui/manual_inspect.fixed | 2 +- tests/ui/manual_inspect.rs | 2 +- tests/ui/manual_instant_elapsed.fixed | 4 - tests/ui/manual_instant_elapsed.rs | 4 - tests/ui/manual_instant_elapsed.stderr | 8 +- tests/ui/manual_is_ascii_check.fixed | 1 - tests/ui/manual_is_ascii_check.rs | 1 - tests/ui/manual_is_ascii_check.stderr | 62 +- tests/ui/manual_is_power_of_two.fixed | 2 +- tests/ui/manual_is_power_of_two.rs | 2 +- tests/ui/manual_is_variant_and.fixed | 42 + tests/ui/manual_is_variant_and.rs | 42 + tests/ui/manual_is_variant_and.stderr | 14 +- tests/ui/manual_isolate_lowest_one.fixed | 92 ++ tests/ui/manual_isolate_lowest_one.rs | 92 ++ tests/ui/manual_isolate_lowest_one.stderr | 59 ++ tests/ui/manual_let_else.fixed | 433 +++++++++ tests/ui/manual_let_else.rs | 69 +- tests/ui/manual_let_else.stderr | 165 +--- tests/ui/manual_let_else_match.fixed | 10 +- tests/ui/manual_let_else_match.rs | 10 +- tests/ui/manual_let_else_match.stderr | 36 +- tests/ui/manual_let_else_question_mark.fixed | 8 - tests/ui/manual_let_else_question_mark.rs | 8 - tests/ui/manual_let_else_question_mark.stderr | 14 +- tests/ui/manual_let_else_unfixable.rs | 75 ++ tests/ui/manual_let_else_unfixable.stderr | 97 ++ tests/ui/manual_main_separator_str.fixed | 1 - tests/ui/manual_main_separator_str.rs | 1 - tests/ui/manual_main_separator_str.stderr | 8 +- tests/ui/manual_map_option.fixed | 12 +- tests/ui/manual_map_option.rs | 12 +- tests/ui/manual_map_option.stderr | 42 +- tests/ui/manual_map_option_2.fixed | 2 +- tests/ui/manual_map_option_2.rs | 2 +- .../ui/manual_memcpy/with_loop_counters.fixed | 7 +- tests/ui/manual_memcpy/with_loop_counters.rs | 7 +- .../manual_memcpy/with_loop_counters.stderr | 22 +- .../manual_memcpy/without_loop_counters.fixed | 10 +- .../ui/manual_memcpy/without_loop_counters.rs | 10 +- .../without_loop_counters.stderr | 36 +- tests/ui/manual_next_back.fixed | 1 - tests/ui/manual_next_back.rs | 1 - tests/ui/manual_next_back.stderr | 4 +- tests/ui/manual_non_exhaustive_enum.rs | 3 +- tests/ui/manual_non_exhaustive_enum.stderr | 8 +- tests/ui/manual_non_exhaustive_struct.rs | 3 +- tests/ui/manual_non_exhaustive_struct.stderr | 24 +- tests/ui/manual_ok_or.fixed | 6 +- tests/ui/manual_ok_or.rs | 6 +- tests/ui/manual_ok_or.stderr | 8 +- tests/ui/manual_option_as_slice.fixed | 2 +- tests/ui/manual_option_as_slice.rs | 2 +- tests/ui/manual_option_zip.fixed | 2 +- tests/ui/manual_option_zip.rs | 2 +- tests/ui/manual_pop_if.fixed | 2 +- tests/ui/manual_pop_if.rs | 2 +- tests/ui/manual_pop_if_unfixable.rs | 2 +- tests/ui/manual_range_patterns.fixed | 2 - tests/ui/manual_range_patterns.rs | 2 - tests/ui/manual_range_patterns.stderr | 38 +- tests/ui/manual_rem_euclid.fixed | 2 +- tests/ui/manual_rem_euclid.rs | 2 +- tests/ui/manual_retain.fixed | 2 +- tests/ui/manual_retain.rs | 2 +- tests/ui/manual_rotate.fixed | 1 - tests/ui/manual_rotate.rs | 1 - tests/ui/manual_rotate.stderr | 34 +- tests/ui/manual_saturating_arithmetic.fixed | 3 +- tests/ui/manual_saturating_arithmetic.rs | 3 +- tests/ui/manual_saturating_arithmetic.stderr | 50 +- tests/ui/manual_slice_fill.fixed | 2 +- tests/ui/manual_slice_fill.rs | 2 +- tests/ui/manual_slice_size_calculation.fixed | 1 - tests/ui/manual_slice_size_calculation.rs | 1 - tests/ui/manual_slice_size_calculation.stderr | 22 +- tests/ui/manual_split_once.fixed | 3 +- tests/ui/manual_split_once.rs | 3 +- tests/ui/manual_split_once.stderr | 38 +- tests/ui/manual_str_repeat.fixed | 2 +- tests/ui/manual_str_repeat.rs | 2 +- tests/ui/manual_string_new.fixed | 2 +- tests/ui/manual_string_new.rs | 2 +- tests/ui/manual_strip_fixable.fixed | 1 - tests/ui/manual_strip_fixable.rs | 1 - tests/ui/manual_strip_fixable.stderr | 8 +- tests/ui/manual_take_nocore.rs | 2 +- tests/ui/manual_try_fold.rs | 3 +- tests/ui/manual_unwrap_or.fixed | 9 +- tests/ui/manual_unwrap_or.rs | 9 +- tests/ui/manual_unwrap_or.stderr | 40 +- tests/ui/manual_while_let_some.fixed | 1 - tests/ui/manual_while_let_some.rs | 1 - tests/ui/manual_while_let_some.stderr | 14 +- tests/ui/many_single_char_names.rs | 2 +- tests/ui/map_clone.fixed | 10 +- tests/ui/map_clone.rs | 10 +- tests/ui/map_clone.stderr | 30 +- tests/ui/map_err.rs | 2 +- tests/ui/map_flatten.fixed | 2 +- tests/ui/map_flatten.rs | 2 +- tests/ui/map_flatten_fixable.fixed | 9 +- tests/ui/map_flatten_fixable.rs | 9 +- tests/ui/map_flatten_fixable.stderr | 18 +- tests/ui/map_identity.fixed | 3 +- tests/ui/map_identity.rs | 3 +- tests/ui/map_identity.stderr | 18 +- tests/ui/map_unit_fn.rs | 1 - tests/ui/map_unwrap_or.rs | 2 +- tests/ui/map_unwrap_or_fixable.fixed | 5 - tests/ui/map_unwrap_or_fixable.rs | 5 - tests/ui/map_unwrap_or_fixable.stderr | 22 +- ...map_with_unused_argument_over_ranges.fixed | 7 +- .../map_with_unused_argument_over_ranges.rs | 7 +- ...ap_with_unused_argument_over_ranges.stderr | 40 +- tests/ui/match_as_ref.fixed | 1 - tests/ui/match_as_ref.rs | 1 - tests/ui/match_as_ref.stderr | 14 +- tests/ui/match_bool.fixed | 4 +- tests/ui/match_bool.rs | 4 +- tests/ui/match_bool.stderr | 7 +- tests/ui/match_like_matches_macro.fixed | 9 +- tests/ui/match_like_matches_macro.rs | 9 +- tests/ui/match_like_matches_macro.stderr | 59 +- tests/ui/match_overlapping_arm.rs | 4 +- tests/ui/match_ref_pats.fixed | 9 +- tests/ui/match_ref_pats.rs | 9 +- tests/ui/match_ref_pats.stderr | 29 +- tests/ui/match_result_ok.fixed | 8 +- tests/ui/match_result_ok.rs | 8 +- tests/ui/match_result_ok.stderr | 6 +- tests/ui/match_same_arms2.fixed | 9 +- tests/ui/match_same_arms2.rs | 9 +- tests/ui/match_same_arms2.stderr | 32 +- tests/ui/match_single_binding.fixed | 9 +- tests/ui/match_single_binding.rs | 9 +- tests/ui/match_single_binding.stderr | 92 +- tests/ui/match_single_binding2.fixed | 2 - tests/ui/match_single_binding2.rs | 2 - tests/ui/match_single_binding2.stderr | 8 +- tests/ui/match_str_case_mismatch.fixed | 1 - tests/ui/match_str_case_mismatch.rs | 1 - tests/ui/match_str_case_mismatch.stderr | 14 +- tests/ui/match_wild_err_arm.rs | 2 +- .../match_wildcard_for_single_variants.fixed | 1 - .../ui/match_wildcard_for_single_variants.rs | 1 - .../match_wildcard_for_single_variants.stderr | 20 +- tests/ui/mem_replace.stderr | 191 ---- tests/ui/mem_replace_macro.rs | 13 - tests/ui/mem_replace_macro.stderr | 12 - tests/ui/mem_replace_no_std.fixed | 84 -- tests/ui/mem_replace_no_std.rs | 84 -- tests/ui/mem_replace_no_std.stderr | 50 -- tests/ui/mem_replace_option_with_none.fixed | 42 + tests/ui/mem_replace_option_with_none.rs | 42 + tests/ui/mem_replace_option_with_none.stderr | 35 + .../mem_replace_option_with_none_no_std.fixed | 13 + .../ui/mem_replace_option_with_none_no_std.rs | 13 + ...mem_replace_option_with_none_no_std.stderr | 17 + tests/ui/mem_replace_option_with_some.fixed | 25 + tests/ui/mem_replace_option_with_some.rs | 25 + tests/ui/mem_replace_option_with_some.stderr | 23 + .../mem_replace_option_with_some_no_std.fixed | 26 + .../ui/mem_replace_option_with_some_no_std.rs | 26 + ...mem_replace_option_with_some_no_std.stderr | 23 + ...e.fixed => mem_replace_with_default.fixed} | 78 +- ...replace.rs => mem_replace_with_default.rs} | 78 +- tests/ui/mem_replace_with_default.stderr | 145 +++ .../ui/mem_replace_with_default_no_std.fixed | 25 + tests/ui/mem_replace_with_default_no_std.rs | 25 + .../ui/mem_replace_with_default_no_std.stderr | 25 + tests/ui/mem_replace_with_uninit.fixed | 50 ++ ...l_uninit.rs => mem_replace_with_uninit.rs} | 21 +- ....stderr => mem_replace_with_uninit.stderr} | 22 +- tests/ui/mem_replace_with_uninit_unfixable.rs | 22 + .../mem_replace_with_uninit_unfixable.stderr | 12 + .../missing_const_for_fn/could_be_const.fixed | 6 + .../ui/missing_const_for_fn/could_be_const.rs | 6 + .../could_be_const.stderr | 17 +- ...needless_borrow_false_positive_16200.fixed | 38 + .../needless_borrow_false_positive_16200.rs | 38 + ...eedless_borrow_false_positive_16200.stderr | 29 + tests/ui/never_loop.rs | 103 +++ tests/ui/never_loop.stderr | 139 ++- tests/ui/range_plus_minus_one.fixed | 4 +- tests/ui/range_plus_minus_one.rs | 2 - tests/ui/range_plus_minus_one.stderr | 28 +- tests/ui/redundant_closure_call_early.rs | 58 +- tests/ui/redundant_closure_call_early.stderr | 4 +- tests/ui/redundant_closure_call_fixable.fixed | 40 +- tests/ui/redundant_closure_call_fixable.rs | 40 +- .../ui/redundant_closure_call_fixable.stderr | 64 +- tests/ui/redundant_closure_call_late.rs | 6 +- tests/ui/redundant_closure_call_late.stderr | 6 +- ...dundant_pattern_matching_drop_order.stderr | 208 ++++- ...undant_pattern_matching_if_let_true.stderr | 55 +- .../redundant_pattern_matching_ipaddr.stderr | 223 ++++- .../redundant_pattern_matching_option.stderr | 385 ++++++-- .../ui/redundant_pattern_matching_poll.stderr | 219 ++++- .../redundant_pattern_matching_result.stderr | 343 ++++++-- tests/ui/renamed_builtin_attr.fixed | 2 - tests/ui/renamed_builtin_attr.rs | 2 - tests/ui/renamed_builtin_attr.stderr | 2 +- tests/ui/result_large_err.rs | 14 + tests/ui/result_large_err.stderr | 18 +- tests/ui/result_unit_error.rs | 12 + tests/ui/result_unit_error.stderr | 10 +- tests/ui/single_range_in_vec_init.1.fixed | 7 + tests/ui/single_range_in_vec_init.2.fixed | 7 + tests/ui/single_range_in_vec_init.rs | 7 + tests/ui/single_range_in_vec_init.stderr | 26 +- .../ui/single_range_in_vec_init_unfixable.rs | 23 + .../single_range_in_vec_init_unfixable.stderr | 50 +- tests/ui/ty_fn_sig.rs | 2 +- tests/ui/unknown_attribute.rs | 2 - tests/ui/unknown_attribute.stderr | 2 +- tests/ui/unused_async_trait_impl.fixed | 33 + tests/ui/unused_async_trait_impl.rs | 33 + tests/ui/unused_async_trait_impl.stderr | 24 +- tests/ui/with_capacity_zero.fixed | 50 ++ tests/ui/with_capacity_zero.rs | 50 ++ tests/ui/with_capacity_zero.stderr | 112 +++ triagebot.toml | 1 + 1044 files changed, 11957 insertions(+), 7828 deletions(-) create mode 100644 clippy_lints/src/combined_early_pass.rs create mode 100644 clippy_lints/src/combined_late_pass.rs create mode 100644 clippy_lints/src/loops/for_unbounded_range.rs delete mode 100644 clippy_lints/src/methods/from_iter_instead_of_collect.rs create mode 100644 clippy_lints/src/operators/manual_isolate_lowest_one.rs create mode 100644 clippy_lints/src/with_capacity_zero.rs create mode 100644 clippy_utils/src/disallowed_profiles.rs create mode 100644 tests/ui-toml/disallowed_profiles_methods/clippy.toml create mode 100644 tests/ui-toml/disallowed_profiles_methods/main.rs create mode 100644 tests/ui-toml/disallowed_profiles_methods/main.stderr create mode 100644 tests/ui-toml/disallowed_profiles_types/clippy.toml create mode 100644 tests/ui-toml/disallowed_profiles_types/main.rs create mode 100644 tests/ui-toml/disallowed_profiles_types/main.stderr delete mode 100644 tests/ui/borrow_box.stderr rename tests/ui/{borrow_box.fixed => borrowed_box.fixed} (87%) rename tests/ui/{borrow_box.rs => borrowed_box.rs} (87%) create mode 100644 tests/ui/borrowed_box.stderr create mode 100644 tests/ui/double_must_use.fixed create mode 100644 tests/ui/double_must_use_unfixable.rs create mode 100644 tests/ui/double_must_use_unfixable.stderr delete mode 100644 tests/ui/find_map.rs create mode 100644 tests/ui/for_unbounded_range.fixed create mode 100644 tests/ui/for_unbounded_range.rs create mode 100644 tests/ui/for_unbounded_range.stderr rename tests/ui/{format_args_unfixable.rs => format_in_format_args_unfixable.rs} (96%) rename tests/ui/{format_args_unfixable.stderr => format_in_format_args_unfixable.stderr} (87%) delete mode 100644 tests/ui/from_iter_instead_of_collect.fixed delete mode 100644 tests/ui/from_iter_instead_of_collect.rs delete mode 100644 tests/ui/from_iter_instead_of_collect.stderr create mode 100644 tests/ui/manual_float_methods.1.fixed create mode 100644 tests/ui/manual_float_methods.2.fixed create mode 100644 tests/ui/manual_float_methods.3.fixed create mode 100644 tests/ui/manual_isolate_lowest_one.fixed create mode 100644 tests/ui/manual_isolate_lowest_one.rs create mode 100644 tests/ui/manual_isolate_lowest_one.stderr create mode 100644 tests/ui/manual_let_else.fixed create mode 100644 tests/ui/manual_let_else_unfixable.rs create mode 100644 tests/ui/manual_let_else_unfixable.stderr delete mode 100644 tests/ui/mem_replace.stderr delete mode 100644 tests/ui/mem_replace_macro.rs delete mode 100644 tests/ui/mem_replace_macro.stderr delete mode 100644 tests/ui/mem_replace_no_std.fixed delete mode 100644 tests/ui/mem_replace_no_std.rs delete mode 100644 tests/ui/mem_replace_no_std.stderr create mode 100644 tests/ui/mem_replace_option_with_none.fixed create mode 100644 tests/ui/mem_replace_option_with_none.rs create mode 100644 tests/ui/mem_replace_option_with_none.stderr create mode 100644 tests/ui/mem_replace_option_with_none_no_std.fixed create mode 100644 tests/ui/mem_replace_option_with_none_no_std.rs create mode 100644 tests/ui/mem_replace_option_with_none_no_std.stderr create mode 100644 tests/ui/mem_replace_option_with_some.fixed create mode 100644 tests/ui/mem_replace_option_with_some.rs create mode 100644 tests/ui/mem_replace_option_with_some.stderr create mode 100644 tests/ui/mem_replace_option_with_some_no_std.fixed create mode 100644 tests/ui/mem_replace_option_with_some_no_std.rs create mode 100644 tests/ui/mem_replace_option_with_some_no_std.stderr rename tests/ui/{mem_replace.fixed => mem_replace_with_default.fixed} (65%) rename tests/ui/{mem_replace.rs => mem_replace_with_default.rs} (66%) create mode 100644 tests/ui/mem_replace_with_default.stderr create mode 100644 tests/ui/mem_replace_with_default_no_std.fixed create mode 100644 tests/ui/mem_replace_with_default_no_std.rs create mode 100644 tests/ui/mem_replace_with_default_no_std.stderr create mode 100644 tests/ui/mem_replace_with_uninit.fixed rename tests/ui/{repl_uninit.rs => mem_replace_with_uninit.rs} (78%) rename tests/ui/{repl_uninit.stderr => mem_replace_with_uninit.stderr} (55%) create mode 100644 tests/ui/mem_replace_with_uninit_unfixable.rs create mode 100644 tests/ui/mem_replace_with_uninit_unfixable.stderr create mode 100644 tests/ui/needless_borrow_false_positive_16200.fixed create mode 100644 tests/ui/needless_borrow_false_positive_16200.rs create mode 100644 tests/ui/needless_borrow_false_positive_16200.stderr create mode 100644 tests/ui/with_capacity_zero.fixed create mode 100644 tests/ui/with_capacity_zero.rs create mode 100644 tests/ui/with_capacity_zero.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index 682e0c7af6d0c..337c900aaf0c8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,101 @@ document. ## Unreleased / Beta / In Rust Nightly -[df995e...master](https://github.com/rust-lang/rust-clippy/compare/df995e...master) +[88f787...master](https://github.com/rust-lang/rust-clippy/compare/88f787...master) + +## Rust 1.96 + +Current stable, released 2026-05-28 + +[View all 48 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2026-02-24T12%3A30%3A17Z..2026-04-03T17%3A32%3A48Z+base%3Amaster) + +### New Lints + +* Added [`manual_noop_waker`] to `complexity` + [#16687](https://github.com/rust-lang/rust-clippy/pull/16687) +* Added [`manual_option_zip`] to `complexity` + [#16600](https://github.com/rust-lang/rust-clippy/pull/16600) +* Added [`manual_pop_if`] to `complexity` + [#16582](https://github.com/rust-lang/rust-clippy/pull/16582) + +### Enhancements + +* [`explicit_counter_loop`] suggest `(init..).take(n)` when loop variable is unused and range is + `0..n` + [#16658](https://github.com/rust-lang/rust-clippy/pull/16658) +* [`iter_kv_map`] handle identity map for `map` and `flat_map` + [#16743](https://github.com/rust-lang/rust-clippy/pull/16743) +* [`manual_noop_waker`] add an MSRV check + [#16850](https://github.com/rust-lang/rust-clippy/pull/16850) +* [`manual_pop_if`] in case the popped value is used, just emit the lint with no suggestion + [#16683](https://github.com/rust-lang/rust-clippy/pull/16683) +* [`manual_pop_if`] also cover `.pop().unwrap_unchecked()` + [#16683](https://github.com/rust-lang/rust-clippy/pull/16683) +* [`manual_pop_if`] detect manual implementations of `BinaryHeap::pop_if()` + [#16734](https://github.com/rust-lang/rust-clippy/pull/16734) +* [`unnecessary_option_map_or_else`] function definitions are no longer traversed when checking if + an expression is the identity + [#15889](https://github.com/rust-lang/rust-clippy/pull/15889) +* [`unnecessary_result_map_or_else`] function definitions are no longer traversed when checking if + an expression is the identity + [#15889](https://github.com/rust-lang/rust-clippy/pull/15889) +* [`question_mark`] fix suggestion-caused error caused by semicolon inference relying only on + parent-node shape + [#16656](https://github.com/rust-lang/rust-clippy/pull/16656) +* Format-related lints now handle `core::panic!` + [#16597](https://github.com/rust-lang/rust-clippy/pull/16597) +* [`explicit_counter_loop`] fix FN when the initializer is not integral + [#16647](https://github.com/rust-lang/rust-clippy/pull/16647) +* [`suboptimal_flops`] fix FN on add and sub assign + [#16625](https://github.com/rust-lang/rust-clippy/pull/16625) +* [`infinite_loop`] fix wrong suggestion to add `-> !` when the loop is inside a conditional branch + [#16619](https://github.com/rust-lang/rust-clippy/pull/16619) +* [`unnecessary_cast`] preserve parentheses in presence of cascaded casts + [#16483](https://github.com/rust-lang/rust-clippy/pull/16483) +* [`cmp_owned`] fix wrong suggestions on `PathBuf` + [#16628](https://github.com/rust-lang/rust-clippy/pull/16628) +* [`redundant_closure`] fix wrong suggestions when local is dereferenced to callable + [#16648](https://github.com/rust-lang/rust-clippy/pull/16648) + +### False Positive Fixes + +* [`collapsible_if`] fix FP when the inner if contains cfg + [#16757](https://github.com/rust-lang/rust-clippy/pull/16757) +* [`collapsible_match`] fix FP when the pat binding is moved or mutated + [#16708](https://github.com/rust-lang/rust-clippy/pull/16708) +* [`collapsible_match`] fix a case where a suggested transformation changes runtime behavior + [#16878](https://github.com/rust-lang/rust-clippy/pull/16878) +* [`match_same_arms`] fix FP with associated consts + [#16701](https://github.com/rust-lang/rust-clippy/pull/16701) +* [`semicolon_inside_block`] fix FP in `try` blocks where moving `;` changes the block's return + type and causes type errors + [#16697](https://github.com/rust-lang/rust-clippy/pull/16697) +* [`unnecessary_safety_comment`] fix FP on code blocks inside inner docs + [#16559](https://github.com/rust-lang/rust-clippy/pull/16559) +* [`doc_paragraphs_missing_punctuation`] no longer lints punctuated paragraphs with a trailing + emoji + [#16514](https://github.com/rust-lang/rust-clippy/pull/16514) + +### ICE Fixes + +* [`match_same_arms`] fix ICE in `match_same_arms` + [#16685](https://github.com/rust-lang/rust-clippy/pull/16685) +* [`nonminimal_bool`] fix ICE in `swap_binop()` by using the proper `TypeckResults` + [#16659](https://github.com/rust-lang/rust-clippy/pull/16659) +* Fix ICE when using the `min_generic_const_args` incomplete feature + [#16692](https://github.com/rust-lang/rust-clippy/pull/16692) + +### Documentation Improvements + +* [`similar_names`] changed the lint docs to reflect its actual behavior + [#16300](https://github.com/rust-lang/rust-clippy/pull/16300) + +### Performance Improvements + +* [`repeat_vec_with_capacity`] optimized by 96.876% (784M -> 24M instructions) + [#16756](https://github.com/rust-lang/rust-clippy/pull/16756) +* [`manual_is_ascii_check`] optimized by 97.125% (822M -> 23M instructions) + [#16755](https://github.com/rust-lang/rust-clippy/pull/16755) ## Rust 1.95 @@ -6746,6 +6840,7 @@ Released 2018-09-13 [`for_loop_over_option`]: https://rust-lang.github.io/rust-clippy/master/index.html#for_loop_over_option [`for_loop_over_result`]: https://rust-lang.github.io/rust-clippy/master/index.html#for_loop_over_result [`for_loops_over_fallibles`]: https://rust-lang.github.io/rust-clippy/master/index.html#for_loops_over_fallibles +[`for_unbounded_range`]: https://rust-lang.github.io/rust-clippy/master/index.html#for_unbounded_range [`forget_copy`]: https://rust-lang.github.io/rust-clippy/master/index.html#forget_copy [`forget_non_drop`]: https://rust-lang.github.io/rust-clippy/master/index.html#forget_non_drop [`forget_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#forget_ref @@ -6906,6 +7001,7 @@ Released 2018-09-13 [`manual_is_multiple_of`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_multiple_of [`manual_is_power_of_two`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_power_of_two [`manual_is_variant_and`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_variant_and +[`manual_isolate_lowest_one`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_isolate_lowest_one [`manual_let_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_let_else [`manual_main_separator_str`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_main_separator_str [`manual_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_map @@ -7424,6 +7520,7 @@ Released 2018-09-13 [`wildcard_enum_match_arm`]: https://rust-lang.github.io/rust-clippy/master/index.html#wildcard_enum_match_arm [`wildcard_imports`]: https://rust-lang.github.io/rust-clippy/master/index.html#wildcard_imports [`wildcard_in_or_patterns`]: https://rust-lang.github.io/rust-clippy/master/index.html#wildcard_in_or_patterns +[`with_capacity_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#with_capacity_zero [`write_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#write_literal [`write_with_newline`]: https://rust-lang.github.io/rust-clippy/master/index.html#write_with_newline [`writeln_empty_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#writeln_empty_string @@ -7511,6 +7608,7 @@ Released 2018-09-13 [`module-items-ordered-within-groupings`]: https://doc.rust-lang.org/clippy/lint_configuration.html#module-items-ordered-within-groupings [`msrv`]: https://doc.rust-lang.org/clippy/lint_configuration.html#msrv [`pass-by-value-size-limit`]: https://doc.rust-lang.org/clippy/lint_configuration.html#pass-by-value-size-limit +[`profiles`]: https://doc.rust-lang.org/clippy/lint_configuration.html#profiles [`pub-underscore-fields-behavior`]: https://doc.rust-lang.org/clippy/lint_configuration.html#pub-underscore-fields-behavior [`recursive-self-in-type-definitions`]: https://doc.rust-lang.org/clippy/lint_configuration.html#recursive-self-in-type-definitions [`semicolon-inside-block-ignore-singleline`]: https://doc.rust-lang.org/clippy/lint_configuration.html#semicolon-inside-block-ignore-singleline diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8aeba28494cb3..ccfbb0b88387e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -124,8 +124,11 @@ To have `rust-analyzer` also work in the `clippy_dev` and `lintcheck` crates, ad ## How Clippy works -[`clippy_lints/src/lib.rs`][lint_crate_entry] imports all the different lint modules and registers in the [`LintStore`]. -For example, the [`else_if_without_else`][else_if_without_else] lint is registered like this: +[`clippy_lints/src/lib.rs`][lint_crate_entry] imports all the different lint modules and registers them in the +[`LintStore`]. All early passes are folded into a single `CombinedEarlyLintPass`, and all late passes into a single +`CombinedLateLintPass`, each registered once with the store. A pass is added to one of these by listing it in the +`early_lint_methods!` or `late_lint_methods!` macro invocation. For example, the +[`else_if_without_else`][else_if_without_else] lint is added like this: ```rust // ./clippy_lints/src/lib.rs @@ -134,18 +137,21 @@ For example, the [`else_if_without_else`][else_if_without_else] lint is register pub mod else_if_without_else; // ... -pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { - // ... - store.register_early_pass(|| Box::new(else_if_without_else::ElseIfWithoutElse)); - // ... -} +rustc_lint::early_lint_methods!( + crate::combined_early_lint_pass, + [CombinedEarlyLintPass, (/* ... */), [ + // ... + ElseIfWithoutElse: else_if_without_else::ElseIfWithoutElse = else_if_without_else::ElseIfWithoutElse, + // ... + ]] +); ``` -The [`rustc_lint::LintStore`][`LintStore`] provides two methods to register lints: -[register_early_pass][reg_early_pass] and [register_late_pass][reg_late_pass]. Both take an object -that implements an [`EarlyLintPass`][early_lint_pass] or [`LateLintPass`][late_lint_pass] respectively. This is done in -every single lint. It's worth noting that the majority of `clippy_lints/src/lib.rs` is autogenerated by `cargo dev -update_lints`. When you are writing your own lint, you can use that script to save you some time. +Each entry has the form `Field: Type = constructor`, where the constructor builds the pass (passing `conf` when the pass +needs the user configuration). The combined passes implement [`EarlyLintPass`][early_lint_pass] and +[`LateLintPass`][late_lint_pass] respectively, so each listed pass must also implement the matching trait. It's worth +noting that the majority of `clippy_lints/src/lib.rs` is autogenerated by `cargo dev update_lints`. When you are +writing your own lint, you can use that script to save you some time. ```rust // ./clippy_lints/src/else_if_without_else.rs @@ -167,14 +173,12 @@ The difference between `EarlyLintPass` and `LateLintPass` is that the methods of AST information. The methods of the `LateLintPass` trait are executed after type checking and contain type information via the `LateContext` parameter. -That's why the `else_if_without_else` example uses the `register_early_pass` function. Because the +That's why the `else_if_without_else` example is listed in `early_lint_methods!`. Because the [actual lint logic][else_if_without_else] does not depend on any type information. [lint_crate_entry]: https://github.com/rust-lang/rust-clippy/blob/master/clippy_lints/src/lib.rs [else_if_without_else]: https://github.com/rust-lang/rust-clippy/blob/4253aa7137cb7378acc96133c787e49a345c2b3c/clippy_lints/src/else_if_without_else.rs [`LintStore`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/struct.LintStore.html -[reg_early_pass]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/struct.LintStore.html#method.register_early_pass -[reg_late_pass]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/struct.LintStore.html#method.register_late_pass [early_lint_pass]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/trait.EarlyLintPass.html [late_lint_pass]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/trait.LateLintPass.html diff --git a/Cargo.toml b/Cargo.toml index b93a3f1cbe9c7..06c1840a3da26 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,7 +34,7 @@ anstream = "0.6.18" [dev-dependencies] cargo_metadata = "0.23" -ui_test = "0.30.5" +ui_test = "0.30.7" regex = "1.5.5" serde = { version = "1.0.145", features = ["derive"] } serde_json = "1.0.122" diff --git a/book/src/configuration.md b/book/src/configuration.md index aff9222ea6066..cb2ac67361bef 100644 --- a/book/src/configuration.md +++ b/book/src/configuration.md @@ -89,7 +89,7 @@ cargo clippy -- -A clippy::all -W clippy::useless_format -W clippy::... #### Lints Section in `Cargo.toml` Finally, lints can be allowed/denied using [the lints -section](https://doc.rust-lang.org/nightly/cargo/reference/manifest.html#the-lints-section)) in the `Cargo.toml` file: +section](https://doc.rust-lang.org/nightly/cargo/reference/manifest.html#the-lints-section) in the `Cargo.toml` file: To deny `clippy::enum_glob_use`, put the following in the `Cargo.toml`: diff --git a/book/src/development/adding_lints.md b/book/src/development/adding_lints.md index d9a5f04c3e1c0..474b8c6c474ef 100644 --- a/book/src/development/adding_lints.md +++ b/book/src/development/adding_lints.md @@ -282,21 +282,22 @@ When using `cargo dev new_lint`, the lint is automatically registered and nothing more has to be done. When declaring a new lint by hand and `cargo dev update_lints` is used, the lint -pass may have to be registered manually in the `register_lints` function in -`clippy_lints/src/lib.rs`: +pass may have to be registered manually by adding an entry to the +`early_lint_methods!` macro invocation in `clippy_lints/src/lib.rs`, at the +`// add early passes here` marker: ```rust,ignore -store.register_early_pass(|| Box::new(foo_functions::FooFunctions)); +FooFunctions: foo_functions::FooFunctions = foo_functions::FooFunctions, ``` -As one may expect, there is a corresponding `register_late_pass` method -available as well. Without a call to one of `register_early_pass` or -`register_late_pass`, the lint pass in question will not be run. +As one may expect, there is a corresponding `late_lint_methods!` macro available +as well. Without an entry in one of `early_lint_methods!` or `late_lint_methods!`, +the lint pass in question will not be run. One reason that `cargo dev update_lints` does not automate this step is that multiple lints can use the same lint pass, so registering the lint pass may already be done when adding a new lint. Another reason that this step is not -automated is that the order that the passes are registered determines the order +automated is that the order that the passes are listed determines the order the passes actually run, which in turn affects the order that any emitted lints are output in. diff --git a/book/src/development/defining_lints.md b/book/src/development/defining_lints.md index cb6d7b740dbd1..cc108ce70d3d7 100644 --- a/book/src/development/defining_lints.md +++ b/book/src/development/defining_lints.md @@ -184,18 +184,19 @@ However, sometimes we might want to declare a new lint by hand. In this case, we'd use `cargo dev update_lints` command afterwards. When a lint is manually declared, we might need to register the lint pass -manually in the `register_lints` function in `clippy_lints/src/lib.rs`: +manually by adding an entry to the `late_lint_methods!` macro invocation in +`clippy_lints/src/lib.rs`, at the `// add late passes here` marker: ```rust -store.register_late_pass(|_| Box::new(foo_functions::FooFunctions)); +FooFunctions: foo_functions::FooFunctions = foo_functions::FooFunctions, ``` As you might have guessed, where there's something late, there is something -early: in Clippy there is a `register_early_pass` method as well. More on early +early: in Clippy there is an `early_lint_methods!` macro as well. More on early vs. late passes in the [Lint Passes] chapter. -Without a call to one of `register_early_pass` or `register_late_pass`, the lint -pass in question will not be run. +Without an entry in one of `early_lint_methods!` or `late_lint_methods!`, the +lint pass in question will not be run. [all_lints]: https://rust-lang.github.io/rust-clippy/master/ diff --git a/book/src/lint_configuration.md b/book/src/lint_configuration.md index 64d0bf9b62f69..e123d7ba5704d 100644 --- a/book/src/lint_configuration.md +++ b/book/src/lint_configuration.md @@ -609,7 +609,7 @@ default configuration of Clippy. By default, any configuration will replace the * `doc-valid-idents = ["ClipPy"]` would replace the default list with `["ClipPy"]`. * `doc-valid-idents = ["ClipPy", ".."]` would append `ClipPy` to the default list. -**Default Value:** `["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "MHz", "GHz", "THz", "AccessKit", "CoAP", "CoreFoundation", "CoreGraphics", "CoreText", "DevOps", "Direct2D", "Direct3D", "DirectWrite", "DirectX", "ECMAScript", "GPLv2", "GPLv3", "GitHub", "GitLab", "IPv4", "IPv6", "InfiniBand", "RoCE", "ClojureScript", "CoffeeScript", "JavaScript", "PostScript", "PureScript", "TypeScript", "PowerPC", "PowerShell", "WebAssembly", "NaN", "NaNs", "OAuth", "GraphQL", "OCaml", "OpenAL", "OpenDNS", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenTelemetry", "OpenType", "WebGL", "WebGL2", "WebGPU", "WebRTC", "WebSocket", "WebTransport", "WebP", "OpenExr", "YCbCr", "sRGB", "TensorFlow", "TrueType", "iOS", "macOS", "FreeBSD", "NetBSD", "OpenBSD", "NixOS", "TeX", "LaTeX", "BibTeX", "BibLaTeX", "MinGW", "CamelCase"]` +**Default Value:** `["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "MHz", "GHz", "THz", "AccessKit", "CoAP", "CoreFoundation", "CoreGraphics", "CoreText", "DevOps", "Direct2D", "Direct3D", "DirectWrite", "DirectX", "ECMAScript", "GPLv2", "GPLv3", "GitHub", "GitLab", "IPv4", "IPv6", "InfiniBand", "RoCE", "ClojureScript", "CoffeeScript", "JavaScript", "PostScript", "PureScript", "TypeScript", "PowerPC", "PowerShell", "WebAssembly", "NaN", "NaNs", "OAuth", "GraphQL", "SQLite", "MySQL", "PostgreSQL", "MariaDB", "MongoDB", "OCaml", "OpenAL", "OpenDNS", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenTelemetry", "OpenType", "WebGL", "WebGL2", "WebGPU", "WebRTC", "WebSocket", "WebTransport", "WebP", "OpenExr", "YCbCr", "sRGB", "TensorFlow", "TrueType", "iOS", "macOS", "FreeBSD", "NetBSD", "OpenBSD", "NixOS", "TeX", "LaTeX", "BibTeX", "BibLaTeX", "MinGW", "CamelCase"]` --- **Affected lints:** @@ -780,7 +780,8 @@ be filtering for common types. ## `max-fn-params-bools` -The maximum number of bool parameters a function can have +The maximum number of bool parameters a function can have. +Use `0` to lint on any function with a bool parameter. **Default Value:** `3` @@ -925,6 +926,7 @@ The minimum rust version that the project supports. Defaults to the `rust-versio * [`manual_hash_one`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_hash_one) * [`manual_is_ascii_check`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_ascii_check) * [`manual_is_power_of_two`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_power_of_two) +* [`manual_isolate_lowest_one`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_isolate_lowest_one) * [`manual_let_else`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_let_else) * [`manual_midpoint`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_midpoint) * [`manual_non_exhaustive`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_non_exhaustive) @@ -984,6 +986,28 @@ The minimum size (in bytes) to consider a type for passing by reference instead * [`large_types_passed_by_value`](https://rust-lang.github.io/rust-clippy/master/index.html#large_types_passed_by_value) +## `profiles` +Named profiles of disallowed items (unrelated to Cargo build profiles). + +#### Example + +```toml +[profiles.persistent] +disallowed-methods = [{ path = "std::env::temp_dir" }] +disallowed-types = [{ path = "std::time::Instant", reason = "use our custom time API" }] + +[profiles.single_threaded] +disallowed-methods = [{ path = "std::thread::spawn" }] +``` + +**Default Value:** `{}` + +--- +**Affected lints:** +* [`disallowed_methods`](https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_methods) +* [`disallowed_types`](https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_types) + + ## `pub-underscore-fields-behavior` Lint "public" fields in a struct that are prefixed with an underscore based on their exported visibility, or whether they are marked as "pub". diff --git a/book/src/lints.md b/book/src/lints.md index 55b382c855651..8943274a38e81 100644 --- a/book/src/lints.md +++ b/book/src/lints.md @@ -5,10 +5,11 @@ and idiomatic Rust code. A full list of all lints, that can be filtered by category, lint level or keywords, can be found in the [Clippy lint documentation]. -This chapter will give an overview of the different lint categories, which kind -of lints they offer and recommended actions when you should see a lint out of +This chapter provides details about the different lint categories, which kind +of lints they offer, and recommended actions when you should see a lint out of that category. For examples, see the [Clippy lint documentation] and filter by -category. +category. For an overview of these categories, see the +[introduction](index.md). The different lint groups were defined in the [Clippy 1.0 RFC]. diff --git a/build.rs b/build.rs index b79d09b0dd2d2..4a28465c77151 100644 --- a/build.rs +++ b/build.rs @@ -1,6 +1,4 @@ fn main() { - // Forward the profile to the main compilation - println!("cargo:rustc-env=PROFILE={}", std::env::var("PROFILE").unwrap()); // Don't rebuild even if nothing changed println!("cargo:rerun-if-changed=build.rs"); rustc_tools_util::setup_version_info!(); diff --git a/clippy_config/src/conf.rs b/clippy_config/src/conf.rs index 465e88a783ed8..47bc7b572c9d0 100644 --- a/clippy_config/src/conf.rs +++ b/clippy_config/src/conf.rs @@ -1,12 +1,13 @@ use crate::ClippyConfiguration; use crate::types::{ - DisallowedPath, DisallowedPathWithoutReplacement, InherentImplLintScope, MacroMatcher, MatchLintBehaviour, - PubUnderscoreFieldsBehaviour, Rename, SourceItemOrdering, SourceItemOrderingCategory, + DisallowedPath, DisallowedPathWithoutReplacement, DisallowedProfile, InherentImplLintScope, MacroMatcher, + MatchLintBehaviour, PubUnderscoreFieldsBehaviour, Rename, SourceItemOrdering, SourceItemOrderingCategory, SourceItemOrderingModuleItemGroupings, SourceItemOrderingModuleItemKind, SourceItemOrderingTraitAssocItemKind, SourceItemOrderingTraitAssocItemKinds, SourceItemOrderingWithinModuleItemGroupings, }; use clippy_utils::msrvs::Msrv; use itertools::Itertools; +use rustc_data_structures::fx::FxHashMap; use rustc_errors::Applicability; use rustc_session::Session; use rustc_span::edit_distance::edit_distance; @@ -38,6 +39,7 @@ const DEFAULT_DOC_VALID_IDENTS: &[&str] = &[ "PowerPC", "PowerShell", "WebAssembly", "NaN", "NaNs", "OAuth", "GraphQL", + "SQLite", "MySQL", "PostgreSQL", "MariaDB", "MongoDB", "OCaml", "OpenAL", "OpenDNS", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenTelemetry", "OpenType", @@ -221,12 +223,74 @@ macro_rules! deserialize { }}; } +macro_rules! parse_conf_value { + ( + $map:expr, + $ty:ty, + $errors:expr, + $file:expr, + $field_span:expr, + profiles @[$($profiles:expr)?], + disallowed @[$($disallowed:expr)?] + ) => { + parse_conf_value_impl!( + $map, + $ty, + $errors, + $file, + $field_span, + ($($profiles)?), + ($($disallowed)?) + ) + }; +} + +macro_rules! parse_conf_value_impl { + ($map:expr, $ty:ty, $errors:expr, $file:expr, $field_span:expr, (), ()) => {{ + let _ = &$field_span; + deserialize!($map, $ty, $errors, $file) + }}; + ($map:expr, $ty:ty, $errors:expr, $file:expr, $field_span:expr, ($profiles:expr), ()) => {{ + let raw_value = $map.next_value::()?; + let value_span = $field_span.clone(); + let toml::Value::Table(table) = raw_value else { + $errors.push(ConfError::spanned( + $file, + "expected table with named profiles", + None, + value_span.clone(), + )); + continue; + }; + + let map = parse_profiles(table, $file, value_span.clone(), &mut $errors); + + (map, value_span) + }}; + ($map:expr, $ty:ty, $errors:expr, $file:expr, $field_span:expr, (), ($disallowed:expr)) => {{ + let _ = &$field_span; + deserialize!($map, $ty, $errors, $file, $disallowed) + }}; + ( + $map:expr, + $ty:ty, + $errors:expr, + $file:expr, + $field_span:expr, + ($profiles:expr), + ($disallowed:expr) + ) => { + compile_error!("field cannot specify both profiles and disallowed-paths attributes") + }; +} + macro_rules! define_Conf { ($( $(#[doc = $doc:literal])+ $(#[conf_deprecated($dep:literal, $new_conf:ident)])? $(#[default_text = $default_text:expr])? $(#[disallowed_paths_allow_replacements = $replacements_allowed:expr])? + $(#[profiles = $profiles:expr])? $(#[lints($($for_lints:ident),* $(,)?)])? $name:ident: $ty:ty = $default:expr, )*) => { @@ -281,10 +345,20 @@ macro_rules! define_Conf { match field { $(Field::$name => { + let field_span = name.span(); // Is this a deprecated field, i.e., is `$dep` set? If so, push a warning. $(warnings.push(ConfError::spanned(self.0, format!("deprecated field `{}`. {}", name.get_ref(), $dep), None, name.span()));)? - let (value, value_span) = - deserialize!(map, $ty, errors, self.0 $(, $replacements_allowed)?); + let (value, value_span) = parse_conf_value!( + map, + $ty, + errors, + self.0, + field_span, + // Disallowed-profile table parsing is special-cased to preserve spans for + // diagnostics in disallowed-path entries. + profiles @[$($profiles)?], + disallowed @[$($replacements_allowed)?] + ); // Was this field set previously? if $name.is_some() { errors.push(ConfError::spanned(self.0, format!("duplicate field `{}`", name.get_ref()), None, name.span())); @@ -341,6 +415,121 @@ fn span_from_toml_range(file: &SourceFile, span: Range) -> Span { ) } +fn parse_profiles( + table: toml::value::Table, + file: &SourceFile, + value_span: Range, + errors: &mut Vec, +) -> FxHashMap { + let mut profiles = FxHashMap::default(); + let config_span = span_from_toml_range(file, value_span.clone()); + + for (profile_name, profile_value) in table { + let toml::Value::Table(mut profile_table) = profile_value else { + errors.push(ConfError::spanned( + file, + format!("invalid profile `{profile_name}`: expected table"), + None, + value_span.clone(), + )); + continue; + }; + + let disallowed_methods = match profile_table + .remove("disallowed-methods") + .or_else(|| profile_table.remove("disallowed_methods")) + { + Some(value) => parse_profile_list( + file, + &profile_name, + "disallowed-methods", + value, + value_span.clone(), + config_span, + errors, + ), + None => Vec::new(), + }; + + let disallowed_types = match profile_table + .remove("disallowed-types") + .or_else(|| profile_table.remove("disallowed_types")) + { + Some(value) => parse_profile_list( + file, + &profile_name, + "disallowed-types", + value, + value_span.clone(), + config_span, + errors, + ), + None => Vec::new(), + }; + + if !profile_table.is_empty() { + let keys = profile_table.keys().map(String::as_str).collect::>().join(", "); + errors.push(ConfError::spanned( + file, + format!("profile `{profile_name}` has unknown keys: {keys}"), + None, + value_span.clone(), + )); + } + + profiles.insert( + profile_name, + DisallowedProfile { + disallowed_methods, + disallowed_types, + }, + ); + } + + profiles +} + +fn parse_profile_list( + file: &SourceFile, + profile_name: &str, + key_name: &str, + value: toml::Value, + value_span: Range, + config_span: Span, + errors: &mut Vec, +) -> Vec { + let toml::Value::Array(entries) = value else { + errors.push(ConfError::spanned( + file, + format!("profile `{profile_name}`: `{key_name}` must be an array"), + None, + value_span, + )); + return Vec::new(); + }; + + let mut disallowed = Vec::with_capacity(entries.len()); + for entry in entries { + match DisallowedPath::deserialize(entry.clone()) { + Ok(mut path) => { + path.set_span(config_span); + disallowed.push(path); + }, + Err(err) => errors.push(ConfError::spanned( + file, + format!( + "profile `{profile_name}`: {}", + err.to_string().replace('\n', " ").trim() + ), + None, + value_span.clone(), + )), + } + } + + disallowed +} + define_Conf! { /// Which crates to allow absolute paths from #[lints(absolute_paths)] @@ -713,7 +902,8 @@ define_Conf! { /// be filtering for common types. #[lints(manual_let_else)] matches_for_let_else: MatchLintBehaviour = MatchLintBehaviour::WellKnownTypes, - /// The maximum number of bool parameters a function can have + /// The maximum number of bool parameters a function can have. + /// Use `0` to lint on any function with a bool parameter. #[lints(fn_params_excessive_bools)] max_fn_params_bools: u64 = 3, /// The maximum size of a file included via `include_bytes!()` or `include_str!()`, in bytes @@ -786,6 +976,7 @@ define_Conf! { manual_hash_one, manual_is_ascii_check, manual_is_power_of_two, + manual_isolate_lowest_one, manual_let_else, manual_midpoint, manual_non_exhaustive, @@ -838,6 +1029,21 @@ define_Conf! { /// The minimum size (in bytes) to consider a type for passing by reference instead of by value. #[lints(large_types_passed_by_value)] pass_by_value_size_limit: u64 = 256, + /// Named profiles of disallowed items (unrelated to Cargo build profiles). + /// + /// #### Example + /// + /// ```toml + /// [profiles.persistent] + /// disallowed-methods = [{ path = "std::env::temp_dir" }] + /// disallowed-types = [{ path = "std::time::Instant", reason = "use our custom time API" }] + /// + /// [profiles.single_threaded] + /// disallowed-methods = [{ path = "std::thread::spawn" }] + /// ``` + #[profiles = true] + #[lints(disallowed_methods, disallowed_types)] + profiles: FxHashMap = FxHashMap::default(), /// Lint "public" fields in a struct that are prefixed with an underscore based on their /// exported visibility, or whether they are marked as "pub". #[lints(pub_underscore_fields)] diff --git a/clippy_config/src/types.rs b/clippy_config/src/types.rs index 8d9326a904b1e..5eaa44ddd51d7 100644 --- a/clippy_config/src/types.rs +++ b/clippy_config/src/types.rs @@ -57,6 +57,15 @@ impl<'de, const REPLACEMENT_ALLOWED: bool> Deserialize<'de> for DisallowedPath, + #[serde(default, alias = "disallowed_types")] + pub disallowed_types: Vec, +} + // `DisallowedPathEnum` is an implementation detail to enable the `Deserialize` implementation just // above. `DisallowedPathEnum` is not meant to be used outside of this file. #[derive(Debug, Deserialize, Serialize)] diff --git a/clippy_dev/src/new_lint.rs b/clippy_dev/src/new_lint.rs index a5e2050a3865e..4e44cad472ae0 100644 --- a/clippy_dev/src/new_lint.rs +++ b/clippy_dev/src/new_lint.rs @@ -157,20 +157,29 @@ fn add_lint(lint: &LintData<'_>, enable_msrv: bool) -> io::Result<()> { let path = "clippy_lints/src/lib.rs"; let mut lib_rs = fs::read_to_string(path).context("reading")?; - let (comment, ctor_arg) = if lint.pass == Pass::Late { - ("// add late passes here", "_") - } else { - ("// add early passes here", "") - }; - let comment_start = lib_rs.find(comment).expect("Couldn't find comment"); let module_name = lint.name; let camel_name = to_camel_case(lint.name); - let new_lint = if enable_msrv { - format!("Box::new(move |{ctor_arg}| Box::new({module_name}::{camel_name}::new(conf))),\n ") + let (comment, new_lint) = if lint.pass == Pass::Late { + // Late passes are folded into the statically-combined struct, so a new + // entry is just `Field: Type = constructor` (see `combined_late_pass`). + let new_lint = if enable_msrv { + format!("{camel_name}: {module_name}::{camel_name} = {module_name}::{camel_name}::new(conf),\n ") + } else { + format!("{camel_name}: {module_name}::{camel_name} = {module_name}::{camel_name},\n ") + }; + ("// add late passes here", new_lint) } else { - format!("Box::new(|{ctor_arg}| Box::new({module_name}::{camel_name})),\n ") + // Early passes are folded into the statically-combined struct, so a new + // entry is just `Field: Type = constructor` (see `combined_early_pass`). + let new_lint = if enable_msrv { + format!("{camel_name}: {module_name}::{camel_name} = {module_name}::{camel_name}::new(conf),\n ") + } else { + format!("{camel_name}: {module_name}::{camel_name} = {module_name}::{camel_name},\n ") + }; + ("// add early passes here", new_lint) }; + let comment_start = lib_rs.find(comment).expect("Couldn't find comment"); lib_rs.insert_str(comment_start, &new_lint); diff --git a/clippy_dummy/Cargo.toml b/clippy_dummy/Cargo.toml index 61bdd421c764e..5c7ed584309aa 100644 --- a/clippy_dummy/Cargo.toml +++ b/clippy_dummy/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy_dummy" # rename to clippy before publishing -version = "0.0.303" +version = "0.0.304" edition = "2024" readme = "crates-readme.md" description = "A bunch of helpful lints to avoid common pitfalls in Rust." @@ -13,4 +13,4 @@ keywords = ["clippy", "lint", "plugin"] categories = ["development-tools", "development-tools::cargo-plugins"] [build-dependencies] -term = "0.7" +term = "1" diff --git a/clippy_lints/src/attrs/inline_always.rs b/clippy_lints/src/attrs/inline_always.rs index c0b14c2a4b66e..7ba7f803d2229 100644 --- a/clippy_lints/src/attrs/inline_always.rs +++ b/clippy_lints/src/attrs/inline_always.rs @@ -1,17 +1,20 @@ use super::INLINE_ALWAYS; +use super::utils::is_relevant_expr; use clippy_utils::diagnostics::span_lint; use rustc_hir::attrs::InlineAttr; -use rustc_hir::{Attribute, find_attr}; +use rustc_hir::{Attribute, BodyId, find_attr}; use rustc_lint::LateContext; use rustc_span::Span; use rustc_span::symbol::Symbol; -pub(super) fn check(cx: &LateContext<'_>, span: Span, name: Symbol, attrs: &[Attribute]) { +pub(super) fn check(cx: &LateContext<'_>, span: Span, name: Symbol, attrs: &[Attribute], body: Option) { if span.from_expansion() { return; } - if let Some(span) = find_attr!(attrs, Inline(InlineAttr::Always, span) => *span) { + if let Some(span) = find_attr!(attrs, Inline(InlineAttr::Always, span) => *span) + && body.is_none_or(|body| is_relevant_expr(cx, cx.tcx.hir_body(body).value)) + { span_lint( cx, INLINE_ALWAYS, diff --git a/clippy_lints/src/attrs/mod.rs b/clippy_lints/src/attrs/mod.rs index 372defbb4d7e2..78701b3368226 100644 --- a/clippy_lints/src/attrs/mod.rs +++ b/clippy_lints/src/attrs/mod.rs @@ -14,14 +14,15 @@ mod useless_attribute; mod utils; use clippy_config::Conf; +use clippy_utils::check_clippy_attr; use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::msrvs::{self, Msrv, MsrvStack}; use rustc_ast::{self as ast, AttrArgs, AttrItemKind, AttrKind, Attribute, MetaItemInner, MetaItemKind}; -use rustc_hir::{ImplItem, Item, ItemKind, TraitItem}; -use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass}; +use rustc_hir::{ImplItem, ImplItemKind, Item, ItemKind, TraitFn, TraitItem, TraitItemKind}; +use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext}; use rustc_session::impl_lint_pass; use rustc_span::sym; -use utils::{is_lint_level, is_relevant_impl, is_relevant_item, is_relevant_trait}; +use utils::is_lint_level; declare_clippy_lint! { /// ### What it does @@ -512,23 +513,31 @@ impl Attributes { impl<'tcx> LateLintPass<'tcx> for Attributes { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { let attrs = cx.tcx.hir_attrs(item.hir_id()); - if let ItemKind::Fn { ident, .. } = item.kind - && is_relevant_item(cx, item) - { - inline_always::check(cx, item.span, ident.name, attrs); + if let ItemKind::Fn { ident, body, .. } = item.kind { + inline_always::check(cx, item.span, ident.name, attrs, Some(body)); } repr_attributes::check(cx, item.span, attrs, self.msrv); } fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>) { - if is_relevant_impl(cx, item) { - inline_always::check(cx, item.span, item.ident.name, cx.tcx.hir_attrs(item.hir_id())); + if let ImplItemKind::Fn(_, body) = item.kind { + inline_always::check( + cx, + item.span, + item.ident.name, + cx.tcx.hir_attrs(item.hir_id()), + Some(body), + ); } } fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) { - if is_relevant_trait(cx, item) { - inline_always::check(cx, item.span, item.ident.name, cx.tcx.hir_attrs(item.hir_id())); + if let TraitItemKind::Fn(_, kind) = item.kind { + let body = match kind { + TraitFn::Required(_) => None, + TraitFn::Provided(body) => Some(body), + }; + inline_always::check(cx, item.span, item.ident.name, cx.tcx.hir_attrs(item.hir_id()), body); } } } @@ -574,6 +583,7 @@ impl EarlyLintPass for PostExpansionEarlyAttributes { } fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &Attribute) { + check_clippy_attr(cx.sess(), attr); if let Some(items) = &attr.meta_item_list() && let Some(name) = attr.name() { diff --git a/clippy_lints/src/attrs/utils.rs b/clippy_lints/src/attrs/utils.rs index 4822bdcb9bde2..9e56e019229ec 100644 --- a/clippy_lints/src/attrs/utils.rs +++ b/clippy_lints/src/attrs/utils.rs @@ -1,10 +1,7 @@ use clippy_utils::macros::{is_panic, macro_backtrace}; use rustc_ast::MetaItemInner; -use rustc_hir::{ - Block, Expr, ExprKind, ImplItem, ImplItemKind, Item, ItemKind, StmtKind, TraitFn, TraitItem, TraitItemKind, -}; +use rustc_hir::{Block, Expr, ExprKind, StmtKind}; use rustc_lint::{LateContext, Level}; -use rustc_middle::ty; use rustc_span::sym; use rustc_span::symbol::Symbol; @@ -20,56 +17,26 @@ pub(super) fn is_lint_level(symbol: Symbol) -> bool { Level::from_symbol(symbol).is_some() } -pub(super) fn is_relevant_item(cx: &LateContext<'_>, item: &Item<'_>) -> bool { - if let ItemKind::Fn { body: eid, .. } = item.kind { - is_relevant_expr(cx, cx.tcx.typeck_body(eid), cx.tcx.hir_body(eid).value) - } else { - false - } -} - -pub(super) fn is_relevant_impl(cx: &LateContext<'_>, item: &ImplItem<'_>) -> bool { - match item.kind { - ImplItemKind::Fn(_, eid) => is_relevant_expr(cx, cx.tcx.typeck_body(eid), cx.tcx.hir_body(eid).value), - _ => false, - } -} - -pub(super) fn is_relevant_trait(cx: &LateContext<'_>, item: &TraitItem<'_>) -> bool { - match item.kind { - TraitItemKind::Fn(_, TraitFn::Required(_)) => true, - TraitItemKind::Fn(_, TraitFn::Provided(eid)) => { - is_relevant_expr(cx, cx.tcx.typeck_body(eid), cx.tcx.hir_body(eid).value) - }, - _ => false, - } -} - -fn is_relevant_block(cx: &LateContext<'_>, typeck_results: &ty::TypeckResults<'_>, block: &Block<'_>) -> bool { +fn is_relevant_block(cx: &LateContext<'_>, block: &Block<'_>) -> bool { block.stmts.first().map_or_else( - || { - block - .expr - .as_ref() - .is_some_and(|e| is_relevant_expr(cx, typeck_results, e)) - }, + || block.expr.as_ref().is_some_and(|e| is_relevant_expr(cx, e)), |stmt| match &stmt.kind { StmtKind::Let(_) => true, - StmtKind::Expr(expr) | StmtKind::Semi(expr) => is_relevant_expr(cx, typeck_results, expr), + StmtKind::Expr(expr) | StmtKind::Semi(expr) => is_relevant_expr(cx, expr), StmtKind::Item(_) => false, }, ) } -fn is_relevant_expr(cx: &LateContext<'_>, typeck_results: &ty::TypeckResults<'_>, expr: &Expr<'_>) -> bool { +pub(super) fn is_relevant_expr(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { if macro_backtrace(expr.span).last().is_some_and(|macro_call| { is_panic(cx, macro_call.def_id) || cx.tcx.item_name(macro_call.def_id) == sym::unreachable }) { return false; } match &expr.kind { - ExprKind::Block(block, _) => is_relevant_block(cx, typeck_results, block), - ExprKind::Ret(Some(e)) => is_relevant_expr(cx, typeck_results, e), + ExprKind::Block(block, _) => is_relevant_block(cx, block), + ExprKind::Ret(Some(e)) => is_relevant_expr(cx, e), ExprKind::Ret(None) | ExprKind::Break(_, None) => false, _ => true, } diff --git a/clippy_lints/src/combined_early_pass.rs b/clippy_lints/src/combined_early_pass.rs new file mode 100644 index 0000000000000..85de0b00a1b04 --- /dev/null +++ b/clippy_lints/src/combined_early_pass.rs @@ -0,0 +1,92 @@ +//! A statically-combined early lint pass. +//! +//! The early-pass analogue of [`combined_late_pass`]. Folds clippy's early +//! passes into one concrete struct, one field per pass, with a single +//! `EarlyLintPass` impl that forwards each `check_*` to every field. Same +//! static-dispatch / DCE win as the late version: because the field types are +//! concrete and the forwards are `#[inline(always)]`, a pass that doesn't +//! override a `check_*` contributes only the empty default body, which is +//! DCE'd away. So the per-node, per-pass indirect (vtable) call into an empty +//! method disappears entirely, and the passes that do override become direct, +//! inlined calls. No vtable, no per-node dynamic dispatch. +//! +//! Unlike the late combine there is no `active` gate. rustc drops fully-disabled +//! late passes via `lints_that_dont_need_to_run`, but the early pass runner has +//! no such filtering, so a plain forward is equivalent and loses nothing. +//! +//! [`combined_late_pass`]: crate::combined_late_pass + +/// Run one field's `check_*`. +/// +/// Fully qualified through [`rustc_lint::EarlyLintPass`] since some passes impl +/// both `EarlyLintPass` and `LateLintPass` with like-named methods, which would +/// be ambiguous on the concrete field type. +#[macro_export] +macro_rules! run_combined_early_lint_pass_field { + ($self:ident, $field:ident, $name:ident, ($($arg:expr),* $(,)?)) => { + rustc_lint::EarlyLintPass::$name(&mut $self.$field, $($arg),*); + }; +} + +/// Forward one `check_*` method to every field of the combined pass. +#[macro_export] +macro_rules! expand_combined_early_lint_pass_method { + ([$($field:ident),*], $self:ident, $name:ident, $args:tt) => ({ + $($crate::run_combined_early_lint_pass_field!($self, $field, $name, $args);)* + }) +} + +/// Generate the combined `EarlyLintPass` impl's `check_*` methods, one per method +/// in rustc's early-pass method list. +#[macro_export] +macro_rules! expand_combined_early_lint_pass_methods { + ($fields:tt, [$($(#[$attr:meta])* fn $name:ident($($param:ident: $arg:ty),*);)*]) => ( + $(#[inline(always)] fn $name(&mut self, cx: &rustc_lint::EarlyContext<'_>, $($param: $arg),*) { + $crate::expand_combined_early_lint_pass_method!($fields, self, $name, (cx, $($param),*)); + })* + ) +} + +/// Declare the combined struct (one field per pass) plus its +/// `LintPass`/`EarlyLintPass` impls. The method list comes from +/// `rustc_lint::early_lint_methods!` so it can't drift from rustc's. +/// +/// Each entry is `Field: Type = constructor`; `new`'s params (`conf`, ...) come +/// from the caller so ctor exprs can name them without hygiene trouble. +#[macro_export] +macro_rules! combined_early_lint_pass { + ( + [$name:ident, ($($pname:ident: $pty:ty),* $(,)?), [$($field:ident: $fty:ty = $ctor:expr,)*]], + $methods:tt + ) => { + #[allow(non_snake_case)] + pub struct $name { + $($field: $fty,)* + } + + impl $name { + pub fn new($($pname: $pty,)*) -> Self { + Self { + $($field: $ctor,)* + } + } + } + + #[allow(rustc::lint_pass_impl_without_macro)] + impl rustc_lint::LintPass for $name { + fn name(&self) -> &'static str { + stringify!($name) + } + fn get_lints(&self) -> rustc_lint::LintVec { + // Reserve at least one slot per pass up front to skip the early reallocations. + let mut lints = Vec::with_capacity([$(stringify!($field)),*].len()); + $(lints.extend(self.$field.get_lints());)* + lints + } + } + + impl rustc_lint::EarlyLintPass for $name { + $crate::expand_combined_early_lint_pass_methods!([$($field),*], $methods); + } + }; +} diff --git a/clippy_lints/src/combined_late_pass.rs b/clippy_lints/src/combined_late_pass.rs new file mode 100644 index 0000000000000..135603fd15d08 --- /dev/null +++ b/clippy_lints/src/combined_late_pass.rs @@ -0,0 +1,106 @@ +//! A statically-combined late lint pass. +//! +//! Folds clippy's ~300 late passes into one concrete struct, one field per pass. +//! The single `LateLintPass` impl forwards each `check_*` to every field; with +//! concrete types and `#[inline(always)]`, unoverridden methods are DCE'd and the +//! rest become direct calls, so there is no vtable or per-node dynamic dispatch. +//! +//! Mirrors rustc's `declare_combined_late_lint_pass!`, but wraps each field in +//! [`Gated`] with a precomputed `active` flag (the same "lint still needs to run" +//! predicate `rustc_lint::late` uses). Disabled passes are skipped by a branch +//! rather than dropped from a `Vec`, keeping clippy's allow-by-default fast path. + +use rustc_lint::{LintPass, LintVec}; + +/// A pass paired with its precomputed "still needs to run" flag. +pub struct Gated

{ + pub(crate) active: bool, + pub(crate) pass: P, +} + +impl Gated

{ + #[inline] + pub fn new bool>(is_active: &F, pass: P) -> Self { + let active = is_active(&pass.get_lints()); + Gated { active, pass } + } +} + +/// Run one field's `check_*`, if that field is active. +/// +/// Fully qualified through [`rustc_lint::LateLintPass`] since some passes impl +/// both `EarlyLintPass` and `LateLintPass` with like-named methods, which would +/// be ambiguous on the concrete field type. The args arrive as one `tt` and are +/// re-parsed here so the per-field and per-argument repetitions never share a +/// nesting level. +#[macro_export] +macro_rules! run_combined_late_lint_pass_field { + ($self:ident, $field:ident, $name:ident, ($($arg:expr),* $(,)?)) => { + if $self.$field.active { + rustc_lint::LateLintPass::$name(&mut $self.$field.pass, $($arg),*); + } + }; +} + +/// Forward one `check_*` method to every field of the combined pass. +#[macro_export] +macro_rules! expand_combined_late_lint_pass_method { + ([$($field:ident),*], $self:ident, $name:ident, $args:tt) => ({ + $($crate::run_combined_late_lint_pass_field!($self, $field, $name, $args);)* + }) +} + +/// Generate the combined `LateLintPass` impl's `check_*` methods, one per method +/// in rustc's late-pass method list. +#[macro_export] +macro_rules! expand_combined_late_lint_pass_methods { + ($fields:tt, [$($(#[$attr:meta])* fn $name:ident($($param:ident: $arg:ty),*);)*]) => ( + $(#[inline(always)] fn $name(&mut self, cx: &rustc_lint::LateContext<'tcx>, $($param: $arg),*) { + $crate::expand_combined_late_lint_pass_method!($fields, self, $name, (cx, $($param),*)); + })* + ) +} + +/// Declare the combined struct (one [`Gated`] field per pass) plus its +/// `LintPass`/`LateLintPass` impls. The method list comes from +/// `rustc_lint::late_lint_methods!` so it can't drift from rustc's. +/// +/// Each entry is `Field: Type = constructor`; `new`'s params (`tcx`, `conf`, ...) +/// come from the caller so ctor exprs can name them without hygiene trouble. +#[macro_export] +macro_rules! combined_late_lint_pass { + ( + [$name:ident, ($($pname:ident: $pty:ty),* $(,)?), [$($field:ident: $fty:ty = $ctor:expr,)*]], + $methods:tt + ) => { + #[allow(non_snake_case)] + pub struct $name<'tcx> { + $($field: $crate::combined_late_pass::Gated<$fty>,)* + } + + impl<'tcx> $name<'tcx> { + pub fn new bool>($($pname: $pty,)* is_active: &F) -> Self { + Self { + $($field: $crate::combined_late_pass::Gated::new(is_active, $ctor),)* + } + } + } + + #[allow(rustc::lint_pass_impl_without_macro)] + impl<'tcx> rustc_lint::LintPass for $name<'tcx> { + fn name(&self) -> &'static str { + stringify!($name) + } + fn get_lints(&self) -> rustc_lint::LintVec { + // Reserve at least one slot per pass up front to skip the early reallocations. + let mut lints = Vec::with_capacity([$(stringify!($field)),*].len()); + $(lints.extend(self.$field.pass.get_lints());)* + lints + } + } + + impl<'tcx> rustc_lint::LateLintPass<'tcx> for $name<'tcx> { + $crate::expand_combined_late_lint_pass_methods!([$($field),*], $methods); + } + }; +} diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index b5047c628d0f0..6daa70f390aaa 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -276,6 +276,7 @@ pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[ crate::loops::EXPLICIT_INTO_ITER_LOOP_INFO, crate::loops::EXPLICIT_ITER_LOOP_INFO, crate::loops::FOR_KV_MAP_INFO, + crate::loops::FOR_UNBOUNDED_RANGE_INFO, crate::loops::INFINITE_LOOP_INFO, crate::loops::ITER_NEXT_LOOP_INFO, crate::loops::MANUAL_FIND_INFO, @@ -385,7 +386,6 @@ pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[ crate::methods::FLAT_MAP_IDENTITY_INFO, crate::methods::FLAT_MAP_OPTION_INFO, crate::methods::FORMAT_COLLECT_INFO, - crate::methods::FROM_ITER_INSTEAD_OF_COLLECT_INFO, crate::methods::GET_FIRST_INFO, crate::methods::GET_LAST_WITH_LEN_INFO, crate::methods::GET_UNWRAP_INFO, @@ -613,6 +613,7 @@ pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[ crate::operators::INVALID_UPCAST_COMPARISONS_INFO, crate::operators::MANUAL_DIV_CEIL_INFO, crate::operators::MANUAL_IS_MULTIPLE_OF_INFO, + crate::operators::MANUAL_ISOLATE_LOWEST_ONE_INFO, crate::operators::MANUAL_MIDPOINT_INFO, crate::operators::MISREFACTORED_ASSIGN_OP_INFO, crate::operators::MODULO_ARITHMETIC_INFO, @@ -807,6 +808,7 @@ pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[ crate::volatile_composites::VOLATILE_COMPOSITES_INFO, crate::wildcard_imports::ENUM_GLOB_USE_INFO, crate::wildcard_imports::WILDCARD_IMPORTS_INFO, + crate::with_capacity_zero::WITH_CAPACITY_ZERO_INFO, crate::write::PRINT_LITERAL_INFO, crate::write::PRINT_STDERR_INFO, crate::write::PRINT_STDOUT_INFO, diff --git a/clippy_lints/src/default_numeric_fallback.rs b/clippy_lints/src/default_numeric_fallback.rs index 9ea70159eb9f1..649d8449e431b 100644 --- a/clippy_lints/src/default_numeric_fallback.rs +++ b/clippy_lints/src/default_numeric_fallback.rs @@ -56,7 +56,11 @@ impl<'tcx> LateLintPass<'tcx> for DefaultNumericFallback { // Inline const supports type inference. let is_parent_const = matches!( cx.tcx.hir_body_const_context(cx.tcx.hir_body_owner_def_id(body.id())), - Some(ConstContext::Const { allow_const_fn_promotion: true } | ConstContext::Static(_)) + Some( + ConstContext::Const { + allow_const_fn_promotion: true + } | ConstContext::Static(_) + ) ); let mut visitor = NumericFallbackVisitor::new(cx, is_parent_const); visitor.visit_body(body); diff --git a/clippy_lints/src/deprecated_lints.rs b/clippy_lints/src/deprecated_lints.rs index ff92cd0598393..f1d481909d675 100644 --- a/clippy_lints/src/deprecated_lints.rs +++ b/clippy_lints/src/deprecated_lints.rs @@ -17,6 +17,8 @@ declare_with_version! { DEPRECATED(DEPRECATED_VERSION) = [ ("clippy::assign_ops", "compound operators are harmless and linting on them is not in scope for clippy"), #[clippy::version = "pre 1.29.0"] ("clippy::extend_from_slice", "`Vec::extend_from_slice` is no longer faster than `Vec::extend` due to specialization"), + #[clippy::version = "1.98.0"] + ("clippy::from_iter_instead_of_collect", "lint has proved problematic"), #[clippy::version = "1.88.0"] ("clippy::match_on_vec_items", "`clippy::indexing_slicing` covers indexing and slicing on `Vec<_>`"), #[clippy::version = "pre 1.29.0"] diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index 7a5150da6593a..26a06992d1a6f 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -2,7 +2,9 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then}; use clippy_utils::res::MaybeResPath; use clippy_utils::source::{snippet_with_applicability, snippet_with_context}; use clippy_utils::sugg::has_enclosing_paren; -use clippy_utils::ty::{adjust_derefs_manually_drop, implements_trait, is_manually_drop, peel_and_count_ty_refs}; +use clippy_utils::ty::{ + adjust_derefs_manually_drop, get_adt_inherent_method, implements_trait, is_manually_drop, peel_and_count_ty_refs, +}; use clippy_utils::{ DefinedTy, ExprUseNode, get_expr_use_site, get_parent_expr, is_block_like, is_from_proc_macro, is_lint_allowed, sym, }; @@ -17,7 +19,7 @@ use rustc_hir::{ }; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability}; -use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, TypeckResults, Unnormalized}; +use rustc_middle::ty::{self, AssocTag, Ty, TyCtxt, TypeVisitableExt, TypeckResults, Unnormalized}; use rustc_session::impl_lint_pass; use rustc_span::{Span, Symbol, SyntaxContext}; use std::borrow::Cow; @@ -368,12 +370,13 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> { }, ExprUseNode::Callee | ExprUseNode::FieldAccess(_) if !use_site.moved_before_use => true, ExprUseNode::MethodArg(hir_id, _, 0) if !use_site.moved_before_use => { - // Check for calls to trait methods where the trait is implemented - // on a reference. - // Two cases need to be handled: + // Check for calls to trait methods where auto-borrow will not resolve. + // Three cases need to be handled: // * `self` methods on `&T` will never have auto-borrow // * `&self` methods on `&T` can have auto-borrow, but `&self` methods on `T` will take // priority. + // * `&self` methods on `T` can have auto-borrow, but if there's another method with the + // same name, it may take priority. if let Some(fn_id) = typeck.type_dependent_def_id(hir_id) && let Some(trait_id) = cx.tcx.trait_of_assoc(fn_id) && let arg_ty = cx.tcx.erase_and_anonymize_regions(adjusted_ty) @@ -395,12 +398,42 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> { // Trait methods taking `self` arg_ty } - && impl_ty.is_ref() - && implements_trait( - cx, - impl_ty, - trait_id, - &args[..cx.tcx.generics_of(trait_id).own_params.len() - 1], + && let method_name = cx.tcx.item_name(fn_id) + && ( + // If this trait impl is implemented on `&T`, then auto-borrowing won't work + (impl_ty.is_ref() + && implements_trait( + cx, + impl_ty, + trait_id, + &args[..cx.tcx.generics_of(trait_id).own_params.len() - 1], + )) + // If there's an inherent method, or a method from another trait, + // with the same name that's also implemented on this same type, + // then removing the borrow might cause that method to be chosen + // instead of the current one. + || get_adt_inherent_method(cx, impl_ty, method_name).is_some() + || cx.tcx.in_scope_traits(hir_id).is_some_and(|traits| { + traits + .iter() + .filter(|trait_| { + cx.tcx + .non_blanket_impls_for_ty(trait_.def_id, impl_ty) + .next() + .is_some() + || !cx + .tcx + .trait_impls_of(trait_.def_id) + .blanket_impls() + .is_empty() + }) + .any(|trait_| { + cx.tcx + .associated_items(trait_.def_id) + .filter_by_name_unhygienic(method_name) + .any(|item| item.tag() == AssocTag::Fn && item.def_id != fn_id) + }) + }) ) { false diff --git a/clippy_lints/src/disallowed_methods.rs b/clippy_lints/src/disallowed_methods.rs index e2fd71b7d990f..58cc318d57ccd 100644 --- a/clippy_lints/src/disallowed_methods.rs +++ b/clippy_lints/src/disallowed_methods.rs @@ -1,13 +1,18 @@ use clippy_config::Conf; use clippy_config::types::{DisallowedPath, create_disallowed_map}; -use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; +use clippy_utils::disallowed_profiles::{ProfileEntry, ProfileResolver}; use clippy_utils::paths::PathNS; +use clippy_utils::sym; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::smallvec::SmallVec; use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def_id::DefIdMap; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::TyCtxt; use rustc_session::impl_lint_pass; +use rustc_span::{Span, Symbol}; declare_clippy_lint! { /// ### What it does @@ -55,6 +60,19 @@ declare_clippy_lint! { /// let mut xs = Vec::new(); // Vec::new is _not_ disallowed in the config. /// xs.push(123); // Vec::push is _not_ disallowed in the config. /// ``` + /// + /// Disallowed profiles allow scoping different disallow lists: + /// ```toml + /// [profiles.forward_pass] + /// disallowed-methods = [{ path = "crate::devices::Buffer::copy_to_host", reason = "Forward code must not touch host buffers" }] + /// ``` + /// + /// ```rust,ignore + /// #[clippy::disallowed_profile("forward_pass")] + /// fn evaluate() { + /// // Method calls in this function use the `forward_pass` profile. + /// } + /// ``` #[clippy::version = "1.49.0"] pub DISALLOWED_METHODS, style, @@ -64,12 +82,22 @@ declare_clippy_lint! { impl_lint_pass!(DisallowedMethods => [DISALLOWED_METHODS]); pub struct DisallowedMethods { - disallowed: DefIdMap<(&'static str, &'static DisallowedPath)>, + default: DefIdMap<(&'static str, &'static DisallowedPath)>, + /// Lookup per profile that declares a non-empty `disallowed_methods` list. Profiles + /// declared in `[profiles.*]` but without `disallowed_methods` entries are absent here. + profiles: FxHashMap>, + /// Every profile name declared in `[profiles.*]`, regardless of whether it contributes + /// to this lint. Used to suppress the "unknown profile" warning for profiles that exist + /// in config but only define entries for other lints (e.g. `disallowed_types`). + known_profiles: FxHashSet, + profile_cache: ProfileResolver, + warned_unknown_profiles: FxHashSet, } impl DisallowedMethods { + #[allow(rustc::potential_query_instability)] // Profiles are sorted for deterministic iteration. pub fn new(tcx: TyCtxt<'_>, conf: &'static Conf) -> Self { - let (disallowed, _) = create_disallowed_map( + let (default, _) = create_disallowed_map( tcx, &conf.disallowed_methods, PathNS::Value, @@ -82,7 +110,62 @@ impl DisallowedMethods { "function", false, ); - Self { disallowed } + + let mut profiles = FxHashMap::default(); + let mut known_profiles = FxHashSet::default(); + let mut profile_entries: Vec<_> = conf.profiles.iter().collect(); + profile_entries.sort_by_key(|(a, _)| *a); + for (name, profile) in profile_entries { + let symbol = Symbol::intern(name.as_str()); + known_profiles.insert(symbol); + + let paths = profile.disallowed_methods.as_slice(); + if paths.is_empty() { + continue; + } + + let (map, _) = create_disallowed_map( + tcx, + paths, + PathNS::Value, + |def_kind| { + matches!( + def_kind, + DefKind::Fn | DefKind::Ctor(_, CtorKind::Fn) | DefKind::AssocFn + ) + }, + "function", + false, + ); + profiles.insert(symbol, map); + } + + Self { + default, + profiles, + known_profiles, + profile_cache: ProfileResolver::default(), + warned_unknown_profiles: FxHashSet::default(), + } + } + + fn warn_unknown_profile(&mut self, cx: &LateContext<'_>, entry: &ProfileEntry) { + if self.warned_unknown_profiles.insert(entry.span) { + let attr_name = if entry.attr_name == sym::disallowed_profiles { + "clippy::disallowed_profiles" + } else { + "clippy::disallowed_profile" + }; + span_lint( + cx, + DISALLOWED_METHODS, + entry.span, + format!( + "`{attr_name}` references unknown profile `{}` for `clippy::disallowed_methods`", + entry.name + ), + ); + } } } @@ -98,13 +181,43 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedMethods { }, _ => return, }; - if let Some(&(path, disallowed_path)) = self.disallowed.get(&id) { + let mut active_profiles = SmallVec::<[Symbol; 2]>::new(); + // Copy entries out of the cache before iterating: `warn_unknown_profile` takes + // `&mut self`, which conflicts with the borrow held by `active_profiles(...)`. + let entries: SmallVec<[ProfileEntry; 2]> = self + .profile_cache + .active_profiles(cx, expr.hir_id) + .map(|selection| selection.iter().copied().collect()) + .unwrap_or_default(); + for entry in &entries { + if self.profiles.contains_key(&entry.name) { + active_profiles.push(entry.name); + } else if !self.known_profiles.contains(&entry.name) { + self.warn_unknown_profile(cx, entry); + } + } + + if let Some((profile, &(path, disallowed_path))) = active_profiles.iter().find_map(|symbol| { + self.profiles + .get(symbol) + .and_then(|map| map.get(&id).map(|info| (*symbol, info))) + }) { + let diag_amendment = disallowed_path.diag_amendment(span); + span_lint_and_then( + cx, + DISALLOWED_METHODS, + span, + format!("use of a disallowed method `{path}` (profile: {profile})"), + |diag| diag_amendment(diag), + ); + } else if let Some(&(path, disallowed_path)) = self.default.get(&id) { + let diag_amendment = disallowed_path.diag_amendment(span); span_lint_and_then( cx, DISALLOWED_METHODS, span, format!("use of a disallowed method `{path}`"), - disallowed_path.diag_amendment(span), + |diag| diag_amendment(diag), ); } } diff --git a/clippy_lints/src/disallowed_types.rs b/clippy_lints/src/disallowed_types.rs index 2c520d053f439..37dd605617a7a 100644 --- a/clippy_lints/src/disallowed_types.rs +++ b/clippy_lints/src/disallowed_types.rs @@ -1,15 +1,18 @@ use clippy_config::Conf; use clippy_config::types::{DisallowedPath, create_disallowed_map}; -use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; +use clippy_utils::disallowed_profiles::{ProfileEntry, ProfileResolver}; use clippy_utils::paths::PathNS; -use rustc_data_structures::fx::FxHashMap; +use clippy_utils::sym; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::smallvec::SmallVec; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefIdMap; use rustc_hir::{AmbigArg, Item, ItemKind, PolyTraitRef, PrimTy, Ty, TyKind, UseKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::TyCtxt; use rustc_session::impl_lint_pass; -use rustc_span::Span; +use rustc_span::{Span, Symbol}; declare_clippy_lint! { /// ### What it does @@ -51,6 +54,17 @@ declare_clippy_lint! { /// // A similar type that is allowed by the config /// use std::collections::HashMap; /// ``` + /// + /// Disallowed profiles can scope lists to specific modules: + /// ```toml + /// [profiles.forward_pass] + /// disallowed-types = [{ path = "crate::buffers::HostBuffer", reason = "Prefer device buffers in forward computations" }] + /// ``` + /// + /// ```rust,ignore + /// #[clippy::disallowed_profile("forward_pass")] + /// fn forward_step(buffer: crate::buffers::DeviceBuffer) { /* ... */ } + /// ``` #[clippy::version = "1.55.0"] pub DISALLOWED_TYPES, style, @@ -59,37 +73,127 @@ declare_clippy_lint! { impl_lint_pass!(DisallowedTypes => [DISALLOWED_TYPES]); -pub struct DisallowedTypes { +struct TypeLookup { def_ids: DefIdMap<(&'static str, &'static DisallowedPath)>, prim_tys: FxHashMap, } +impl TypeLookup { + fn from_config(tcx: TyCtxt<'_>, paths: &'static [DisallowedPath]) -> Self { + let (def_ids, prim_tys) = create_disallowed_map(tcx, paths, PathNS::Type, def_kind_predicate, "type", true); + Self { def_ids, prim_tys } + } + + fn find(&self, res: &Res) -> Option<(&'static str, &'static DisallowedPath)> { + match res { + Res::Def(_, did) => self.def_ids.get(did).copied(), + Res::PrimTy(prim) => self.prim_tys.get(prim).copied(), + _ => None, + } + } +} + +pub struct DisallowedTypes { + default: TypeLookup, + /// Lookup per profile that declares a non-empty `disallowed_types` list. Profiles + /// declared in `[profiles.*]` but without `disallowed_types` entries are absent here. + profiles: FxHashMap, + /// Every profile name declared in `[profiles.*]`, regardless of whether it contributes + /// to this lint. Used to suppress the "unknown profile" warning for profiles that exist + /// in config but only define entries for other lints (e.g. `disallowed_methods`). + known_profiles: FxHashSet, + profile_cache: ProfileResolver, + warned_unknown_profiles: FxHashSet, +} + impl DisallowedTypes { + #[allow(rustc::potential_query_instability)] // Profiles are sorted for deterministic iteration. pub fn new(tcx: TyCtxt<'_>, conf: &'static Conf) -> Self { - let (def_ids, prim_tys) = create_disallowed_map( - tcx, - &conf.disallowed_types, - PathNS::Type, - def_kind_predicate, - "type", - true, - ); - Self { def_ids, prim_tys } + let default = TypeLookup::from_config(tcx, &conf.disallowed_types); + + let mut profiles = FxHashMap::default(); + let mut known_profiles = FxHashSet::default(); + let mut profile_entries: Vec<_> = conf.profiles.iter().collect(); + profile_entries.sort_by_key(|(a, _)| *a); + for (name, profile) in profile_entries { + let symbol = Symbol::intern(name.as_str()); + known_profiles.insert(symbol); + + let paths = profile.disallowed_types.as_slice(); + if paths.is_empty() { + continue; + } + profiles.insert(symbol, TypeLookup::from_config(tcx, paths)); + } + + Self { + default, + profiles, + known_profiles, + profile_cache: ProfileResolver::default(), + warned_unknown_profiles: FxHashSet::default(), + } } - fn check_res_emit(&self, cx: &LateContext<'_>, res: &Res, span: Span) { - let (path, disallowed_path) = match res { - Res::Def(_, did) if let Some(&x) = self.def_ids.get(did) => x, - Res::PrimTy(prim) if let Some(&x) = self.prim_tys.get(prim) => x, - _ => return, - }; - span_lint_and_then( - cx, - DISALLOWED_TYPES, - span, - format!("use of a disallowed type `{path}`"), - disallowed_path.diag_amendment(span), - ); + fn warn_unknown_profile(&mut self, cx: &LateContext<'_>, entry: &ProfileEntry) { + if self.warned_unknown_profiles.insert(entry.span) { + let attr_name = if entry.attr_name == sym::disallowed_profiles { + "clippy::disallowed_profiles" + } else { + "clippy::disallowed_profile" + }; + span_lint( + cx, + DISALLOWED_TYPES, + entry.span, + format!( + "`{attr_name}` references unknown profile `{}` for `clippy::disallowed_types`", + entry.name + ), + ); + } + } + + fn check_res_emit(&mut self, cx: &LateContext<'_>, hir_id: rustc_hir::HirId, res: &Res, span: Span) { + let mut active_profiles = SmallVec::<[Symbol; 2]>::new(); + // Copy entries out of the cache before iterating: `warn_unknown_profile` takes + // `&mut self`, which conflicts with the borrow held by `active_profiles(...)`. + let entries: SmallVec<[ProfileEntry; 2]> = self + .profile_cache + .active_profiles(cx, hir_id) + .map(|selection| selection.iter().copied().collect()) + .unwrap_or_default(); + for entry in &entries { + if self.profiles.contains_key(&entry.name) { + active_profiles.push(entry.name); + } else if !self.known_profiles.contains(&entry.name) { + self.warn_unknown_profile(cx, entry); + } + } + + if let Some((profile, (path, disallowed_path))) = active_profiles.iter().find_map(|symbol| { + self.profiles + .get(symbol) + .and_then(|lookup| lookup.find(res).map(|info| (*symbol, info))) + }) { + let diag_amendment = disallowed_path.diag_amendment(span); + span_lint_and_then( + cx, + DISALLOWED_TYPES, + span, + format!("use of a disallowed type `{path}` (profile: {profile})"), + |diag| diag_amendment(diag), + ); + } else if let Some((path, disallowed_path)) = self.default.find(res) { + let diag_amendment = disallowed_path.diag_amendment(span); + span_lint_and_then( + cx, + DISALLOWED_TYPES, + span, + format!("use of a disallowed type `{path}`"), + |diag| diag_amendment(diag), + ); + } } } @@ -111,17 +215,22 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedTypes { if let ItemKind::Use(path, UseKind::Single(_)) = &item.kind && let Some(res) = path.res.type_ns { - self.check_res_emit(cx, &res, item.span); + self.check_res_emit(cx, item.hir_id(), &res, item.span); } } fn check_ty(&mut self, cx: &LateContext<'tcx>, ty: &'tcx Ty<'tcx, AmbigArg>) { if let TyKind::Path(path) = &ty.kind { - self.check_res_emit(cx, &cx.qpath_res(path, ty.hir_id), ty.span); + self.check_res_emit(cx, ty.hir_id, &cx.qpath_res(path, ty.hir_id), ty.span); } } fn check_poly_trait_ref(&mut self, cx: &LateContext<'tcx>, poly: &'tcx PolyTraitRef<'tcx>) { - self.check_res_emit(cx, &poly.trait_ref.path.res, poly.trait_ref.path.span); + self.check_res_emit( + cx, + poly.trait_ref.hir_ref_id, + &poly.trait_ref.path.res, + poly.trait_ref.path.span, + ); } } diff --git a/clippy_lints/src/doc/mod.rs b/clippy_lints/src/doc/mod.rs index 1da0a010668bb..81da571bdd601 100644 --- a/clippy_lints/src/doc/mod.rs +++ b/clippy_lints/src/doc/mod.rs @@ -906,29 +906,35 @@ fn check_attrs(cx: &LateContext<'_>, valid_idents: &FxHashSet, attrs: &[ return Some(DocHeaders::default()); } - check_for_code_clusters( - cx, - pulldown_cmark::Parser::new_with_broken_link_callback( + // Only emits the allow-by-default `DOC_LINK_CODE`; skip its extra markdown reparse when it's off. + if !clippy_utils::is_lint_allowed(cx, DOC_LINK_CODE, cx.last_node_with_lint_attrs) { + check_for_code_clusters( + cx, + pulldown_cmark::Parser::new_with_broken_link_callback( + &doc, + main_body_opts() - Options::ENABLE_SMART_PUNCTUATION, + Some(&mut fake_broken_link_callback), + ) + .into_offset_iter(), &doc, - main_body_opts() - Options::ENABLE_SMART_PUNCTUATION, - Some(&mut fake_broken_link_callback), - ) - .into_offset_iter(), - &doc, - Fragments { - doc: &doc, - fragments: &fragments, - }, - ); + Fragments { + doc: &doc, + fragments: &fragments, + }, + ); + } - doc_paragraphs_missing_punctuation::check( - cx, - &doc, - Fragments { - doc: &doc, - fragments: &fragments, - }, - ); + // Same for the allow-by-default `DOC_PARAGRAPHS_MISSING_PUNCTUATION`, which also reparses. + if !clippy_utils::is_lint_allowed(cx, DOC_PARAGRAPHS_MISSING_PUNCTUATION, cx.last_node_with_lint_attrs) { + doc_paragraphs_missing_punctuation::check( + cx, + &doc, + Fragments { + doc: &doc, + fragments: &fragments, + }, + ); + } // NOTE: check_doc uses it own cb function, // to avoid causing duplicated diagnostics for the broken link checker. diff --git a/clippy_lints/src/empty_line_after.rs b/clippy_lints/src/empty_line_after.rs index b7b84c173f418..9df1919867e2e 100644 --- a/clippy_lints/src/empty_line_after.rs +++ b/clippy_lints/src/empty_line_after.rs @@ -93,14 +93,48 @@ impl_lint_pass!(EmptyLineAfter => [ EMPTY_LINE_AFTER_OUTER_ATTR, ]); +/// The kind of the item a doc comment or attribute applies to. Used in lint messages and to +/// detect the first item of a module or crate. `Other` holds the description string from +/// `ItemKind::descr` or `assoc_item_descr`. +#[derive(Debug, Clone, Copy)] +enum ItemKindDescr { + Crate, + Module, + Other(&'static str), +} + +impl ItemKindDescr { + fn as_str(self) -> &'static str { + match self { + Self::Crate => "crate", + Self::Module => "module", + Self::Other(descr) => descr, + } + } +} + #[derive(Debug)] struct ItemInfo { - kind: &'static str, + kind: ItemKindDescr, name: Option, span: Span, mod_items: Option, } +impl ItemInfo { + fn new(kind: ItemKindDescr, ident: Option, span: Span, mod_items: Option) -> Self { + Self { + kind, + name: ident.map(|ident| ident.name), + span: match ident { + Some(ident) => span.with_hi(ident.span.hi()), + None => span.shrink_to_lo(), + }, + mod_items, + } + } +} + pub struct EmptyLineAfter { items: Vec, } @@ -339,8 +373,8 @@ impl EmptyLineAfter { diag.span_label( info.span, match kind { - StopKind::Attr => format!("the attribute applies to this {}", info.kind), - StopKind::Doc(_) => format!("the comment documents this {}", info.kind), + StopKind::Attr => format!("the attribute applies to this {}", info.kind.as_str()), + StopKind::Doc(_) => format!("the comment documents this {}", info.kind.as_str()), }, ); @@ -364,7 +398,7 @@ impl EmptyLineAfter { stop.comment_out(cx, &mut suggestions); } let name = match info.name { - Some(name) => format!("{} `{name}`", info.kind).into(), + Some(name) => format!("{} `{name}`", info.kind.as_str()).into(), None => Cow::from("the following item"), }; diag.multipart_suggestion( @@ -400,7 +434,7 @@ impl EmptyLineAfter { /// them to inner attributes/docs fn suggest_inner(&self, diag: &mut Diag<'_, ()>, kind: StopKind, gaps: &[Gap<'_>], id: NodeId) { if let Some(parent) = self.items.iter().rev().nth(1) - && (parent.kind == "module" || parent.kind == "crate") + && matches!(parent.kind, ItemKindDescr::Module | ItemKindDescr::Crate) && parent.mod_items == Some(id) && let suggestions = gaps .iter() @@ -409,10 +443,9 @@ impl EmptyLineAfter { .collect::>() && !suggestions.is_empty() { - let desc = if parent.kind == "module" { - "parent module" - } else { - parent.kind + let desc = match parent.kind { + ItemKindDescr::Module => "parent module", + _ => parent.kind.as_str(), }; diag.multipart_suggestion( match kind { @@ -425,31 +458,8 @@ impl EmptyLineAfter { } } - fn check_item_kind( - &mut self, - cx: &EarlyContext<'_>, - kind: &ItemKind, - ident: Option, - span: Span, - attrs: &[Attribute], - id: NodeId, - ) { - self.items.push(ItemInfo { - kind: kind.descr(), - name: ident.map(|ident| ident.name), - span: match ident { - Some(ident) => span.with_hi(ident.span.hi()), - None => span.shrink_to_lo(), - }, - mod_items: match kind { - ItemKind::Mod(_, _, ModKind::Loaded(items, _, _)) => items - .iter() - .filter(|i| !matches!(i.span.ctxt().outer_expn_data().kind, ExpnKind::AstPass(_))) - .map(|i| i.id) - .next(), - _ => None, - }, - }); + fn check_item_kind(&mut self, cx: &EarlyContext<'_>, info: ItemInfo, attrs: &[Attribute], id: NodeId) { + self.items.push(info); let mut outer = attrs .iter() @@ -496,10 +506,21 @@ impl EmptyLineAfter { } } +fn assoc_item_descr(kind: &AssocItemKind) -> &'static str { + match kind { + AssocItemKind::Const(_) => "constant item", + AssocItemKind::Fn(_) => "function", + AssocItemKind::Type(_) => "type alias", + AssocItemKind::MacCall(_) => "item macro invocation", + AssocItemKind::Delegation(_) => "delegated function", + AssocItemKind::DelegationMac(_) => "delegation", + } +} + impl EarlyLintPass for EmptyLineAfter { fn check_crate(&mut self, _: &EarlyContext<'_>, krate: &Crate) { self.items.push(ItemInfo { - kind: "crate", + kind: ItemKindDescr::Crate, name: Some(kw::Crate), span: krate.spans.inner_span.with_hi(krate.spans.inner_span.lo()), mod_items: krate @@ -522,28 +543,31 @@ impl EarlyLintPass for EmptyLineAfter { } fn check_impl_item(&mut self, cx: &EarlyContext<'_>, item: &Item) { - self.check_item_kind( - cx, - &item.kind.clone().into(), - item.kind.ident(), - item.span, - &item.attrs, - item.id, - ); + let kind = ItemKindDescr::Other(assoc_item_descr(&item.kind)); + let info = ItemInfo::new(kind, item.kind.ident(), item.span, None); + self.check_item_kind(cx, info, &item.attrs, item.id); } fn check_trait_item(&mut self, cx: &EarlyContext<'_>, item: &Item) { - self.check_item_kind( - cx, - &item.kind.clone().into(), - item.kind.ident(), - item.span, - &item.attrs, - item.id, - ); + let kind = ItemKindDescr::Other(assoc_item_descr(&item.kind)); + let info = ItemInfo::new(kind, item.kind.ident(), item.span, None); + self.check_item_kind(cx, info, &item.attrs, item.id); } fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) { - self.check_item_kind(cx, &item.kind, item.kind.ident(), item.span, &item.attrs, item.id); + let (kind, mod_items) = match &item.kind { + ItemKind::Mod(_, _, ModKind::Loaded(items, _, _)) => { + let first = items + .iter() + .filter(|i| !matches!(i.span.ctxt().outer_expn_data().kind, ExpnKind::AstPass(_))) + .map(|i| i.id) + .next(); + (ItemKindDescr::Module, first) + }, + ItemKind::Mod(..) => (ItemKindDescr::Module, None), + _ => (ItemKindDescr::Other(item.kind.descr()), None), + }; + let info = ItemInfo::new(kind, item.kind.ident(), item.span, mod_items); + self.check_item_kind(cx, info, &item.attrs, item.id); } } diff --git a/clippy_lints/src/escape.rs b/clippy_lints/src/escape.rs index 2e88d78ce9095..e7df5fa020e34 100644 --- a/clippy_lints/src/escape.rs +++ b/clippy_lints/src/escape.rs @@ -2,12 +2,12 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_hir; use rustc_abi::ExternAbi; use rustc_hir::def::DefKind; -use rustc_hir::{Body, FnDecl, HirId, HirIdSet, Node, Pat, PatKind, intravisit}; +use rustc_hir::{Body, FnDecl, HirId, HirIdSet, PatKind, intravisit}; use rustc_hir_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::mir::FakeReadCause; use rustc_middle::ty::layout::LayoutOf; -use rustc_middle::ty::{self, TraitRef, Ty, TyCtxt}; +use rustc_middle::ty::{self, TraitRef, Ty}; use rustc_session::impl_lint_pass; use rustc_span::Span; use rustc_span::def_id::LocalDefId; @@ -52,15 +52,16 @@ declare_clippy_lint! { impl_lint_pass!(BoxedLocal => [BOXED_LOCAL]); -fn is_non_trait_box(ty: Ty<'_>) -> bool { - ty.boxed_ty().is_some_and(|boxed| !boxed.is_trait()) +/// Whether `ty` is a `Box` where `T` is not a trait object and is small enough to live on the +/// stack (large types are boxed to avoid stack overflows). +fn is_small_non_trait_box<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, too_large_for_stack: u64) -> bool { + ty.boxed_ty().is_some_and(|boxed| { + !boxed.is_trait() && cx.layout_of(boxed).map_or(0, |l| l.size.bytes()) <= too_large_for_stack + }) } -struct EscapeDelegate<'a, 'tcx> { - cx: &'a LateContext<'tcx>, +struct EscapeDelegate { set: HirIdSet, - trait_self_ty: Option>, - too_large_for_stack: u64, } impl<'tcx> LateLintPass<'tcx> for BoxedLocal { @@ -73,6 +74,11 @@ impl<'tcx> LateLintPass<'tcx> for BoxedLocal { _: Span, fn_def_id: LocalDefId, ) { + // Skip closures + if matches!(fn_kind, intravisit::FnKind::Closure) { + return; + } + if let Some(header) = fn_kind.header() && header.abi != ExternAbi::Rust { @@ -97,12 +103,42 @@ impl<'tcx> LateLintPass<'tcx> for BoxedLocal { _ => {}, } - let mut v = EscapeDelegate { - cx, - set: HirIdSet::default(), - trait_self_ty, - too_large_for_stack: self.too_large_for_stack, - }; + let typeck_results = cx.tcx.typeck_body(body.id()); + + // Seed the set with the `Box` parameters that could be unboxed. The `ExprUseVisitor` walk + // below then removes any that escape by being moved or borrowed. + let set: HirIdSet = body + .params + .iter() + .filter_map(|param| { + // Only simple bindings (`x: Box<_>`) bind a local that the walk can track and report. + if !matches!(param.pat.kind, PatKind::Binding(..)) { + return None; + } + + let ty = typeck_results.pat_ty(param.pat); + if !is_small_non_trait_box(cx, ty, self.too_large_for_stack) { + return None; + } + + // skip `self` parameters whose type contains `Self` (i.e.: `self: Box`), see #4804 + if let Some(trait_self_ty) = trait_self_ty + && cx.tcx.hir_name(param.pat.hir_id) == kw::SelfLower + && ty.contains(trait_self_ty) + { + return None; + } + + Some(param.pat.hir_id) + }) + .collect(); + + // Without any candidate parameter, the expensive `ExprUseVisitor` walk can never lint. + if set.is_empty() { + return; + } + + let mut v = EscapeDelegate { set }; ExprUseVisitor::for_clippy(cx, fn_def_id, &mut v) .consume_body(body) @@ -120,20 +156,7 @@ impl<'tcx> LateLintPass<'tcx> for BoxedLocal { } } -// TODO: Replace with Map::is_argument(..) when it's fixed -fn is_argument(tcx: TyCtxt<'_>, id: HirId) -> bool { - match tcx.hir_node(id) { - Node::Pat(Pat { - kind: PatKind::Binding(..), - .. - }) => (), - _ => return false, - } - - matches!(tcx.parent_hir_node(id), Node::Param(_)) -} - -impl<'tcx> Delegate<'tcx> for EscapeDelegate<'_, 'tcx> { +impl<'tcx> Delegate<'tcx> for EscapeDelegate { fn consume(&mut self, cmt: &PlaceWithHirId<'tcx>, _: HirId) { if cmt.place.projections.is_empty() && let PlaceBase::Local(lid) = cmt.place.base @@ -154,39 +177,7 @@ impl<'tcx> Delegate<'tcx> for EscapeDelegate<'_, 'tcx> { } } - fn mutate(&mut self, cmt: &PlaceWithHirId<'tcx>, _: HirId) { - if cmt.place.projections.is_empty() && is_argument(self.cx.tcx, cmt.hir_id) { - // Skip closure arguments - let parent_id = self.cx.tcx.parent_hir_id(cmt.hir_id); - if let Node::Expr(..) = self.cx.tcx.parent_hir_node(parent_id) { - return; - } - - // skip if there is a `self` parameter binding to a type - // that contains `Self` (i.e.: `self: Box`), see #4804 - if let Some(trait_self_ty) = self.trait_self_ty - && self.cx.tcx.hir_name(cmt.hir_id) == kw::SelfLower - && cmt.place.ty().contains(trait_self_ty) - { - return; - } - - if is_non_trait_box(cmt.place.ty()) && !self.is_large_box(cmt.place.ty()) { - self.set.insert(cmt.hir_id); - } - } - } + fn mutate(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {} fn fake_read(&mut self, _: &PlaceWithHirId<'tcx>, _: FakeReadCause, _: HirId) {} } - -impl<'tcx> EscapeDelegate<'_, 'tcx> { - fn is_large_box(&self, ty: Ty<'tcx>) -> bool { - // Large types need to be boxed to avoid stack overflows. - if let Some(boxed_ty) = ty.boxed_ty() { - self.cx.layout_of(boxed_ty).map_or(0, |l| l.size.bytes()) > self.too_large_for_stack - } else { - false - } - } -} diff --git a/clippy_lints/src/excessive_bools.rs b/clippy_lints/src/excessive_bools.rs index 65d0ff9b543f8..b44497ded301e 100644 --- a/clippy_lints/src/excessive_bools.rs +++ b/clippy_lints/src/excessive_bools.rs @@ -11,35 +11,51 @@ use rustc_span::def_id::LocalDefId; declare_clippy_lint! { /// ### What it does - /// Checks for excessive use of - /// bools in function definitions. + /// Checks for excessive use of bools in function declarations. /// /// ### Why is this bad? - /// Calls to such functions - /// are confusing and error prone, because it's - /// hard to remember argument order and you have - /// no type system support to back you up. Using - /// two-variant enums instead of bools often makes - /// API easier to use. + /// Boolean parameters obscure meaning at the call site. The reader has to + /// remember what each `true` or `false` means and which position each flag + /// belongs in, with no help from the type system. + /// + /// The best replacement depends on what role the bool plays: + /// + /// - Use a two-variant enum when one parameter selects a mode. + /// - Split one function into two named operations when the choices are + /// distinct actions. + /// - Group multiple related flags into a struct or options type when they + /// travel together. + /// - Move the setting onto `self` or an existing config/context parameter + /// when it is really part of the surrounding state. + /// + /// This optimizes for readability of the calling code, which future readers + /// encounter more often than the function declaration. + /// + /// The `max-fn-params-bools` configuration accepts `0`, which lints on any + /// function with a bool parameter. /// /// ### Example /// ```rust,ignore - /// fn f(is_round: bool, is_hot: bool) { ... } + /// fn render_document(show_hidden: bool, is_draft: bool) { ... } /// ``` /// /// Use instead: /// ```rust,ignore - /// enum Shape { - /// Round, - /// Spiky, + /// enum Visibility { + /// ShowHidden, + /// HideHidden, /// } /// - /// enum Temperature { - /// Hot, - /// IceCold, + /// enum DocumentKind { + /// Draft, + /// Final, /// } /// - /// fn f(shape: Shape, temperature: Temperature) { ... } + /// fn render_document(visibility: Visibility, kind: DocumentKind) { ... } + /// + /// // or split the operation when the choices are distinct + /// fn render_draft() { ... } + /// fn render_final() { ... } /// ``` #[clippy::version = "1.43.0"] pub FN_PARAMS_EXCESSIVE_BOOLS, diff --git a/clippy_lints/src/functions/must_use.rs b/clippy_lints/src/functions/must_use.rs index 7c1b3ef225c6a..a3e982bb09430 100644 --- a/clippy_lints/src/functions/must_use.rs +++ b/clippy_lints/src/functions/must_use.rs @@ -10,7 +10,7 @@ use rustc_middle::ty::{self, Ty}; use rustc_span::{Span, sym}; use clippy_utils::attrs::is_proc_macro; -use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then}; +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet_indent; use clippy_utils::ty::is_must_use_ty; use clippy_utils::visitors::for_each_expr_without_closures; @@ -145,31 +145,24 @@ fn check_needless_must_use( return; } if returns_unit(decl) { - if attrs.len() == 1 { - span_lint_and_then( - cx, - MUST_USE_UNIT, - fn_header_span, - "this unit-returning function has a `#[must_use]` attribute", - |diag| { + span_lint_and_then( + cx, + MUST_USE_UNIT, + fn_header_span, + "this unit-returning function has a `#[must_use]` attribute", + |diag| { + // When there are multiple attributes, it is not sufficient to simply make `must_use` empty, see + // issue #12320. + // FIXME(jdonszelmann): this used to give a machine-applicable fix. However, it was super fragile, + // honestly looked incorrect, and is a little hard to support for a little bit now. Some day this + // could be re-added. + if attrs.len() == 1 { diag.span_suggestion(attr_span, "remove the attribute", "", Applicability::MachineApplicable); - }, - ); - } else { - // When there are multiple attributes, it is not sufficient to simply make `must_use` empty, see - // issue #12320. - // FIXME(jdonszelmann): this used to give a machine-applicable fix. However, it was super fragile, - // honestly looked incorrect, and is a little hard to support for a little bit now. Some day this - // could be re-added. - span_lint_and_help( - cx, - MUST_USE_UNIT, - fn_header_span, - "this unit-returning function has a `#[must_use]` attribute", - Some(attr_span), - "remove `must_use`", - ); - } + } else { + diag.span_help(attr_span, "remove `must_use`"); + } + }, + ); } else if reason.is_none() && is_must_use_ty(cx, return_ty(cx, item_id)) { // Ignore async functions unless Future::Output type is a must_use type if sig.header.is_async() { @@ -181,13 +174,24 @@ fn check_needless_must_use( } } - span_lint_and_help( + span_lint_and_then( cx, DOUBLE_MUST_USE, fn_header_span, "this function has a `#[must_use]` attribute with no message, but returns a type already marked as `#[must_use]`", - None, - "either add some descriptive message or remove the attribute", + |diag| { + // When there are multiple attributes, it is not sufficient to simply make `must_use` empty, see + // issue #12320. + // FIXME(jdonszelmann): this used to give a machine-applicable fix. However, it was super fragile, + // honestly looked incorrect, and is a little hard to support for a little bit now. Some day this + // could be re-added. + if attrs.len() == 1 { + diag.span_suggestion(attr_span, "remove the attribute", "", Applicability::MachineApplicable); + } else { + diag.span_help(attr_span, "remove `must_use`"); + } + diag.note("alternatively, you may add an explicit reason to the `must_use` attribute"); + }, ); } } diff --git a/clippy_lints/src/functions/result.rs b/clippy_lints/src/functions/result.rs index 829f054d8854e..331c6e23bddd7 100644 --- a/clippy_lints/src/functions/result.rs +++ b/clippy_lints/src/functions/result.rs @@ -2,10 +2,12 @@ use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::res::MaybeDef; use rustc_errors::Diag; use rustc_hir as hir; +use rustc_infer::infer::TyCtxtInferExt as _; use rustc_lint::{LateContext, LintContext}; use rustc_middle::ty::{self, Ty}; use rustc_span::def_id::DefIdSet; use rustc_span::{Span, sym}; +use rustc_trait_selection::error_reporting::InferCtxtErrorExt as _; use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then}; use clippy_utils::ty::{AdtVariantInfo, approx_ty_size}; @@ -23,17 +25,31 @@ fn result_err_ty<'tcx>( ) -> Option<(&'tcx hir::Ty<'tcx>, Ty<'tcx>)> { if !item_span.in_external_macro(cx.sess().source_map()) && let hir::FnRetTy::Return(hir_ty) = decl.output - && let ty = cx - .tcx - .instantiate_bound_regions_with_erased(cx.tcx.fn_sig(id).instantiate_identity().skip_norm_wip().output()) - && ty.is_diag_item(cx, sym::Result) - && let ty::Adt(_, args) = ty.kind() { - let err_ty = args.type_at(1); - Some((hir_ty, err_ty)) - } else { - None + let mut ty = cx + .tcx + .instantiate_bound_regions_with_erased(cx.tcx.fn_sig(id).instantiate_identity().skip_norm_wip().output()); + + // for async functions, peel through `impl Future` to get `T` + if cx.tcx.ty_is_opaque_future(ty) + && let Some(future_output_ty) = cx + .tcx + .infer_ctxt() + .build(cx.typing_mode()) + .err_ctxt() + .get_impl_future_output_ty(ty) + { + ty = future_output_ty; + } + + if let ty::Adt(adt_def, args) = ty.kind() + && cx.tcx.is_diagnostic_item(sym::Result, adt_def.did()) + { + let err_ty = args.type_at(1); + return Some((hir_ty, err_ty)); + } } + None } pub(super) fn check_item<'tcx>( diff --git a/clippy_lints/src/inline_trait_bounds.rs b/clippy_lints/src/inline_trait_bounds.rs index 99716253c53e7..3ffa23dcd6046 100644 --- a/clippy_lints/src/inline_trait_bounds.rs +++ b/clippy_lints/src/inline_trait_bounds.rs @@ -1,11 +1,12 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::{HasSession, snippet}; -use rustc_ast::NodeId; +use clippy_utils::sym; use rustc_ast::ast::{Fn, FnRetTy, GenericParam, GenericParamKind}; use rustc_ast::visit::{FnCtxt, FnKind}; +use rustc_ast::{HasAttrs as _, NodeId}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::declare_lint_pass; +use rustc_session::impl_lint_pass; use rustc_span::Span; declare_clippy_lint! { @@ -37,9 +38,30 @@ declare_clippy_lint! { "enforce that `where` bounds are used for all trait bounds" } -declare_lint_pass!(InlineTraitBounds => [INLINE_TRAIT_BOUNDS]); +impl_lint_pass!(InlineTraitBounds => [INLINE_TRAIT_BOUNDS]); + +#[derive(Default)] +pub struct InlineTraitBounds { + /// The top-level item onto which `#[automatically_derived]` has been encountered + automatically_derived_at: Option, +} impl EarlyLintPass for InlineTraitBounds { + fn check_item(&mut self, _: &EarlyContext<'_>, item: &rustc_ast::Item) { + if self.automatically_derived_at.is_none() + && item + .attrs() + .iter() + .any(|attr| attr.has_name(sym::automatically_derived)) + { + self.automatically_derived_at = Some(item.id); + } + } + + fn check_item_post(&mut self, _: &EarlyContext<'_>, item: &rustc_ast::Item) { + self.automatically_derived_at.take_if(|id| *id == item.id); + } + fn check_fn(&mut self, cx: &EarlyContext<'_>, kind: FnKind<'_>, _: Span, _: NodeId) { let FnKind::Fn(ctxt, _vis, f) = kind else { return; @@ -50,6 +72,11 @@ impl EarlyLintPass for InlineTraitBounds { return; } + // Skip automatically derived functions + if self.automatically_derived_at.is_some() { + return; + } + if f.sig.span.in_external_macro(cx.sess().source_map()) { return; } diff --git a/clippy_lints/src/large_const_arrays.rs b/clippy_lints/src/large_const_arrays.rs index 80b49ecc7a40b..9835c1decceee 100644 --- a/clippy_lints/src/large_const_arrays.rs +++ b/clippy_lints/src/large_const_arrays.rs @@ -3,9 +3,8 @@ use clippy_utils::diagnostics::span_lint_and_then; use rustc_errors::Applicability; use rustc_hir::{Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty; -use rustc_middle::ty::Unnormalized; use rustc_middle::ty::layout::LayoutOf; +use rustc_middle::ty::{self, Ty, Unnormalized}; use rustc_session::impl_lint_pass; use rustc_span::{BytePos, Pos, Span}; @@ -45,6 +44,31 @@ impl LargeConstArrays { maximum_allowed_size: conf.array_size_threshold, } } + + /// Checks recursively checks whether `ty` has an array exceeding allowed size + fn check_impl<'a>(&self, cx: &LateContext<'a>, ty: Ty<'a>) -> bool { + match ty.kind() { + ty::Adt(adt_def, args) => adt_def + .all_fields() + .any(|f| self.check_impl(cx, f.ty(cx.tcx, args).skip_norm_wip())), + ty::Array(element_type, cst) => { + let normalized = cx + .tcx + .try_normalize_erasing_regions(cx.typing_env(), Unnormalized::new_wip(*cst)) + .unwrap_or(*cst); + if let Some(element_count) = normalized.try_to_target_usize(cx.tcx) + && let Ok(element_size) = cx.layout_of(*element_type).map(|l| l.size.bytes()) + && u128::from(self.maximum_allowed_size) < u128::from(element_count) * u128::from(element_size) + { + true + } else { + false + } + }, + ty::Tuple(fields) => fields.iter().any(|f| self.check_impl(cx, f)), + _ => false, + } + } } impl<'tcx> LateLintPass<'tcx> for LargeConstArrays { @@ -56,13 +80,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeConstArrays { && generics.params.is_empty() && !generics.has_where_clause_predicates && !item.span.from_expansion() && let ty = cx.tcx.type_of(item.owner_id).instantiate_identity().skip_norm_wip() - && let ty::Array(element_type, cst) = ty.kind() - && let Some(element_count) = cx.tcx - .try_normalize_erasing_regions(cx.typing_env(), Unnormalized::new_wip(*cst)) - .unwrap_or(*cst) - .try_to_target_usize(cx.tcx) - && let Ok(element_size) = cx.layout_of(*element_type).map(|l| l.size.bytes()) - && u128::from(self.maximum_allowed_size) < u128::from(element_count) * u128::from(element_size) + && self.check_impl(cx, ty) { let hi_pos = ident.span.lo() - BytePos::from_usize(1); let sugg_span = Span::new( diff --git a/clippy_lints/src/large_futures.rs b/clippy_lints/src/large_futures.rs index 56ae1d04827e8..caa44d5ef1235 100644 --- a/clippy_lints/src/large_futures.rs +++ b/clippy_lints/src/large_futures.rs @@ -64,7 +64,9 @@ impl<'tcx> LateLintPass<'tcx> for LargeFuture { && let ty = cx.typeck_results().expr_ty(arg) && let Some(future_trait_def_id) = cx.tcx.lang_items().future_trait() && implements_trait(cx, ty, future_trait_def_id, &[]) - && let Ok(layout) = cx.tcx.layout_of(cx.typing_env().with_codegen_normalized(cx.tcx).as_query_input(ty)) + && let Ok(layout) = cx + .tcx + .layout_of(cx.typing_env().with_codegen_normalized(cx.tcx).as_query_input(ty)) && let size = layout.layout.size() && size >= Size::from_bytes(self.future_size_threshold) { diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index af25b1f7f1aac..4a7659a9cc210 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -55,6 +55,9 @@ extern crate declare_clippy_lint; mod utils; +mod combined_early_pass; +mod combined_late_pass; + pub mod declared_lints; pub mod deprecated_lints; @@ -400,6 +403,7 @@ mod vec_init_then_push; mod visibility; mod volatile_composites; mod wildcard_imports; +mod with_capacity_zero; mod write; mod zero_div_zero; mod zero_repeat_side_effects; @@ -410,10 +414,9 @@ mod zombie_processes; use clippy_config::{Conf, get_configuration_metadata, sanitize_explanation}; use clippy_utils::macros::FormatArgsStorage; use rustc_data_structures::fx::FxHashSet; -use rustc_data_structures::sync; -use rustc_lint::{EarlyLintPass, LateLintPass, Lint}; +use rustc_lint::Lint; use rustc_middle::ty::TyCtxt; -use utils::attr_collector::{AttrCollector, AttrStorage}; +use utils::attr_collector::AttrStorage; pub fn explain(name: &str) -> i32 { let target = format!("clippy::{}", name.to_ascii_uppercase()); @@ -440,7 +443,6 @@ pub fn explain(name: &str) -> i32 { /// Register all lints and lint groups with the rustc lint store /// /// Used in `./src/driver.rs`. -#[expect(clippy::too_many_lines)] pub fn register_lint_passes(store: &mut rustc_lint::LintStore, conf: &'static Conf) { for (old_name, new_name) in deprecated_lints::RENAMED { store.register_renamed(old_name, new_name); @@ -457,421 +459,409 @@ pub fn register_lint_passes(store: &mut rustc_lint::LintStore, conf: &'static Co let format_args_storage = FormatArgsStorage::default(); let attr_storage = AttrStorage::default(); - let early_lints: [Box Box + sync::DynSend + sync::DynSync>; _] = [ - { - let format_args = format_args_storage.clone(); - Box::new(move || { - Box::new(utils::format_args_collector::FormatArgsCollector::new( - format_args.clone(), - )) - }) - }, - { - let attrs = attr_storage.clone(); - Box::new(move || Box::new(AttrCollector::new(attrs.clone()))) - }, - Box::new(move || Box::new(attrs::PostExpansionEarlyAttributes::new(conf))), - Box::new(|| Box::new(unnecessary_self_imports::UnnecessarySelfImports)), - Box::new(move || Box::new(redundant_static_lifetimes::RedundantStaticLifetimes::new(conf))), - Box::new(move || Box::new(redundant_field_names::RedundantFieldNames::new(conf))), - Box::new(move || Box::new(unnested_or_patterns::UnnestedOrPatterns::new(conf))), - Box::new(|| Box::new(functions::EarlyFunctions)), - Box::new(move || Box::new(doc::Documentation::new(conf))), - Box::new(|| Box::new(suspicious_operation_groupings::SuspiciousOperationGroupings)), - Box::new(|| Box::new(double_parens::DoubleParens)), - Box::new(|| Box::new(unsafe_removed_from_name::UnsafeNameRemoval)), - Box::new(|| Box::new(else_if_without_else::ElseIfWithoutElse)), - Box::new(|| Box::new(int_plus_one::IntPlusOne)), - Box::new(|| Box::new(formatting::Formatting)), - Box::new(|| Box::new(misc_early::MiscEarlyLints)), - Box::new(|| Box::new(unused_unit::UnusedUnit)), - Box::new(|| Box::new(precedence::Precedence)), - Box::new(|| Box::new(redundant_else::RedundantElse)), - Box::new(|| Box::new(needless_arbitrary_self_type::NeedlessArbitrarySelfType)), - Box::new(move || Box::new(literal_representation::LiteralDigitGrouping::new(conf))), - Box::new(move || Box::new(literal_representation::DecimalLiteralRepresentation::new(conf))), - Box::new(|| Box::new(tabs_in_doc_comments::TabsInDocComments)), - Box::new(|| Box::::default()), - Box::new(|| Box::new(option_env_unwrap::OptionEnvUnwrap)), - Box::new(move || Box::new(non_expressive_names::NonExpressiveNames::new(conf))), - Box::new(move || Box::new(nonstandard_macro_braces::MacroBraces::new(conf))), - Box::new(|| Box::new(asm_syntax::InlineAsmX86AttSyntax)), - Box::new(|| Box::new(asm_syntax::InlineAsmX86IntelSyntax)), - Box::new(move || Box::new(module_style::ModStyle::default())), - Box::new(move || Box::new(disallowed_script_idents::DisallowedScriptIdents::new(conf))), - Box::new(|| Box::new(octal_escapes::OctalEscapes)), - Box::new(|| Box::new(single_char_lifetime_names::SingleCharLifetimeNames)), - Box::new(|| Box::new(crate_in_macro_def::CrateInMacroDef)), - Box::new(|| Box::new(pub_use::PubUse)), - Box::new(move || Box::new(large_include_file::LargeIncludeFile::new(conf))), - Box::new(|| Box::::default()), - Box::new(|| Box::new(unused_rounding::UnusedRounding)), - Box::new(move || Box::new(almost_complete_range::AlmostCompleteRange::new(conf))), - Box::new(|| Box::new(multi_assignments::MultiAssignments)), - Box::new(|| Box::new(partial_pub_fields::PartialPubFields)), - Box::new(|| Box::new(let_with_type_underscore::UnderscoreTyped)), - Box::new(move || Box::new(excessive_nesting::ExcessiveNesting::new(conf))), - Box::new(|| Box::new(ref_patterns::RefPatterns)), - Box::new(|| Box::new(needless_else::NeedlessElse)), - Box::new(move || Box::new(raw_strings::RawStrings::new(conf))), - Box::new(|| Box::new(visibility::Visibility)), - Box::new(|| Box::new(multiple_bound_locations::MultipleBoundLocations)), - Box::new(|| Box::new(field_scoped_visibility_modifiers::FieldScopedVisibilityModifiers)), - Box::new(|| Box::new(cfg_not_test::CfgNotTest)), - Box::new(|| Box::new(empty_line_after::EmptyLineAfter::new())), - Box::new(|| Box::new(inline_trait_bounds::InlineTraitBounds)), + { + let format_args = format_args_storage.clone(); + let attrs = attr_storage.clone(); + store.early_passes.push(Box::new(move || { + Box::new(CombinedEarlyLintPass::new(conf, format_args.clone(), attrs.clone())) + })); + } + + store.late_passes.push(Box::new(move |tcx: TyCtxt<'_>| { + let dont_need = tcx.lints_that_dont_need_to_run(()); + let is_active = |lints: &rustc_lint::LintVec| { + lints.is_empty() + || !lints + .iter() + .all(|lint| dont_need.contains(&rustc_lint::LintId::of(lint))) + }; + Box::new(CombinedLateLintPass::new( + tcx, + conf, + format_args_storage.clone(), + attr_storage.clone(), + &is_active, + )) + })); +} + +// Fold every early pass into one statically-combined struct (see +// `combined_early_pass`); the method list comes from `early_lint_methods!`. +#[rustfmt::skip] +rustc_lint::early_lint_methods!( + crate::combined_early_lint_pass, + [CombinedEarlyLintPass, (conf: &'static Conf, format_args: FormatArgsStorage, attrs: AttrStorage), [ + FormatArgsCollector: utils::format_args_collector::FormatArgsCollector = utils::format_args_collector::FormatArgsCollector::new(format_args.clone()), + AttrCollector: utils::attr_collector::AttrCollector = utils::attr_collector::AttrCollector::new(attrs.clone()), + PostExpansionEarlyAttributes: attrs::PostExpansionEarlyAttributes = attrs::PostExpansionEarlyAttributes::new(conf), + UnnecessarySelfImports: unnecessary_self_imports::UnnecessarySelfImports = unnecessary_self_imports::UnnecessarySelfImports, + RedundantStaticLifetimes: redundant_static_lifetimes::RedundantStaticLifetimes = redundant_static_lifetimes::RedundantStaticLifetimes::new(conf), + RedundantFieldNames: redundant_field_names::RedundantFieldNames = redundant_field_names::RedundantFieldNames::new(conf), + UnnestedOrPatterns: unnested_or_patterns::UnnestedOrPatterns = unnested_or_patterns::UnnestedOrPatterns::new(conf), + EarlyFunctions: functions::EarlyFunctions = functions::EarlyFunctions, + Documentation: doc::Documentation = doc::Documentation::new(conf), + SuspiciousOperationGroupings: suspicious_operation_groupings::SuspiciousOperationGroupings = suspicious_operation_groupings::SuspiciousOperationGroupings, + DoubleParens: double_parens::DoubleParens = double_parens::DoubleParens, + UnsafeNameRemoval: unsafe_removed_from_name::UnsafeNameRemoval = unsafe_removed_from_name::UnsafeNameRemoval, + ElseIfWithoutElse: else_if_without_else::ElseIfWithoutElse = else_if_without_else::ElseIfWithoutElse, + IntPlusOne: int_plus_one::IntPlusOne = int_plus_one::IntPlusOne, + Formatting: formatting::Formatting = formatting::Formatting, + MiscEarlyLints: misc_early::MiscEarlyLints = misc_early::MiscEarlyLints, + UnusedUnit: unused_unit::UnusedUnit = unused_unit::UnusedUnit, + Precedence: precedence::Precedence = precedence::Precedence, + RedundantElse: redundant_else::RedundantElse = redundant_else::RedundantElse, + NeedlessArbitrarySelfType: needless_arbitrary_self_type::NeedlessArbitrarySelfType = needless_arbitrary_self_type::NeedlessArbitrarySelfType, + LiteralDigitGrouping: literal_representation::LiteralDigitGrouping = literal_representation::LiteralDigitGrouping::new(conf), + DecimalLiteralRepresentation: literal_representation::DecimalLiteralRepresentation = literal_representation::DecimalLiteralRepresentation::new(conf), + TabsInDocComments: tabs_in_doc_comments::TabsInDocComments = tabs_in_doc_comments::TabsInDocComments, + SingleComponentPathImports: single_component_path_imports::SingleComponentPathImports = single_component_path_imports::SingleComponentPathImports::default(), + OptionEnvUnwrap: option_env_unwrap::OptionEnvUnwrap = option_env_unwrap::OptionEnvUnwrap, + NonExpressiveNames: non_expressive_names::NonExpressiveNames = non_expressive_names::NonExpressiveNames::new(conf), + MacroBraces: nonstandard_macro_braces::MacroBraces = nonstandard_macro_braces::MacroBraces::new(conf), + InlineAsmX86AttSyntax: asm_syntax::InlineAsmX86AttSyntax = asm_syntax::InlineAsmX86AttSyntax, + InlineAsmX86IntelSyntax: asm_syntax::InlineAsmX86IntelSyntax = asm_syntax::InlineAsmX86IntelSyntax, + ModStyle: module_style::ModStyle = module_style::ModStyle::default(), + DisallowedScriptIdents: disallowed_script_idents::DisallowedScriptIdents = disallowed_script_idents::DisallowedScriptIdents::new(conf), + OctalEscapes: octal_escapes::OctalEscapes = octal_escapes::OctalEscapes, + SingleCharLifetimeNames: single_char_lifetime_names::SingleCharLifetimeNames = single_char_lifetime_names::SingleCharLifetimeNames, + CrateInMacroDef: crate_in_macro_def::CrateInMacroDef = crate_in_macro_def::CrateInMacroDef, + PubUse: pub_use::PubUse = pub_use::PubUse, + LargeIncludeFile: large_include_file::LargeIncludeFile = large_include_file::LargeIncludeFile::new(conf), + DuplicateMod: duplicate_mod::DuplicateMod = duplicate_mod::DuplicateMod::default(), + UnusedRounding: unused_rounding::UnusedRounding = unused_rounding::UnusedRounding, + AlmostCompleteRange: almost_complete_range::AlmostCompleteRange = almost_complete_range::AlmostCompleteRange::new(conf), + MultiAssignments: multi_assignments::MultiAssignments = multi_assignments::MultiAssignments, + PartialPubFields: partial_pub_fields::PartialPubFields = partial_pub_fields::PartialPubFields, + UnderscoreTyped: let_with_type_underscore::UnderscoreTyped = let_with_type_underscore::UnderscoreTyped, + ExcessiveNesting: excessive_nesting::ExcessiveNesting = excessive_nesting::ExcessiveNesting::new(conf), + RefPatterns: ref_patterns::RefPatterns = ref_patterns::RefPatterns, + NeedlessElse: needless_else::NeedlessElse = needless_else::NeedlessElse, + RawStrings: raw_strings::RawStrings = raw_strings::RawStrings::new(conf), + Visibility: visibility::Visibility = visibility::Visibility, + MultipleBoundLocations: multiple_bound_locations::MultipleBoundLocations = multiple_bound_locations::MultipleBoundLocations, + FieldScopedVisibilityModifiers: field_scoped_visibility_modifiers::FieldScopedVisibilityModifiers = field_scoped_visibility_modifiers::FieldScopedVisibilityModifiers, + CfgNotTest: cfg_not_test::CfgNotTest = cfg_not_test::CfgNotTest, + EmptyLineAfter: empty_line_after::EmptyLineAfter = empty_line_after::EmptyLineAfter::new(), + InlineTraitBounds: inline_trait_bounds::InlineTraitBounds = inline_trait_bounds::InlineTraitBounds::default(), // add early passes here, used by `cargo dev new_lint` - ]; - store.early_passes.extend(early_lints); + ]] +); - #[expect(clippy::type_complexity)] - let late_lints: [Box< - dyn for<'tcx> Fn(TyCtxt<'tcx>) -> Box + 'tcx> + sync::DynSend + sync::DynSync, - >; _] = [ - Box::new(move |_| Box::new(operators::arithmetic_side_effects::ArithmeticSideEffects::new(conf))), - Box::new(|_| Box::new(utils::dump_hir::DumpHir)), - Box::new(|_| Box::new(utils::author::Author)), - Box::new(move |tcx| Box::new(await_holding_invalid::AwaitHolding::new(tcx, conf))), - Box::new(|_| Box::new(serde_api::SerdeApi)), - Box::new(move |_| Box::new(types::Types::new(conf))), - Box::new(move |_| Box::new(booleans::NonminimalBool::new(conf))), - Box::new(|_| Box::new(enum_clike::UnportableVariant)), - Box::new(move |_| Box::new(float_literal::FloatLiteral::new(conf))), - Box::new(|_| Box::new(ptr::Ptr)), - Box::new(|_| Box::new(needless_bool::NeedlessBool)), - Box::new(|_| Box::new(bool_comparison::BoolComparison)), - Box::new(|_| Box::new(needless_for_each::NeedlessForEach)), - Box::new(|_| Box::new(misc::LintPass)), - Box::new(|_| Box::new(eta_reduction::EtaReduction)), - Box::new(|_| Box::new(mut_mut::MutMut::default())), - Box::new(|_| Box::new(unnecessary_mut_passed::UnnecessaryMutPassed)), - Box::new(|_| Box::>::default()), - Box::new(move |_| Box::new(len_zero::LenZero::new(conf))), - Box::new(|_| Box::new(len_without_is_empty::LenWithoutIsEmpty)), - Box::new(move |_| Box::new(attrs::Attributes::new(conf))), - Box::new(|_| Box::new(blocks_in_conditions::BlocksInConditions)), - Box::new(|_| Box::new(unicode::Unicode)), - Box::new(|_| Box::new(uninit_vec::UninitVec)), - Box::new(|_| Box::new(unit_return_expecting_ord::UnitReturnExpectingOrd)), - Box::new(|_| Box::new(strings::StringAdd)), - Box::new(|_| Box::new(implicit_return::ImplicitReturn)), - Box::new(move |_| Box::new(implicit_saturating_sub::ImplicitSaturatingSub::new(conf))), - Box::new(|_| Box::new(default_numeric_fallback::DefaultNumericFallback)), - Box::new(|_| Box::new(non_octal_unix_permissions::NonOctalUnixPermissions)), - Box::new(move |_| Box::new(approx_const::ApproxConstant::new(conf))), - Box::new(move |_| Box::new(matches::Matches::new(conf))), - Box::new(move |_| Box::new(manual_non_exhaustive::ManualNonExhaustive::new(conf))), - Box::new(move |_| Box::new(manual_strip::ManualStrip::new(conf))), - Box::new(move |_| Box::new(checked_conversions::CheckedConversions::new(conf))), - Box::new(move |_| Box::new(mem_replace::MemReplace::new(conf))), - Box::new(move |_| Box::new(ranges::Ranges::new(conf))), - Box::new(move |_| Box::new(from_over_into::FromOverInto::new(conf))), - Box::new(move |_| Box::new(use_self::UseSelf::new(conf))), - Box::new(move |_| Box::new(missing_const_for_fn::MissingConstForFn::new(conf))), - Box::new(move |_| Box::new(needless_question_mark::NeedlessQuestionMark)), - Box::new(move |_| Box::new(casts::Casts::new(conf))), - Box::new(|_| Box::new(size_of_in_element_count::SizeOfInElementCount)), - Box::new(|_| Box::new(same_name_method::SameNameMethod)), - Box::new(move |_| Box::new(index_refutable_slice::IndexRefutableSlice::new(conf))), - Box::new(|_| Box::::default()), - Box::new(move |_| { - Box::new(inconsistent_struct_constructor::InconsistentStructConstructor::new( - conf, - )) - }), - { - let format_args = format_args_storage.clone(); - Box::new(move |_| Box::new(methods::Methods::new(conf, format_args.clone()))) - }, - { - let format_args = format_args_storage.clone(); - Box::new(move |_| Box::new(unit_types::UnitTypes::new(format_args.clone()))) - }, - Box::new(move |_| Box::new(loops::Loops::new(conf))), - Box::new(|_| Box::::default()), - Box::new(move |_| Box::new(lifetimes::Lifetimes::new(conf))), - Box::new(|_| Box::new(entry::HashMapPass)), - Box::new(|_| Box::new(minmax::MinMaxPass)), - Box::new(|_| Box::new(zero_div_zero::ZeroDiv)), - Box::new(|_| Box::new(mutex_atomic::Mutex)), - Box::new(|_| Box::new(needless_update::NeedlessUpdate)), - Box::new(|_| Box::new(needless_borrowed_ref::NeedlessBorrowedRef)), - Box::new(|_| Box::new(borrow_deref_ref::BorrowDerefRef)), - Box::new(|_| Box::::default()), - Box::new(|_| Box::new(temporary_assignment::TemporaryAssignment)), - Box::new(move |_| Box::new(transmute::Transmute::new(conf))), - Box::new(move |_| Box::new(cognitive_complexity::CognitiveComplexity::new(conf))), - Box::new(move |_| Box::new(escape::BoxedLocal::new(conf))), - Box::new(move |_| Box::new(useless_vec::UselessVec::new(conf))), - Box::new(move |_| Box::new(panic_unimplemented::PanicUnimplemented::new(conf))), - Box::new(|_| Box::new(strings::StringLitAsBytes)), - Box::new(|_| Box::new(derive::Derive)), - Box::new(move |_| Box::new(derivable_impls::DerivableImpls::new(conf))), - Box::new(|_| Box::new(drop_forget_ref::DropForgetRef)), - Box::new(|_| Box::new(empty_enums::EmptyEnums)), - Box::new(|_| Box::::default()), - Box::new(move |tcx| Box::new(ifs::CopyAndPaste::new(tcx, conf))), - Box::new(|_| Box::new(copy_iterator::CopyIterator)), - { - let format_args = format_args_storage.clone(); - Box::new(move |_| Box::new(format::UselessFormat::new(format_args.clone()))) - }, - Box::new(|_| Box::new(swap::Swap)), - Box::new(|_| Box::new(panicking_overflow_checks::PanickingOverflowChecks)), - Box::new(|_| Box::::default()), - Box::new(move |_| Box::new(disallowed_names::DisallowedNames::new(conf))), - Box::new(move |tcx| Box::new(functions::Functions::new(tcx, conf))), - Box::new(move |_| Box::new(doc::Documentation::new(conf))), - Box::new(|_| Box::new(neg_multiply::NegMultiply)), - Box::new(|_| Box::new(let_if_seq::LetIfSeq)), - Box::new(|_| Box::new(mixed_read_write_in_expression::EvalOrderDependence)), - Box::new(move |_| Box::new(missing_doc::MissingDoc::new(conf))), - Box::new(|_| Box::new(missing_inline::MissingInline)), - Box::new(move |_| Box::new(exhaustive_items::ExhaustiveItems)), - Box::new(|_| Box::new(unused_result_ok::UnusedResultOk)), - Box::new(|_| Box::new(match_result_ok::MatchResultOk)), - Box::new(|_| Box::new(partialeq_ne_impl::PartialEqNeImpl)), - Box::new(|_| Box::new(unused_io_amount::UnusedIoAmount)), - Box::new(move |_| Box::new(large_enum_variant::LargeEnumVariant::new(conf))), - { - let format_args = format_args_storage.clone(); - Box::new(move |_| Box::new(explicit_write::ExplicitWrite::new(format_args.clone()))) - }, - Box::new(|_| Box::new(needless_pass_by_value::NeedlessPassByValue)), - Box::new(move |tcx| Box::new(pass_by_ref_or_value::PassByRefOrValue::new(tcx, conf))), - Box::new(|_| Box::new(ref_option_ref::RefOptionRef)), - Box::new(|_| Box::new(infinite_iter::InfiniteIter)), - Box::new(|_| Box::new(inline_fn_without_body::InlineFnWithoutBody)), - Box::new(|_| Box::::default()), - Box::new(|_| Box::new(implicit_hasher::ImplicitHasher)), - Box::new(|_| Box::new(fallible_impl_from::FallibleImplFrom)), - Box::new(move |_| Box::new(question_mark::QuestionMark::new(conf))), - Box::new(|_| Box::new(question_mark_used::QuestionMarkUsed)), - Box::new(|_| Box::new(suspicious_trait_impl::SuspiciousImpl)), - Box::new(|_| Box::new(map_unit_fn::MapUnit)), - Box::new(move |_| Box::new(inherent_impl::MultipleInherentImpl::new(conf))), - Box::new(|_| Box::new(neg_cmp_op_on_partial_ord::NoNegCompOpForPartialOrd)), - Box::new(move |_| Box::new(unwrap::Unwrap::new(conf))), - Box::new(move |_| Box::new(indexing_slicing::IndexingSlicing::new(conf))), - Box::new(move |tcx| Box::new(non_copy_const::NonCopyConst::new(tcx, conf))), - Box::new(|_| Box::new(redundant_clone::RedundantClone)), - Box::new(|_| Box::new(slow_vector_initialization::SlowVectorInit)), - Box::new(move |_| Box::new(unnecessary_wraps::UnnecessaryWraps::new(conf))), - Box::new(|_| Box::new(assertions_on_constants::AssertionsOnConstants::new(conf))), - Box::new(|_| Box::new(assertions_on_result_states::AssertionsOnResultStates)), - Box::new(|_| Box::new(inherent_to_string::InherentToString)), - Box::new(move |_| Box::new(trait_bounds::TraitBounds::new(conf))), - Box::new(|_| Box::new(comparison_chain::ComparisonChain)), - Box::new(move |tcx| Box::new(mut_key::MutableKeyType::new(tcx, conf))), - Box::new(|_| Box::new(reference::DerefAddrOf)), - { - let format_args = format_args_storage.clone(); - Box::new(move |_| Box::new(format_impl::FormatImpl::new(format_args.clone()))) - }, - Box::new(|_| Box::new(redundant_closure_call::RedundantClosureCall)), - Box::new(|_| Box::new(unused_unit::UnusedUnit)), - Box::new(|_| Box::new(returns::Return)), - Box::new(move |_| Box::new(collapsible_if::CollapsibleIf::new(conf))), - Box::new(|_| Box::new(items_after_statements::ItemsAfterStatements)), - Box::new(|_| Box::new(needless_parens_on_range_literals::NeedlessParensOnRangeLiterals)), - Box::new(|_| Box::new(needless_continue::NeedlessContinue)), - Box::new(|_| Box::new(create_dir::CreateDir)), - Box::new(move |_| Box::new(item_name_repetitions::ItemNameRepetitions::new(conf))), - Box::new(move |_| Box::new(upper_case_acronyms::UpperCaseAcronyms::new(conf))), - Box::new(|_| Box::::default()), - Box::new(move |_| Box::new(unused_self::UnusedSelf::new(conf))), - Box::new(|_| Box::new(mutable_debug_assertion::DebugAssertWithMutCall)), - Box::new(|_| Box::new(exit::Exit)), - Box::new(move |_| Box::new(to_digit_is_some::ToDigitIsSome::new(conf))), - Box::new(move |_| Box::new(large_stack_arrays::LargeStackArrays::new(conf))), - Box::new(move |_| Box::new(large_const_arrays::LargeConstArrays::new(conf))), - Box::new(|_| Box::new(floating_point_arithmetic::FloatingPointArithmetic)), - Box::new(|_| Box::new(as_conversions::AsConversions)), - Box::new(|_| Box::new(let_underscore::LetUnderscore)), - Box::new(move |_| Box::new(excessive_bools::ExcessiveBools::new(conf))), - Box::new(move |_| Box::new(wildcard_imports::WildcardImports::new(conf))), - Box::new(|_| Box::::default()), - Box::new(|_| Box::>::default()), - Box::new(|_| Box::new(option_if_let_else::OptionIfLetElse)), - Box::new(|_| Box::new(future_not_send::FutureNotSend)), - Box::new(move |_| Box::new(large_futures::LargeFuture::new(conf))), - Box::new(|_| Box::new(if_let_mutex::IfLetMutex)), - Box::new(|_| Box::new(if_not_else::IfNotElse)), - Box::new(|_| Box::new(equatable_if_let::PatternEquality)), - Box::new(|_| Box::new(manual_async_fn::ManualAsyncFn)), - Box::new(|_| Box::new(panic_in_result_fn::PanicInResultFn)), - Box::new(|_| Box::::default()), - Box::new(|_| Box::new(pattern_type_mismatch::PatternTypeMismatch)), - Box::new(|_| Box::::default()), - Box::new(|_| Box::new(semicolon_if_nothing_returned::SemicolonIfNothingReturned)), - Box::new(|_| Box::new(async_yields_async::AsyncYieldsAsync)), - { - let attrs = attr_storage.clone(); - Box::new(move |tcx| Box::new(disallowed_macros::DisallowedMacros::new(tcx, conf, attrs.clone()))) - }, - Box::new(move |tcx| Box::new(disallowed_methods::DisallowedMethods::new(tcx, conf))), - Box::new(|_| Box::new(empty_drop::EmptyDrop)), - Box::new(|_| Box::new(strings::StrToString)), - Box::new(|_| Box::new(zero_sized_map_values::ZeroSizedMapValues)), - Box::new(|_| Box::::default()), - Box::new(|_| Box::new(redundant_slicing::RedundantSlicing)), - Box::new(|_| Box::new(from_str_radix_10::FromStrRadix10)), - Box::new(move |_| Box::new(if_then_some_else_none::IfThenSomeElseNone::new(conf))), - Box::new(|_| Box::new(bool_assert_comparison::BoolAssertComparison)), - Box::new(|_| Box::::default()), - Box::new(move |tcx| Box::new(disallowed_types::DisallowedTypes::new(tcx, conf))), - Box::new(move |tcx| Box::new(missing_enforced_import_rename::ImportRename::new(tcx, conf))), - Box::new(move |_| Box::new(strlen_on_c_strings::StrlenOnCStrings::new(conf))), - Box::new(move |_| Box::new(self_named_constructors::SelfNamedConstructors)), - Box::new(move |_| Box::new(iter_not_returning_iterator::IterNotReturningIterator)), - Box::new(move |_| Box::new(manual_assert::ManualAssert)), - Box::new(move |_| Box::new(non_send_fields_in_send_ty::NonSendFieldInSendTy::new(conf))), - Box::new(move |_| Box::new(undocumented_unsafe_blocks::UndocumentedUnsafeBlocks::new(conf))), - { - let format_args = format_args_storage.clone(); - Box::new(move |tcx| Box::new(format_args::FormatArgs::new(tcx, conf, format_args.clone()))) - }, - Box::new(|_| Box::new(trailing_empty_array::TrailingEmptyArray)), - Box::new(|_| Box::new(needless_late_init::NeedlessLateInit)), - Box::new(|_| Box::new(return_self_not_must_use::ReturnSelfNotMustUse)), - Box::new(|_| Box::new(init_numbered_fields::NumberedFields)), - Box::new(move |_| Box::new(manual_bits::ManualBits::new(conf))), - Box::new(|_| Box::new(default_union_representation::DefaultUnionRepresentation)), - Box::new(|_| Box::::default()), - Box::new(move |_| Box::new(dbg_macro::DbgMacro::new(conf))), - { - let format_args = format_args_storage.clone(); - Box::new(move |_| Box::new(write::Write::new(conf, format_args.clone()))) - }, - Box::new(move |_| Box::new(cargo::Cargo::new(conf))), - Box::new(|_| Box::new(empty_with_brackets::EmptyWithBrackets::default())), - Box::new(|_| Box::new(unnecessary_owned_empty_strings::UnnecessaryOwnedEmptyStrings)), - { - let format_args = format_args_storage.clone(); - Box::new(move |_| Box::new(format_push_string::FormatPushString::new(format_args.clone()))) - }, - Box::new(move |_| Box::new(large_include_file::LargeIncludeFile::new(conf))), - Box::new(|_| Box::new(strings::TrimSplitWhitespace)), - Box::new(|_| Box::new(rc_clone_in_vec_init::RcCloneInVecInit)), - Box::new(|_| Box::new(swap_ptr_to_ref::SwapPtrToRef)), - Box::new(|_| Box::new(mismatching_type_param_order::TypeParamMismatch)), - Box::new(|_| Box::new(read_zero_byte_vec::ReadZeroByteVec)), - Box::new(|_| Box::new(default_instead_of_iter_empty::DefaultIterEmpty)), - Box::new(move |_| Box::new(manual_rem_euclid::ManualRemEuclid::new(conf))), - Box::new(move |_| Box::new(manual_retain::ManualRetain::new(conf))), - Box::new(move |_| Box::new(manual_rotate::ManualRotate)), - Box::new(move |_| Box::new(operators::Operators::new(conf))), - Box::new(move |_| Box::new(std_instead_of_core::StdReexports::new(conf))), - Box::new(move |_| Box::new(time_subtraction::UncheckedTimeSubtraction::new(conf))), - Box::new(|_| Box::new(partialeq_to_none::PartialeqToNone)), - Box::new(move |_| Box::new(manual_abs_diff::ManualAbsDiff::new(conf))), - Box::new(move |_| Box::new(manual_clamp::ManualClamp::new(conf))), - Box::new(|_| Box::new(manual_string_new::ManualStringNew)), - Box::new(|_| Box::new(unused_peekable::UnusedPeekable)), - Box::new(|_| Box::new(bool_to_int_with_if::BoolToIntWithIf)), - Box::new(|_| Box::new(box_default::BoxDefault)), - Box::new(|_| Box::new(implicit_saturating_add::ImplicitSaturatingAdd)), - Box::new(|_| Box::new(missing_trait_methods::MissingTraitMethods)), - Box::new(|_| Box::new(from_raw_with_void_ptr::FromRawWithVoidPtr)), - Box::new(|_| Box::new(suspicious_xor_used_as_pow::ConfusingXorAndPow)), - Box::new(move |_| Box::new(manual_is_ascii_check::ManualIsAsciiCheck::new(conf))), - Box::new(move |_| Box::new(semicolon_block::SemicolonBlock::new(conf))), - Box::new(|_| Box::new(permissions_set_readonly_false::PermissionsSetReadonlyFalse)), - Box::new(|_| Box::new(size_of_ref::SizeOfRef)), - Box::new(|_| Box::new(multiple_unsafe_ops_per_block::MultipleUnsafeOpsPerBlock)), - Box::new(move |_| Box::new(extra_unused_type_parameters::ExtraUnusedTypeParameters::new(conf))), - Box::new(|_| Box::new(no_mangle_with_rust_abi::NoMangleWithRustAbi)), - Box::new(|_| Box::new(collection_is_never_read::CollectionIsNeverRead)), - Box::new(|_| Box::new(missing_assert_message::MissingAssertMessage)), - Box::new(|_| Box::new(needless_maybe_sized::NeedlessMaybeSized)), - Box::new(|_| Box::new(redundant_async_block::RedundantAsyncBlock)), - Box::new(move |_| Box::new(manual_main_separator_str::ManualMainSeparatorStr::new(conf))), - Box::new(|_| Box::new(unnecessary_struct_initialization::UnnecessaryStruct)), - Box::new(move |_| Box::new(unnecessary_box_returns::UnnecessaryBoxReturns::new(conf))), - Box::new(|_| Box::new(tests_outside_test_module::TestsOutsideTestModule)), - Box::new(|_| Box::new(manual_slice_size_calculation::ManualSliceSizeCalculation::new(conf))), - Box::new(|_| Box::new(items_after_test_module::ItemsAfterTestModule)), - Box::new(|_| Box::new(default_constructed_unit_structs::DefaultConstructedUnitStructs)), - Box::new(|_| Box::new(missing_fields_in_debug::MissingFieldsInDebug)), - Box::new(|_| Box::new(endian_bytes::EndianBytes)), - Box::new(|_| Box::new(redundant_type_annotations::RedundantTypeAnnotations)), - Box::new(|_| Box::new(arc_with_non_send_sync::ArcWithNonSendSync)), - Box::new(|_| Box::new(needless_ifs::NeedlessIfs)), - Box::new(move |_| Box::new(min_ident_chars::MinIdentChars::new(conf))), - Box::new(move |_| Box::new(large_stack_frames::LargeStackFrames::new(conf))), - Box::new(|_| Box::new(single_range_in_vec_init::SingleRangeInVecInit)), - Box::new(move |_| Box::new(needless_pass_by_ref_mut::NeedlessPassByRefMut::new(conf))), - Box::new(|tcx| Box::new(non_canonical_impls::NonCanonicalImpls::new(tcx))), - Box::new(move |_| Box::new(single_call_fn::SingleCallFn::new(conf))), - Box::new(move |_| Box::new(legacy_numeric_constants::LegacyNumericConstants::new(conf))), - Box::new(|_| Box::new(manual_range_patterns::ManualRangePatterns)), - Box::new(move |_| Box::new(tuple_array_conversions::TupleArrayConversions::new(conf))), - Box::new(move |_| Box::new(manual_float_methods::ManualFloatMethods::new(conf))), - Box::new(|_| Box::new(four_forward_slashes::FourForwardSlashes)), - Box::new(|_| Box::new(error_impl_error::ErrorImplError)), - Box::new(move |_| Box::new(absolute_paths::AbsolutePaths::new(conf))), - Box::new(|_| Box::new(redundant_locals::RedundantLocals)), - Box::new(|_| Box::new(ignored_unit_patterns::IgnoredUnitPatterns)), - Box::new(|_| Box::::default()), - Box::new(|_| Box::new(implied_bounds_in_impls::ImpliedBoundsInImpls)), - Box::new(|_| Box::new(missing_asserts_for_indexing::MissingAssertsForIndexing)), - Box::new(|_| Box::new(unnecessary_map_on_constructor::UnnecessaryMapOnConstructor)), - Box::new(move |_| { - Box::new(needless_borrows_for_generic_args::NeedlessBorrowsForGenericArgs::new( - conf, - )) - }), - Box::new(move |_| Box::new(manual_hash_one::ManualHashOne::new(conf))), - Box::new(|_| Box::new(iter_without_into_iter::IterWithoutIntoIter)), - Box::new(|_| Box::>::default()), - Box::new(|_| Box::new(iter_over_hash_type::IterOverHashType)), - Box::new(|_| Box::new(impl_hash_with_borrow_str_and_bytes::ImplHashWithBorrowStrBytes)), - Box::new(move |_| Box::new(repeat_vec_with_capacity::RepeatVecWithCapacity::new(conf))), - Box::new(|_| Box::new(uninhabited_references::UninhabitedReferences)), - Box::new(|_| Box::new(ineffective_open_options::IneffectiveOpenOptions)), - Box::new(|_| Box::::default()), - Box::new(move |_| Box::new(pub_underscore_fields::PubUnderscoreFields::new(conf))), - Box::new(move |_| Box::new(missing_const_for_thread_local::MissingConstForThreadLocal::new(conf))), - Box::new(move |tcx| Box::new(incompatible_msrv::IncompatibleMsrv::new(tcx, conf))), - Box::new(|_| Box::new(to_string_trait_impl::ToStringTraitImpl)), - Box::new(move |_| Box::new(assigning_clones::AssigningClones::new(conf))), - Box::new(|_| Box::new(zero_repeat_side_effects::ZeroRepeatSideEffects)), - Box::new(move |_| Box::new(macro_metavars_in_unsafe::ExprMetavarsInUnsafe::new(conf))), - Box::new(move |_| Box::new(string_patterns::StringPatterns::new(conf))), - Box::new(|_| Box::new(set_contains_or_insert::SetContainsOrInsert)), - Box::new(|_| Box::new(zombie_processes::ZombieProcesses)), - Box::new(|_| Box::new(pointers_in_nomem_asm_block::PointersInNomemAsmBlock)), - Box::new(move |_| Box::new(manual_is_power_of_two::ManualIsPowerOfTwo::new(conf))), - Box::new(|_| Box::new(non_zero_suggestions::NonZeroSuggestions)), - Box::new(|_| Box::new(literal_string_with_formatting_args::LiteralStringWithFormattingArg)), - Box::new(move |_| Box::new(unused_trait_names::UnusedTraitNames::new(conf))), - Box::new(|_| Box::new(manual_ignore_case_cmp::ManualIgnoreCaseCmp)), - Box::new(|_| Box::new(unnecessary_literal_bound::UnnecessaryLiteralBound)), - Box::new(move |_| Box::new(arbitrary_source_item_ordering::ArbitrarySourceItemOrdering::new(conf))), - Box::new(|_| Box::new(useless_concat::UselessConcat)), - Box::new(|_| Box::new(unneeded_struct_pattern::UnneededStructPattern)), - Box::new(|_| Box::::default()), - Box::new(move |_| Box::new(non_std_lazy_statics::NonStdLazyStatic::new(conf))), - Box::new(|_| Box::new(manual_option_as_slice::ManualOptionAsSlice::new(conf))), - Box::new(|_| Box::new(single_option_map::SingleOptionMap)), - Box::new(move |_| Box::new(redundant_test_prefix::RedundantTestPrefix)), - Box::new(|_| Box::new(cloned_ref_to_slice_refs::ClonedRefToSliceRefs::new(conf))), - Box::new(|_| Box::new(infallible_try_from::InfallibleTryFrom)), - Box::new(|_| Box::new(coerce_container_to_any::CoerceContainerToAny)), - Box::new(|_| Box::new(toplevel_ref_arg::ToplevelRefArg)), - Box::new(|_| Box::new(volatile_composites::VolatileComposites)), - Box::new(|_| Box::::default()), - Box::new(move |tcx| Box::new(disallowed_fields::DisallowedFields::new(tcx, conf))), - Box::new(move |_| Box::new(manual_ilog2::ManualIlog2::new(conf))), - Box::new(|_| Box::new(same_length_and_capacity::SameLengthAndCapacity)), - Box::new(move |tcx| Box::new(duration_suboptimal_units::DurationSuboptimalUnits::new(tcx, conf))), - Box::new(move |_| Box::new(manual_take::ManualTake::new(conf))), - Box::new(|_| Box::new(manual_checked_ops::ManualCheckedOps)), - Box::new(move |tcx| Box::new(manual_pop_if::ManualPopIf::new(tcx, conf))), - Box::new(move |_| Box::new(manual_noop_waker::ManualNoopWaker::new(conf))), - Box::new(|_| Box::new(byte_char_slices::ByteCharSlice)), - Box::new(|_| Box::new(manual_assert_eq::ManualAssertEq)), +// Fold every late pass into one statically-combined struct (see +// `combined_late_pass`); the method list comes from `late_lint_methods!`. +#[rustfmt::skip] +rustc_lint::late_lint_methods!( + crate::combined_late_lint_pass, + [CombinedLateLintPass, (tcx: TyCtxt<'tcx>, conf: &'static Conf, format_args: FormatArgsStorage, attrs: AttrStorage), [ + ArithmeticSideEffects: operators::arithmetic_side_effects::ArithmeticSideEffects = operators::arithmetic_side_effects::ArithmeticSideEffects::new(conf), + DumpHir: utils::dump_hir::DumpHir = utils::dump_hir::DumpHir, + Author: utils::author::Author = utils::author::Author, + AwaitHolding: await_holding_invalid::AwaitHolding = await_holding_invalid::AwaitHolding::new(tcx, conf), + SerdeApi: serde_api::SerdeApi = serde_api::SerdeApi, + Types: types::Types = types::Types::new(conf), + NonminimalBool: booleans::NonminimalBool = booleans::NonminimalBool::new(conf), + UnportableVariant: enum_clike::UnportableVariant = enum_clike::UnportableVariant, + FloatLiteral: float_literal::FloatLiteral = float_literal::FloatLiteral::new(conf), + Ptr: ptr::Ptr = ptr::Ptr, + NeedlessBool: needless_bool::NeedlessBool = needless_bool::NeedlessBool, + BoolComparison: bool_comparison::BoolComparison = bool_comparison::BoolComparison, + NeedlessForEach: needless_for_each::NeedlessForEach = needless_for_each::NeedlessForEach, + LintPass: misc::LintPass = misc::LintPass, + EtaReduction: eta_reduction::EtaReduction = eta_reduction::EtaReduction, + MutMut: mut_mut::MutMut = mut_mut::MutMut::default(), + UnnecessaryMutPassed: unnecessary_mut_passed::UnnecessaryMutPassed = unnecessary_mut_passed::UnnecessaryMutPassed, + SignificantDropTightening: significant_drop_tightening::SignificantDropTightening<'tcx> = >::default(), + LenZero: len_zero::LenZero = len_zero::LenZero::new(conf), + LenWithoutIsEmpty: len_without_is_empty::LenWithoutIsEmpty = len_without_is_empty::LenWithoutIsEmpty, + Attributes: attrs::Attributes = attrs::Attributes::new(conf), + BlocksInConditions: blocks_in_conditions::BlocksInConditions = blocks_in_conditions::BlocksInConditions, + Unicode: unicode::Unicode = unicode::Unicode, + UninitVec: uninit_vec::UninitVec = uninit_vec::UninitVec, + UnitReturnExpectingOrd: unit_return_expecting_ord::UnitReturnExpectingOrd = unit_return_expecting_ord::UnitReturnExpectingOrd, + StringAdd: strings::StringAdd = strings::StringAdd, + ImplicitReturn: implicit_return::ImplicitReturn = implicit_return::ImplicitReturn, + ImplicitSaturatingSub: implicit_saturating_sub::ImplicitSaturatingSub = implicit_saturating_sub::ImplicitSaturatingSub::new(conf), + DefaultNumericFallback: default_numeric_fallback::DefaultNumericFallback = default_numeric_fallback::DefaultNumericFallback, + NonOctalUnixPermissions: non_octal_unix_permissions::NonOctalUnixPermissions = non_octal_unix_permissions::NonOctalUnixPermissions, + ApproxConstant: approx_const::ApproxConstant = approx_const::ApproxConstant::new(conf), + Matches: matches::Matches = matches::Matches::new(conf), + ManualNonExhaustive: manual_non_exhaustive::ManualNonExhaustive = manual_non_exhaustive::ManualNonExhaustive::new(conf), + ManualStrip: manual_strip::ManualStrip = manual_strip::ManualStrip::new(conf), + CheckedConversions: checked_conversions::CheckedConversions = checked_conversions::CheckedConversions::new(conf), + MemReplace: mem_replace::MemReplace = mem_replace::MemReplace::new(conf), + Ranges: ranges::Ranges = ranges::Ranges::new(conf), + FromOverInto: from_over_into::FromOverInto = from_over_into::FromOverInto::new(conf), + UseSelf: use_self::UseSelf = use_self::UseSelf::new(conf), + MissingConstForFn: missing_const_for_fn::MissingConstForFn = missing_const_for_fn::MissingConstForFn::new(conf), + NeedlessQuestionMark: needless_question_mark::NeedlessQuestionMark = needless_question_mark::NeedlessQuestionMark, + Casts: casts::Casts = casts::Casts::new(conf), + SizeOfInElementCount: size_of_in_element_count::SizeOfInElementCount = size_of_in_element_count::SizeOfInElementCount, + SameNameMethod: same_name_method::SameNameMethod = same_name_method::SameNameMethod, + IndexRefutableSlice: index_refutable_slice::IndexRefutableSlice = index_refutable_slice::IndexRefutableSlice::new(conf), + Shadow: shadow::Shadow = ::default(), + InconsistentStructConstructor: inconsistent_struct_constructor::InconsistentStructConstructor = inconsistent_struct_constructor::InconsistentStructConstructor::new( conf, ), + Methods: methods::Methods = methods::Methods::new(conf, format_args.clone()), + UnitTypes: unit_types::UnitTypes = unit_types::UnitTypes::new(format_args.clone()), + Loops: loops::Loops = loops::Loops::new(conf), + MainRecursion: main_recursion::MainRecursion = ::default(), + Lifetimes: lifetimes::Lifetimes = lifetimes::Lifetimes::new(conf), + HashMapPass: entry::HashMapPass = entry::HashMapPass, + MinMaxPass: minmax::MinMaxPass = minmax::MinMaxPass, + ZeroDiv: zero_div_zero::ZeroDiv = zero_div_zero::ZeroDiv, + Mutex: mutex_atomic::Mutex = mutex_atomic::Mutex, + NeedlessUpdate: needless_update::NeedlessUpdate = needless_update::NeedlessUpdate, + NeedlessBorrowedRef: needless_borrowed_ref::NeedlessBorrowedRef = needless_borrowed_ref::NeedlessBorrowedRef, + BorrowDerefRef: borrow_deref_ref::BorrowDerefRef = borrow_deref_ref::BorrowDerefRef, + NoEffect: no_effect::NoEffect = ::default(), + TemporaryAssignment: temporary_assignment::TemporaryAssignment = temporary_assignment::TemporaryAssignment, + Transmute: transmute::Transmute = transmute::Transmute::new(conf), + CognitiveComplexity: cognitive_complexity::CognitiveComplexity = cognitive_complexity::CognitiveComplexity::new(conf), + BoxedLocal: escape::BoxedLocal = escape::BoxedLocal::new(conf), + UselessVec: useless_vec::UselessVec = useless_vec::UselessVec::new(conf), + PanicUnimplemented: panic_unimplemented::PanicUnimplemented = panic_unimplemented::PanicUnimplemented::new(conf), + StringLitAsBytes: strings::StringLitAsBytes = strings::StringLitAsBytes, + Derive: derive::Derive = derive::Derive, + DerivableImpls: derivable_impls::DerivableImpls = derivable_impls::DerivableImpls::new(conf), + DropForgetRef: drop_forget_ref::DropForgetRef = drop_forget_ref::DropForgetRef, + EmptyEnums: empty_enums::EmptyEnums = empty_enums::EmptyEnums, + Regex: regex::Regex = ::default(), + CopyAndPaste: ifs::CopyAndPaste<'tcx> = ifs::CopyAndPaste::new(tcx, conf), + CopyIterator: copy_iterator::CopyIterator = copy_iterator::CopyIterator, + UselessFormat: format::UselessFormat = format::UselessFormat::new(format_args.clone()), + Swap: swap::Swap = swap::Swap, + PanickingOverflowChecks: panicking_overflow_checks::PanickingOverflowChecks = panicking_overflow_checks::PanickingOverflowChecks, + NewWithoutDefault: new_without_default::NewWithoutDefault = ::default(), + DisallowedNames: disallowed_names::DisallowedNames = disallowed_names::DisallowedNames::new(conf), + Functions: functions::Functions = functions::Functions::new(tcx, conf), + Documentation: doc::Documentation = doc::Documentation::new(conf), + NegMultiply: neg_multiply::NegMultiply = neg_multiply::NegMultiply, + LetIfSeq: let_if_seq::LetIfSeq = let_if_seq::LetIfSeq, + EvalOrderDependence: mixed_read_write_in_expression::EvalOrderDependence = mixed_read_write_in_expression::EvalOrderDependence, + MissingDoc: missing_doc::MissingDoc = missing_doc::MissingDoc::new(conf), + MissingInline: missing_inline::MissingInline = missing_inline::MissingInline, + ExhaustiveItems: exhaustive_items::ExhaustiveItems = exhaustive_items::ExhaustiveItems, + UnusedResultOk: unused_result_ok::UnusedResultOk = unused_result_ok::UnusedResultOk, + MatchResultOk: match_result_ok::MatchResultOk = match_result_ok::MatchResultOk, + PartialEqNeImpl: partialeq_ne_impl::PartialEqNeImpl = partialeq_ne_impl::PartialEqNeImpl, + UnusedIoAmount: unused_io_amount::UnusedIoAmount = unused_io_amount::UnusedIoAmount, + LargeEnumVariant: large_enum_variant::LargeEnumVariant = large_enum_variant::LargeEnumVariant::new(conf), + ExplicitWrite: explicit_write::ExplicitWrite = explicit_write::ExplicitWrite::new(format_args.clone()), + NeedlessPassByValue: needless_pass_by_value::NeedlessPassByValue = needless_pass_by_value::NeedlessPassByValue, + PassByRefOrValue: pass_by_ref_or_value::PassByRefOrValue = pass_by_ref_or_value::PassByRefOrValue::new(tcx, conf), + RefOptionRef: ref_option_ref::RefOptionRef = ref_option_ref::RefOptionRef, + InfiniteIter: infinite_iter::InfiniteIter = infinite_iter::InfiniteIter, + InlineFnWithoutBody: inline_fn_without_body::InlineFnWithoutBody = inline_fn_without_body::InlineFnWithoutBody, + UselessConversion: useless_conversion::UselessConversion = ::default(), + ImplicitHasher: implicit_hasher::ImplicitHasher = implicit_hasher::ImplicitHasher, + FallibleImplFrom: fallible_impl_from::FallibleImplFrom = fallible_impl_from::FallibleImplFrom, + QuestionMark: question_mark::QuestionMark = question_mark::QuestionMark::new(conf), + QuestionMarkUsed: question_mark_used::QuestionMarkUsed = question_mark_used::QuestionMarkUsed, + SuspiciousImpl: suspicious_trait_impl::SuspiciousImpl = suspicious_trait_impl::SuspiciousImpl, + MapUnit: map_unit_fn::MapUnit = map_unit_fn::MapUnit, + MultipleInherentImpl: inherent_impl::MultipleInherentImpl = inherent_impl::MultipleInherentImpl::new(conf), + NoNegCompOpForPartialOrd: neg_cmp_op_on_partial_ord::NoNegCompOpForPartialOrd = neg_cmp_op_on_partial_ord::NoNegCompOpForPartialOrd, + Unwrap: unwrap::Unwrap = unwrap::Unwrap::new(conf), + IndexingSlicing: indexing_slicing::IndexingSlicing = indexing_slicing::IndexingSlicing::new(conf), + NonCopyConst: non_copy_const::NonCopyConst<'tcx> = non_copy_const::NonCopyConst::new(tcx, conf), + RedundantClone: redundant_clone::RedundantClone = redundant_clone::RedundantClone, + SlowVectorInit: slow_vector_initialization::SlowVectorInit = slow_vector_initialization::SlowVectorInit, + UnnecessaryWraps: unnecessary_wraps::UnnecessaryWraps = unnecessary_wraps::UnnecessaryWraps::new(conf), + AssertionsOnConstants: assertions_on_constants::AssertionsOnConstants = assertions_on_constants::AssertionsOnConstants::new(conf), + AssertionsOnResultStates: assertions_on_result_states::AssertionsOnResultStates = assertions_on_result_states::AssertionsOnResultStates, + InherentToString: inherent_to_string::InherentToString = inherent_to_string::InherentToString, + TraitBounds: trait_bounds::TraitBounds = trait_bounds::TraitBounds::new(conf), + ComparisonChain: comparison_chain::ComparisonChain = comparison_chain::ComparisonChain, + MutableKeyType: mut_key::MutableKeyType<'tcx> = mut_key::MutableKeyType::new(tcx, conf), + DerefAddrOf: reference::DerefAddrOf = reference::DerefAddrOf, + FormatImpl: format_impl::FormatImpl = format_impl::FormatImpl::new(format_args.clone()), + RedundantClosureCall: redundant_closure_call::RedundantClosureCall = redundant_closure_call::RedundantClosureCall, + UnusedUnit: unused_unit::UnusedUnit = unused_unit::UnusedUnit, + Return: returns::Return = returns::Return, + CollapsibleIf: collapsible_if::CollapsibleIf = collapsible_if::CollapsibleIf::new(conf), + ItemsAfterStatements: items_after_statements::ItemsAfterStatements = items_after_statements::ItemsAfterStatements, + NeedlessParensOnRangeLiterals: needless_parens_on_range_literals::NeedlessParensOnRangeLiterals = needless_parens_on_range_literals::NeedlessParensOnRangeLiterals, + NeedlessContinue: needless_continue::NeedlessContinue = needless_continue::NeedlessContinue, + CreateDir: create_dir::CreateDir = create_dir::CreateDir, + ItemNameRepetitions: item_name_repetitions::ItemNameRepetitions = item_name_repetitions::ItemNameRepetitions::new(conf), + UpperCaseAcronyms: upper_case_acronyms::UpperCaseAcronyms = upper_case_acronyms::UpperCaseAcronyms::new(conf), + Default: default::Default = ::default(), + UnusedSelf: unused_self::UnusedSelf = unused_self::UnusedSelf::new(conf), + DebugAssertWithMutCall: mutable_debug_assertion::DebugAssertWithMutCall = mutable_debug_assertion::DebugAssertWithMutCall, + Exit: exit::Exit = exit::Exit, + ToDigitIsSome: to_digit_is_some::ToDigitIsSome = to_digit_is_some::ToDigitIsSome::new(conf), + LargeStackArrays: large_stack_arrays::LargeStackArrays = large_stack_arrays::LargeStackArrays::new(conf), + LargeConstArrays: large_const_arrays::LargeConstArrays = large_const_arrays::LargeConstArrays::new(conf), + FloatingPointArithmetic: floating_point_arithmetic::FloatingPointArithmetic = floating_point_arithmetic::FloatingPointArithmetic, + AsConversions: as_conversions::AsConversions = as_conversions::AsConversions, + LetUnderscore: let_underscore::LetUnderscore = let_underscore::LetUnderscore, + ExcessiveBools: excessive_bools::ExcessiveBools = excessive_bools::ExcessiveBools::new(conf), + WildcardImports: wildcard_imports::WildcardImports = wildcard_imports::WildcardImports::new(conf), + RedundantPubCrate: redundant_pub_crate::RedundantPubCrate = ::default(), + Dereferencing: dereference::Dereferencing<'tcx> = >::default(), + OptionIfLetElse: option_if_let_else::OptionIfLetElse = option_if_let_else::OptionIfLetElse, + FutureNotSend: future_not_send::FutureNotSend = future_not_send::FutureNotSend, + LargeFuture: large_futures::LargeFuture = large_futures::LargeFuture::new(conf), + IfLetMutex: if_let_mutex::IfLetMutex = if_let_mutex::IfLetMutex, + IfNotElse: if_not_else::IfNotElse = if_not_else::IfNotElse, + PatternEquality: equatable_if_let::PatternEquality = equatable_if_let::PatternEquality, + ManualAsyncFn: manual_async_fn::ManualAsyncFn = manual_async_fn::ManualAsyncFn, + PanicInResultFn: panic_in_result_fn::PanicInResultFn = panic_in_result_fn::PanicInResultFn, + MacroUseImports: macro_use::MacroUseImports = ::default(), + PatternTypeMismatch: pattern_type_mismatch::PatternTypeMismatch = pattern_type_mismatch::PatternTypeMismatch, + UnwrapInResult: unwrap_in_result::UnwrapInResult = ::default(), + SemicolonIfNothingReturned: semicolon_if_nothing_returned::SemicolonIfNothingReturned = semicolon_if_nothing_returned::SemicolonIfNothingReturned, + AsyncYieldsAsync: async_yields_async::AsyncYieldsAsync = async_yields_async::AsyncYieldsAsync, + DisallowedMacros: disallowed_macros::DisallowedMacros = disallowed_macros::DisallowedMacros::new(tcx, conf, attrs.clone()), + DisallowedMethods: disallowed_methods::DisallowedMethods = disallowed_methods::DisallowedMethods::new(tcx, conf), + EmptyDrop: empty_drop::EmptyDrop = empty_drop::EmptyDrop, + StrToString: strings::StrToString = strings::StrToString, + ZeroSizedMapValues: zero_sized_map_values::ZeroSizedMapValues = zero_sized_map_values::ZeroSizedMapValues, + VecInitThenPush: vec_init_then_push::VecInitThenPush = ::default(), + RedundantSlicing: redundant_slicing::RedundantSlicing = redundant_slicing::RedundantSlicing, + FromStrRadix10: from_str_radix_10::FromStrRadix10 = from_str_radix_10::FromStrRadix10, + IfThenSomeElseNone: if_then_some_else_none::IfThenSomeElseNone = if_then_some_else_none::IfThenSomeElseNone::new(conf), + BoolAssertComparison: bool_assert_comparison::BoolAssertComparison = bool_assert_comparison::BoolAssertComparison, + UnusedAsync: unused_async::UnusedAsync = ::default(), + DisallowedTypes: disallowed_types::DisallowedTypes = disallowed_types::DisallowedTypes::new(tcx, conf), + ImportRename: missing_enforced_import_rename::ImportRename = missing_enforced_import_rename::ImportRename::new(tcx, conf), + StrlenOnCStrings: strlen_on_c_strings::StrlenOnCStrings = strlen_on_c_strings::StrlenOnCStrings::new(conf), + SelfNamedConstructors: self_named_constructors::SelfNamedConstructors = self_named_constructors::SelfNamedConstructors, + IterNotReturningIterator: iter_not_returning_iterator::IterNotReturningIterator = iter_not_returning_iterator::IterNotReturningIterator, + ManualAssert: manual_assert::ManualAssert = manual_assert::ManualAssert, + NonSendFieldInSendTy: non_send_fields_in_send_ty::NonSendFieldInSendTy = non_send_fields_in_send_ty::NonSendFieldInSendTy::new(conf), + UndocumentedUnsafeBlocks: undocumented_unsafe_blocks::UndocumentedUnsafeBlocks = undocumented_unsafe_blocks::UndocumentedUnsafeBlocks::new(conf), + FormatArgs: format_args::FormatArgs<'tcx> = format_args::FormatArgs::new(tcx, conf, format_args.clone()), + TrailingEmptyArray: trailing_empty_array::TrailingEmptyArray = trailing_empty_array::TrailingEmptyArray, + NeedlessLateInit: needless_late_init::NeedlessLateInit = needless_late_init::NeedlessLateInit, + ReturnSelfNotMustUse: return_self_not_must_use::ReturnSelfNotMustUse = return_self_not_must_use::ReturnSelfNotMustUse, + NumberedFields: init_numbered_fields::NumberedFields = init_numbered_fields::NumberedFields, + ManualBits: manual_bits::ManualBits = manual_bits::ManualBits::new(conf), + DefaultUnionRepresentation: default_union_representation::DefaultUnionRepresentation = default_union_representation::DefaultUnionRepresentation, + OnlyUsedInRecursion: only_used_in_recursion::OnlyUsedInRecursion = ::default(), + DbgMacro: dbg_macro::DbgMacro = dbg_macro::DbgMacro::new(conf), + Write: write::Write = write::Write::new(conf, format_args.clone()), + Cargo: cargo::Cargo = cargo::Cargo::new(conf), + EmptyWithBrackets: empty_with_brackets::EmptyWithBrackets = empty_with_brackets::EmptyWithBrackets::default(), + UnnecessaryOwnedEmptyStrings: unnecessary_owned_empty_strings::UnnecessaryOwnedEmptyStrings = unnecessary_owned_empty_strings::UnnecessaryOwnedEmptyStrings, + FormatPushString: format_push_string::FormatPushString = format_push_string::FormatPushString::new(format_args.clone()), + LargeIncludeFile: large_include_file::LargeIncludeFile = large_include_file::LargeIncludeFile::new(conf), + TrimSplitWhitespace: strings::TrimSplitWhitespace = strings::TrimSplitWhitespace, + RcCloneInVecInit: rc_clone_in_vec_init::RcCloneInVecInit = rc_clone_in_vec_init::RcCloneInVecInit, + SwapPtrToRef: swap_ptr_to_ref::SwapPtrToRef = swap_ptr_to_ref::SwapPtrToRef, + TypeParamMismatch: mismatching_type_param_order::TypeParamMismatch = mismatching_type_param_order::TypeParamMismatch, + ReadZeroByteVec: read_zero_byte_vec::ReadZeroByteVec = read_zero_byte_vec::ReadZeroByteVec, + DefaultIterEmpty: default_instead_of_iter_empty::DefaultIterEmpty = default_instead_of_iter_empty::DefaultIterEmpty, + ManualRemEuclid: manual_rem_euclid::ManualRemEuclid = manual_rem_euclid::ManualRemEuclid::new(conf), + ManualRetain: manual_retain::ManualRetain = manual_retain::ManualRetain::new(conf), + ManualRotate: manual_rotate::ManualRotate = manual_rotate::ManualRotate, + Operators: operators::Operators = operators::Operators::new(conf), + StdReexports: std_instead_of_core::StdReexports = std_instead_of_core::StdReexports::new(conf), + UncheckedTimeSubtraction: time_subtraction::UncheckedTimeSubtraction = time_subtraction::UncheckedTimeSubtraction::new(conf), + PartialeqToNone: partialeq_to_none::PartialeqToNone = partialeq_to_none::PartialeqToNone, + ManualAbsDiff: manual_abs_diff::ManualAbsDiff = manual_abs_diff::ManualAbsDiff::new(conf), + ManualClamp: manual_clamp::ManualClamp = manual_clamp::ManualClamp::new(conf), + ManualStringNew: manual_string_new::ManualStringNew = manual_string_new::ManualStringNew, + UnusedPeekable: unused_peekable::UnusedPeekable = unused_peekable::UnusedPeekable, + BoolToIntWithIf: bool_to_int_with_if::BoolToIntWithIf = bool_to_int_with_if::BoolToIntWithIf, + BoxDefault: box_default::BoxDefault = box_default::BoxDefault, + ImplicitSaturatingAdd: implicit_saturating_add::ImplicitSaturatingAdd = implicit_saturating_add::ImplicitSaturatingAdd, + MissingTraitMethods: missing_trait_methods::MissingTraitMethods = missing_trait_methods::MissingTraitMethods, + FromRawWithVoidPtr: from_raw_with_void_ptr::FromRawWithVoidPtr = from_raw_with_void_ptr::FromRawWithVoidPtr, + ConfusingXorAndPow: suspicious_xor_used_as_pow::ConfusingXorAndPow = suspicious_xor_used_as_pow::ConfusingXorAndPow, + ManualIsAsciiCheck: manual_is_ascii_check::ManualIsAsciiCheck = manual_is_ascii_check::ManualIsAsciiCheck::new(conf), + SemicolonBlock: semicolon_block::SemicolonBlock = semicolon_block::SemicolonBlock::new(conf), + PermissionsSetReadonlyFalse: permissions_set_readonly_false::PermissionsSetReadonlyFalse = permissions_set_readonly_false::PermissionsSetReadonlyFalse, + SizeOfRef: size_of_ref::SizeOfRef = size_of_ref::SizeOfRef, + MultipleUnsafeOpsPerBlock: multiple_unsafe_ops_per_block::MultipleUnsafeOpsPerBlock = multiple_unsafe_ops_per_block::MultipleUnsafeOpsPerBlock, + ExtraUnusedTypeParameters: extra_unused_type_parameters::ExtraUnusedTypeParameters = extra_unused_type_parameters::ExtraUnusedTypeParameters::new(conf), + NoMangleWithRustAbi: no_mangle_with_rust_abi::NoMangleWithRustAbi = no_mangle_with_rust_abi::NoMangleWithRustAbi, + CollectionIsNeverRead: collection_is_never_read::CollectionIsNeverRead = collection_is_never_read::CollectionIsNeverRead, + MissingAssertMessage: missing_assert_message::MissingAssertMessage = missing_assert_message::MissingAssertMessage, + NeedlessMaybeSized: needless_maybe_sized::NeedlessMaybeSized = needless_maybe_sized::NeedlessMaybeSized, + RedundantAsyncBlock: redundant_async_block::RedundantAsyncBlock = redundant_async_block::RedundantAsyncBlock, + ManualMainSeparatorStr: manual_main_separator_str::ManualMainSeparatorStr = manual_main_separator_str::ManualMainSeparatorStr::new(conf), + UnnecessaryStruct: unnecessary_struct_initialization::UnnecessaryStruct = unnecessary_struct_initialization::UnnecessaryStruct, + UnnecessaryBoxReturns: unnecessary_box_returns::UnnecessaryBoxReturns = unnecessary_box_returns::UnnecessaryBoxReturns::new(conf), + TestsOutsideTestModule: tests_outside_test_module::TestsOutsideTestModule = tests_outside_test_module::TestsOutsideTestModule, + ManualSliceSizeCalculation: manual_slice_size_calculation::ManualSliceSizeCalculation = manual_slice_size_calculation::ManualSliceSizeCalculation::new(conf), + ItemsAfterTestModule: items_after_test_module::ItemsAfterTestModule = items_after_test_module::ItemsAfterTestModule, + DefaultConstructedUnitStructs: default_constructed_unit_structs::DefaultConstructedUnitStructs = default_constructed_unit_structs::DefaultConstructedUnitStructs, + MissingFieldsInDebug: missing_fields_in_debug::MissingFieldsInDebug = missing_fields_in_debug::MissingFieldsInDebug, + EndianBytes: endian_bytes::EndianBytes = endian_bytes::EndianBytes, + RedundantTypeAnnotations: redundant_type_annotations::RedundantTypeAnnotations = redundant_type_annotations::RedundantTypeAnnotations, + ArcWithNonSendSync: arc_with_non_send_sync::ArcWithNonSendSync = arc_with_non_send_sync::ArcWithNonSendSync, + NeedlessIfs: needless_ifs::NeedlessIfs = needless_ifs::NeedlessIfs, + MinIdentChars: min_ident_chars::MinIdentChars = min_ident_chars::MinIdentChars::new(conf), + LargeStackFrames: large_stack_frames::LargeStackFrames = large_stack_frames::LargeStackFrames::new(conf), + SingleRangeInVecInit: single_range_in_vec_init::SingleRangeInVecInit = single_range_in_vec_init::SingleRangeInVecInit, + NeedlessPassByRefMut: needless_pass_by_ref_mut::NeedlessPassByRefMut<'tcx> = needless_pass_by_ref_mut::NeedlessPassByRefMut::new(conf), + NonCanonicalImpls: non_canonical_impls::NonCanonicalImpls = non_canonical_impls::NonCanonicalImpls::new(tcx), + SingleCallFn: single_call_fn::SingleCallFn = single_call_fn::SingleCallFn::new(conf), + LegacyNumericConstants: legacy_numeric_constants::LegacyNumericConstants = legacy_numeric_constants::LegacyNumericConstants::new(conf), + ManualRangePatterns: manual_range_patterns::ManualRangePatterns = manual_range_patterns::ManualRangePatterns, + TupleArrayConversions: tuple_array_conversions::TupleArrayConversions = tuple_array_conversions::TupleArrayConversions::new(conf), + ManualFloatMethods: manual_float_methods::ManualFloatMethods = manual_float_methods::ManualFloatMethods::new(conf), + FourForwardSlashes: four_forward_slashes::FourForwardSlashes = four_forward_slashes::FourForwardSlashes, + ErrorImplError: error_impl_error::ErrorImplError = error_impl_error::ErrorImplError, + AbsolutePaths: absolute_paths::AbsolutePaths = absolute_paths::AbsolutePaths::new(conf), + RedundantLocals: redundant_locals::RedundantLocals = redundant_locals::RedundantLocals, + IgnoredUnitPatterns: ignored_unit_patterns::IgnoredUnitPatterns = ignored_unit_patterns::IgnoredUnitPatterns, + ReserveAfterInitialization: reserve_after_initialization::ReserveAfterInitialization = ::default(), + ImpliedBoundsInImpls: implied_bounds_in_impls::ImpliedBoundsInImpls = implied_bounds_in_impls::ImpliedBoundsInImpls, + MissingAssertsForIndexing: missing_asserts_for_indexing::MissingAssertsForIndexing = missing_asserts_for_indexing::MissingAssertsForIndexing, + UnnecessaryMapOnConstructor: unnecessary_map_on_constructor::UnnecessaryMapOnConstructor = unnecessary_map_on_constructor::UnnecessaryMapOnConstructor, + NeedlessBorrowsForGenericArgs: needless_borrows_for_generic_args::NeedlessBorrowsForGenericArgs<'tcx> = needless_borrows_for_generic_args::NeedlessBorrowsForGenericArgs::new( conf, ), + ManualHashOne: manual_hash_one::ManualHashOne = manual_hash_one::ManualHashOne::new(conf), + IterWithoutIntoIter: iter_without_into_iter::IterWithoutIntoIter = iter_without_into_iter::IterWithoutIntoIter, + PathbufThenPush: pathbuf_init_then_push::PathbufThenPush<'tcx> = >::default(), + IterOverHashType: iter_over_hash_type::IterOverHashType = iter_over_hash_type::IterOverHashType, + ImplHashWithBorrowStrBytes: impl_hash_with_borrow_str_and_bytes::ImplHashWithBorrowStrBytes = impl_hash_with_borrow_str_and_bytes::ImplHashWithBorrowStrBytes, + RepeatVecWithCapacity: repeat_vec_with_capacity::RepeatVecWithCapacity = repeat_vec_with_capacity::RepeatVecWithCapacity::new(conf), + UninhabitedReferences: uninhabited_references::UninhabitedReferences = uninhabited_references::UninhabitedReferences, + IneffectiveOpenOptions: ineffective_open_options::IneffectiveOpenOptions = ineffective_open_options::IneffectiveOpenOptions, + UnconditionalRecursion: unconditional_recursion::UnconditionalRecursion = ::default(), + PubUnderscoreFields: pub_underscore_fields::PubUnderscoreFields = pub_underscore_fields::PubUnderscoreFields::new(conf), + MissingConstForThreadLocal: missing_const_for_thread_local::MissingConstForThreadLocal = missing_const_for_thread_local::MissingConstForThreadLocal::new(conf), + IncompatibleMsrv: incompatible_msrv::IncompatibleMsrv = incompatible_msrv::IncompatibleMsrv::new(tcx, conf), + ToStringTraitImpl: to_string_trait_impl::ToStringTraitImpl = to_string_trait_impl::ToStringTraitImpl, + AssigningClones: assigning_clones::AssigningClones = assigning_clones::AssigningClones::new(conf), + ZeroRepeatSideEffects: zero_repeat_side_effects::ZeroRepeatSideEffects = zero_repeat_side_effects::ZeroRepeatSideEffects, + ExprMetavarsInUnsafe: macro_metavars_in_unsafe::ExprMetavarsInUnsafe = macro_metavars_in_unsafe::ExprMetavarsInUnsafe::new(conf), + StringPatterns: string_patterns::StringPatterns = string_patterns::StringPatterns::new(conf), + SetContainsOrInsert: set_contains_or_insert::SetContainsOrInsert = set_contains_or_insert::SetContainsOrInsert, + ZombieProcesses: zombie_processes::ZombieProcesses = zombie_processes::ZombieProcesses, + PointersInNomemAsmBlock: pointers_in_nomem_asm_block::PointersInNomemAsmBlock = pointers_in_nomem_asm_block::PointersInNomemAsmBlock, + ManualIsPowerOfTwo: manual_is_power_of_two::ManualIsPowerOfTwo = manual_is_power_of_two::ManualIsPowerOfTwo::new(conf), + NonZeroSuggestions: non_zero_suggestions::NonZeroSuggestions = non_zero_suggestions::NonZeroSuggestions, + LiteralStringWithFormattingArg: literal_string_with_formatting_args::LiteralStringWithFormattingArg = literal_string_with_formatting_args::LiteralStringWithFormattingArg, + UnusedTraitNames: unused_trait_names::UnusedTraitNames = unused_trait_names::UnusedTraitNames::new(conf), + ManualIgnoreCaseCmp: manual_ignore_case_cmp::ManualIgnoreCaseCmp = manual_ignore_case_cmp::ManualIgnoreCaseCmp, + UnnecessaryLiteralBound: unnecessary_literal_bound::UnnecessaryLiteralBound = unnecessary_literal_bound::UnnecessaryLiteralBound, + ArbitrarySourceItemOrdering: arbitrary_source_item_ordering::ArbitrarySourceItemOrdering = arbitrary_source_item_ordering::ArbitrarySourceItemOrdering::new(conf), + UselessConcat: useless_concat::UselessConcat = useless_concat::UselessConcat, + UnneededStructPattern: unneeded_struct_pattern::UnneededStructPattern = unneeded_struct_pattern::UnneededStructPattern, + UnnecessarySemicolon: unnecessary_semicolon::UnnecessarySemicolon = ::default(), + NonStdLazyStatic: non_std_lazy_statics::NonStdLazyStatic = non_std_lazy_statics::NonStdLazyStatic::new(conf), + ManualOptionAsSlice: manual_option_as_slice::ManualOptionAsSlice = manual_option_as_slice::ManualOptionAsSlice::new(conf), + SingleOptionMap: single_option_map::SingleOptionMap = single_option_map::SingleOptionMap, + RedundantTestPrefix: redundant_test_prefix::RedundantTestPrefix = redundant_test_prefix::RedundantTestPrefix, + ClonedRefToSliceRefs: cloned_ref_to_slice_refs::ClonedRefToSliceRefs<'tcx> = cloned_ref_to_slice_refs::ClonedRefToSliceRefs::new(conf), + InfallibleTryFrom: infallible_try_from::InfallibleTryFrom = infallible_try_from::InfallibleTryFrom, + CoerceContainerToAny: coerce_container_to_any::CoerceContainerToAny = coerce_container_to_any::CoerceContainerToAny, + ToplevelRefArg: toplevel_ref_arg::ToplevelRefArg = toplevel_ref_arg::ToplevelRefArg, + VolatileComposites: volatile_composites::VolatileComposites = volatile_composites::VolatileComposites, + ReplaceBox: replace_box::ReplaceBox = ::default(), + DisallowedFields: disallowed_fields::DisallowedFields = disallowed_fields::DisallowedFields::new(tcx, conf), + ManualIlog2: manual_ilog2::ManualIlog2 = manual_ilog2::ManualIlog2::new(conf), + SameLengthAndCapacity: same_length_and_capacity::SameLengthAndCapacity = same_length_and_capacity::SameLengthAndCapacity, + DurationSuboptimalUnits: duration_suboptimal_units::DurationSuboptimalUnits = duration_suboptimal_units::DurationSuboptimalUnits::new(tcx, conf), + ManualTake: manual_take::ManualTake = manual_take::ManualTake::new(conf), + ManualCheckedOps: manual_checked_ops::ManualCheckedOps = manual_checked_ops::ManualCheckedOps, + ManualPopIf: manual_pop_if::ManualPopIf = manual_pop_if::ManualPopIf::new(tcx, conf), + ManualNoopWaker: manual_noop_waker::ManualNoopWaker = manual_noop_waker::ManualNoopWaker::new(conf), + ByteCharSlice: byte_char_slices::ByteCharSlice = byte_char_slices::ByteCharSlice, + ManualAssertEq: manual_assert_eq::ManualAssertEq = manual_assert_eq::ManualAssertEq, + WithCapacityZero: with_capacity_zero::WithCapacityZero = with_capacity_zero::WithCapacityZero, // add late passes here, used by `cargo dev new_lint` - ]; - store.late_passes.extend(late_lints); -} + ]] +); diff --git a/clippy_lints/src/lifetimes.rs b/clippy_lints/src/lifetimes.rs index 8b50ce279b4b1..2b4828872b202 100644 --- a/clippy_lints/src/lifetimes.rs +++ b/clippy_lints/src/lifetimes.rs @@ -9,14 +9,14 @@ use rustc_errors::Applicability; use rustc_hir::FnRetTy::Return; use rustc_hir::intravisit::nested_filter::{self as hir_nested_filter, NestedFilter}; use rustc_hir::intravisit::{ - Visitor, VisitorExt, walk_fn_decl, walk_generic_args, walk_generics, walk_impl_item_ref, walk_param_bound, - walk_poly_trait_ref, walk_trait_ref, walk_ty, walk_unambig_ty, walk_where_predicate, + Visitor, VisitorExt, walk_fn_decl, walk_generic_args, walk_generic_param, walk_generics, walk_impl_item_ref, + walk_param_bound, walk_poly_trait_ref, walk_trait_ref, walk_ty, walk_unambig_ty, walk_where_predicate, }; use rustc_hir::{ AmbigArg, BodyId, FnDecl, FnPtrTy, FnSig, GenericArg, GenericArgs, GenericBound, GenericParam, GenericParamKind, Generics, HirId, Impl, ImplItem, ImplItemKind, Item, ItemKind, Lifetime, LifetimeKind, LifetimeParamKind, Node, - PolyTraitRef, PredicateOrigin, TraitFn, TraitItem, TraitItemKind, Ty, TyKind, WhereBoundPredicate, WherePredicate, - WherePredicateKind, lang_items, + PolyTraitRef, PredicateOrigin, TraitFn, TraitItem, TraitItemKind, TraitRef, Ty, TyKind, WhereBoundPredicate, + WherePredicate, WherePredicateKind, lang_items, }; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::hir::nested_filter as middle_nested_filter; @@ -160,6 +160,10 @@ impl<'tcx> LateLintPass<'tcx> for Lifetimes { } } + fn check_poly_trait_ref(&mut self, cx: &LateContext<'tcx>, poly_trait_ref: &'tcx PolyTraitRef<'tcx>) { + report_extra_trait_object_lifetimes(cx, poly_trait_ref.bound_generic_params, &poly_trait_ref.trait_ref); + } + fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>) { if let ImplItemKind::Fn(ref sig, id) = item.kind { let report_extra_lifetimes = trait_ref_of_method(cx, item.owner_id).is_none(); @@ -579,9 +583,8 @@ impl<'cx, 'tcx, F> LifetimeChecker<'cx, 'tcx, F> where F: NestedFilter<'tcx>, { - fn new(cx: &'cx LateContext<'tcx>, generics: &'tcx Generics<'_>) -> LifetimeChecker<'cx, 'tcx, F> { - let map = generics - .params + fn new(cx: &'cx LateContext<'tcx>, generic_params: &'tcx [GenericParam<'_>]) -> LifetimeChecker<'cx, 'tcx, F> { + let map = generic_params .iter() .filter_map(|par| match par.kind { GenericParamKind::Lifetime { @@ -590,6 +593,7 @@ where _ => None, }) .collect(); + Self { cx, map, @@ -703,8 +707,36 @@ fn is_candidate_for_elision(fd: &FnDecl<'_>) -> bool { } } +fn report_extra_trait_object_lifetimes<'tcx>( + cx: &LateContext<'tcx>, + generic_params: &'tcx [GenericParam<'_>], + trait_ref: &'tcx TraitRef<'tcx>, +) { + let mut checker = LifetimeChecker::::new(cx, generic_params); + + for param in generic_params { + walk_generic_param(&mut checker, param); + } + + walk_trait_ref(&mut checker, trait_ref); + + for (def_id, usages) in checker.map { + if usages + .iter() + .all(|usage| usage.in_where_predicate && !usage.in_bounded_ty && !usage.in_generics_arg) + { + span_lint( + cx, + EXTRA_UNUSED_LIFETIMES, + cx.tcx.def_span(def_id), + "this lifetime isn't used in the type", + ); + } + } +} + fn report_extra_lifetimes<'tcx>(cx: &LateContext<'tcx>, func: &'tcx FnDecl<'_>, generics: &'tcx Generics<'_>) { - let mut checker = LifetimeChecker::::new(cx, generics); + let mut checker = LifetimeChecker::::new(cx, generics.params); walk_generics(&mut checker, generics); walk_fn_decl(&mut checker, func); @@ -725,7 +757,7 @@ fn report_extra_lifetimes<'tcx>(cx: &LateContext<'tcx>, func: &'tcx FnDecl<'_>, } fn report_extra_impl_lifetimes<'tcx>(cx: &LateContext<'tcx>, impl_: &'tcx Impl<'_>) { - let mut checker = LifetimeChecker::::new(cx, impl_.generics); + let mut checker = LifetimeChecker::::new(cx, impl_.generics.params); walk_generics(&mut checker, impl_.generics); if let Some(of_trait) = impl_.of_trait { diff --git a/clippy_lints/src/loops/explicit_counter_loop.rs b/clippy_lints/src/loops/explicit_counter_loop.rs index b813a18b221ea..b10584fb9bd7c 100644 --- a/clippy_lints/src/loops/explicit_counter_loop.rs +++ b/clippy_lints/src/loops/explicit_counter_loop.rs @@ -5,7 +5,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::higher::Range; use clippy_utils::source::snippet_with_applicability; use clippy_utils::sugg::{EMPTY, Sugg}; -use clippy_utils::{get_enclosing_block, is_integer_const, is_integer_literal_untyped}; +use clippy_utils::{get_enclosing_block, is_integer_literal, is_integer_literal_untyped}; use rustc_ast::{Label, RangeLimits}; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_block, walk_expr}; @@ -44,7 +44,7 @@ pub(super) fn check<'tcx>( continue; } - let is_zero = is_integer_const(cx, initializer, 0); + let is_zero = is_integer_literal(initializer, 0); let mut applicability = Applicability::MaybeIncorrect; let span = expr.span.with_hi(arg.span.hi()); let loop_label = label.map_or(String::new(), |l| format!("{}: ", l.ident.name)); @@ -88,7 +88,7 @@ pub(super) fn check<'tcx>( if pat_snippet == "_" && let Some(range) = Range::hir(cx, arg) && range.limits == RangeLimits::HalfOpen - && range.start.is_some_and(|start| is_integer_const(cx, start, 0)) + && range.start.is_some_and(|start| is_integer_literal(start, 0)) && let Some(end) = range.end { let end = snippet_with_applicability(cx, end.span, "..", &mut applicability); diff --git a/clippy_lints/src/loops/for_unbounded_range.rs b/clippy_lints/src/loops/for_unbounded_range.rs new file mode 100644 index 0000000000000..4691ee02d9539 --- /dev/null +++ b/clippy_lints/src/loops/for_unbounded_range.rs @@ -0,0 +1,42 @@ +use super::FOR_UNBOUNDED_RANGE; +use super::infinite_loop::LoopVisitor; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::higher; +use rustc_ast::Label; +use rustc_hir::Expr; +use rustc_hir::intravisit::Visitor as _; +use rustc_lint::LateContext; +use rustc_span::Span; + +pub fn check<'tcx>( + cx: &LateContext<'tcx>, + label: Option)` on an `Option` value - --> tests/ui/map_unwrap_or_fixable.rs:66:20 + --> tests/ui/map_unwrap_or_fixable.rs:61:20 | LL | println!("{}", o.map(|y| y + 1).unwrap_or(3)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -32,13 +32,13 @@ LL + println!("{}", o.map_or(3, |y| y + 1)); | error: called `map().unwrap_or_else()` on an `Option` value - --> tests/ui/map_unwrap_or_fixable.rs:68:20 + --> tests/ui/map_unwrap_or_fixable.rs:63:20 | LL | println!("{}", o.map(|y| y + 1).unwrap_or_else(|| 3)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `o.map_or_else(|| 3, |y| y + 1)` error: called `map().unwrap_or()` on a `Result` value - --> tests/ui/map_unwrap_or_fixable.rs:70:20 + --> tests/ui/map_unwrap_or_fixable.rs:65:20 | LL | println!("{}", r.map(|y| y + 1).unwrap_or(3)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -50,13 +50,13 @@ LL + println!("{}", r.map_or(3, |y| y + 1)); | error: called `map().unwrap_or_else()` on a `Result` value - --> tests/ui/map_unwrap_or_fixable.rs:72:20 + --> tests/ui/map_unwrap_or_fixable.rs:67:20 | LL | println!("{}", r.map(|y| y + 1).unwrap_or_else(|()| 3)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `r.map_or_else(|()| 3, |y| y + 1)` error: called `map().unwrap_or(false)` on a `Result` value - --> tests/ui/map_unwrap_or_fixable.rs:75:20 + --> tests/ui/map_unwrap_or_fixable.rs:70:20 | LL | println!("{}", r.map(|y| y == 1).unwrap_or(false)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -68,7 +68,7 @@ LL + println!("{}", r.is_ok_and(|y| y == 1)); | error: called `map().unwrap_or()` on an `Option` value - --> tests/ui/map_unwrap_or_fixable.rs:81:20 + --> tests/ui/map_unwrap_or_fixable.rs:76:20 | LL | println!("{}", x.map(|y| y + 1).unwrap_or(3)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -80,7 +80,7 @@ LL + println!("{}", x.map_or(3, |y| y + 1)); | error: called `map().unwrap_or()` on a `Result` value - --> tests/ui/map_unwrap_or_fixable.rs:85:20 + --> tests/ui/map_unwrap_or_fixable.rs:80:20 | LL | println!("{}", x.map(|y| y + 1).unwrap_or(3)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -92,13 +92,13 @@ LL + println!("{}", x.map_or(3, |y| y + 1)); | error: called `map().unwrap_or_else()` on an `Option` value - --> tests/ui/map_unwrap_or_fixable.rs:89:20 + --> tests/ui/map_unwrap_or_fixable.rs:84:20 | LL | println!("{}", x.map(|y| y + 1).unwrap_or_else(|| 3)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `x.map_or_else(|| 3, |y| y + 1)` error: called `map().unwrap_or_else()` on a `Result` value - --> tests/ui/map_unwrap_or_fixable.rs:93:20 + --> tests/ui/map_unwrap_or_fixable.rs:88:20 | LL | println!("{}", x.map(|y| y + 1).unwrap_or_else(|_| 3)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `x.map_or_else(|_| 3, |y| y + 1)` diff --git a/tests/ui/map_with_unused_argument_over_ranges.fixed b/tests/ui/map_with_unused_argument_over_ranges.fixed index 97cb727488395..3d4432f8181ac 100644 --- a/tests/ui/map_with_unused_argument_over_ranges.fixed +++ b/tests/ui/map_with_unused_argument_over_ranges.fixed @@ -1,10 +1,5 @@ -#![allow( - unused, - clippy::redundant_closure, - clippy::reversed_empty_ranges, - clippy::identity_op -)] #![warn(clippy::map_with_unused_argument_over_ranges)] +#![allow(clippy::identity_op, clippy::redundant_closure, clippy::reversed_empty_ranges)] fn do_something() -> usize { todo!() diff --git a/tests/ui/map_with_unused_argument_over_ranges.rs b/tests/ui/map_with_unused_argument_over_ranges.rs index f0222f407b8ca..991c4cdbbcc87 100644 --- a/tests/ui/map_with_unused_argument_over_ranges.rs +++ b/tests/ui/map_with_unused_argument_over_ranges.rs @@ -1,10 +1,5 @@ -#![allow( - unused, - clippy::redundant_closure, - clippy::reversed_empty_ranges, - clippy::identity_op -)] #![warn(clippy::map_with_unused_argument_over_ranges)] +#![allow(clippy::identity_op, clippy::redundant_closure, clippy::reversed_empty_ranges)] fn do_something() -> usize { todo!() diff --git a/tests/ui/map_with_unused_argument_over_ranges.stderr b/tests/ui/map_with_unused_argument_over_ranges.stderr index ba72a6b9d89f4..c4bb1a90b1637 100644 --- a/tests/ui/map_with_unused_argument_over_ranges.stderr +++ b/tests/ui/map_with_unused_argument_over_ranges.stderr @@ -1,5 +1,5 @@ error: map of a closure that does not depend on its parameter over a range - --> tests/ui/map_with_unused_argument_over_ranges.rs:25:5 + --> tests/ui/map_with_unused_argument_over_ranges.rs:20:5 | LL | (0..10).map(|_| do_something()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -13,7 +13,7 @@ LL + std::iter::repeat_with(|| do_something()).take(10); | error: map of a closure that does not depend on its parameter over a range - --> tests/ui/map_with_unused_argument_over_ranges.rs:27:5 + --> tests/ui/map_with_unused_argument_over_ranges.rs:22:5 | LL | (0..10).map(|_foo| do_something()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL + std::iter::repeat_with(|| do_something()).take(10); | error: map of a closure that does not depend on its parameter over a range - --> tests/ui/map_with_unused_argument_over_ranges.rs:29:5 + --> tests/ui/map_with_unused_argument_over_ranges.rs:24:5 | LL | (0..=10).map(|_| do_something()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -37,7 +37,7 @@ LL + std::iter::repeat_with(|| do_something()).take(11); | error: map of a closure that does not depend on its parameter over a range - --> tests/ui/map_with_unused_argument_over_ranges.rs:31:5 + --> tests/ui/map_with_unused_argument_over_ranges.rs:26:5 | LL | (3..10).map(|_| do_something()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -49,7 +49,7 @@ LL + std::iter::repeat_with(|| do_something()).take(7); | error: map of a closure that does not depend on its parameter over a range - --> tests/ui/map_with_unused_argument_over_ranges.rs:33:5 + --> tests/ui/map_with_unused_argument_over_ranges.rs:28:5 | LL | (3..=10).map(|_| do_something()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -61,7 +61,7 @@ LL + std::iter::repeat_with(|| do_something()).take(8); | error: map of a closure that does not depend on its parameter over a range - --> tests/ui/map_with_unused_argument_over_ranges.rs:35:5 + --> tests/ui/map_with_unused_argument_over_ranges.rs:30:5 | LL | (0..10).map(|_| 3); | ^^^^^^^^^^^^^^^^^^ @@ -73,7 +73,7 @@ LL + std::iter::repeat_n(3, 10); | error: map of a closure that does not depend on its parameter over a range - --> tests/ui/map_with_unused_argument_over_ranges.rs:37:5 + --> tests/ui/map_with_unused_argument_over_ranges.rs:32:5 | LL | / (0..10).map(|_| { LL | | @@ -92,7 +92,7 @@ LL ~ }).take(10); | error: map of a closure that does not depend on its parameter over a range - --> tests/ui/map_with_unused_argument_over_ranges.rs:42:5 + --> tests/ui/map_with_unused_argument_over_ranges.rs:37:5 | LL | (0..10).map(|_| do_something()).collect::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -104,7 +104,7 @@ LL + std::iter::repeat_with(|| do_something()).take(10).collect::>(); | error: map of a closure that does not depend on its parameter over a range - --> tests/ui/map_with_unused_argument_over_ranges.rs:45:5 + --> tests/ui/map_with_unused_argument_over_ranges.rs:40:5 | LL | (0..upper).map(|_| do_something()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -116,7 +116,7 @@ LL + std::iter::repeat_with(|| do_something()).take(upper); | error: map of a closure that does not depend on its parameter over a range - --> tests/ui/map_with_unused_argument_over_ranges.rs:48:5 + --> tests/ui/map_with_unused_argument_over_ranges.rs:43:5 | LL | (0..upper_fn()).map(|_| do_something()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -128,7 +128,7 @@ LL + std::iter::repeat_with(|| do_something()).take(upper_fn()); | error: map of a closure that does not depend on its parameter over a range - --> tests/ui/map_with_unused_argument_over_ranges.rs:50:5 + --> tests/ui/map_with_unused_argument_over_ranges.rs:45:5 | LL | (0..=upper_fn()).map(|_| do_something()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -140,7 +140,7 @@ LL + std::iter::repeat_with(|| do_something()).take(upper_fn() + 1); | error: map of a closure that does not depend on its parameter over a range - --> tests/ui/map_with_unused_argument_over_ranges.rs:52:5 + --> tests/ui/map_with_unused_argument_over_ranges.rs:47:5 | LL | (2..upper_fn()).map(|_| do_something()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -152,7 +152,7 @@ LL + std::iter::repeat_with(|| do_something()).take(upper_fn() - 2); | error: map of a closure that does not depend on its parameter over a range - --> tests/ui/map_with_unused_argument_over_ranges.rs:54:5 + --> tests/ui/map_with_unused_argument_over_ranges.rs:49:5 | LL | (2..=upper_fn()).map(|_| do_something()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -164,7 +164,7 @@ LL + std::iter::repeat_with(|| do_something()).take(upper_fn() - 1); | error: map of a closure that does not depend on its parameter over a range - --> tests/ui/map_with_unused_argument_over_ranges.rs:57:5 + --> tests/ui/map_with_unused_argument_over_ranges.rs:52:5 | LL | (9..3).map(|_| do_something()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -176,7 +176,7 @@ LL + std::iter::repeat_with(|| do_something()).take(0); | error: map of a closure that does not depend on its parameter over a range - --> tests/ui/map_with_unused_argument_over_ranges.rs:59:5 + --> tests/ui/map_with_unused_argument_over_ranges.rs:54:5 | LL | (9..=9).map(|_| do_something()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -188,7 +188,7 @@ LL + std::iter::repeat_with(|| do_something()).take(1); | error: map of a closure that does not depend on its parameter over a range - --> tests/ui/map_with_unused_argument_over_ranges.rs:61:5 + --> tests/ui/map_with_unused_argument_over_ranges.rs:56:5 | LL | (1..=1 << 4).map(|_| do_something()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -200,7 +200,7 @@ LL + std::iter::repeat_with(|| do_something()).take((1 << 4) - 0); | error: map of a closure that does not depend on its parameter over a range - --> tests/ui/map_with_unused_argument_over_ranges.rs:83:5 + --> tests/ui/map_with_unused_argument_over_ranges.rs:78:5 | LL | (0..10).map(|_| do_something()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -212,7 +212,7 @@ LL + std::iter::repeat_with(|| do_something()).take(10); | error: map of a closure that does not depend on its parameter over a range - --> tests/ui/map_with_unused_argument_over_ranges.rs:89:5 + --> tests/ui/map_with_unused_argument_over_ranges.rs:84:5 | LL | (0..10).map(|_| 3); | ^^^^^^^^^^^^^^^^^^ @@ -224,7 +224,7 @@ LL + std::iter::repeat(3).take(10); | error: map of a closure that does not depend on its parameter over a range - --> tests/ui/map_with_unused_argument_over_ranges.rs:100:5 + --> tests/ui/map_with_unused_argument_over_ranges.rs:95:5 | LL | (0..test!(10)).map(|_| do_something()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -236,7 +236,7 @@ LL + std::iter::repeat_with(|| do_something()).take(test!(10)); | error: map of a closure that does not depend on its parameter over a range - --> tests/ui/map_with_unused_argument_over_ranges.rs:103:5 + --> tests/ui/map_with_unused_argument_over_ranges.rs:98:5 | LL | (0..10).map(|_| test!(3)); | ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/match_as_ref.fixed b/tests/ui/match_as_ref.fixed index b1b8ffb885f52..940d5e3a336a5 100644 --- a/tests/ui/match_as_ref.fixed +++ b/tests/ui/match_as_ref.fixed @@ -1,4 +1,3 @@ -#![allow(unused)] #![warn(clippy::match_as_ref)] fn match_as_ref() { diff --git a/tests/ui/match_as_ref.rs b/tests/ui/match_as_ref.rs index 3113167957d44..58873a5d1f85c 100644 --- a/tests/ui/match_as_ref.rs +++ b/tests/ui/match_as_ref.rs @@ -1,4 +1,3 @@ -#![allow(unused)] #![warn(clippy::match_as_ref)] fn match_as_ref() { diff --git a/tests/ui/match_as_ref.stderr b/tests/ui/match_as_ref.stderr index 3eab499fe409b..e041d75ed9683 100644 --- a/tests/ui/match_as_ref.stderr +++ b/tests/ui/match_as_ref.stderr @@ -1,5 +1,5 @@ error: manual implementation of `Option::as_ref` - --> tests/ui/match_as_ref.rs:6:33 + --> tests/ui/match_as_ref.rs:5:33 | LL | let borrowed: Option<&()> = match owned { | _________________________________^ @@ -22,7 +22,7 @@ LL + let borrowed: Option<&()> = owned.as_ref(); | error: manual implementation of `Option::as_mut` - --> tests/ui/match_as_ref.rs:13:39 + --> tests/ui/match_as_ref.rs:12:39 | LL | let borrow_mut: Option<&mut ()> = match mut_owned { | _______________________________________^ @@ -43,7 +43,7 @@ LL + let borrow_mut: Option<&mut ()> = mut_owned.as_mut(); | error: manual implementation of `Option::as_ref` - --> tests/ui/match_as_ref.rs:32:13 + --> tests/ui/match_as_ref.rs:31:13 | LL | / match self.source { LL | | @@ -63,7 +63,7 @@ LL + self.source.as_ref().map(|x| x as _) | error: manual implementation of `Option::as_ref` - --> tests/ui/match_as_ref.rs:97:13 + --> tests/ui/match_as_ref.rs:96:13 | LL | let _ = match !S { | _____________^ @@ -84,7 +84,7 @@ LL + let _ = (!S).as_ref(); | error: manual implementation of `Option::as_mut` - --> tests/ui/match_as_ref.rs:105:27 + --> tests/ui/match_as_ref.rs:104:27 | LL | let _: Option<&u32> = match Some(0) { | ___________________________^ @@ -106,7 +106,7 @@ LL + let _: Option<&u32> = Some(0).as_ref(); | error: manual implementation of `Option::as_mut` - --> tests/ui/match_as_ref.rs:111:43 + --> tests/ui/match_as_ref.rs:110:43 | LL | let _: Option<&dyn std::fmt::Debug> = match Some(0) { | ___________________________________________^ @@ -128,7 +128,7 @@ LL + let _: Option<&dyn std::fmt::Debug> = Some(0).as_ref().map(|x| x as _); | error: manual implementation of `Option::as_ref` - --> tests/ui/match_as_ref.rs:125:27 + --> tests/ui/match_as_ref.rs:124:27 | LL | let _: Option<&u32> = match test_expr!(42) { | ___________________________^ diff --git a/tests/ui/match_bool.fixed b/tests/ui/match_bool.fixed index 3d5d0a0d532c8..e813c208dc0ab 100644 --- a/tests/ui/match_bool.fixed +++ b/tests/ui/match_bool.fixed @@ -1,5 +1,5 @@ -#![deny(clippy::match_bool)] -#![allow(clippy::nonminimal_bool, clippy::eq_op)] +#![warn(clippy::match_bool)] +#![expect(clippy::eq_op, clippy::nonminimal_bool)] fn match_bool() { let test: bool = true; diff --git a/tests/ui/match_bool.rs b/tests/ui/match_bool.rs index 4db0aedf3260b..92061d0da8242 100644 --- a/tests/ui/match_bool.rs +++ b/tests/ui/match_bool.rs @@ -1,5 +1,5 @@ -#![deny(clippy::match_bool)] -#![allow(clippy::nonminimal_bool, clippy::eq_op)] +#![warn(clippy::match_bool)] +#![expect(clippy::eq_op, clippy::nonminimal_bool)] fn match_bool() { let test: bool = true; diff --git a/tests/ui/match_bool.stderr b/tests/ui/match_bool.stderr index 223acd17aead5..59982dd6b86c5 100644 --- a/tests/ui/match_bool.stderr +++ b/tests/ui/match_bool.stderr @@ -8,11 +8,8 @@ LL | | false => 42, LL | | }; | |_____^ help: consider using an `if`/`else` expression: `if test { 0 } else { 42 }` | -note: the lint level is defined here - --> tests/ui/match_bool.rs:1:9 - | -LL | #![deny(clippy::match_bool)] - | ^^^^^^^^^^^^^^^^^^ + = note: `-D clippy::match-bool` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::match_bool)]` error: `match` on a boolean expression --> tests/ui/match_bool.rs:14:5 diff --git a/tests/ui/match_like_matches_macro.fixed b/tests/ui/match_like_matches_macro.fixed index 045ee32bd8bb8..9ca9005c8bcd7 100644 --- a/tests/ui/match_like_matches_macro.fixed +++ b/tests/ui/match_like_matches_macro.fixed @@ -1,11 +1,6 @@ #![warn(clippy::match_like_matches_macro)] -#![allow( - unreachable_patterns, - irrefutable_let_patterns, - clippy::equatable_if_let, - clippy::needless_borrowed_reference, - clippy::redundant_guards -)] +#![allow(irrefutable_let_patterns, clippy::redundant_guards)] +#![expect(clippy::needless_borrowed_reference)] fn main() { let x = Some(5); diff --git a/tests/ui/match_like_matches_macro.rs b/tests/ui/match_like_matches_macro.rs index 231e1ae98f86a..1d94afac952c2 100644 --- a/tests/ui/match_like_matches_macro.rs +++ b/tests/ui/match_like_matches_macro.rs @@ -1,11 +1,6 @@ #![warn(clippy::match_like_matches_macro)] -#![allow( - unreachable_patterns, - irrefutable_let_patterns, - clippy::equatable_if_let, - clippy::needless_borrowed_reference, - clippy::redundant_guards -)] +#![allow(irrefutable_let_patterns, clippy::redundant_guards)] +#![expect(clippy::needless_borrowed_reference)] fn main() { let x = Some(5); diff --git a/tests/ui/match_like_matches_macro.stderr b/tests/ui/match_like_matches_macro.stderr index bc3e3584938ed..3caa3572e43be 100644 --- a/tests/ui/match_like_matches_macro.stderr +++ b/tests/ui/match_like_matches_macro.stderr @@ -1,5 +1,5 @@ error: match expression looks like `matches!` macro - --> tests/ui/match_like_matches_macro.rs:14:14 + --> tests/ui/match_like_matches_macro.rs:9:14 | LL | let _y = match x { | ______________^ @@ -19,31 +19,48 @@ LL - }; LL + let _y = matches!(x, Some(0)); | -error: redundant pattern matching, consider using `is_some()` - --> tests/ui/match_like_matches_macro.rs:21:14 +error: redundant pattern matching + --> tests/ui/match_like_matches_macro.rs:16:14 | LL | let _w = match x { | ______________^ LL | | Some(_) => true, LL | | _ => false, LL | | }; - | |_____^ help: try: `x.is_some()` + | |_____^ | = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::redundant_pattern_matching)]` +help: consider using `is_some()` + | +LL - let _w = match x { +LL - Some(_) => true, +LL - _ => false, +LL - }; +LL + let _w = x.is_some(); + | -error: redundant pattern matching, consider using `is_none()` - --> tests/ui/match_like_matches_macro.rs:28:14 +error: redundant pattern matching + --> tests/ui/match_like_matches_macro.rs:23:14 | LL | let _z = match x { | ______________^ LL | | Some(_) => false, LL | | None => true, LL | | }; - | |_____^ help: try: `x.is_none()` + | |_____^ + | +help: consider using `is_none()` + | +LL - let _z = match x { +LL - Some(_) => false, +LL - None => true, +LL - }; +LL + let _z = x.is_none(); + | error: match expression looks like `matches!` macro - --> tests/ui/match_like_matches_macro.rs:35:15 + --> tests/ui/match_like_matches_macro.rs:30:15 | LL | let _zz = match x { | _______________^ @@ -62,7 +79,7 @@ LL + let _zz = !matches!(x, Some(r) if r == 0); | error: `if let .. else` expression looks like `matches!` macro - --> tests/ui/match_like_matches_macro.rs:42:16 + --> tests/ui/match_like_matches_macro.rs:37:16 | LL | let _zzz = if let Some(5) = x { true } else { false }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -74,7 +91,7 @@ LL + let _zzz = matches!(x, Some(5)); | error: match expression looks like `matches!` macro - --> tests/ui/match_like_matches_macro.rs:67:20 + --> tests/ui/match_like_matches_macro.rs:62:20 | LL | let _ans = match x { | ____________________^ @@ -95,7 +112,7 @@ LL + let _ans = matches!(x, E::A(_) | E::B(_)); | error: match expression looks like `matches!` macro - --> tests/ui/match_like_matches_macro.rs:78:20 + --> tests/ui/match_like_matches_macro.rs:73:20 | LL | let _ans = match x { | ____________________^ @@ -119,7 +136,7 @@ LL + let _ans = matches!(x, E::A(_) | E::B(_)); | error: match expression looks like `matches!` macro - --> tests/ui/match_like_matches_macro.rs:89:20 + --> tests/ui/match_like_matches_macro.rs:84:20 | LL | let _ans = match x { | ____________________^ @@ -140,7 +157,7 @@ LL + let _ans = !matches!(x, E::B(_) | E::C); | error: match expression looks like `matches!` macro - --> tests/ui/match_like_matches_macro.rs:150:18 + --> tests/ui/match_like_matches_macro.rs:145:18 | LL | let _z = match &z { | __________________^ @@ -159,7 +176,7 @@ LL + let _z = matches!(z, Some(3)); | error: match expression looks like `matches!` macro - --> tests/ui/match_like_matches_macro.rs:160:18 + --> tests/ui/match_like_matches_macro.rs:155:18 | LL | let _z = match &z { | __________________^ @@ -178,7 +195,7 @@ LL + let _z = matches!(&z, Some(3)); | error: match expression looks like `matches!` macro - --> tests/ui/match_like_matches_macro.rs:178:21 + --> tests/ui/match_like_matches_macro.rs:173:21 | LL | let _ = match &z { | _____________________^ @@ -197,7 +214,7 @@ LL + let _ = matches!(&z, AnEnum::X); | error: match expression looks like `matches!` macro - --> tests/ui/match_like_matches_macro.rs:193:20 + --> tests/ui/match_like_matches_macro.rs:188:20 | LL | let _res = match &val { | ____________________^ @@ -216,7 +233,7 @@ LL + let _res = matches!(&val, &Some(ref _a)); | error: match expression looks like `matches!` macro - --> tests/ui/match_like_matches_macro.rs:206:20 + --> tests/ui/match_like_matches_macro.rs:201:20 | LL | let _res = match &val { | ____________________^ @@ -235,7 +252,7 @@ LL + let _res = matches!(&val, &Some(ref _a)); | error: match expression looks like `matches!` macro - --> tests/ui/match_like_matches_macro.rs:265:14 + --> tests/ui/match_like_matches_macro.rs:260:14 | LL | let _y = match Some(5) { | ______________^ @@ -254,7 +271,7 @@ LL + let _y = matches!(Some(5), Some(0)); | error: match expression looks like `matches!` macro - --> tests/ui/match_like_matches_macro.rs:275:13 + --> tests/ui/match_like_matches_macro.rs:270:13 | LL | let _ = match opt { | _____________^ @@ -273,7 +290,7 @@ LL + let _ = matches!(opt, Some(first) if (if let Some(second) = first { tru | error: match expression looks like `matches!` macro - --> tests/ui/match_like_matches_macro.rs:296:5 + --> tests/ui/match_like_matches_macro.rs:291:5 | LL | / match typeid!(T) { LL | | _ => true, @@ -291,7 +308,7 @@ LL + matches!(typeid!(T), _); | error: `if let .. else` expression looks like `matches!` macro - --> tests/ui/match_like_matches_macro.rs:302:5 + --> tests/ui/match_like_matches_macro.rs:297:5 | LL | if let _ = typeid!(U) { true } else { false } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/match_overlapping_arm.rs b/tests/ui/match_overlapping_arm.rs index 224cac055f251..25df602fe3afd 100644 --- a/tests/ui/match_overlapping_arm.rs +++ b/tests/ui/match_overlapping_arm.rs @@ -1,6 +1,6 @@ #![warn(clippy::match_overlapping_arm)] -#![allow(clippy::redundant_pattern_matching)] -#![allow(clippy::if_same_then_else, clippy::equatable_if_let, clippy::needless_ifs)] +#![expect(clippy::redundant_pattern_matching)] +#![allow(clippy::equatable_if_let, clippy::if_same_then_else, clippy::needless_ifs)] fn overlapping() { const FOO: u64 = 2; diff --git a/tests/ui/match_ref_pats.fixed b/tests/ui/match_ref_pats.fixed index f727546838b43..58a580cc099fd 100644 --- a/tests/ui/match_ref_pats.fixed +++ b/tests/ui/match_ref_pats.fixed @@ -1,12 +1,5 @@ #![warn(clippy::match_ref_pats)] -#![allow(dead_code, unused_variables)] -#![allow( - clippy::enum_variant_names, - clippy::equatable_if_let, - clippy::uninlined_format_args, - clippy::empty_loop, - clippy::diverging_sub_expression -)] +#![expect(clippy::diverging_sub_expression, clippy::empty_loop, clippy::enum_variant_names)] fn ref_pats() { { diff --git a/tests/ui/match_ref_pats.rs b/tests/ui/match_ref_pats.rs index eca4d584acd2b..8b4f7e1febf4f 100644 --- a/tests/ui/match_ref_pats.rs +++ b/tests/ui/match_ref_pats.rs @@ -1,12 +1,5 @@ #![warn(clippy::match_ref_pats)] -#![allow(dead_code, unused_variables)] -#![allow( - clippy::enum_variant_names, - clippy::equatable_if_let, - clippy::uninlined_format_args, - clippy::empty_loop, - clippy::diverging_sub_expression -)] +#![expect(clippy::diverging_sub_expression, clippy::empty_loop, clippy::enum_variant_names)] fn ref_pats() { { diff --git a/tests/ui/match_ref_pats.stderr b/tests/ui/match_ref_pats.stderr index ecb08e6972d9a..0cc92391b31f8 100644 --- a/tests/ui/match_ref_pats.stderr +++ b/tests/ui/match_ref_pats.stderr @@ -1,5 +1,5 @@ error: you don't need to add `&` to all patterns - --> tests/ui/match_ref_pats.rs:14:9 + --> tests/ui/match_ref_pats.rs:7:9 | LL | / match v { LL | | @@ -19,7 +19,7 @@ LL ~ None => println!("none"), | error: you don't need to add `&` to both the expression and the patterns - --> tests/ui/match_ref_pats.rs:32:5 + --> tests/ui/match_ref_pats.rs:25:5 | LL | / match &w { LL | | @@ -36,23 +36,34 @@ LL ~ Some(v) => println!("{:?}", v), LL ~ None => println!("none"), | -error: redundant pattern matching, consider using `is_none()` - --> tests/ui/match_ref_pats.rs:45:12 +error: redundant pattern matching + --> tests/ui/match_ref_pats.rs:38:12 | LL | if let &None = a { - | -------^^^^^---- help: try: `if a.is_none()` + | ^^^^^ | = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::redundant_pattern_matching)]` +help: consider using `is_none()` + | +LL - if let &None = a { +LL + if a.is_none() { + | -error: redundant pattern matching, consider using `is_none()` - --> tests/ui/match_ref_pats.rs:51:12 +error: redundant pattern matching + --> tests/ui/match_ref_pats.rs:44:12 | LL | if let &None = &b { - | -------^^^^^----- help: try: `if b.is_none()` + | ^^^^^ + | +help: consider using `is_none()` + | +LL - if let &None = &b { +LL + if b.is_none() { + | error: you don't need to add `&` to all patterns - --> tests/ui/match_ref_pats.rs:112:9 + --> tests/ui/match_ref_pats.rs:105:9 | LL | / match foobar_variant!(0) { LL | | diff --git a/tests/ui/match_result_ok.fixed b/tests/ui/match_result_ok.fixed index 0e630e6a29045..076a7f5144389 100644 --- a/tests/ui/match_result_ok.fixed +++ b/tests/ui/match_result_ok.fixed @@ -1,11 +1,5 @@ #![warn(clippy::match_result_ok)] -#![allow(dead_code)] -#![allow( - clippy::boxed_local, - clippy::uninlined_format_args, - clippy::manual_unwrap_or_default, - clippy::manual_unwrap_or -)] +#![expect(clippy::boxed_local, clippy::manual_unwrap_or_default)] // Checking `if` cases diff --git a/tests/ui/match_result_ok.rs b/tests/ui/match_result_ok.rs index 63bf6e8ab5087..1d428f0907b61 100644 --- a/tests/ui/match_result_ok.rs +++ b/tests/ui/match_result_ok.rs @@ -1,11 +1,5 @@ #![warn(clippy::match_result_ok)] -#![allow(dead_code)] -#![allow( - clippy::boxed_local, - clippy::uninlined_format_args, - clippy::manual_unwrap_or_default, - clippy::manual_unwrap_or -)] +#![expect(clippy::boxed_local, clippy::manual_unwrap_or_default)] // Checking `if` cases diff --git a/tests/ui/match_result_ok.stderr b/tests/ui/match_result_ok.stderr index 822cc4de77f3d..a419e9931bfd3 100644 --- a/tests/ui/match_result_ok.stderr +++ b/tests/ui/match_result_ok.stderr @@ -1,5 +1,5 @@ error: matching on `Some` with `ok()` is redundant - --> tests/ui/match_result_ok.rs:13:5 + --> tests/ui/match_result_ok.rs:7:5 | LL | if let Some(y) = x.parse().ok() { y } else { 0 } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -13,7 +13,7 @@ LL + if let Ok(y) = x.parse() { y } else { 0 } | error: matching on `Some` with `ok()` is redundant - --> tests/ui/match_result_ok.rs:24:9 + --> tests/ui/match_result_ok.rs:18:9 | LL | if let Some(y) = x . parse() . ok () { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL + if let Ok(y) = x . parse() { | error: matching on `Some` with `ok()` is redundant - --> tests/ui/match_result_ok.rs:51:5 + --> tests/ui/match_result_ok.rs:45:5 | LL | while let Some(a) = wat.next().ok() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/match_same_arms2.fixed b/tests/ui/match_same_arms2.fixed index cb860cef1e688..0b3619ed9d472 100644 --- a/tests/ui/match_same_arms2.fixed +++ b/tests/ui/match_same_arms2.fixed @@ -1,11 +1,6 @@ #![warn(clippy::match_same_arms)] -#![allow( - clippy::disallowed_names, - clippy::diverging_sub_expression, - clippy::uninlined_format_args, - clippy::match_single_binding, - clippy::match_like_matches_macro -)] +#![allow(clippy::match_single_binding)] +#![expect(clippy::disallowed_names, clippy::match_like_matches_macro)] fn bar(_: T) {} fn foo() -> bool { diff --git a/tests/ui/match_same_arms2.rs b/tests/ui/match_same_arms2.rs index 0fd5d76e7d3e7..a4677c2fc7d2b 100644 --- a/tests/ui/match_same_arms2.rs +++ b/tests/ui/match_same_arms2.rs @@ -1,11 +1,6 @@ #![warn(clippy::match_same_arms)] -#![allow( - clippy::disallowed_names, - clippy::diverging_sub_expression, - clippy::uninlined_format_args, - clippy::match_single_binding, - clippy::match_like_matches_macro -)] +#![allow(clippy::match_single_binding)] +#![expect(clippy::disallowed_names, clippy::match_like_matches_macro)] fn bar(_: T) {} fn foo() -> bool { diff --git a/tests/ui/match_same_arms2.stderr b/tests/ui/match_same_arms2.stderr index f3031619cce56..135b6279eacc8 100644 --- a/tests/ui/match_same_arms2.stderr +++ b/tests/ui/match_same_arms2.stderr @@ -1,5 +1,5 @@ error: these match arms have identical bodies - --> tests/ui/match_same_arms2.rs:17:9 + --> tests/ui/match_same_arms2.rs:12:9 | LL | / 42 => { LL | | foo(); @@ -36,7 +36,7 @@ LL - }, | error: these match arms have identical bodies - --> tests/ui/match_same_arms2.rs:39:9 + --> tests/ui/match_same_arms2.rs:34:9 | LL | 42 => foo(), | ^^^^^^^^^^^ @@ -52,7 +52,7 @@ LL ~ 42 | 51 => foo(), | error: these match arms have identical bodies - --> tests/ui/match_same_arms2.rs:46:9 + --> tests/ui/match_same_arms2.rs:41:9 | LL | Some(_) => 24, | ^^^^^^^^^^^^^ @@ -68,7 +68,7 @@ LL ~ Some(_) | None => 24, | error: these match arms have identical bodies - --> tests/ui/match_same_arms2.rs:69:9 + --> tests/ui/match_same_arms2.rs:64:9 | LL | (Some(a), None) => bar(a), | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -84,7 +84,7 @@ LL ~ (Some(a), None) | (None, Some(a)) => bar(a), | error: these match arms have identical bodies - --> tests/ui/match_same_arms2.rs:84:9 + --> tests/ui/match_same_arms2.rs:79:9 | LL | (Some(a), None) if a == 42 => a, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -100,7 +100,7 @@ LL ~ (Some(a), None) | (None, Some(a)) if a == 42 => a, | error: these match arms have identical bodies - --> tests/ui/match_same_arms2.rs:91:9 + --> tests/ui/match_same_arms2.rs:86:9 | LL | (Some(a), ..) => bar(a), | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -117,7 +117,7 @@ LL ~ _ => (), | error: these match arms have identical bodies - --> tests/ui/match_same_arms2.rs:126:9 + --> tests/ui/match_same_arms2.rs:121:9 | LL | (Ok(x), Some(_)) => println!("ok {}", x), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -134,7 +134,7 @@ LL ~ _ => println!("err"), | error: these match arms have identical bodies - --> tests/ui/match_same_arms2.rs:142:9 + --> tests/ui/match_same_arms2.rs:137:9 | LL | Ok(3) => println!("ok"), | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -150,7 +150,7 @@ LL ~ Ok(3) | Ok(_) => println!("ok"), | error: these match arms have identical bodies - --> tests/ui/match_same_arms2.rs:168:9 + --> tests/ui/match_same_arms2.rs:163:9 | LL | / 0 => { LL | | empty!(0); @@ -170,7 +170,7 @@ LL ~ 0 | 1 => { | error: these match arms have identical bodies - --> tests/ui/match_same_arms2.rs:222:9 + --> tests/ui/match_same_arms2.rs:217:9 | LL | Foo::X(0) => 1, | ^^^^^^^^^^^^^^ @@ -188,7 +188,7 @@ LL ~ _ => 0, | error: these match arms have identical bodies - --> tests/ui/match_same_arms2.rs:231:9 + --> tests/ui/match_same_arms2.rs:226:9 | LL | Foo::X(0) => 1, | ^^^^^^^^^^^^^^ @@ -205,7 +205,7 @@ LL ~ Foo::X(0) | Foo::Z(_) => 1, | error: these match arms have identical bodies - --> tests/ui/match_same_arms2.rs:254:9 + --> tests/ui/match_same_arms2.rs:249:9 | LL | Some(Bar { x: 0, y: 5, .. }) => 1, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -223,7 +223,7 @@ LL ~ Some(Bar { x: 0, y: 5, .. }) | Some(Bar { y: 0, x: 5, .. }) => 1, | error: these match arms have identical bodies - --> tests/ui/match_same_arms2.rs:271:9 + --> tests/ui/match_same_arms2.rs:266:9 | LL | 0 => cfg!(not_enable), | ^^^^^^^^^^^^^^^^^^^^^ @@ -239,7 +239,7 @@ LL ~ 0 | 1 => cfg!(not_enable), | error: these match arms have identical bodies - --> tests/ui/match_same_arms2.rs:288:17 + --> tests/ui/match_same_arms2.rs:283:17 | LL | MaybeStaticStr::Static(s) => s, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -255,7 +255,7 @@ LL ~ MaybeStaticStr::Static(s) | MaybeStaticStr::Borrowed(s) => | error: these match arms have identical bodies - --> tests/ui/match_same_arms2.rs:306:9 + --> tests/ui/match_same_arms2.rs:301:9 | LL | 1 => "b", | ^^^^^^^^ @@ -272,7 +272,7 @@ LL ~ #[allow(clippy::match_same_arms)] | error: these match arms have identical bodies - --> tests/ui/match_same_arms2.rs:315:9 + --> tests/ui/match_same_arms2.rs:310:9 | LL | 1 => "b", | ^^^^^^^^ diff --git a/tests/ui/match_single_binding.fixed b/tests/ui/match_single_binding.fixed index fa82a316d64d9..f2296c14f9b6e 100644 --- a/tests/ui/match_single_binding.fixed +++ b/tests/ui/match_single_binding.fixed @@ -1,11 +1,6 @@ #![warn(clippy::match_single_binding)] -#![allow( - unused, - clippy::let_unit_value, - clippy::no_effect, - clippy::toplevel_ref_arg, - clippy::useless_vec -)] +#![allow(clippy::no_effect, clippy::toplevel_ref_arg)] +#![expect(clippy::let_unit_value, clippy::useless_vec)] struct Point { x: i32, diff --git a/tests/ui/match_single_binding.rs b/tests/ui/match_single_binding.rs index 6c1fae89e230d..03eaecff343aa 100644 --- a/tests/ui/match_single_binding.rs +++ b/tests/ui/match_single_binding.rs @@ -1,11 +1,6 @@ #![warn(clippy::match_single_binding)] -#![allow( - unused, - clippy::let_unit_value, - clippy::no_effect, - clippy::toplevel_ref_arg, - clippy::useless_vec -)] +#![allow(clippy::no_effect, clippy::toplevel_ref_arg)] +#![expect(clippy::let_unit_value, clippy::useless_vec)] struct Point { x: i32, diff --git a/tests/ui/match_single_binding.stderr b/tests/ui/match_single_binding.stderr index 8a402dcca8470..686c8894f688f 100644 --- a/tests/ui/match_single_binding.stderr +++ b/tests/ui/match_single_binding.stderr @@ -1,5 +1,5 @@ error: this match could be written as a `let` statement - --> tests/ui/match_single_binding.rs:32:5 + --> tests/ui/match_single_binding.rs:27:5 | LL | / match (a, b, c) { LL | | @@ -20,7 +20,7 @@ LL + } | error: this match could be written as a `let` statement - --> tests/ui/match_single_binding.rs:39:5 + --> tests/ui/match_single_binding.rs:34:5 | LL | / match (a, b, c) { LL | | @@ -35,7 +35,7 @@ LL + println!("{x} {y} {z}"); | error: this match could be replaced by its body itself - --> tests/ui/match_single_binding.rs:57:5 + --> tests/ui/match_single_binding.rs:52:5 | LL | / match a { LL | | @@ -44,7 +44,7 @@ LL | | } | |_____^ help: consider using the match body instead: `println!("whatever");` error: this match could be replaced by its body itself - --> tests/ui/match_single_binding.rs:62:5 + --> tests/ui/match_single_binding.rs:57:5 | LL | / match a { LL | | @@ -64,7 +64,7 @@ LL + } | error: this match could be replaced by its body itself - --> tests/ui/match_single_binding.rs:70:5 + --> tests/ui/match_single_binding.rs:65:5 | LL | / match a { LL | | @@ -86,7 +86,7 @@ LL + } | error: this match could be written as a `let` statement - --> tests/ui/match_single_binding.rs:81:5 + --> tests/ui/match_single_binding.rs:76:5 | LL | / match p { LL | | @@ -101,7 +101,7 @@ LL + println!("Coords: ({x}, {y})"); | error: this match could be written as a `let` statement - --> tests/ui/match_single_binding.rs:86:5 + --> tests/ui/match_single_binding.rs:81:5 | LL | / match p { LL | | @@ -116,7 +116,7 @@ LL + println!("Coords: ({x1}, {y1})"); | error: this match could be written as a `let` statement - --> tests/ui/match_single_binding.rs:92:5 + --> tests/ui/match_single_binding.rs:87:5 | LL | / match x { LL | | @@ -131,7 +131,7 @@ LL + println!("Got a reference to {r}"); | error: this match could be written as a `let` statement - --> tests/ui/match_single_binding.rs:98:5 + --> tests/ui/match_single_binding.rs:93:5 | LL | / match x { LL | | @@ -146,7 +146,7 @@ LL + println!("Got a mutable reference to {mr}"); | error: this match could be written as a `let` statement - --> tests/ui/match_single_binding.rs:103:5 + --> tests/ui/match_single_binding.rs:98:5 | LL | / let product = match coords() { LL | | @@ -161,7 +161,7 @@ LL + let product = x * y; | error: this match could be written as a `let` statement - --> tests/ui/match_single_binding.rs:112:18 + --> tests/ui/match_single_binding.rs:107:18 | LL | .map(|i| match i.unwrap() { | __________________^ @@ -179,7 +179,7 @@ LL ~ }) | error: this match could be replaced by its body itself - --> tests/ui/match_single_binding.rs:139:5 + --> tests/ui/match_single_binding.rs:134:5 | LL | / match x { LL | | @@ -189,7 +189,7 @@ LL | | } | |_____^ help: consider using the match body instead: `println!("Not an array index start")` error: this assignment could be simplified - --> tests/ui/match_single_binding.rs:149:5 + --> tests/ui/match_single_binding.rs:144:5 | LL | / val = match val.split_at(idx) { LL | | @@ -210,7 +210,7 @@ LL ~ }; | error: this match could be replaced by its scrutinee and body - --> tests/ui/match_single_binding.rs:163:16 + --> tests/ui/match_single_binding.rs:158:16 | LL | let _ = || match side_effects() { | ________________^ @@ -228,7 +228,7 @@ LL ~ }; | error: this match could be written as a `let` statement - --> tests/ui/match_single_binding.rs:170:5 + --> tests/ui/match_single_binding.rs:165:5 | LL | / match r { LL | | @@ -253,7 +253,7 @@ LL ~ }; | error: this match could be replaced by its body itself - --> tests/ui/match_single_binding.rs:184:5 + --> tests/ui/match_single_binding.rs:179:5 | LL | / match 1 { LL | | @@ -262,7 +262,7 @@ LL | | } | |_____^ help: consider using the match body instead: `();` error: this match could be replaced by its body itself - --> tests/ui/match_single_binding.rs:189:13 + --> tests/ui/match_single_binding.rs:184:13 | LL | let a = match 1 { | _____________^ @@ -272,7 +272,7 @@ LL | | }; | |_____^ help: consider using the match body instead: `()` error: this match could be replaced by its body itself - --> tests/ui/match_single_binding.rs:194:5 + --> tests/ui/match_single_binding.rs:189:5 | LL | / match 1 { LL | | @@ -281,7 +281,7 @@ LL | | } | |_____^ help: consider using the match body instead: `side_effects();` error: this match could be replaced by its body itself - --> tests/ui/match_single_binding.rs:199:13 + --> tests/ui/match_single_binding.rs:194:13 | LL | let b = match 1 { | _____________^ @@ -291,7 +291,7 @@ LL | | }; | |_____^ help: consider using the match body instead: `side_effects()` error: this match could be replaced by its body itself - --> tests/ui/match_single_binding.rs:204:5 + --> tests/ui/match_single_binding.rs:199:5 | LL | / match 1 { LL | | @@ -300,7 +300,7 @@ LL | | } | |_____^ help: consider using the match body instead: `println!("1");` error: this match could be replaced by its body itself - --> tests/ui/match_single_binding.rs:209:13 + --> tests/ui/match_single_binding.rs:204:13 | LL | let c = match 1 { | _____________^ @@ -310,7 +310,7 @@ LL | | }; | |_____^ help: consider using the match body instead: `println!("1")` error: this match could be replaced by its body itself - --> tests/ui/match_single_binding.rs:215:9 + --> tests/ui/match_single_binding.rs:210:9 | LL | / match 1 { LL | | @@ -319,7 +319,7 @@ LL | | }, | |_________^ help: consider using the match body instead: `()` error: this match could be replaced by its body itself - --> tests/ui/match_single_binding.rs:219:9 + --> tests/ui/match_single_binding.rs:214:9 | LL | / match 1 { LL | | @@ -328,7 +328,7 @@ LL | | }, | |_________^ help: consider using the match body instead: `side_effects()` error: this match could be replaced by its body itself - --> tests/ui/match_single_binding.rs:223:9 + --> tests/ui/match_single_binding.rs:218:9 | LL | / match 1 { LL | | @@ -337,7 +337,7 @@ LL | | }, | |_________^ help: consider using the match body instead: `println!("1")` error: this match could be replaced by its scrutinee and body - --> tests/ui/match_single_binding.rs:238:5 + --> tests/ui/match_single_binding.rs:233:5 | LL | / match dbg!(3) { LL | | _ => println!("here"), @@ -351,7 +351,7 @@ LL + println!("here"); | error: this match could be written as a `let` statement - --> tests/ui/match_single_binding.rs:242:5 + --> tests/ui/match_single_binding.rs:237:5 | LL | / match dbg!(3) { LL | | id!(a) => println!("found {a}"), @@ -365,7 +365,7 @@ LL + println!("found {a}"); | error: this match could be written as a `let` statement - --> tests/ui/match_single_binding.rs:246:5 + --> tests/ui/match_single_binding.rs:241:5 | LL | / let id!(_a) = match dbg!(3) { LL | | id!(b) => dbg!(b + 1), @@ -379,7 +379,7 @@ LL + let id!(_a) = dbg!(b + 1); | error: this match could be written as a `let` statement - --> tests/ui/match_single_binding.rs:254:21 + --> tests/ui/match_single_binding.rs:249:21 | LL | inner: [(); match 1 { | _____________________^ @@ -397,7 +397,7 @@ LL ~ }], | error: this match could be written as a `let` statement - --> tests/ui/match_single_binding.rs:262:13 + --> tests/ui/match_single_binding.rs:257:13 | LL | / match 1 { LL | | @@ -412,7 +412,7 @@ LL + 42 | error: this match could be written as a `let` statement - --> tests/ui/match_single_binding.rs:273:9 + --> tests/ui/match_single_binding.rs:268:9 | LL | / match (a, b, c) { LL | | @@ -429,7 +429,7 @@ LL + } | error: this match could be written as a `let` statement - --> tests/ui/match_single_binding.rs:281:9 + --> tests/ui/match_single_binding.rs:276:9 | LL | / match (a, b, c) { LL | | @@ -444,7 +444,7 @@ LL + println!("{x} {y} {z}") | error: this match could be written as a `let` statement - --> tests/ui/match_single_binding.rs:289:9 + --> tests/ui/match_single_binding.rs:284:9 | LL | / match (a, b, c) { LL | | @@ -459,7 +459,7 @@ LL + println!("{x} {y} {z}"); | error: this match could be written as a `let` statement - --> tests/ui/match_single_binding.rs:299:9 + --> tests/ui/match_single_binding.rs:294:9 | LL | / match (a, b, c) { LL | | @@ -474,7 +474,7 @@ LL + println!("{x} {x} {y}"); | error: this match could be written as a `let` statement - --> tests/ui/match_single_binding.rs:309:13 + --> tests/ui/match_single_binding.rs:304:13 | LL | / match (a, b, c) { LL | | @@ -491,7 +491,7 @@ LL + } | error: this match could be written as a `let` statement - --> tests/ui/match_single_binding.rs:319:13 + --> tests/ui/match_single_binding.rs:314:13 | LL | / match (a, b, c) { LL | | @@ -506,7 +506,7 @@ LL + println!("{x} {y} {z}"); | error: this match could be replaced by its body itself - --> tests/ui/match_single_binding.rs:334:12 + --> tests/ui/match_single_binding.rs:329:12 | LL | && match b { | ____________^ @@ -516,7 +516,7 @@ LL | | }; | |_________^ help: consider using the match body instead: `b < c` error: this match could be replaced by its body itself - --> tests/ui/match_single_binding.rs:340:12 + --> tests/ui/match_single_binding.rs:335:12 | LL | && match (a, b) { | ____________^ @@ -526,7 +526,7 @@ LL | | } | |_________^ help: consider using the match body instead: `b < c` error: this match could be replaced by its scrutinee and body - --> tests/ui/match_single_binding.rs:357:9 + --> tests/ui/match_single_binding.rs:352:9 | LL | / match { a } { LL | | @@ -543,7 +543,7 @@ LL ~ }, | error: this match could be replaced by its scrutinee and body - --> tests/ui/match_single_binding.rs:366:9 + --> tests/ui/match_single_binding.rs:361:9 | LL | / match { a } { LL | | @@ -560,7 +560,7 @@ LL ~ }, | error: this match could be replaced by its scrutinee and body - --> tests/ui/match_single_binding.rs:376:9 + --> tests/ui/match_single_binding.rs:371:9 | LL | / match { a } { LL | | @@ -577,7 +577,7 @@ LL ~ }, | error: this match could be replaced by its scrutinee and body - --> tests/ui/match_single_binding.rs:390:9 + --> tests/ui/match_single_binding.rs:385:9 | LL | / match { a } { LL | | @@ -594,7 +594,7 @@ LL ~ }, | error: this match could be replaced by its scrutinee and body - --> tests/ui/match_single_binding.rs:397:6 + --> tests/ui/match_single_binding.rs:392:6 | LL | -match { a } { | ______^ @@ -612,7 +612,7 @@ LL ~ }; | error: this match could be replaced by its scrutinee and body - --> tests/ui/match_single_binding.rs:402:9 + --> tests/ui/match_single_binding.rs:397:9 | LL | _ = match { a } { | _________^ @@ -628,7 +628,7 @@ LL ~ 1; | error: this match could be replaced by its scrutinee and body - --> tests/ui/match_single_binding.rs:407:16 + --> tests/ui/match_single_binding.rs:402:16 | LL | if let x = match { a } { | ________________^ @@ -646,7 +646,7 @@ LL ~ } {} | error: this match could be replaced by its scrutinee and body - --> tests/ui/match_single_binding.rs:412:8 + --> tests/ui/match_single_binding.rs:407:8 | LL | if match { a } { | ________^ @@ -664,7 +664,7 @@ LL ~ } { | error: this match could be replaced by its scrutinee and body - --> tests/ui/match_single_binding.rs:419:15 + --> tests/ui/match_single_binding.rs:414:15 | LL | [1, 2, 3][match { a } { | _______________^ diff --git a/tests/ui/match_single_binding2.fixed b/tests/ui/match_single_binding2.fixed index f00987470ae1b..aad585d55a6da 100644 --- a/tests/ui/match_single_binding2.fixed +++ b/tests/ui/match_single_binding2.fixed @@ -1,5 +1,4 @@ #![warn(clippy::match_single_binding)] -#![allow(unused_variables)] fn main() { // Lint (additional curly braces needed, see #6572) @@ -10,7 +9,6 @@ fn main() { inner: Option<(I, ::Item)>, } - #[allow(dead_code)] fn size_hint(iter: &AppendIter) -> (usize, Option) { match &iter.inner { Some((iter, _item)) => { diff --git a/tests/ui/match_single_binding2.rs b/tests/ui/match_single_binding2.rs index 5416f647b4e6c..e0d0dac054585 100644 --- a/tests/ui/match_single_binding2.rs +++ b/tests/ui/match_single_binding2.rs @@ -1,5 +1,4 @@ #![warn(clippy::match_single_binding)] -#![allow(unused_variables)] fn main() { // Lint (additional curly braces needed, see #6572) @@ -10,7 +9,6 @@ fn main() { inner: Option<(I, ::Item)>, } - #[allow(dead_code)] fn size_hint(iter: &AppendIter) -> (usize, Option) { match &iter.inner { Some((iter, _item)) => match iter.size_hint() { diff --git a/tests/ui/match_single_binding2.stderr b/tests/ui/match_single_binding2.stderr index 65b8aa6acd5e1..4479c5f153aef 100644 --- a/tests/ui/match_single_binding2.stderr +++ b/tests/ui/match_single_binding2.stderr @@ -1,5 +1,5 @@ error: this match could be written as a `let` statement - --> tests/ui/match_single_binding2.rs:16:36 + --> tests/ui/match_single_binding2.rs:14:36 | LL | Some((iter, _item)) => match iter.size_hint() { | ____________________________________^ @@ -19,7 +19,7 @@ LL ~ }, | error: this match could be written as a `let` statement - --> tests/ui/match_single_binding2.rs:30:13 + --> tests/ui/match_single_binding2.rs:28:13 | LL | / match get_tup() { LL | | @@ -34,7 +34,7 @@ LL + println!("a {a:?} and b {b:?}") | error: this match could be replaced by its scrutinee and body - --> tests/ui/match_single_binding2.rs:42:5 + --> tests/ui/match_single_binding2.rs:40:5 | LL | / match side_effects() { LL | | @@ -49,7 +49,7 @@ LL + println!("Side effects"); | error: this match could be replaced by its scrutinee and body - --> tests/ui/match_single_binding2.rs:50:5 + --> tests/ui/match_single_binding2.rs:48:5 | LL | / match match x { LL | | diff --git a/tests/ui/match_str_case_mismatch.fixed b/tests/ui/match_str_case_mismatch.fixed index 5f41f29f8a466..8ab6a33dab490 100644 --- a/tests/ui/match_str_case_mismatch.fixed +++ b/tests/ui/match_str_case_mismatch.fixed @@ -1,5 +1,4 @@ #![warn(clippy::match_str_case_mismatch)] -#![allow(dead_code)] // Valid diff --git a/tests/ui/match_str_case_mismatch.rs b/tests/ui/match_str_case_mismatch.rs index fa5d5a8ebc317..8533404bcea7b 100644 --- a/tests/ui/match_str_case_mismatch.rs +++ b/tests/ui/match_str_case_mismatch.rs @@ -1,5 +1,4 @@ #![warn(clippy::match_str_case_mismatch)] -#![allow(dead_code)] // Valid diff --git a/tests/ui/match_str_case_mismatch.stderr b/tests/ui/match_str_case_mismatch.stderr index c2b58b952aaa5..e1f7ef8de7cd1 100644 --- a/tests/ui/match_str_case_mismatch.stderr +++ b/tests/ui/match_str_case_mismatch.stderr @@ -1,5 +1,5 @@ error: this `match` arm has a differing case than its expression - --> tests/ui/match_str_case_mismatch.rs:112:9 + --> tests/ui/match_str_case_mismatch.rs:111:9 | LL | "Bar" => {}, | ^^^^^ @@ -13,7 +13,7 @@ LL + "bar" => {}, | error: this `match` arm has a differing case than its expression - --> tests/ui/match_str_case_mismatch.rs:123:9 + --> tests/ui/match_str_case_mismatch.rs:122:9 | LL | "~!@#$%^&*()-_=+Foo" => {}, | ^^^^^^^^^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL + "~!@#$%^&*()-_=+foo" => {}, | error: this `match` arm has a differing case than its expression - --> tests/ui/match_str_case_mismatch.rs:136:9 + --> tests/ui/match_str_case_mismatch.rs:135:9 | LL | "Воды" => {}, | ^^^^^^ @@ -37,7 +37,7 @@ LL + "воды" => {}, | error: this `match` arm has a differing case than its expression - --> tests/ui/match_str_case_mismatch.rs:148:9 + --> tests/ui/match_str_case_mismatch.rs:147:9 | LL | "barDz" => {}, | ^^^^^^ @@ -49,7 +49,7 @@ LL + "bardz" => {}, | error: this `match` arm has a differing case than its expression - --> tests/ui/match_str_case_mismatch.rs:159:9 + --> tests/ui/match_str_case_mismatch.rs:158:9 | LL | "bARʁ" => {}, | ^^^^^^ @@ -61,7 +61,7 @@ LL + "BARʁ" => {}, | error: this `match` arm has a differing case than its expression - --> tests/ui/match_str_case_mismatch.rs:170:9 + --> tests/ui/match_str_case_mismatch.rs:169:9 | LL | "Bar" => {}, | ^^^^^ @@ -73,7 +73,7 @@ LL + "bar" => {}, | error: this `match` arm has a differing case than its expression - --> tests/ui/match_str_case_mismatch.rs:186:9 + --> tests/ui/match_str_case_mismatch.rs:185:9 | LL | "bAR" => {}, | ^^^^^ diff --git a/tests/ui/match_wild_err_arm.rs b/tests/ui/match_wild_err_arm.rs index d18d4047e2a64..11c096e2d1e01 100644 --- a/tests/ui/match_wild_err_arm.rs +++ b/tests/ui/match_wild_err_arm.rs @@ -1,5 +1,5 @@ -#![allow(clippy::match_same_arms, dead_code)] #![warn(clippy::match_wild_err_arm)] +#![expect(clippy::match_same_arms)] fn issue_10635() { enum Error { diff --git a/tests/ui/match_wildcard_for_single_variants.fixed b/tests/ui/match_wildcard_for_single_variants.fixed index c34f49df6549f..de5cdb14ccc2f 100644 --- a/tests/ui/match_wildcard_for_single_variants.fixed +++ b/tests/ui/match_wildcard_for_single_variants.fixed @@ -1,5 +1,4 @@ #![warn(clippy::match_wildcard_for_single_variants)] -#![allow(dead_code)] enum Foo { A, diff --git a/tests/ui/match_wildcard_for_single_variants.rs b/tests/ui/match_wildcard_for_single_variants.rs index ecdb7d2fa3af2..23e873482cd89 100644 --- a/tests/ui/match_wildcard_for_single_variants.rs +++ b/tests/ui/match_wildcard_for_single_variants.rs @@ -1,5 +1,4 @@ #![warn(clippy::match_wildcard_for_single_variants)] -#![allow(dead_code)] enum Foo { A, diff --git a/tests/ui/match_wildcard_for_single_variants.stderr b/tests/ui/match_wildcard_for_single_variants.stderr index 3c0cc53b1bf27..c2f47835b578a 100644 --- a/tests/ui/match_wildcard_for_single_variants.stderr +++ b/tests/ui/match_wildcard_for_single_variants.stderr @@ -1,5 +1,5 @@ error: wildcard matches only a single variant and will also match any future added variants - --> tests/ui/match_wildcard_for_single_variants.rs:22:13 + --> tests/ui/match_wildcard_for_single_variants.rs:21:13 | LL | _ => (), | ^ help: try: `Self::Rgb(..)` @@ -8,55 +8,55 @@ LL | _ => (), = help: to override `-D warnings` add `#[allow(clippy::match_wildcard_for_single_variants)]` error: wildcard matches only a single variant and will also match any future added variants - --> tests/ui/match_wildcard_for_single_variants.rs:33:9 + --> tests/ui/match_wildcard_for_single_variants.rs:32:9 | LL | _ => {}, | ^ help: try: `Foo::C` error: wildcard matches only a single variant and will also match any future added variants - --> tests/ui/match_wildcard_for_single_variants.rs:44:9 + --> tests/ui/match_wildcard_for_single_variants.rs:43:9 | LL | _ => {}, | ^ help: try: `Color::Blue` error: wildcard matches only a single variant and will also match any future added variants - --> tests/ui/match_wildcard_for_single_variants.rs:53:9 + --> tests/ui/match_wildcard_for_single_variants.rs:52:9 | LL | _ => {}, | ^ help: try: `Color::Blue` error: wildcard matches only a single variant and will also match any future added variants - --> tests/ui/match_wildcard_for_single_variants.rs:60:9 + --> tests/ui/match_wildcard_for_single_variants.rs:59:9 | LL | _ => {}, | ^ help: try: `Color::Blue` error: wildcard matches only a single variant and will also match any future added variants - --> tests/ui/match_wildcard_for_single_variants.rs:78:9 + --> tests/ui/match_wildcard_for_single_variants.rs:77:9 | LL | &_ => (), | ^^ help: try: `Color::Blue` error: wildcard matches only a single variant and will also match any future added variants - --> tests/ui/match_wildcard_for_single_variants.rs:88:9 + --> tests/ui/match_wildcard_for_single_variants.rs:87:9 | LL | _ => (), | ^ help: try: `C::Blue` error: wildcard matches only a single variant and will also match any future added variants - --> tests/ui/match_wildcard_for_single_variants.rs:96:9 + --> tests/ui/match_wildcard_for_single_variants.rs:95:9 | LL | _ => (), | ^ help: try: `Color::Blue` error: wildcard matches only a single variant and will also match any future added variants - --> tests/ui/match_wildcard_for_single_variants.rs:132:13 + --> tests/ui/match_wildcard_for_single_variants.rs:131:13 | LL | _ => (), | ^ help: try: `Enum::__Private` error: wildcard matches only a single variant and will also match any future added variants - --> tests/ui/match_wildcard_for_single_variants.rs:160:13 + --> tests/ui/match_wildcard_for_single_variants.rs:159:13 | LL | _ => 2, | ^ help: try: `Foo::B` diff --git a/tests/ui/mem_replace.stderr b/tests/ui/mem_replace.stderr deleted file mode 100644 index bc374930cf0f2..0000000000000 --- a/tests/ui/mem_replace.stderr +++ /dev/null @@ -1,191 +0,0 @@ -error: replacing an `Option` with `None` - --> tests/ui/mem_replace.rs:13:13 - | -LL | let _ = mem::replace(&mut an_option, None); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::take()` instead: `an_option.take()` - | - = note: `-D clippy::mem-replace-option-with-none` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::mem_replace_option_with_none)]` - -error: replacing an `Option` with `None` - --> tests/ui/mem_replace.rs:16:13 - | -LL | let _ = mem::replace(an_option, None); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::take()` instead: `an_option.take()` - -error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` - --> tests/ui/mem_replace.rs:22:13 - | -LL | let _ = std::mem::replace(&mut s, String::default()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut s)` - | - = note: `-D clippy::mem-replace-with-default` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::mem_replace_with_default)]` - -error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` - --> tests/ui/mem_replace.rs:24:13 - | -LL | let _ = std::mem::replace(&mut s, String::new()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut s)` - -error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` - --> tests/ui/mem_replace.rs:28:13 - | -LL | let _ = std::mem::replace(s, String::default()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(s)` - -error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` - --> tests/ui/mem_replace.rs:30:13 - | -LL | let _ = std::mem::replace(s, String::new()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(s)` - -error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` - --> tests/ui/mem_replace.rs:32:13 - | -LL | let _ = std::mem::replace(s, Default::default()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(s)` - -error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` - --> tests/ui/mem_replace.rs:36:13 - | -LL | let _ = std::mem::replace(&mut v, Vec::default()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut v)` - -error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` - --> tests/ui/mem_replace.rs:38:13 - | -LL | let _ = std::mem::replace(&mut v, Default::default()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut v)` - -error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` - --> tests/ui/mem_replace.rs:40:13 - | -LL | let _ = std::mem::replace(&mut v, Vec::new()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut v)` - -error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` - --> tests/ui/mem_replace.rs:42:13 - | -LL | let _ = std::mem::replace(&mut v, vec![]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut v)` - -error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` - --> tests/ui/mem_replace.rs:46:13 - | -LL | let _ = std::mem::replace(&mut hash_map, HashMap::new()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut hash_map)` - -error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` - --> tests/ui/mem_replace.rs:50:13 - | -LL | let _ = std::mem::replace(&mut btree_map, BTreeMap::new()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut btree_map)` - -error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` - --> tests/ui/mem_replace.rs:54:13 - | -LL | let _ = std::mem::replace(&mut vd, VecDeque::new()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut vd)` - -error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` - --> tests/ui/mem_replace.rs:58:13 - | -LL | let _ = std::mem::replace(&mut hash_set, HashSet::new()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut hash_set)` - -error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` - --> tests/ui/mem_replace.rs:62:13 - | -LL | let _ = std::mem::replace(&mut btree_set, BTreeSet::new()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut btree_set)` - -error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` - --> tests/ui/mem_replace.rs:66:13 - | -LL | let _ = std::mem::replace(&mut list, LinkedList::new()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut list)` - -error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` - --> tests/ui/mem_replace.rs:70:13 - | -LL | let _ = std::mem::replace(&mut binary_heap, BinaryHeap::new()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut binary_heap)` - -error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` - --> tests/ui/mem_replace.rs:74:13 - | -LL | let _ = std::mem::replace(&mut tuple, (vec![], BinaryHeap::new())); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut tuple)` - -error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` - --> tests/ui/mem_replace.rs:78:13 - | -LL | let _ = std::mem::replace(&mut refstr, ""); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut refstr)` - -error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` - --> tests/ui/mem_replace.rs:82:13 - | -LL | let _ = std::mem::replace(&mut slice, &[]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut slice)` - -error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` - --> tests/ui/mem_replace.rs:115:13 - | -LL | let _ = std::mem::replace(&mut s, String::default()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut s)` - -error: replacing an `Option` with `None` - --> tests/ui/mem_replace.rs:146:13 - | -LL | let _ = std::mem::replace(&mut f.0, None); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::take()` instead: `f.0.take()` - -error: replacing an `Option` with `None` - --> tests/ui/mem_replace.rs:148:13 - | -LL | let _ = std::mem::replace(&mut *f, None); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::take()` instead: `(*f).take()` - -error: replacing an `Option` with `None` - --> tests/ui/mem_replace.rs:150:13 - | -LL | let _ = std::mem::replace(&mut b.opt, None); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::take()` instead: `b.opt.take()` - -error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` - --> tests/ui/mem_replace.rs:153:13 - | -LL | let _ = std::mem::replace(&mut b.val, String::default()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut b.val)` - -error: replacing an `Option` with `Some(..)` - --> tests/ui/mem_replace.rs:160:20 - | -LL | let replaced = mem::replace(&mut an_option, Some(1)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::replace()` instead: `an_option.replace(1)` - | - = note: `-D clippy::mem-replace-option-with-some` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::mem_replace_option_with_some)]` - -error: replacing an `Option` with `Some(..)` - --> tests/ui/mem_replace.rs:164:20 - | -LL | let replaced = mem::replace(an_option, Some(1)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::replace()` instead: `an_option.replace(1)` - -error: replacing an `Option` with `Some(..)` - --> tests/ui/mem_replace.rs:169:20 - | -LL | let replaced = mem::replace(if b { &mut opt1 } else { &mut opt2 }, Some(1)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::replace()` instead: `(if b { &mut opt1 } else { &mut opt2 }).replace(1)` - -error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` - --> tests/ui/mem_replace.rs:181:20 - | -LL | let replaced = std::mem::replace(dbg!(&mut text), String::default()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(dbg!(&mut text))` - -error: aborting due to 30 previous errors - diff --git a/tests/ui/mem_replace_macro.rs b/tests/ui/mem_replace_macro.rs deleted file mode 100644 index 9458dade3a9c7..0000000000000 --- a/tests/ui/mem_replace_macro.rs +++ /dev/null @@ -1,13 +0,0 @@ -//@aux-build:proc_macros.rs -#![warn(clippy::mem_replace_with_default)] - -extern crate proc_macros; -use proc_macros::{external, inline_macros}; - -#[inline_macros] -fn main() { - let s = &mut String::from("foo"); - let _ = inline!(std::mem::replace($s, Default::default())); - //~^ mem_replace_with_default - let _ = external!(std::mem::replace($s, Default::default())); -} diff --git a/tests/ui/mem_replace_macro.stderr b/tests/ui/mem_replace_macro.stderr deleted file mode 100644 index 0c98200bf04e5..0000000000000 --- a/tests/ui/mem_replace_macro.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` - --> tests/ui/mem_replace_macro.rs:10:21 - | -LL | let _ = inline!(std::mem::replace($s, Default::default())); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: `-D clippy::mem-replace-with-default` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::mem_replace_with_default)]` - = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: aborting due to 1 previous error - diff --git a/tests/ui/mem_replace_no_std.fixed b/tests/ui/mem_replace_no_std.fixed deleted file mode 100644 index 4e2d413af6cdf..0000000000000 --- a/tests/ui/mem_replace_no_std.fixed +++ /dev/null @@ -1,84 +0,0 @@ -#![allow(unused, clippy::needless_lifetimes)] -#![warn( - clippy::style, - clippy::mem_replace_option_with_none, - clippy::mem_replace_with_default -)] -#![feature(lang_items)] -#![no_std] - -use core::mem; -use core::panic::PanicInfo; - -#[lang = "eh_personality"] -extern "C" fn eh_personality() {} - -#[panic_handler] -fn panic(info: &PanicInfo) -> ! { - loop {} -} - -fn replace_option_with_none() { - let mut an_option = Some(1); - let _ = an_option.take(); - //~^ mem_replace_option_with_none - let an_option = &mut Some(1); - let _ = an_option.take(); - //~^ mem_replace_option_with_none -} - -fn replace_with_default() { - let mut refstr = "hello"; - let _ = core::mem::take(&mut refstr); - //~^ mem_replace_with_default - - let mut slice: &[i32] = &[1, 2, 3]; - let _ = core::mem::take(&mut slice); - //~^ mem_replace_with_default -} - -// lint is disabled for primitives because in this case `take` -// has no clear benefit over `replace` and sometimes is harder to read -fn dont_lint_primitive() { - let mut pbool = true; - let _ = mem::replace(&mut pbool, false); - - let mut pint = 5; - let _ = mem::replace(&mut pint, 0); -} - -fn main() {} - -fn issue9824() { - struct Foo<'a>(Option<&'a str>); - impl<'a> core::ops::Deref for Foo<'a> { - type Target = Option<&'a str>; - - fn deref(&self) -> &Self::Target { - &self.0 - } - } - impl<'a> core::ops::DerefMut for Foo<'a> { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 - } - } - - struct Bar { - opt: Option, - val: u8, - } - - let mut f = Foo(Some("foo")); - let mut b = Bar { opt: Some(1), val: 12 }; - - // replace option with none - let _ = f.0.take(); - //~^ mem_replace_option_with_none - let _ = (*f).take(); - //~^ mem_replace_option_with_none - let _ = b.opt.take(); - //~^ mem_replace_option_with_none - // replace with default - let _ = mem::replace(&mut b.val, u8::default()); -} diff --git a/tests/ui/mem_replace_no_std.rs b/tests/ui/mem_replace_no_std.rs deleted file mode 100644 index c0892304aba86..0000000000000 --- a/tests/ui/mem_replace_no_std.rs +++ /dev/null @@ -1,84 +0,0 @@ -#![allow(unused, clippy::needless_lifetimes)] -#![warn( - clippy::style, - clippy::mem_replace_option_with_none, - clippy::mem_replace_with_default -)] -#![feature(lang_items)] -#![no_std] - -use core::mem; -use core::panic::PanicInfo; - -#[lang = "eh_personality"] -extern "C" fn eh_personality() {} - -#[panic_handler] -fn panic(info: &PanicInfo) -> ! { - loop {} -} - -fn replace_option_with_none() { - let mut an_option = Some(1); - let _ = mem::replace(&mut an_option, None); - //~^ mem_replace_option_with_none - let an_option = &mut Some(1); - let _ = mem::replace(an_option, None); - //~^ mem_replace_option_with_none -} - -fn replace_with_default() { - let mut refstr = "hello"; - let _ = mem::replace(&mut refstr, ""); - //~^ mem_replace_with_default - - let mut slice: &[i32] = &[1, 2, 3]; - let _ = mem::replace(&mut slice, &[]); - //~^ mem_replace_with_default -} - -// lint is disabled for primitives because in this case `take` -// has no clear benefit over `replace` and sometimes is harder to read -fn dont_lint_primitive() { - let mut pbool = true; - let _ = mem::replace(&mut pbool, false); - - let mut pint = 5; - let _ = mem::replace(&mut pint, 0); -} - -fn main() {} - -fn issue9824() { - struct Foo<'a>(Option<&'a str>); - impl<'a> core::ops::Deref for Foo<'a> { - type Target = Option<&'a str>; - - fn deref(&self) -> &Self::Target { - &self.0 - } - } - impl<'a> core::ops::DerefMut for Foo<'a> { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 - } - } - - struct Bar { - opt: Option, - val: u8, - } - - let mut f = Foo(Some("foo")); - let mut b = Bar { opt: Some(1), val: 12 }; - - // replace option with none - let _ = mem::replace(&mut f.0, None); - //~^ mem_replace_option_with_none - let _ = mem::replace(&mut *f, None); - //~^ mem_replace_option_with_none - let _ = mem::replace(&mut b.opt, None); - //~^ mem_replace_option_with_none - // replace with default - let _ = mem::replace(&mut b.val, u8::default()); -} diff --git a/tests/ui/mem_replace_no_std.stderr b/tests/ui/mem_replace_no_std.stderr deleted file mode 100644 index 34e81a9f07504..0000000000000 --- a/tests/ui/mem_replace_no_std.stderr +++ /dev/null @@ -1,50 +0,0 @@ -error: replacing an `Option` with `None` - --> tests/ui/mem_replace_no_std.rs:23:13 - | -LL | let _ = mem::replace(&mut an_option, None); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::take()` instead: `an_option.take()` - | - = note: `-D clippy::mem-replace-option-with-none` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::mem_replace_option_with_none)]` - -error: replacing an `Option` with `None` - --> tests/ui/mem_replace_no_std.rs:26:13 - | -LL | let _ = mem::replace(an_option, None); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::take()` instead: `an_option.take()` - -error: replacing a value of type `T` with `T::default()` is better expressed using `core::mem::take` - --> tests/ui/mem_replace_no_std.rs:32:13 - | -LL | let _ = mem::replace(&mut refstr, ""); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `core::mem::take(&mut refstr)` - | - = note: `-D clippy::mem-replace-with-default` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::mem_replace_with_default)]` - -error: replacing a value of type `T` with `T::default()` is better expressed using `core::mem::take` - --> tests/ui/mem_replace_no_std.rs:36:13 - | -LL | let _ = mem::replace(&mut slice, &[]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `core::mem::take(&mut slice)` - -error: replacing an `Option` with `None` - --> tests/ui/mem_replace_no_std.rs:76:13 - | -LL | let _ = mem::replace(&mut f.0, None); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::take()` instead: `f.0.take()` - -error: replacing an `Option` with `None` - --> tests/ui/mem_replace_no_std.rs:78:13 - | -LL | let _ = mem::replace(&mut *f, None); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::take()` instead: `(*f).take()` - -error: replacing an `Option` with `None` - --> tests/ui/mem_replace_no_std.rs:80:13 - | -LL | let _ = mem::replace(&mut b.opt, None); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::take()` instead: `b.opt.take()` - -error: aborting due to 7 previous errors - diff --git a/tests/ui/mem_replace_option_with_none.fixed b/tests/ui/mem_replace_option_with_none.fixed new file mode 100644 index 0000000000000..9041e8595d6dd --- /dev/null +++ b/tests/ui/mem_replace_option_with_none.fixed @@ -0,0 +1,42 @@ +#![warn(clippy::mem_replace_option_with_none)] + +use std::mem; + +fn main() { + let mut an_option = Some(1); + let _ = an_option.take(); + //~^ mem_replace_option_with_none + let an_option = &mut Some(1); + let _ = an_option.take(); + //~^ mem_replace_option_with_none +} + +fn issue9824() { + struct Foo<'a>(Option<&'a str>); + impl<'a> std::ops::Deref for Foo<'a> { + type Target = Option<&'a str>; + + fn deref(&self) -> &Self::Target { + &self.0 + } + } + impl<'a> std::ops::DerefMut for Foo<'a> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } + } + + struct Bar { + opt: Option, + } + + let mut f = Foo(Some("foo")); + let mut b = Bar { opt: Some(1) }; + + let _ = f.0.take(); + //~^ mem_replace_option_with_none + let _ = (*f).take(); + //~^ mem_replace_option_with_none + let _ = b.opt.take(); + //~^ mem_replace_option_with_none +} diff --git a/tests/ui/mem_replace_option_with_none.rs b/tests/ui/mem_replace_option_with_none.rs new file mode 100644 index 0000000000000..b51115f02e1b2 --- /dev/null +++ b/tests/ui/mem_replace_option_with_none.rs @@ -0,0 +1,42 @@ +#![warn(clippy::mem_replace_option_with_none)] + +use std::mem; + +fn main() { + let mut an_option = Some(1); + let _ = mem::replace(&mut an_option, None); + //~^ mem_replace_option_with_none + let an_option = &mut Some(1); + let _ = mem::replace(an_option, None); + //~^ mem_replace_option_with_none +} + +fn issue9824() { + struct Foo<'a>(Option<&'a str>); + impl<'a> std::ops::Deref for Foo<'a> { + type Target = Option<&'a str>; + + fn deref(&self) -> &Self::Target { + &self.0 + } + } + impl<'a> std::ops::DerefMut for Foo<'a> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } + } + + struct Bar { + opt: Option, + } + + let mut f = Foo(Some("foo")); + let mut b = Bar { opt: Some(1) }; + + let _ = std::mem::replace(&mut f.0, None); + //~^ mem_replace_option_with_none + let _ = std::mem::replace(&mut *f, None); + //~^ mem_replace_option_with_none + let _ = std::mem::replace(&mut b.opt, None); + //~^ mem_replace_option_with_none +} diff --git a/tests/ui/mem_replace_option_with_none.stderr b/tests/ui/mem_replace_option_with_none.stderr new file mode 100644 index 0000000000000..d72aef7195535 --- /dev/null +++ b/tests/ui/mem_replace_option_with_none.stderr @@ -0,0 +1,35 @@ +error: replacing an `Option` with `None` + --> tests/ui/mem_replace_option_with_none.rs:7:13 + | +LL | let _ = mem::replace(&mut an_option, None); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `Option::take()` instead: `an_option.take()` + | + = note: `-D clippy::mem-replace-option-with-none` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::mem_replace_option_with_none)]` + +error: replacing an `Option` with `None` + --> tests/ui/mem_replace_option_with_none.rs:10:13 + | +LL | let _ = mem::replace(an_option, None); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `Option::take()` instead: `an_option.take()` + +error: replacing an `Option` with `None` + --> tests/ui/mem_replace_option_with_none.rs:36:13 + | +LL | let _ = std::mem::replace(&mut f.0, None); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `Option::take()` instead: `f.0.take()` + +error: replacing an `Option` with `None` + --> tests/ui/mem_replace_option_with_none.rs:38:13 + | +LL | let _ = std::mem::replace(&mut *f, None); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `Option::take()` instead: `(*f).take()` + +error: replacing an `Option` with `None` + --> tests/ui/mem_replace_option_with_none.rs:40:13 + | +LL | let _ = std::mem::replace(&mut b.opt, None); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `Option::take()` instead: `b.opt.take()` + +error: aborting due to 5 previous errors + diff --git a/tests/ui/mem_replace_option_with_none_no_std.fixed b/tests/ui/mem_replace_option_with_none_no_std.fixed new file mode 100644 index 0000000000000..a018547e920b7 --- /dev/null +++ b/tests/ui/mem_replace_option_with_none_no_std.fixed @@ -0,0 +1,13 @@ +#![warn(clippy::mem_replace_option_with_none)] +#![no_std] + +use core::mem; + +fn it_works() { + let mut an_option = Some(1); + let _ = an_option.take(); + //~^ mem_replace_option_with_none + let an_option = &mut Some(1); + let _ = an_option.take(); + //~^ mem_replace_option_with_none +} diff --git a/tests/ui/mem_replace_option_with_none_no_std.rs b/tests/ui/mem_replace_option_with_none_no_std.rs new file mode 100644 index 0000000000000..a2cc68e49d7df --- /dev/null +++ b/tests/ui/mem_replace_option_with_none_no_std.rs @@ -0,0 +1,13 @@ +#![warn(clippy::mem_replace_option_with_none)] +#![no_std] + +use core::mem; + +fn it_works() { + let mut an_option = Some(1); + let _ = mem::replace(&mut an_option, None); + //~^ mem_replace_option_with_none + let an_option = &mut Some(1); + let _ = mem::replace(an_option, None); + //~^ mem_replace_option_with_none +} diff --git a/tests/ui/mem_replace_option_with_none_no_std.stderr b/tests/ui/mem_replace_option_with_none_no_std.stderr new file mode 100644 index 0000000000000..085ef4462d5f1 --- /dev/null +++ b/tests/ui/mem_replace_option_with_none_no_std.stderr @@ -0,0 +1,17 @@ +error: replacing an `Option` with `None` + --> tests/ui/mem_replace_option_with_none_no_std.rs:8:13 + | +LL | let _ = mem::replace(&mut an_option, None); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `Option::take()` instead: `an_option.take()` + | + = note: `-D clippy::mem-replace-option-with-none` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::mem_replace_option_with_none)]` + +error: replacing an `Option` with `None` + --> tests/ui/mem_replace_option_with_none_no_std.rs:11:13 + | +LL | let _ = mem::replace(an_option, None); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `Option::take()` instead: `an_option.take()` + +error: aborting due to 2 previous errors + diff --git a/tests/ui/mem_replace_option_with_some.fixed b/tests/ui/mem_replace_option_with_some.fixed new file mode 100644 index 0000000000000..dc0652ae3645e --- /dev/null +++ b/tests/ui/mem_replace_option_with_some.fixed @@ -0,0 +1,25 @@ +#![warn(clippy::mem_replace_option_with_some)] + +use std::mem; + +#[clippy::msrv = "1.31"] +fn main() { + let mut an_option = Some(0); + let replaced = an_option.replace(1); + //~^ mem_replace_option_with_some + + let mut an_option = &mut Some(0); + let replaced = an_option.replace(1); + //~^ mem_replace_option_with_some + + let (mut opt1, mut opt2) = (Some(0), Some(0)); + let b = true; + let replaced = (if b { &mut opt1 } else { &mut opt2 }).replace(1); + //~^ mem_replace_option_with_some +} + +#[clippy::msrv = "1.30"] +fn bad_msrv() { + let mut an_option = Some(0); + let replaced = mem::replace(&mut an_option, Some(1)); +} diff --git a/tests/ui/mem_replace_option_with_some.rs b/tests/ui/mem_replace_option_with_some.rs new file mode 100644 index 0000000000000..dca2849837952 --- /dev/null +++ b/tests/ui/mem_replace_option_with_some.rs @@ -0,0 +1,25 @@ +#![warn(clippy::mem_replace_option_with_some)] + +use std::mem; + +#[clippy::msrv = "1.31"] +fn main() { + let mut an_option = Some(0); + let replaced = mem::replace(&mut an_option, Some(1)); + //~^ mem_replace_option_with_some + + let mut an_option = &mut Some(0); + let replaced = mem::replace(an_option, Some(1)); + //~^ mem_replace_option_with_some + + let (mut opt1, mut opt2) = (Some(0), Some(0)); + let b = true; + let replaced = mem::replace(if b { &mut opt1 } else { &mut opt2 }, Some(1)); + //~^ mem_replace_option_with_some +} + +#[clippy::msrv = "1.30"] +fn bad_msrv() { + let mut an_option = Some(0); + let replaced = mem::replace(&mut an_option, Some(1)); +} diff --git a/tests/ui/mem_replace_option_with_some.stderr b/tests/ui/mem_replace_option_with_some.stderr new file mode 100644 index 0000000000000..a064084c5face --- /dev/null +++ b/tests/ui/mem_replace_option_with_some.stderr @@ -0,0 +1,23 @@ +error: replacing an `Option` with `Some(..)` + --> tests/ui/mem_replace_option_with_some.rs:8:20 + | +LL | let replaced = mem::replace(&mut an_option, Some(1)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `Option::replace()` instead: `an_option.replace(1)` + | + = note: `-D clippy::mem-replace-option-with-some` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::mem_replace_option_with_some)]` + +error: replacing an `Option` with `Some(..)` + --> tests/ui/mem_replace_option_with_some.rs:12:20 + | +LL | let replaced = mem::replace(an_option, Some(1)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `Option::replace()` instead: `an_option.replace(1)` + +error: replacing an `Option` with `Some(..)` + --> tests/ui/mem_replace_option_with_some.rs:17:20 + | +LL | let replaced = mem::replace(if b { &mut opt1 } else { &mut opt2 }, Some(1)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `Option::replace()` instead: `(if b { &mut opt1 } else { &mut opt2 }).replace(1)` + +error: aborting due to 3 previous errors + diff --git a/tests/ui/mem_replace_option_with_some_no_std.fixed b/tests/ui/mem_replace_option_with_some_no_std.fixed new file mode 100644 index 0000000000000..7f882519aa624 --- /dev/null +++ b/tests/ui/mem_replace_option_with_some_no_std.fixed @@ -0,0 +1,26 @@ +#![warn(clippy::mem_replace_option_with_some)] +#![no_std] + +use core::mem; + +#[clippy::msrv = "1.31"] +fn it_works() { + let mut an_option = Some(0); + let replaced = an_option.replace(1); + //~^ mem_replace_option_with_some + + let mut an_option = &mut Some(0); + let replaced = an_option.replace(1); + //~^ mem_replace_option_with_some + + let (mut opt1, mut opt2) = (Some(0), Some(0)); + let b = true; + let replaced = (if b { &mut opt1 } else { &mut opt2 }).replace(1); + //~^ mem_replace_option_with_some +} + +#[clippy::msrv = "1.30"] +fn bad_msrv() { + let mut an_option = Some(0); + let replaced = mem::replace(&mut an_option, Some(1)); +} diff --git a/tests/ui/mem_replace_option_with_some_no_std.rs b/tests/ui/mem_replace_option_with_some_no_std.rs new file mode 100644 index 0000000000000..539c911a7efd9 --- /dev/null +++ b/tests/ui/mem_replace_option_with_some_no_std.rs @@ -0,0 +1,26 @@ +#![warn(clippy::mem_replace_option_with_some)] +#![no_std] + +use core::mem; + +#[clippy::msrv = "1.31"] +fn it_works() { + let mut an_option = Some(0); + let replaced = mem::replace(&mut an_option, Some(1)); + //~^ mem_replace_option_with_some + + let mut an_option = &mut Some(0); + let replaced = mem::replace(an_option, Some(1)); + //~^ mem_replace_option_with_some + + let (mut opt1, mut opt2) = (Some(0), Some(0)); + let b = true; + let replaced = mem::replace(if b { &mut opt1 } else { &mut opt2 }, Some(1)); + //~^ mem_replace_option_with_some +} + +#[clippy::msrv = "1.30"] +fn bad_msrv() { + let mut an_option = Some(0); + let replaced = mem::replace(&mut an_option, Some(1)); +} diff --git a/tests/ui/mem_replace_option_with_some_no_std.stderr b/tests/ui/mem_replace_option_with_some_no_std.stderr new file mode 100644 index 0000000000000..67965f3335b0a --- /dev/null +++ b/tests/ui/mem_replace_option_with_some_no_std.stderr @@ -0,0 +1,23 @@ +error: replacing an `Option` with `Some(..)` + --> tests/ui/mem_replace_option_with_some_no_std.rs:9:20 + | +LL | let replaced = mem::replace(&mut an_option, Some(1)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `Option::replace()` instead: `an_option.replace(1)` + | + = note: `-D clippy::mem-replace-option-with-some` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::mem_replace_option_with_some)]` + +error: replacing an `Option` with `Some(..)` + --> tests/ui/mem_replace_option_with_some_no_std.rs:13:20 + | +LL | let replaced = mem::replace(an_option, Some(1)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `Option::replace()` instead: `an_option.replace(1)` + +error: replacing an `Option` with `Some(..)` + --> tests/ui/mem_replace_option_with_some_no_std.rs:18:20 + | +LL | let replaced = mem::replace(if b { &mut opt1 } else { &mut opt2 }, Some(1)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `Option::replace()` instead: `(if b { &mut opt1 } else { &mut opt2 }).replace(1)` + +error: aborting due to 3 previous errors + diff --git a/tests/ui/mem_replace.fixed b/tests/ui/mem_replace_with_default.fixed similarity index 65% rename from tests/ui/mem_replace.fixed rename to tests/ui/mem_replace_with_default.fixed index 26aa7aa1b2703..af88a473e19ac 100644 --- a/tests/ui/mem_replace.fixed +++ b/tests/ui/mem_replace_with_default.fixed @@ -1,23 +1,13 @@ -#![allow(unused, clippy::needless_lifetimes)] -#![warn( - clippy::style, - clippy::mem_replace_option_with_none, - clippy::mem_replace_with_default -)] +//@aux-build:proc_macros.rs +#![warn(clippy::mem_replace_with_default)] + +extern crate proc_macros; +use proc_macros::{external, inline_macros}; use std::collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, LinkedList, VecDeque}; use std::mem; -fn replace_option_with_none() { - let mut an_option = Some(1); - let _ = an_option.take(); - //~^ mem_replace_option_with_none - let an_option = &mut Some(1); - let _ = an_option.take(); - //~^ mem_replace_option_with_none -} - -fn replace_with_default() { +fn main() { let mut s = String::from("foo"); let _ = std::mem::take(&mut s); //~^ mem_replace_with_default @@ -83,6 +73,13 @@ fn replace_with_default() { //~^ mem_replace_with_default } +#[inline_macros] +fn macros(s: &mut String) { + let _ = inline!(std::mem::take($s)); + //~^ mem_replace_with_default + let _ = external!(std::mem::replace($s, Default::default())); +} + // lint is disabled for primitives because in this case `take` // has no clear benefit over `replace` and sometimes is harder to read fn dont_lint_primitive() { @@ -101,8 +98,6 @@ fn dont_lint_not_used() { std::mem::replace(&mut s, String::default()); } -fn main() {} - #[clippy::msrv = "1.39"] fn msrv_1_39() { let mut s = String::from("foo"); @@ -117,65 +112,18 @@ fn msrv_1_40() { } fn issue9824() { - struct Foo<'a>(Option<&'a str>); - impl<'a> std::ops::Deref for Foo<'a> { - type Target = Option<&'a str>; - - fn deref(&self) -> &Self::Target { - &self.0 - } - } - impl<'a> std::ops::DerefMut for Foo<'a> { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 - } - } - struct Bar { - opt: Option, val: String, } - let mut f = Foo(Some("foo")); let mut b = Bar { - opt: Some(1), val: String::from("bar"), }; - // replace option with none - let _ = f.0.take(); - //~^ mem_replace_option_with_none - let _ = (*f).take(); - //~^ mem_replace_option_with_none - let _ = b.opt.take(); - //~^ mem_replace_option_with_none - // replace with default let _ = std::mem::take(&mut b.val); //~^ mem_replace_with_default } -#[clippy::msrv = "1.31"] -fn mem_replace_option_with_some() { - let mut an_option = Some(0); - let replaced = an_option.replace(1); - //~^ ERROR: replacing an `Option` with `Some(..)` - - let mut an_option = &mut Some(0); - let replaced = an_option.replace(1); - //~^ ERROR: replacing an `Option` with `Some(..)` - - let (mut opt1, mut opt2) = (Some(0), Some(0)); - let b = true; - let replaced = (if b { &mut opt1 } else { &mut opt2 }).replace(1); - //~^ ERROR: replacing an `Option` with `Some(..)` -} - -#[clippy::msrv = "1.30"] -fn mem_replace_option_with_some_bad_msrv() { - let mut an_option = Some(0); - let replaced = mem::replace(&mut an_option, Some(1)); -} - fn issue15785() { let mut text = String::from("foo"); let replaced = std::mem::take(dbg!(&mut text)); diff --git a/tests/ui/mem_replace.rs b/tests/ui/mem_replace_with_default.rs similarity index 66% rename from tests/ui/mem_replace.rs rename to tests/ui/mem_replace_with_default.rs index cd675f5735a19..6642a8340d5fa 100644 --- a/tests/ui/mem_replace.rs +++ b/tests/ui/mem_replace_with_default.rs @@ -1,23 +1,13 @@ -#![allow(unused, clippy::needless_lifetimes)] -#![warn( - clippy::style, - clippy::mem_replace_option_with_none, - clippy::mem_replace_with_default -)] +//@aux-build:proc_macros.rs +#![warn(clippy::mem_replace_with_default)] + +extern crate proc_macros; +use proc_macros::{external, inline_macros}; use std::collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, LinkedList, VecDeque}; use std::mem; -fn replace_option_with_none() { - let mut an_option = Some(1); - let _ = mem::replace(&mut an_option, None); - //~^ mem_replace_option_with_none - let an_option = &mut Some(1); - let _ = mem::replace(an_option, None); - //~^ mem_replace_option_with_none -} - -fn replace_with_default() { +fn main() { let mut s = String::from("foo"); let _ = std::mem::replace(&mut s, String::default()); //~^ mem_replace_with_default @@ -83,6 +73,13 @@ fn replace_with_default() { //~^ mem_replace_with_default } +#[inline_macros] +fn macros(s: &mut String) { + let _ = inline!(std::mem::replace($s, Default::default())); + //~^ mem_replace_with_default + let _ = external!(std::mem::replace($s, Default::default())); +} + // lint is disabled for primitives because in this case `take` // has no clear benefit over `replace` and sometimes is harder to read fn dont_lint_primitive() { @@ -101,8 +98,6 @@ fn dont_lint_not_used() { std::mem::replace(&mut s, String::default()); } -fn main() {} - #[clippy::msrv = "1.39"] fn msrv_1_39() { let mut s = String::from("foo"); @@ -117,65 +112,18 @@ fn msrv_1_40() { } fn issue9824() { - struct Foo<'a>(Option<&'a str>); - impl<'a> std::ops::Deref for Foo<'a> { - type Target = Option<&'a str>; - - fn deref(&self) -> &Self::Target { - &self.0 - } - } - impl<'a> std::ops::DerefMut for Foo<'a> { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 - } - } - struct Bar { - opt: Option, val: String, } - let mut f = Foo(Some("foo")); let mut b = Bar { - opt: Some(1), val: String::from("bar"), }; - // replace option with none - let _ = std::mem::replace(&mut f.0, None); - //~^ mem_replace_option_with_none - let _ = std::mem::replace(&mut *f, None); - //~^ mem_replace_option_with_none - let _ = std::mem::replace(&mut b.opt, None); - //~^ mem_replace_option_with_none - // replace with default let _ = std::mem::replace(&mut b.val, String::default()); //~^ mem_replace_with_default } -#[clippy::msrv = "1.31"] -fn mem_replace_option_with_some() { - let mut an_option = Some(0); - let replaced = mem::replace(&mut an_option, Some(1)); - //~^ ERROR: replacing an `Option` with `Some(..)` - - let mut an_option = &mut Some(0); - let replaced = mem::replace(an_option, Some(1)); - //~^ ERROR: replacing an `Option` with `Some(..)` - - let (mut opt1, mut opt2) = (Some(0), Some(0)); - let b = true; - let replaced = mem::replace(if b { &mut opt1 } else { &mut opt2 }, Some(1)); - //~^ ERROR: replacing an `Option` with `Some(..)` -} - -#[clippy::msrv = "1.30"] -fn mem_replace_option_with_some_bad_msrv() { - let mut an_option = Some(0); - let replaced = mem::replace(&mut an_option, Some(1)); -} - fn issue15785() { let mut text = String::from("foo"); let replaced = std::mem::replace(dbg!(&mut text), String::default()); diff --git a/tests/ui/mem_replace_with_default.stderr b/tests/ui/mem_replace_with_default.stderr new file mode 100644 index 0000000000000..8690ba4a198a9 --- /dev/null +++ b/tests/ui/mem_replace_with_default.stderr @@ -0,0 +1,145 @@ +error: replacing a value of type `T` with `T::default()` + --> tests/ui/mem_replace_with_default.rs:12:13 + | +LL | let _ = std::mem::replace(&mut s, String::default()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `std::mem::take` instead: `std::mem::take(&mut s)` + | + = note: `-D clippy::mem-replace-with-default` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::mem_replace_with_default)]` + +error: replacing a value of type `T` with `T::default()` + --> tests/ui/mem_replace_with_default.rs:14:13 + | +LL | let _ = std::mem::replace(&mut s, String::new()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `std::mem::take` instead: `std::mem::take(&mut s)` + +error: replacing a value of type `T` with `T::default()` + --> tests/ui/mem_replace_with_default.rs:18:13 + | +LL | let _ = std::mem::replace(s, String::default()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `std::mem::take` instead: `std::mem::take(s)` + +error: replacing a value of type `T` with `T::default()` + --> tests/ui/mem_replace_with_default.rs:20:13 + | +LL | let _ = std::mem::replace(s, String::new()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `std::mem::take` instead: `std::mem::take(s)` + +error: replacing a value of type `T` with `T::default()` + --> tests/ui/mem_replace_with_default.rs:22:13 + | +LL | let _ = std::mem::replace(s, Default::default()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `std::mem::take` instead: `std::mem::take(s)` + +error: replacing a value of type `T` with `T::default()` + --> tests/ui/mem_replace_with_default.rs:26:13 + | +LL | let _ = std::mem::replace(&mut v, Vec::default()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `std::mem::take` instead: `std::mem::take(&mut v)` + +error: replacing a value of type `T` with `T::default()` + --> tests/ui/mem_replace_with_default.rs:28:13 + | +LL | let _ = std::mem::replace(&mut v, Default::default()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `std::mem::take` instead: `std::mem::take(&mut v)` + +error: replacing a value of type `T` with `T::default()` + --> tests/ui/mem_replace_with_default.rs:30:13 + | +LL | let _ = std::mem::replace(&mut v, Vec::new()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `std::mem::take` instead: `std::mem::take(&mut v)` + +error: replacing a value of type `T` with `T::default()` + --> tests/ui/mem_replace_with_default.rs:32:13 + | +LL | let _ = std::mem::replace(&mut v, vec![]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `std::mem::take` instead: `std::mem::take(&mut v)` + +error: replacing a value of type `T` with `T::default()` + --> tests/ui/mem_replace_with_default.rs:36:13 + | +LL | let _ = std::mem::replace(&mut hash_map, HashMap::new()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `std::mem::take` instead: `std::mem::take(&mut hash_map)` + +error: replacing a value of type `T` with `T::default()` + --> tests/ui/mem_replace_with_default.rs:40:13 + | +LL | let _ = std::mem::replace(&mut btree_map, BTreeMap::new()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `std::mem::take` instead: `std::mem::take(&mut btree_map)` + +error: replacing a value of type `T` with `T::default()` + --> tests/ui/mem_replace_with_default.rs:44:13 + | +LL | let _ = std::mem::replace(&mut vd, VecDeque::new()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `std::mem::take` instead: `std::mem::take(&mut vd)` + +error: replacing a value of type `T` with `T::default()` + --> tests/ui/mem_replace_with_default.rs:48:13 + | +LL | let _ = std::mem::replace(&mut hash_set, HashSet::new()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `std::mem::take` instead: `std::mem::take(&mut hash_set)` + +error: replacing a value of type `T` with `T::default()` + --> tests/ui/mem_replace_with_default.rs:52:13 + | +LL | let _ = std::mem::replace(&mut btree_set, BTreeSet::new()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `std::mem::take` instead: `std::mem::take(&mut btree_set)` + +error: replacing a value of type `T` with `T::default()` + --> tests/ui/mem_replace_with_default.rs:56:13 + | +LL | let _ = std::mem::replace(&mut list, LinkedList::new()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `std::mem::take` instead: `std::mem::take(&mut list)` + +error: replacing a value of type `T` with `T::default()` + --> tests/ui/mem_replace_with_default.rs:60:13 + | +LL | let _ = std::mem::replace(&mut binary_heap, BinaryHeap::new()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `std::mem::take` instead: `std::mem::take(&mut binary_heap)` + +error: replacing a value of type `T` with `T::default()` + --> tests/ui/mem_replace_with_default.rs:64:13 + | +LL | let _ = std::mem::replace(&mut tuple, (vec![], BinaryHeap::new())); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `std::mem::take` instead: `std::mem::take(&mut tuple)` + +error: replacing a value of type `T` with `T::default()` + --> tests/ui/mem_replace_with_default.rs:68:13 + | +LL | let _ = std::mem::replace(&mut refstr, ""); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `std::mem::take` instead: `std::mem::take(&mut refstr)` + +error: replacing a value of type `T` with `T::default()` + --> tests/ui/mem_replace_with_default.rs:72:13 + | +LL | let _ = std::mem::replace(&mut slice, &[]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `std::mem::take` instead: `std::mem::take(&mut slice)` + +error: replacing a value of type `T` with `T::default()` + --> tests/ui/mem_replace_with_default.rs:78:21 + | +LL | let _ = inline!(std::mem::replace($s, Default::default())); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `std::mem::take` instead: `std::mem::take($s)` + | + = note: this error originates in the macro `__inline_mac_fn_macros` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: replacing a value of type `T` with `T::default()` + --> tests/ui/mem_replace_with_default.rs:110:13 + | +LL | let _ = std::mem::replace(&mut s, String::default()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `std::mem::take` instead: `std::mem::take(&mut s)` + +error: replacing a value of type `T` with `T::default()` + --> tests/ui/mem_replace_with_default.rs:123:13 + | +LL | let _ = std::mem::replace(&mut b.val, String::default()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `std::mem::take` instead: `std::mem::take(&mut b.val)` + +error: replacing a value of type `T` with `T::default()` + --> tests/ui/mem_replace_with_default.rs:129:20 + | +LL | let replaced = std::mem::replace(dbg!(&mut text), String::default()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `std::mem::take` instead: `std::mem::take(dbg!(&mut text))` + +error: aborting due to 23 previous errors + diff --git a/tests/ui/mem_replace_with_default_no_std.fixed b/tests/ui/mem_replace_with_default_no_std.fixed new file mode 100644 index 0000000000000..0486bf1a173f5 --- /dev/null +++ b/tests/ui/mem_replace_with_default_no_std.fixed @@ -0,0 +1,25 @@ +//@aux-build:proc_macros.rs +#![warn(clippy::mem_replace_with_default)] +#![no_std] + +extern crate proc_macros; +use proc_macros::{external, inline_macros}; + +use core::mem; + +fn it_works() { + let mut refstr = "hello"; + let _ = core::mem::take(&mut refstr); + //~^ mem_replace_with_default + + let mut slice: &[i32] = &[1, 2, 3]; + let _ = core::mem::take(&mut slice); + //~^ mem_replace_with_default +} + +#[inline_macros] +fn macros(mut refstr: &str) { + let _ = inline!(core::mem::take(&mut $refstr)); + //~^ mem_replace_with_default + let _ = external!(mem::replace(&mut $refstr, "")); +} diff --git a/tests/ui/mem_replace_with_default_no_std.rs b/tests/ui/mem_replace_with_default_no_std.rs new file mode 100644 index 0000000000000..c2670ece76ae1 --- /dev/null +++ b/tests/ui/mem_replace_with_default_no_std.rs @@ -0,0 +1,25 @@ +//@aux-build:proc_macros.rs +#![warn(clippy::mem_replace_with_default)] +#![no_std] + +extern crate proc_macros; +use proc_macros::{external, inline_macros}; + +use core::mem; + +fn it_works() { + let mut refstr = "hello"; + let _ = mem::replace(&mut refstr, ""); + //~^ mem_replace_with_default + + let mut slice: &[i32] = &[1, 2, 3]; + let _ = mem::replace(&mut slice, &[]); + //~^ mem_replace_with_default +} + +#[inline_macros] +fn macros(mut refstr: &str) { + let _ = inline!(mem::replace(&mut $refstr, "")); + //~^ mem_replace_with_default + let _ = external!(mem::replace(&mut $refstr, "")); +} diff --git a/tests/ui/mem_replace_with_default_no_std.stderr b/tests/ui/mem_replace_with_default_no_std.stderr new file mode 100644 index 0000000000000..7fb72cdf5a480 --- /dev/null +++ b/tests/ui/mem_replace_with_default_no_std.stderr @@ -0,0 +1,25 @@ +error: replacing a value of type `T` with `T::default()` + --> tests/ui/mem_replace_with_default_no_std.rs:12:13 + | +LL | let _ = mem::replace(&mut refstr, ""); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `core::mem::take` instead: `core::mem::take(&mut refstr)` + | + = note: `-D clippy::mem-replace-with-default` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::mem_replace_with_default)]` + +error: replacing a value of type `T` with `T::default()` + --> tests/ui/mem_replace_with_default_no_std.rs:16:13 + | +LL | let _ = mem::replace(&mut slice, &[]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `core::mem::take` instead: `core::mem::take(&mut slice)` + +error: replacing a value of type `T` with `T::default()` + --> tests/ui/mem_replace_with_default_no_std.rs:22:21 + | +LL | let _ = inline!(mem::replace(&mut $refstr, "")); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `core::mem::take` instead: `core::mem::take(&mut $refstr)` + | + = note: this error originates in the macro `__inline_mac_fn_macros` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 3 previous errors + diff --git a/tests/ui/mem_replace_with_uninit.fixed b/tests/ui/mem_replace_with_uninit.fixed new file mode 100644 index 0000000000000..d55ac85dfc71f --- /dev/null +++ b/tests/ui/mem_replace_with_uninit.fixed @@ -0,0 +1,50 @@ +#![warn(clippy::mem_replace_with_uninit)] +#![allow( + // These get removed by the suggestion + deprecated, // for `std::mem::uninitialized` + invalid_value, + clippy::uninit_assumed_init, + + // Added because the suggestion is `std::ptr::read(&mut v)` + // (which might be considered a bug) + clippy::unnecessary_mut_passed, +)] + +use std::mem; + +fn might_panic(x: X) -> X { + // in practice this would be a possibly-panicky operation + x +} + +fn main() { + let mut v = vec![0i32; 4]; + // the following is UB if `might_panic` panics + unsafe { + let taken_v = std::ptr::read(&mut v); + //~^ mem_replace_with_uninit + + let new_v = might_panic(taken_v); + std::mem::forget(mem::replace(&mut v, new_v)); + } + + unsafe { + let taken_v = std::ptr::read(&mut v); + //~^ mem_replace_with_uninit + + let new_v = might_panic(taken_v); + std::mem::forget(mem::replace(&mut v, new_v)); + } + + // this is silly but OK, because usize is a primitive type + let mut u: usize = 42; + let uref = &mut u; + let taken_u = unsafe { mem::replace(uref, mem::zeroed()) }; + *uref = taken_u + 1; + + // this is still not OK, because uninit + let taken_u = unsafe { std::ptr::read(uref) }; + //~^ mem_replace_with_uninit + + *uref = taken_u + 1; +} diff --git a/tests/ui/repl_uninit.rs b/tests/ui/mem_replace_with_uninit.rs similarity index 78% rename from tests/ui/repl_uninit.rs rename to tests/ui/mem_replace_with_uninit.rs index e9469d4c5e2ff..0e6ede307f02c 100644 --- a/tests/ui/repl_uninit.rs +++ b/tests/ui/mem_replace_with_uninit.rs @@ -1,6 +1,15 @@ -#![allow(deprecated, invalid_value, clippy::uninit_assumed_init)] #![warn(clippy::mem_replace_with_uninit)] -//@no-rustfix +#![allow( + // These get removed by the suggestion + deprecated, // for `std::mem::uninitialized` + invalid_value, + clippy::uninit_assumed_init, + + // Added because the suggestion is `std::ptr::read(&mut v)` + // (which might be considered a bug) + clippy::unnecessary_mut_passed, +)] + use std::mem; fn might_panic(x: X) -> X { @@ -27,14 +36,6 @@ fn main() { std::mem::forget(mem::replace(&mut v, new_v)); } - unsafe { - let taken_v = mem::replace(&mut v, mem::zeroed()); - //~^ mem_replace_with_uninit - - let new_v = might_panic(taken_v); - std::mem::forget(mem::replace(&mut v, new_v)); - } - // this is silly but OK, because usize is a primitive type let mut u: usize = 42; let uref = &mut u; diff --git a/tests/ui/repl_uninit.stderr b/tests/ui/mem_replace_with_uninit.stderr similarity index 55% rename from tests/ui/repl_uninit.stderr rename to tests/ui/mem_replace_with_uninit.stderr index 08b0b265942d7..b5616ab722261 100644 --- a/tests/ui/repl_uninit.stderr +++ b/tests/ui/mem_replace_with_uninit.stderr @@ -1,31 +1,23 @@ error: replacing with `mem::uninitialized()` - --> tests/ui/repl_uninit.rs:15:23 + --> tests/ui/mem_replace_with_uninit.rs:24:23 | LL | let taken_v = mem::replace(&mut v, mem::uninitialized()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::ptr::read(&mut v)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `std::ptr::read` instead: `std::ptr::read(&mut v)` | = note: `-D clippy::mem-replace-with-uninit` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::mem_replace_with_uninit)]` error: replacing with `mem::MaybeUninit::uninit().assume_init()` - --> tests/ui/repl_uninit.rs:23:23 + --> tests/ui/mem_replace_with_uninit.rs:32:23 | LL | let taken_v = mem::replace(&mut v, mem::MaybeUninit::uninit().assume_init()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::ptr::read(&mut v)` - -error: replacing with `mem::zeroed()` - --> tests/ui/repl_uninit.rs:31:23 - | -LL | let taken_v = mem::replace(&mut v, mem::zeroed()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: consider using a default value or the `take_mut` crate instead + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `std::ptr::read` instead: `std::ptr::read(&mut v)` error: replacing with `mem::uninitialized()` - --> tests/ui/repl_uninit.rs:45:28 + --> tests/ui/mem_replace_with_uninit.rs:46:28 | LL | let taken_u = unsafe { mem::replace(uref, mem::uninitialized()) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::ptr::read(uref)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `std::ptr::read` instead: `std::ptr::read(uref)` -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors diff --git a/tests/ui/mem_replace_with_uninit_unfixable.rs b/tests/ui/mem_replace_with_uninit_unfixable.rs new file mode 100644 index 0000000000000..7abb7f2c5dc35 --- /dev/null +++ b/tests/ui/mem_replace_with_uninit_unfixable.rs @@ -0,0 +1,22 @@ +// The lint does not offer a suggestion for the `zeroed` case +//@ no-rustfix +#![warn(clippy::mem_replace_with_uninit)] +#![expect(invalid_value)] + +use std::mem; + +fn might_panic(x: X) -> X { + // in practice this would be a possibly-panicky operation + x +} + +fn main() { + let mut v = vec![0i32; 4]; + unsafe { + let taken_v = mem::replace(&mut v, mem::zeroed()); + //~^ mem_replace_with_uninit + + let new_v = might_panic(taken_v); + std::mem::forget(mem::replace(&mut v, new_v)); + } +} diff --git a/tests/ui/mem_replace_with_uninit_unfixable.stderr b/tests/ui/mem_replace_with_uninit_unfixable.stderr new file mode 100644 index 0000000000000..166d9fdd2ea8f --- /dev/null +++ b/tests/ui/mem_replace_with_uninit_unfixable.stderr @@ -0,0 +1,12 @@ +error: replacing with `mem::zeroed()` + --> tests/ui/mem_replace_with_uninit_unfixable.rs:16:23 + | +LL | let taken_v = mem::replace(&mut v, mem::zeroed()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using a default value or the `take_mut` crate instead + = note: `-D clippy::mem-replace-with-uninit` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::mem_replace_with_uninit)]` + +error: aborting due to 1 previous error + diff --git a/tests/ui/missing_const_for_fn/could_be_const.fixed b/tests/ui/missing_const_for_fn/could_be_const.fixed index 95bf63ed1df6f..46a7f79ac16ce 100644 --- a/tests/ui/missing_const_for_fn/could_be_const.fixed +++ b/tests/ui/missing_const_for_fn/could_be_const.fixed @@ -278,3 +278,9 @@ mod issue_15079 { } } } + +pub const fn issue17119(s: &str) -> bool { + //~^ missing_const_for_fn + let [_] = s.as_bytes() else { return false }; + true +} diff --git a/tests/ui/missing_const_for_fn/could_be_const.rs b/tests/ui/missing_const_for_fn/could_be_const.rs index 8290be6754621..78e1939a85973 100644 --- a/tests/ui/missing_const_for_fn/could_be_const.rs +++ b/tests/ui/missing_const_for_fn/could_be_const.rs @@ -278,3 +278,9 @@ mod issue_15079 { } } } + +pub fn issue17119(s: &str) -> bool { + //~^ missing_const_for_fn + let [_] = s.as_bytes() else { return false }; + true +} diff --git a/tests/ui/missing_const_for_fn/could_be_const.stderr b/tests/ui/missing_const_for_fn/could_be_const.stderr index 17cbc4312766a..4465b51e47719 100644 --- a/tests/ui/missing_const_for_fn/could_be_const.stderr +++ b/tests/ui/missing_const_for_fn/could_be_const.stderr @@ -402,5 +402,20 @@ help: make the function `const` LL | pub const fn new_1_61() -> Self { | +++++ -error: aborting due to 30 previous errors +error: this could be a `const fn` + --> tests/ui/missing_const_for_fn/could_be_const.rs:282:1 + | +LL | / pub fn issue17119(s: &str) -> bool { +LL | | +LL | | let [_] = s.as_bytes() else { return false }; +LL | | true +LL | | } + | |_^ + | +help: make the function `const` + | +LL | pub const fn issue17119(s: &str) -> bool { + | +++++ + +error: aborting due to 31 previous errors diff --git a/tests/ui/needless_borrow_false_positive_16200.fixed b/tests/ui/needless_borrow_false_positive_16200.fixed new file mode 100644 index 0000000000000..45c827ab09463 --- /dev/null +++ b/tests/ui/needless_borrow_false_positive_16200.fixed @@ -0,0 +1,38 @@ +trait Trait { + fn run(&self); +} + +struct Test; +impl Test { + fn run(self, x: f32) {} +} +impl Trait for Test { + fn run(&self) {} +} + +struct Test2; +trait Trait2: Sized { + fn run(self, _x: f32) {} +} +impl Trait2 for Test2 { + fn run(self, _x: f32) {} +} +impl Trait for Test2 { + fn run(&self) {} +} + +struct Test3; +impl Trait for Test3 { + fn run(&self) {} +} + +fn main() { + (&Test).run(); + (&Test).run(); //~ needless_borrow + + (&Test2).run(); + (&Test2).run(); //~ needless_borrow + + Test3.run(); //~ needless_borrow + Test3.run(); //~ needless_borrow +} diff --git a/tests/ui/needless_borrow_false_positive_16200.rs b/tests/ui/needless_borrow_false_positive_16200.rs new file mode 100644 index 0000000000000..686dded57b504 --- /dev/null +++ b/tests/ui/needless_borrow_false_positive_16200.rs @@ -0,0 +1,38 @@ +trait Trait { + fn run(&self); +} + +struct Test; +impl Test { + fn run(self, x: f32) {} +} +impl Trait for Test { + fn run(&self) {} +} + +struct Test2; +trait Trait2: Sized { + fn run(self, _x: f32) {} +} +impl Trait2 for Test2 { + fn run(self, _x: f32) {} +} +impl Trait for Test2 { + fn run(&self) {} +} + +struct Test3; +impl Trait for Test3 { + fn run(&self) {} +} + +fn main() { + (&Test).run(); + (&&Test).run(); //~ needless_borrow + + (&Test2).run(); + (&&Test2).run(); //~ needless_borrow + + (&Test3).run(); //~ needless_borrow + (&&Test3).run(); //~ needless_borrow +} diff --git a/tests/ui/needless_borrow_false_positive_16200.stderr b/tests/ui/needless_borrow_false_positive_16200.stderr new file mode 100644 index 0000000000000..de70635dc50c1 --- /dev/null +++ b/tests/ui/needless_borrow_false_positive_16200.stderr @@ -0,0 +1,29 @@ +error: this expression creates a reference which is immediately dereferenced by the compiler + --> tests/ui/needless_borrow_false_positive_16200.rs:31:5 + | +LL | (&&Test).run(); + | ^^^^^^^^ help: change this to: `(&Test)` + | + = note: `-D clippy::needless-borrow` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::needless_borrow)]` + +error: this expression creates a reference which is immediately dereferenced by the compiler + --> tests/ui/needless_borrow_false_positive_16200.rs:34:5 + | +LL | (&&Test2).run(); + | ^^^^^^^^^ help: change this to: `(&Test2)` + +error: this expression borrows a value the compiler would automatically borrow + --> tests/ui/needless_borrow_false_positive_16200.rs:36:5 + | +LL | (&Test3).run(); + | ^^^^^^^^ help: change this to: `Test3` + +error: this expression creates a reference which is immediately dereferenced by the compiler + --> tests/ui/needless_borrow_false_positive_16200.rs:37:5 + | +LL | (&&Test3).run(); + | ^^^^^^^^^ help: change this to: `Test3` + +error: aborting due to 4 previous errors + diff --git a/tests/ui/never_loop.rs b/tests/ui/never_loop.rs index 7b2d66450f171..5d9d93dc49c3c 100644 --- a/tests/ui/never_loop.rs +++ b/tests/ui/never_loop.rs @@ -541,3 +541,106 @@ fn issue16462() { n >= 0 || break; } } + +fn issue16056_basic() { + let x = || Some(panic!()); + + //~v never_loop + loop { + x().unwrap(); + } +} + +fn issue16056_nested_loops() { + let x = || Some(panic!()); + + //~v never_loop + loop { + //~v never_loop + loop { + x().unwrap(); + } + } +} + +fn issue16056_nested_block() { + let x = || Some(panic!()); + + //~v never_loop + loop { + { + x().unwrap(); + } + } +} + +fn issue16056_nested_blocks() { + let x = || Some(panic!()); + + //~v never_loop + loop { + { + { + x().unwrap(); + } + } + } +} + +fn issue16056_match() { + let x = || Some(panic!()); + + let mut y = 1; + //~v never_loop + loop { + y += 1; + match y { + 5 => return, + _ => { + x().unwrap(); + }, + } + } +} + +fn issue16056_if_no_trigger() { + let x = || Some(panic!()); + let mut y = 0; + //~v never_loop + loop { + y += 1; + if y == 1 { + // No extra note for this + x().unwrap(); + } + break; + } +} + +fn issue16056_if_trigger() { + let x = || Some(panic!()); + + //~v never_loop + loop { + if true { + x().unwrap(); + } else { + break; + } + } +} + +macro_rules! test_macro { + ($e:expr) => { + $e + }; +} + +fn issue16056_macro() { + let x = || Some(panic!()); + + //~v never_loop + loop { + test_macro!(x().unwrap()); + } +} diff --git a/tests/ui/never_loop.stderr b/tests/ui/never_loop.stderr index 815758107884c..7bc53289e76ff 100644 --- a/tests/ui/never_loop.stderr +++ b/tests/ui/never_loop.stderr @@ -404,5 +404,142 @@ LL | | return; LL | | } | |_____^ -error: aborting due to 30 previous errors +error: this loop never actually loops + --> tests/ui/never_loop.rs:549:5 + | +LL | / loop { +LL | | x().unwrap(); +LL | | } + | |_____^ + | +note: this expression never returns + --> tests/ui/never_loop.rs:550:9 + | +LL | x().unwrap(); + | ^^^^^^^^^^^^ + +error: this loop never actually loops + --> tests/ui/never_loop.rs:558:5 + | +LL | / loop { +LL | | +LL | | loop { +LL | | x().unwrap(); +LL | | } +LL | | } + | |_____^ + | +note: this expression never returns + --> tests/ui/never_loop.rs:561:13 + | +LL | x().unwrap(); + | ^^^^^^^^^^^^ + +error: this loop never actually loops + --> tests/ui/never_loop.rs:560:9 + | +LL | / loop { +LL | | x().unwrap(); +LL | | } + | |_________^ + | +note: this expression never returns + --> tests/ui/never_loop.rs:561:13 + | +LL | x().unwrap(); + | ^^^^^^^^^^^^ + +error: this loop never actually loops + --> tests/ui/never_loop.rs:570:5 + | +LL | / loop { +LL | | { +LL | | x().unwrap(); +LL | | } +LL | | } + | |_____^ + | +note: this expression never returns + --> tests/ui/never_loop.rs:572:13 + | +LL | x().unwrap(); + | ^^^^^^^^^^^^ + +error: this loop never actually loops + --> tests/ui/never_loop.rs:581:5 + | +LL | / loop { +LL | | { +LL | | { +LL | | x().unwrap(); +... | +LL | | } + | |_____^ + | +note: this expression never returns + --> tests/ui/never_loop.rs:584:17 + | +LL | x().unwrap(); + | ^^^^^^^^^^^^ + +error: this loop never actually loops + --> tests/ui/never_loop.rs:595:5 + | +LL | / loop { +LL | | y += 1; +LL | | match y { +LL | | 5 => return, +... | +LL | | } + | |_____^ + | +note: this expression never returns + --> tests/ui/never_loop.rs:600:17 + | +LL | x().unwrap(); + | ^^^^^^^^^^^^ + +error: this loop never actually loops + --> tests/ui/never_loop.rs:610:5 + | +LL | / loop { +LL | | y += 1; +LL | | if y == 1 { +... | +LL | | break; +LL | | } + | |_____^ + +error: this loop never actually loops + --> tests/ui/never_loop.rs:624:5 + | +LL | / loop { +LL | | if true { +LL | | x().unwrap(); +LL | | } else { +... | +LL | | } + | |_____^ + | +note: this expression never returns + --> tests/ui/never_loop.rs:626:13 + | +LL | x().unwrap(); + | ^^^^^^^^^^^^ + +error: this loop never actually loops + --> tests/ui/never_loop.rs:643:5 + | +LL | / loop { +LL | | test_macro!(x().unwrap()); +LL | | } + | |_____^ + | +note: this expression never returns + --> tests/ui/never_loop.rs:644:21 + | +LL | test_macro!(x().unwrap()); + | ^^^^^^^^^^^^ + +error: aborting due to 39 previous errors diff --git a/tests/ui/range_plus_minus_one.fixed b/tests/ui/range_plus_minus_one.fixed index e07a0e07368b5..4c0cb86611973 100644 --- a/tests/ui/range_plus_minus_one.fixed +++ b/tests/ui/range_plus_minus_one.fixed @@ -56,9 +56,7 @@ fn main() { let _ = (f() + 1)..(f() + 1); const ONE: usize = 1; - // integer consts are linted, too - for _ in 1..=ONE {} - //~^ range_plus_one + for _ in 1..ONE + ONE {} let mut vec: Vec<()> = std::vec::Vec::new(); vec.drain(..); diff --git a/tests/ui/range_plus_minus_one.rs b/tests/ui/range_plus_minus_one.rs index 3e6e4f629a51a..c853d1f9387a2 100644 --- a/tests/ui/range_plus_minus_one.rs +++ b/tests/ui/range_plus_minus_one.rs @@ -56,9 +56,7 @@ fn main() { let _ = (f() + 1)..(f() + 1); const ONE: usize = 1; - // integer consts are linted, too for _ in 1..ONE + ONE {} - //~^ range_plus_one let mut vec: Vec<()> = std::vec::Vec::new(); vec.drain(..); diff --git a/tests/ui/range_plus_minus_one.stderr b/tests/ui/range_plus_minus_one.stderr index 79c482aeaa6bb..93d74b1d840c9 100644 --- a/tests/ui/range_plus_minus_one.stderr +++ b/tests/ui/range_plus_minus_one.stderr @@ -26,61 +26,55 @@ LL | for _ in 0..(1 + f()) {} | ^^^^^^^^^^^^ help: use: `0..=f()` error: an inclusive range would be more readable - --> tests/ui/range_plus_minus_one.rs:60:14 - | -LL | for _ in 1..ONE + ONE {} - | ^^^^^^^^^^^^ help: use: `1..=ONE` - -error: an inclusive range would be more readable - --> tests/ui/range_plus_minus_one.rs:70:6 + --> tests/ui/range_plus_minus_one.rs:68:6 | LL | (1..10 + 1).for_each(|_| {}); | ^^^^^^^^^ help: use: `1..=10` error: an inclusive range would be more readable - --> tests/ui/range_plus_minus_one.rs:75:6 + --> tests/ui/range_plus_minus_one.rs:73:6 | LL | (1..10 + 1).into_iter().for_each(|_| {}); | ^^^^^^^^^ help: use: `1..=10` error: an inclusive range would be more readable - --> tests/ui/range_plus_minus_one.rs:80:18 + --> tests/ui/range_plus_minus_one.rs:78:18 | LL | let _ = (1..10 + 1).start_bound(); | ^^^^^^^^^ help: use: `1..=10` error: an inclusive range would be more readable - --> tests/ui/range_plus_minus_one.rs:86:16 + --> tests/ui/range_plus_minus_one.rs:84:16 | LL | let _ = &a[1..1 + 1]; | ^^^^^^^^ help: use: `1..=1` error: an inclusive range would be more readable - --> tests/ui/range_plus_minus_one.rs:90:15 + --> tests/ui/range_plus_minus_one.rs:88:15 | LL | vec.drain(2..3 + 1); | ^^^^^^^^ help: use: `2..=3` error: an inclusive range would be more readable - --> tests/ui/range_plus_minus_one.rs:94:14 + --> tests/ui/range_plus_minus_one.rs:92:14 | LL | take_arg(10..20 + 1); | ^^^^^^^^^^ help: use: `10..=20` error: an inclusive range would be more readable - --> tests/ui/range_plus_minus_one.rs:98:16 + --> tests/ui/range_plus_minus_one.rs:96:16 | LL | take_arg({ 10..20 + 1 }); | ^^^^^^^^^^ help: use: `10..=20` error: an inclusive range would be more readable - --> tests/ui/range_plus_minus_one.rs:112:7 + --> tests/ui/range_plus_minus_one.rs:110:7 | LL | a[0..2 + 1][0] = 1; | ^^^^^^^^ help: use: `0..=2` error: an exclusive range would be more readable - --> tests/ui/range_plus_minus_one.rs:180:6 + --> tests/ui/range_plus_minus_one.rs:178:6 | LL | (1..=n - 1).sum() | ^^^^^^^^^ help: use: `1..n` @@ -89,10 +83,10 @@ LL | (1..=n - 1).sum() = help: to override `-D warnings` add `#[allow(clippy::range_minus_one)]` error: an inclusive range would be more readable - --> tests/ui/range_plus_minus_one.rs:192:14 + --> tests/ui/range_plus_minus_one.rs:190:14 | LL | for _ in test!(x)..test!(x) + 1 { | ^^^^^^^^^^^^^^^^^^^^^^ help: use: `test!(x)..=test!(x)` -error: aborting due to 15 previous errors +error: aborting due to 14 previous errors diff --git a/tests/ui/redundant_closure_call_early.rs b/tests/ui/redundant_closure_call_early.rs index 722f7c03909f0..a78d6c07a5e03 100644 --- a/tests/ui/redundant_closure_call_early.rs +++ b/tests/ui/redundant_closure_call_early.rs @@ -1,6 +1,7 @@ // non rustfixable, see redundant_closure_call_fixable.rs -#![warn(clippy::redundant_closure_call)] +#![expect(incomplete_features)] +#![feature(ergonomic_clones)] fn main() { let mut i = 1; @@ -14,9 +15,60 @@ fn main() { //~^ redundant_closure_call // don't lint these - #[allow(clippy::needless_return)] + #[expect(clippy::needless_return)] (|| return 2)(); (|| -> Option { None? })(); - #[allow(clippy::try_err)] + #[expect(clippy::try_err)] (|| -> Result { Err(2)? })(); + + // don't lint async equivalents either + #[expect(clippy::needless_return)] + (|| async { return })(); + (|| async { + let x: Option = None; + x?; + Some(1) + })(); + #[expect(clippy::try_err)] + (|| async { + Err::<(), i32>(2)?; + Ok::<(), i32>(()) + })(); + + #[expect(clippy::needless_return)] + (|| async move { return })(); + (|| async move { + let x: Option = None; + x?; + Some(1) + })(); + + #[expect(clippy::needless_return)] + (async || return)(); + (async || { + let x: Option = None; + x?; + Some(1) + })(); + #[expect(clippy::try_err)] + (async || { + Err::<(), i32>(2)?; + Ok::<(), i32>(()) + })(); + + #[expect(clippy::needless_return)] + (async move || return)(); + (async move || { + let x: Option = None; + x?; + Some(1) + })(); + + #[expect(clippy::needless_return)] + (async use || return)(); + (async use || { + let x: Option = None; + x?; + Some(1) + })(); } diff --git a/tests/ui/redundant_closure_call_early.stderr b/tests/ui/redundant_closure_call_early.stderr index 1dd24baf9daeb..e72499a7fb438 100644 --- a/tests/ui/redundant_closure_call_early.stderr +++ b/tests/ui/redundant_closure_call_early.stderr @@ -1,5 +1,5 @@ error: try not to call a closure in the expression where it is declared - --> tests/ui/redundant_closure_call_early.rs:9:17 + --> tests/ui/redundant_closure_call_early.rs:10:17 | LL | let mut k = (|m| m + 1)(i); | ^^^^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | let mut k = (|m| m + 1)(i); = help: to override `-D warnings` add `#[allow(clippy::redundant_closure_call)]` error: try not to call a closure in the expression where it is declared - --> tests/ui/redundant_closure_call_early.rs:13:9 + --> tests/ui/redundant_closure_call_early.rs:14:9 | LL | k = (|a, b| a * b)(1, 5); | ^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/redundant_closure_call_fixable.fixed b/tests/ui/redundant_closure_call_fixable.fixed index 9f6643e8d52e8..d10063251accd 100644 --- a/tests/ui/redundant_closure_call_fixable.fixed +++ b/tests/ui/redundant_closure_call_fixable.fixed @@ -1,7 +1,6 @@ -#![warn(clippy::redundant_closure_call)] -#![allow(clippy::redundant_async_block)] -#![allow(clippy::type_complexity)] -#![allow(unused)] +#![expect(unused)] +#![expect(incomplete_features)] +#![feature(ergonomic_clones)] async fn something() -> u32 { 21 @@ -67,6 +66,7 @@ fn issue9956() { // nested async closures let a = async { 1 }; //~^ redundant_closure_call + #[expect(clippy::redundant_async_block)] let h = async { a.await }; // macro expansion tests @@ -83,6 +83,7 @@ fn issue9956() { assert_eq!(a, 123); // chaining calls, but not closures + #[expect(clippy::type_complexity)] fn x() -> fn() -> fn() -> fn() -> i32 { || || || 42 } @@ -112,6 +113,37 @@ mod issue11707 { spawn_on(async move {}); //~^ redundant_closure_call } + + fn demo_with_captures() { + let name = String::from("world"); + spawn_on(async move { drop(format!("hello, {name}")) }); + //~^ redundant_closure_call + } + + fn demo_async_move_closure() { + let name = String::from("world"); + spawn_on(async move { drop(format!("hello, {name}")) }); + //~^ redundant_closure_call + } +} + +mod issue16232 { + use core::future::Future; + + fn spawn_on(fut: impl Future) {} + + fn closure_async_use_block() { + let name = String::from("world"); + #[rustfmt::skip] + spawn_on(async use { drop(format!("hello, {name:?}")) }); + //~^ redundant_closure_call + } + + fn async_use_closure() { + let name = String::from("world"); + spawn_on(async use { drop(format!("hello, {name}")) }); + //~^ redundant_closure_call + } } fn avoid_double_parens() { diff --git a/tests/ui/redundant_closure_call_fixable.rs b/tests/ui/redundant_closure_call_fixable.rs index 34f228786786b..eccfb2e3c3a74 100644 --- a/tests/ui/redundant_closure_call_fixable.rs +++ b/tests/ui/redundant_closure_call_fixable.rs @@ -1,7 +1,6 @@ -#![warn(clippy::redundant_closure_call)] -#![allow(clippy::redundant_async_block)] -#![allow(clippy::type_complexity)] -#![allow(unused)] +#![expect(unused)] +#![expect(incomplete_features)] +#![feature(ergonomic_clones)] async fn something() -> u32 { 21 @@ -67,6 +66,7 @@ fn issue9956() { // nested async closures let a = (|| || || || async || 1)()()()()(); //~^ redundant_closure_call + #[expect(clippy::redundant_async_block)] let h = async { a.await }; // macro expansion tests @@ -83,6 +83,7 @@ fn issue9956() { assert_eq!(a, 123); // chaining calls, but not closures + #[expect(clippy::type_complexity)] fn x() -> fn() -> fn() -> fn() -> i32 { || || || 42 } @@ -112,6 +113,37 @@ mod issue11707 { spawn_on((|| async move {})()); //~^ redundant_closure_call } + + fn demo_with_captures() { + let name = String::from("world"); + spawn_on((|| async move { drop(format!("hello, {name}")) })()); + //~^ redundant_closure_call + } + + fn demo_async_move_closure() { + let name = String::from("world"); + spawn_on((async move || drop(format!("hello, {name}")))()); + //~^ redundant_closure_call + } +} + +mod issue16232 { + use core::future::Future; + + fn spawn_on(fut: impl Future) {} + + fn closure_async_use_block() { + let name = String::from("world"); + #[rustfmt::skip] + spawn_on((|| async use { drop(format!("hello, {name:?}")) })()); + //~^ redundant_closure_call + } + + fn async_use_closure() { + let name = String::from("world"); + spawn_on((async use || drop(format!("hello, {name}")))()); + //~^ redundant_closure_call + } } fn avoid_double_parens() { diff --git a/tests/ui/redundant_closure_call_fixable.stderr b/tests/ui/redundant_closure_call_fixable.stderr index a5591cf7813b7..d9d2335ef9031 100644 --- a/tests/ui/redundant_closure_call_fixable.stderr +++ b/tests/ui/redundant_closure_call_fixable.stderr @@ -1,5 +1,5 @@ error: try not to call a closure in the expression where it is declared - --> tests/ui/redundant_closure_call_fixable.rs:15:13 + --> tests/ui/redundant_closure_call_fixable.rs:14:13 | LL | let a = (|| 42)(); | ^^^^^^^^^ help: try doing something like: `42` @@ -8,7 +8,7 @@ LL | let a = (|| 42)(); = help: to override `-D warnings` add `#[allow(clippy::redundant_closure_call)]` error: try not to call a closure in the expression where it is declared - --> tests/ui/redundant_closure_call_fixable.rs:17:13 + --> tests/ui/redundant_closure_call_fixable.rs:16:13 | LL | let b = (async || { | _____________^ @@ -30,7 +30,7 @@ LL ~ }; | error: try not to call a closure in the expression where it is declared - --> tests/ui/redundant_closure_call_fixable.rs:23:13 + --> tests/ui/redundant_closure_call_fixable.rs:22:13 | LL | let c = (|| { | _____________^ @@ -52,13 +52,13 @@ LL ~ }; | error: try not to call a closure in the expression where it is declared - --> tests/ui/redundant_closure_call_fixable.rs:29:13 + --> tests/ui/redundant_closure_call_fixable.rs:28:13 | LL | let d = (async || something().await)(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try doing something like: `async { something().await }` error: try not to call a closure in the expression where it is declared - --> tests/ui/redundant_closure_call_fixable.rs:39:13 + --> tests/ui/redundant_closure_call_fixable.rs:38:13 | LL | (|| m!())() | ^^^^^^^^^^^ help: try doing something like: `m!()` @@ -69,7 +69,7 @@ LL | m2!(); = note: this error originates in the macro `m2` (in Nightly builds, run with -Z macro-backtrace for more info) error: try not to call a closure in the expression where it is declared - --> tests/ui/redundant_closure_call_fixable.rs:34:13 + --> tests/ui/redundant_closure_call_fixable.rs:33:13 | LL | (|| 0)() | ^^^^^^^^ help: try doing something like: `0` @@ -80,25 +80,25 @@ LL | m2!(); = note: this error originates in the macro `m` which comes from the expansion of the macro `m2` (in Nightly builds, run with -Z macro-backtrace for more info) error: try not to call a closure in the expression where it is declared - --> tests/ui/redundant_closure_call_fixable.rs:49:16 + --> tests/ui/redundant_closure_call_fixable.rs:48:16 | LL | assert_eq!((|| || 43)()(), 42); | ^^^^^^^^^^^^^^ help: try doing something like: `43` error: try not to call a closure in the expression where it is declared - --> tests/ui/redundant_closure_call_fixable.rs:59:10 + --> tests/ui/redundant_closure_call_fixable.rs:58:10 | LL | dbg!((|| 42)()); | ^^^^^^^^^ help: try doing something like: `42` error: try not to call a closure in the expression where it is declared - --> tests/ui/redundant_closure_call_fixable.rs:63:13 + --> tests/ui/redundant_closure_call_fixable.rs:62:13 | LL | let a = (|| || || 123)(); | ^^^^^^^^^^^^^^^^ help: try doing something like: `|| || 123` error: try not to call a closure in the expression where it is declared - --> tests/ui/redundant_closure_call_fixable.rs:68:13 + --> tests/ui/redundant_closure_call_fixable.rs:67:13 | LL | let a = (|| || || || async || 1)()()()()(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try doing something like: `async { 1 }` @@ -116,58 +116,82 @@ LL | let a = (|| echo!((|| 123)))()(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try doing something like: `123` error: try not to call a closure in the expression where it is declared - --> tests/ui/redundant_closure_call_fixable.rs:95:11 + --> tests/ui/redundant_closure_call_fixable.rs:96:11 | LL | bar()((|| || 42)()(), 5); | ^^^^^^^^^^^^^^ help: try doing something like: `42` error: try not to call a closure in the expression where it is declared - --> tests/ui/redundant_closure_call_fixable.rs:97:9 + --> tests/ui/redundant_closure_call_fixable.rs:98:9 | LL | foo((|| || 42)()(), 5); | ^^^^^^^^^^^^^^ help: try doing something like: `42` error: try not to call a closure in the expression where it is declared - --> tests/ui/redundant_closure_call_fixable.rs:102:5 + --> tests/ui/redundant_closure_call_fixable.rs:103:5 | LL | (|| async {})().await; | ^^^^^^^^^^^^^^^ help: try doing something like: `async {}` error: try not to call a closure in the expression where it is declared - --> tests/ui/redundant_closure_call_fixable.rs:112:18 + --> tests/ui/redundant_closure_call_fixable.rs:113:18 | LL | spawn_on((|| async move {})()); | ^^^^^^^^^^^^^^^^^^^^ help: try doing something like: `async move {}` error: try not to call a closure in the expression where it is declared - --> tests/ui/redundant_closure_call_fixable.rs:118:28 + --> tests/ui/redundant_closure_call_fixable.rs:119:18 + | +LL | spawn_on((|| async move { drop(format!("hello, {name}")) })()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try doing something like: `async move { drop(format!("hello, {name}")) }` + +error: try not to call a closure in the expression where it is declared + --> tests/ui/redundant_closure_call_fixable.rs:125:18 + | +LL | spawn_on((async move || drop(format!("hello, {name}")))()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try doing something like: `async move { drop(format!("hello, {name}")) }` + +error: try not to call a closure in the expression where it is declared + --> tests/ui/redundant_closure_call_fixable.rs:138:18 + | +LL | spawn_on((|| async use { drop(format!("hello, {name:?}")) })()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try doing something like: `async use { drop(format!("hello, {name:?}")) }` + +error: try not to call a closure in the expression where it is declared + --> tests/ui/redundant_closure_call_fixable.rs:144:18 + | +LL | spawn_on((async use || drop(format!("hello, {name}")))()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try doing something like: `async use { drop(format!("hello, {name}")) }` + +error: try not to call a closure in the expression where it is declared + --> tests/ui/redundant_closure_call_fixable.rs:150:28 | LL | std::convert::identity((|| 13_i32 + 36_i32)()).leading_zeros(); | ^^^^^^^^^^^^^^^^^^^^^^ help: try doing something like: `13_i32 + 36_i32` error: try not to call a closure in the expression where it is declared - --> tests/ui/redundant_closure_call_fixable.rs:150:5 + --> tests/ui/redundant_closure_call_fixable.rs:182:5 | LL | (|| { Some(true) })() == Some(true); | ^^^^^^^^^^^^^^^^^^^^^ help: try doing something like: `Some(true)` error: try not to call a closure in the expression where it is declared - --> tests/ui/redundant_closure_call_fixable.rs:152:5 + --> tests/ui/redundant_closure_call_fixable.rs:184:5 | LL | (|| Some(true))() == Some(true); | ^^^^^^^^^^^^^^^^^ help: try doing something like: `Some(true)` error: try not to call a closure in the expression where it is declared - --> tests/ui/redundant_closure_call_fixable.rs:154:5 + --> tests/ui/redundant_closure_call_fixable.rs:186:5 | LL | (|| { Some(if 1 > 2 {1} else {2}) })() == Some(2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try doing something like: `Some(if 1 > 2 {1} else {2})` error: try not to call a closure in the expression where it is declared - --> tests/ui/redundant_closure_call_fixable.rs:156:5 + --> tests/ui/redundant_closure_call_fixable.rs:188:5 | LL | (|| { Some( 1 > 2 ) })() == Some(true); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try doing something like: `Some( 1 > 2 )` -error: aborting due to 21 previous errors +error: aborting due to 25 previous errors diff --git a/tests/ui/redundant_closure_call_late.rs b/tests/ui/redundant_closure_call_late.rs index fd997b1b5fa7b..ceb42dc0ce75d 100644 --- a/tests/ui/redundant_closure_call_late.rs +++ b/tests/ui/redundant_closure_call_late.rs @@ -1,9 +1,8 @@ // non rustfixable, see redundant_closure_call_fixable.rs - -#![warn(clippy::redundant_closure_call)] -#![allow(clippy::needless_late_init)] +#![expect(unused_assignments)] fn main() { + #[expect(unused_variables)] let mut i = 1; // don't lint here, the closure is used more than once @@ -31,6 +30,7 @@ fn main() { i = shadowed_closure(); // Fix FP in #5916 + #[expect(unused_variables)] let mut x; let create = || 2 * 2; x = create(); diff --git a/tests/ui/redundant_closure_call_late.stderr b/tests/ui/redundant_closure_call_late.stderr index ce2a21c23872e..1455ec8c78a5c 100644 --- a/tests/ui/redundant_closure_call_late.stderr +++ b/tests/ui/redundant_closure_call_late.stderr @@ -1,5 +1,5 @@ error: closure called just once immediately after it was declared - --> tests/ui/redundant_closure_call_late.rs:16:5 + --> tests/ui/redundant_closure_call_late.rs:15:5 | LL | i = redun_closure(); | ^^^^^^^^^^^^^^^^^^^ @@ -8,13 +8,13 @@ LL | i = redun_closure(); = help: to override `-D warnings` add `#[allow(clippy::redundant_closure_call)]` error: closure called just once immediately after it was declared - --> tests/ui/redundant_closure_call_late.rs:21:5 + --> tests/ui/redundant_closure_call_late.rs:20:5 | LL | i = shadowed_closure(); | ^^^^^^^^^^^^^^^^^^^^^^ error: closure called just once immediately after it was declared - --> tests/ui/redundant_closure_call_late.rs:25:5 + --> tests/ui/redundant_closure_call_late.rs:24:5 | LL | i = shadowed_closure(); | ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/redundant_pattern_matching_drop_order.stderr b/tests/ui/redundant_pattern_matching_drop_order.stderr index 74462f022f702..7f0171b8424ab 100644 --- a/tests/ui/redundant_pattern_matching_drop_order.stderr +++ b/tests/ui/redundant_pattern_matching_drop_order.stderr @@ -1,172 +1,292 @@ -error: redundant pattern matching, consider using `is_ok()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_drop_order.rs:15:12 | LL | if let Ok(_) = m.lock() {} - | -------^^^^^----------- help: try: `if m.lock().is_ok()` + | ^^^^^ | = note: this will change drop order of the result, as well as all temporaries = note: add `#[allow(clippy::redundant_pattern_matching)]` if this is important = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::redundant_pattern_matching)]` +help: consider using `is_ok()` + | +LL - if let Ok(_) = m.lock() {} +LL + if m.lock().is_ok() {} + | -error: redundant pattern matching, consider using `is_err()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_drop_order.rs:17:12 | LL | if let Err(_) = Err::<(), _>(m.lock().unwrap().0) {} - | -------^^^^^^------------------------------------ help: try: `if Err::<(), _>(m.lock().unwrap().0).is_err()` + | ^^^^^^ | = note: this will change drop order of the result, as well as all temporaries = note: add `#[allow(clippy::redundant_pattern_matching)]` if this is important +help: consider using `is_err()` + | +LL - if let Err(_) = Err::<(), _>(m.lock().unwrap().0) {} +LL + if Err::<(), _>(m.lock().unwrap().0).is_err() {} + | -error: redundant pattern matching, consider using `is_ok()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_drop_order.rs:21:16 | LL | if let Ok(_) = Ok::<_, std::sync::MutexGuard<()>>(()) {} - | -------^^^^^----------------------------------------- help: try: `if Ok::<_, std::sync::MutexGuard<()>>(()).is_ok()` + | ^^^^^ | = note: this will change drop order of the result, as well as all temporaries = note: add `#[allow(clippy::redundant_pattern_matching)]` if this is important +help: consider using `is_ok()` + | +LL - if let Ok(_) = Ok::<_, std::sync::MutexGuard<()>>(()) {} +LL + if Ok::<_, std::sync::MutexGuard<()>>(()).is_ok() {} + | -error: redundant pattern matching, consider using `is_ok()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_drop_order.rs:24:12 | LL | if let Ok(_) = Ok::<_, std::sync::MutexGuard<()>>(()) { - | -------^^^^^----------------------------------------- help: try: `if Ok::<_, std::sync::MutexGuard<()>>(()).is_ok()` + | ^^^^^ | = note: this will change drop order of the result, as well as all temporaries = note: add `#[allow(clippy::redundant_pattern_matching)]` if this is important +help: consider using `is_ok()` + | +LL - if let Ok(_) = Ok::<_, std::sync::MutexGuard<()>>(()) { +LL + if Ok::<_, std::sync::MutexGuard<()>>(()).is_ok() { + | -error: redundant pattern matching, consider using `is_ok()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_drop_order.rs:28:12 | LL | if let Ok(_) = Ok::<_, std::sync::MutexGuard<()>>(()) {} - | -------^^^^^----------------------------------------- help: try: `if Ok::<_, std::sync::MutexGuard<()>>(()).is_ok()` + | ^^^^^ + | +help: consider using `is_ok()` + | +LL - if let Ok(_) = Ok::<_, std::sync::MutexGuard<()>>(()) {} +LL + if Ok::<_, std::sync::MutexGuard<()>>(()).is_ok() {} + | -error: redundant pattern matching, consider using `is_err()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_drop_order.rs:30:12 | LL | if let Err(_) = Err::, _>(()) {} - | -------^^^^^^------------------------------------------ help: try: `if Err::, _>(()).is_err()` + | ^^^^^^ + | +help: consider using `is_err()` + | +LL - if let Err(_) = Err::, _>(()) {} +LL + if Err::, _>(()).is_err() {} + | -error: redundant pattern matching, consider using `is_ok()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_drop_order.rs:33:12 | LL | if let Ok(_) = Ok::<_, ()>(String::new()) {} - | -------^^^^^----------------------------- help: try: `if Ok::<_, ()>(String::new()).is_ok()` + | ^^^^^ + | +help: consider using `is_ok()` + | +LL - if let Ok(_) = Ok::<_, ()>(String::new()) {} +LL + if Ok::<_, ()>(String::new()).is_ok() {} + | -error: redundant pattern matching, consider using `is_err()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_drop_order.rs:35:12 | LL | if let Err(_) = Err::<(), _>((String::new(), ())) {} - | -------^^^^^^------------------------------------ help: try: `if Err::<(), _>((String::new(), ())).is_err()` + | ^^^^^^ + | +help: consider using `is_err()` + | +LL - if let Err(_) = Err::<(), _>((String::new(), ())) {} +LL + if Err::<(), _>((String::new(), ())).is_err() {} + | -error: redundant pattern matching, consider using `is_some()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_drop_order.rs:39:12 | LL | if let Some(_) = Some(m.lock()) {} - | -------^^^^^^^----------------- help: try: `if Some(m.lock()).is_some()` + | ^^^^^^^ | = note: this will change drop order of the result, as well as all temporaries = note: add `#[allow(clippy::redundant_pattern_matching)]` if this is important +help: consider using `is_some()` + | +LL - if let Some(_) = Some(m.lock()) {} +LL + if Some(m.lock()).is_some() {} + | -error: redundant pattern matching, consider using `is_some()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_drop_order.rs:41:12 | LL | if let Some(_) = Some(m.lock().unwrap().0) {} - | -------^^^^^^^---------------------------- help: try: `if Some(m.lock().unwrap().0).is_some()` + | ^^^^^^^ | = note: this will change drop order of the result, as well as all temporaries = note: add `#[allow(clippy::redundant_pattern_matching)]` if this is important +help: consider using `is_some()` + | +LL - if let Some(_) = Some(m.lock().unwrap().0) {} +LL + if Some(m.lock().unwrap().0).is_some() {} + | -error: redundant pattern matching, consider using `is_none()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_drop_order.rs:45:16 | LL | if let None = None::> {} - | -------^^^^------------------------------------ help: try: `if None::>.is_none()` + | ^^^^ | = note: this will change drop order of the result, as well as all temporaries = note: add `#[allow(clippy::redundant_pattern_matching)]` if this is important +help: consider using `is_none()` + | +LL - if let None = None::> {} +LL + if None::>.is_none() {} + | -error: redundant pattern matching, consider using `is_none()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_drop_order.rs:48:12 | LL | if let None = None::> { - | -------^^^^------------------------------------ help: try: `if None::>.is_none()` + | ^^^^ | = note: this will change drop order of the result, as well as all temporaries = note: add `#[allow(clippy::redundant_pattern_matching)]` if this is important +help: consider using `is_none()` + | +LL - if let None = None::> { +LL + if None::>.is_none() { + | -error: redundant pattern matching, consider using `is_none()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_drop_order.rs:53:12 | LL | if let None = None::> {} - | -------^^^^------------------------------------ help: try: `if None::>.is_none()` + | ^^^^ + | +help: consider using `is_none()` + | +LL - if let None = None::> {} +LL + if None::>.is_none() {} + | -error: redundant pattern matching, consider using `is_some()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_drop_order.rs:56:12 | LL | if let Some(_) = Some(String::new()) {} - | -------^^^^^^^---------------------- help: try: `if Some(String::new()).is_some()` + | ^^^^^^^ + | +help: consider using `is_some()` + | +LL - if let Some(_) = Some(String::new()) {} +LL + if Some(String::new()).is_some() {} + | -error: redundant pattern matching, consider using `is_some()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_drop_order.rs:58:12 | LL | if let Some(_) = Some((String::new(), ())) {} - | -------^^^^^^^---------------------------- help: try: `if Some((String::new(), ())).is_some()` + | ^^^^^^^ + | +help: consider using `is_some()` + | +LL - if let Some(_) = Some((String::new(), ())) {} +LL + if Some((String::new(), ())).is_some() {} + | -error: redundant pattern matching, consider using `is_ready()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_drop_order.rs:62:12 | LL | if let Ready(_) = Ready(m.lock()) {} - | -------^^^^^^^^------------------ help: try: `if Ready(m.lock()).is_ready()` + | ^^^^^^^^ | = note: this will change drop order of the result, as well as all temporaries = note: add `#[allow(clippy::redundant_pattern_matching)]` if this is important +help: consider using `is_ready()` + | +LL - if let Ready(_) = Ready(m.lock()) {} +LL + if Ready(m.lock()).is_ready() {} + | -error: redundant pattern matching, consider using `is_ready()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_drop_order.rs:64:12 | LL | if let Ready(_) = Ready(m.lock().unwrap().0) {} - | -------^^^^^^^^----------------------------- help: try: `if Ready(m.lock().unwrap().0).is_ready()` + | ^^^^^^^^ | = note: this will change drop order of the result, as well as all temporaries = note: add `#[allow(clippy::redundant_pattern_matching)]` if this is important +help: consider using `is_ready()` + | +LL - if let Ready(_) = Ready(m.lock().unwrap().0) {} +LL + if Ready(m.lock().unwrap().0).is_ready() {} + | -error: redundant pattern matching, consider using `is_pending()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_drop_order.rs:68:16 | LL | if let Pending = Pending::> {} - | -------^^^^^^^--------------------------------------- help: try: `if Pending::>.is_pending()` + | ^^^^^^^ | = note: this will change drop order of the result, as well as all temporaries = note: add `#[allow(clippy::redundant_pattern_matching)]` if this is important +help: consider using `is_pending()` + | +LL - if let Pending = Pending::> {} +LL + if Pending::>.is_pending() {} + | -error: redundant pattern matching, consider using `is_pending()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_drop_order.rs:71:12 | LL | if let Pending = Pending::> { - | -------^^^^^^^--------------------------------------- help: try: `if Pending::>.is_pending()` + | ^^^^^^^ | = note: this will change drop order of the result, as well as all temporaries = note: add `#[allow(clippy::redundant_pattern_matching)]` if this is important +help: consider using `is_pending()` + | +LL - if let Pending = Pending::> { +LL + if Pending::>.is_pending() { + | -error: redundant pattern matching, consider using `is_pending()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_drop_order.rs:76:12 | LL | if let Pending = Pending::> {} - | -------^^^^^^^--------------------------------------- help: try: `if Pending::>.is_pending()` + | ^^^^^^^ + | +help: consider using `is_pending()` + | +LL - if let Pending = Pending::> {} +LL + if Pending::>.is_pending() {} + | -error: redundant pattern matching, consider using `is_ready()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_drop_order.rs:79:12 | LL | if let Ready(_) = Ready(String::new()) {} - | -------^^^^^^^^----------------------- help: try: `if Ready(String::new()).is_ready()` + | ^^^^^^^^ + | +help: consider using `is_ready()` + | +LL - if let Ready(_) = Ready(String::new()) {} +LL + if Ready(String::new()).is_ready() {} + | -error: redundant pattern matching, consider using `is_ready()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_drop_order.rs:81:12 | LL | if let Ready(_) = Ready((String::new(), ())) {} - | -------^^^^^^^^----------------------------- help: try: `if Ready((String::new(), ())).is_ready()` + | ^^^^^^^^ + | +help: consider using `is_ready()` + | +LL - if let Ready(_) = Ready((String::new(), ())) {} +LL + if Ready((String::new(), ())).is_ready() {} + | error: aborting due to 22 previous errors diff --git a/tests/ui/redundant_pattern_matching_if_let_true.stderr b/tests/ui/redundant_pattern_matching_if_let_true.stderr index db86462706097..1e26fc759d4ea 100644 --- a/tests/ui/redundant_pattern_matching_if_let_true.stderr +++ b/tests/ui/redundant_pattern_matching_if_let_true.stderr @@ -2,46 +2,87 @@ error: using `if let` to pattern match a bool --> tests/ui/redundant_pattern_matching_if_let_true.rs:22:8 | LL | if let true = k > 1 {} - | ^^^^^^^^^^^^^^^^ help: consider using the condition directly: `k > 1` + | ^^^^^^^^^^^^^^^^ | = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::redundant_pattern_matching)]` +help: consider using the condition directly + | +LL - if let true = k > 1 {} +LL + if k > 1 {} + | error: using `if let` to pattern match a bool --> tests/ui/redundant_pattern_matching_if_let_true.rs:24:8 | LL | if let false = k > 5 {} - | ^^^^^^^^^^^^^^^^^ help: consider using the condition directly: `!(k > 5)` + | ^^^^^^^^^^^^^^^^^ + | +help: consider using the condition directly + | +LL - if let false = k > 5 {} +LL + if !(k > 5) {} + | error: using `if let` to pattern match a bool --> tests/ui/redundant_pattern_matching_if_let_true.rs:26:8 | LL | if let (true) = k > 1 {} - | ^^^^^^^^^^^^^^^^^^ help: consider using the condition directly: `k > 1` + | ^^^^^^^^^^^^^^^^^^ + | +help: consider using the condition directly + | +LL - if let (true) = k > 1 {} +LL + if k > 1 {} + | error: using `if let` to pattern match a bool --> tests/ui/redundant_pattern_matching_if_let_true.rs:29:11 | LL | while let true = k > 1 { - | ^^^^^^^^^^^^^^^^ help: consider using the condition directly: `k > 1` + | ^^^^^^^^^^^^^^^^ + | +help: consider using the condition directly + | +LL - while let true = k > 1 { +LL + while k > 1 { + | error: using `if let` to pattern match a bool --> tests/ui/redundant_pattern_matching_if_let_true.rs:33:11 | LL | while let true = condition!() { - | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using the condition directly: `condition!()` + | ^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using the condition directly + | +LL - while let true = condition!() { +LL + while condition!() { + | error: using `matches!` to pattern match a bool --> tests/ui/redundant_pattern_matching_if_let_true.rs:38:5 | LL | matches!(k > 5, true); - | ^^^^^^^^^^^^^^^^^^^^^ help: consider using the condition directly: `k > 5` + | ^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using the condition directly + | +LL - matches!(k > 5, true); +LL + k > 5; + | error: using `matches!` to pattern match a bool --> tests/ui/redundant_pattern_matching_if_let_true.rs:40:5 | LL | matches!(k > 5, false); - | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using the condition directly: `!(k > 5)` + | ^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using the condition directly + | +LL - matches!(k > 5, false); +LL + !(k > 5); + | error: aborting due to 7 previous errors diff --git a/tests/ui/redundant_pattern_matching_ipaddr.stderr b/tests/ui/redundant_pattern_matching_ipaddr.stderr index 3be7cf81afe95..9f65f85fad436 100644 --- a/tests/ui/redundant_pattern_matching_ipaddr.stderr +++ b/tests/ui/redundant_pattern_matching_ipaddr.stderr @@ -1,49 +1,90 @@ -error: redundant pattern matching, consider using `is_ipv4()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_ipaddr.rs:14:12 | LL | if let V4(_) = &ipaddr {} - | -------^^^^^---------- help: try: `if ipaddr.is_ipv4()` + | ^^^^^ | = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::redundant_pattern_matching)]` +help: consider using `is_ipv4()` + | +LL - if let V4(_) = &ipaddr {} +LL + if ipaddr.is_ipv4() {} + | -error: redundant pattern matching, consider using `is_ipv4()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_ipaddr.rs:17:12 | LL | if let V4(_) = V4(Ipv4Addr::LOCALHOST) {} - | -------^^^^^-------------------------- help: try: `if V4(Ipv4Addr::LOCALHOST).is_ipv4()` + | ^^^^^ + | +help: consider using `is_ipv4()` + | +LL - if let V4(_) = V4(Ipv4Addr::LOCALHOST) {} +LL + if V4(Ipv4Addr::LOCALHOST).is_ipv4() {} + | -error: redundant pattern matching, consider using `is_ipv6()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_ipaddr.rs:20:12 | LL | if let V6(_) = V6(Ipv6Addr::LOCALHOST) {} - | -------^^^^^-------------------------- help: try: `if V6(Ipv6Addr::LOCALHOST).is_ipv6()` + | ^^^^^ + | +help: consider using `is_ipv6()` + | +LL - if let V6(_) = V6(Ipv6Addr::LOCALHOST) {} +LL + if V6(Ipv6Addr::LOCALHOST).is_ipv6() {} + | -error: redundant pattern matching, consider using `is_ipv4()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_ipaddr.rs:24:8 | LL | if matches!(V4(Ipv4Addr::LOCALHOST), V4(_)) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `V4(Ipv4Addr::LOCALHOST).is_ipv4()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `is_ipv4()` + | +LL - if matches!(V4(Ipv4Addr::LOCALHOST), V4(_)) {} +LL + if V4(Ipv4Addr::LOCALHOST).is_ipv4() {} + | -error: redundant pattern matching, consider using `is_ipv6()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_ipaddr.rs:28:8 | LL | if matches!(V6(Ipv6Addr::LOCALHOST), V6(_)) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `V6(Ipv6Addr::LOCALHOST).is_ipv6()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `is_ipv6()` + | +LL - if matches!(V6(Ipv6Addr::LOCALHOST), V6(_)) {} +LL + if V6(Ipv6Addr::LOCALHOST).is_ipv6() {} + | -error: redundant pattern matching, consider using `is_ipv4()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_ipaddr.rs:31:15 | LL | while let V4(_) = V4(Ipv4Addr::LOCALHOST) {} - | ----------^^^^^-------------------------- help: try: `while V4(Ipv4Addr::LOCALHOST).is_ipv4()` + | ^^^^^ + | +help: consider using `is_ipv4()` + | +LL - while let V4(_) = V4(Ipv4Addr::LOCALHOST) {} +LL + while V4(Ipv4Addr::LOCALHOST).is_ipv4() {} + | -error: redundant pattern matching, consider using `is_ipv6()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_ipaddr.rs:34:15 | LL | while let V6(_) = V6(Ipv6Addr::LOCALHOST) {} - | ----------^^^^^-------------------------- help: try: `while V6(Ipv6Addr::LOCALHOST).is_ipv6()` + | ^^^^^ + | +help: consider using `is_ipv6()` + | +LL - while let V6(_) = V6(Ipv6Addr::LOCALHOST) {} +LL + while V6(Ipv6Addr::LOCALHOST).is_ipv6() {} + | -error: redundant pattern matching, consider using `is_ipv4()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_ipaddr.rs:45:5 | LL | / match V4(Ipv4Addr::LOCALHOST) { @@ -51,9 +92,19 @@ LL | | LL | | V4(_) => true, LL | | V6(_) => false, LL | | }; - | |_____^ help: try: `V4(Ipv4Addr::LOCALHOST).is_ipv4()` + | |_____^ + | +help: consider using `is_ipv4()` + | +LL - match V4(Ipv4Addr::LOCALHOST) { +LL - +LL - V4(_) => true, +LL - V6(_) => false, +LL - }; +LL + V4(Ipv4Addr::LOCALHOST).is_ipv4(); + | -error: redundant pattern matching, consider using `is_ipv6()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_ipaddr.rs:51:5 | LL | / match V4(Ipv4Addr::LOCALHOST) { @@ -61,9 +112,19 @@ LL | | LL | | V4(_) => false, LL | | V6(_) => true, LL | | }; - | |_____^ help: try: `V4(Ipv4Addr::LOCALHOST).is_ipv6()` + | |_____^ + | +help: consider using `is_ipv6()` + | +LL - match V4(Ipv4Addr::LOCALHOST) { +LL - +LL - V4(_) => false, +LL - V6(_) => true, +LL - }; +LL + V4(Ipv4Addr::LOCALHOST).is_ipv6(); + | -error: redundant pattern matching, consider using `is_ipv6()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_ipaddr.rs:57:5 | LL | / match V6(Ipv6Addr::LOCALHOST) { @@ -71,9 +132,19 @@ LL | | LL | | V4(_) => false, LL | | V6(_) => true, LL | | }; - | |_____^ help: try: `V6(Ipv6Addr::LOCALHOST).is_ipv6()` + | |_____^ + | +help: consider using `is_ipv6()` + | +LL - match V6(Ipv6Addr::LOCALHOST) { +LL - +LL - V4(_) => false, +LL - V6(_) => true, +LL - }; +LL + V6(Ipv6Addr::LOCALHOST).is_ipv6(); + | -error: redundant pattern matching, consider using `is_ipv4()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_ipaddr.rs:63:5 | LL | / match V6(Ipv6Addr::LOCALHOST) { @@ -81,51 +152,103 @@ LL | | LL | | V4(_) => true, LL | | V6(_) => false, LL | | }; - | |_____^ help: try: `V6(Ipv6Addr::LOCALHOST).is_ipv4()` + | |_____^ + | +help: consider using `is_ipv4()` + | +LL - match V6(Ipv6Addr::LOCALHOST) { +LL - +LL - V4(_) => true, +LL - V6(_) => false, +LL - }; +LL + V6(Ipv6Addr::LOCALHOST).is_ipv4(); + | -error: redundant pattern matching, consider using `is_ipv4()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_ipaddr.rs:69:20 | LL | let _ = if let V4(_) = V4(Ipv4Addr::LOCALHOST) { - | -------^^^^^-------------------------- help: try: `if V4(Ipv4Addr::LOCALHOST).is_ipv4()` + | ^^^^^ + | +help: consider using `is_ipv4()` + | +LL - let _ = if let V4(_) = V4(Ipv4Addr::LOCALHOST) { +LL + let _ = if V4(Ipv4Addr::LOCALHOST).is_ipv4() { + | -error: redundant pattern matching, consider using `is_ipv4()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_ipaddr.rs:78:20 | LL | let _ = if let V4(_) = gen_ipaddr() { - | -------^^^^^--------------- help: try: `if gen_ipaddr().is_ipv4()` + | ^^^^^ + | +help: consider using `is_ipv4()` + | +LL - let _ = if let V4(_) = gen_ipaddr() { +LL + let _ = if gen_ipaddr().is_ipv4() { + | -error: redundant pattern matching, consider using `is_ipv6()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_ipaddr.rs:81:19 | LL | } else if let V6(_) = gen_ipaddr() { - | -------^^^^^--------------- help: try: `if gen_ipaddr().is_ipv6()` + | ^^^^^ + | +help: consider using `is_ipv6()` + | +LL - } else if let V6(_) = gen_ipaddr() { +LL + } else if gen_ipaddr().is_ipv6() { + | -error: redundant pattern matching, consider using `is_ipv4()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_ipaddr.rs:94:12 | LL | if let V4(_) = V4(Ipv4Addr::LOCALHOST) {} - | -------^^^^^-------------------------- help: try: `if V4(Ipv4Addr::LOCALHOST).is_ipv4()` + | ^^^^^ + | +help: consider using `is_ipv4()` + | +LL - if let V4(_) = V4(Ipv4Addr::LOCALHOST) {} +LL + if V4(Ipv4Addr::LOCALHOST).is_ipv4() {} + | -error: redundant pattern matching, consider using `is_ipv6()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_ipaddr.rs:97:12 | LL | if let V6(_) = V6(Ipv6Addr::LOCALHOST) {} - | -------^^^^^-------------------------- help: try: `if V6(Ipv6Addr::LOCALHOST).is_ipv6()` + | ^^^^^ + | +help: consider using `is_ipv6()` + | +LL - if let V6(_) = V6(Ipv6Addr::LOCALHOST) {} +LL + if V6(Ipv6Addr::LOCALHOST).is_ipv6() {} + | -error: redundant pattern matching, consider using `is_ipv4()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_ipaddr.rs:100:15 | LL | while let V4(_) = V4(Ipv4Addr::LOCALHOST) {} - | ----------^^^^^-------------------------- help: try: `while V4(Ipv4Addr::LOCALHOST).is_ipv4()` + | ^^^^^ + | +help: consider using `is_ipv4()` + | +LL - while let V4(_) = V4(Ipv4Addr::LOCALHOST) {} +LL + while V4(Ipv4Addr::LOCALHOST).is_ipv4() {} + | -error: redundant pattern matching, consider using `is_ipv6()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_ipaddr.rs:103:15 | LL | while let V6(_) = V6(Ipv6Addr::LOCALHOST) {} - | ----------^^^^^-------------------------- help: try: `while V6(Ipv6Addr::LOCALHOST).is_ipv6()` + | ^^^^^ + | +help: consider using `is_ipv6()` + | +LL - while let V6(_) = V6(Ipv6Addr::LOCALHOST) {} +LL + while V6(Ipv6Addr::LOCALHOST).is_ipv6() {} + | -error: redundant pattern matching, consider using `is_ipv4()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_ipaddr.rs:106:5 | LL | / match V4(Ipv4Addr::LOCALHOST) { @@ -133,9 +256,19 @@ LL | | LL | | V4(_) => true, LL | | V6(_) => false, LL | | }; - | |_____^ help: try: `V4(Ipv4Addr::LOCALHOST).is_ipv4()` + | |_____^ + | +help: consider using `is_ipv4()` + | +LL - match V4(Ipv4Addr::LOCALHOST) { +LL - +LL - V4(_) => true, +LL - V6(_) => false, +LL - }; +LL + V4(Ipv4Addr::LOCALHOST).is_ipv4(); + | -error: redundant pattern matching, consider using `is_ipv6()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_ipaddr.rs:112:5 | LL | / match V6(Ipv6Addr::LOCALHOST) { @@ -143,7 +276,17 @@ LL | | LL | | V4(_) => false, LL | | V6(_) => true, LL | | }; - | |_____^ help: try: `V6(Ipv6Addr::LOCALHOST).is_ipv6()` + | |_____^ + | +help: consider using `is_ipv6()` + | +LL - match V6(Ipv6Addr::LOCALHOST) { +LL - +LL - V4(_) => false, +LL - V6(_) => true, +LL - }; +LL + V6(Ipv6Addr::LOCALHOST).is_ipv6(); + | error: aborting due to 20 previous errors diff --git a/tests/ui/redundant_pattern_matching_option.stderr b/tests/ui/redundant_pattern_matching_option.stderr index 62ead95235aba..8f02838feb355 100644 --- a/tests/ui/redundant_pattern_matching_option.stderr +++ b/tests/ui/redundant_pattern_matching_option.stderr @@ -1,61 +1,114 @@ -error: redundant pattern matching, consider using `is_none()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_option.rs:11:5 | LL | matches!(maybe_some, None if !boolean) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `maybe_some.is_none() && (!boolean)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::redundant_pattern_matching)]` +help: consider using `is_none()` + | +LL - matches!(maybe_some, None if !boolean) +LL + maybe_some.is_none() && (!boolean) + | -error: redundant pattern matching, consider using `is_none()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_option.rs:16:13 | LL | let _ = matches!(maybe_some, None if boolean || boolean2); // guard needs parentheses - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `maybe_some.is_none() && (boolean || boolean2)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `is_none()` + | +LL - let _ = matches!(maybe_some, None if boolean || boolean2); // guard needs parentheses +LL + let _ = maybe_some.is_none() && (boolean || boolean2); // guard needs parentheses + | -error: redundant pattern matching, consider using `is_none()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_option.rs:32:12 | LL | if let None = None::<()> {} - | -------^^^^------------- help: try: `if None::<()>.is_none()` + | ^^^^ + | +help: consider using `is_none()` + | +LL - if let None = None::<()> {} +LL + if None::<()>.is_none() {} + | -error: redundant pattern matching, consider using `is_some()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_option.rs:35:12 | LL | if let Some(_) = Some(42) {} - | -------^^^^^^^----------- help: try: `if Some(42).is_some()` + | ^^^^^^^ + | +help: consider using `is_some()` + | +LL - if let Some(_) = Some(42) {} +LL + if Some(42).is_some() {} + | -error: redundant pattern matching, consider using `is_some()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_option.rs:38:12 | LL | if let Some(_) = Some(42) { - | -------^^^^^^^----------- help: try: `if Some(42).is_some()` + | ^^^^^^^ + | +help: consider using `is_some()` + | +LL - if let Some(_) = Some(42) { +LL + if Some(42).is_some() { + | -error: redundant pattern matching, consider using `is_some()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_option.rs:45:15 | LL | while let Some(_) = Some(42) {} - | ----------^^^^^^^----------- help: try: `while Some(42).is_some()` + | ^^^^^^^ + | +help: consider using `is_some()` + | +LL - while let Some(_) = Some(42) {} +LL + while Some(42).is_some() {} + | -error: redundant pattern matching, consider using `is_none()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_option.rs:48:15 | LL | while let None = Some(42) {} - | ----------^^^^----------- help: try: `while Some(42).is_none()` + | ^^^^ + | +help: consider using `is_none()` + | +LL - while let None = Some(42) {} +LL + while Some(42).is_none() {} + | -error: redundant pattern matching, consider using `is_none()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_option.rs:51:15 | LL | while let None = None::<()> {} - | ----------^^^^------------- help: try: `while None::<()>.is_none()` + | ^^^^ + | +help: consider using `is_none()` + | +LL - while let None = None::<()> {} +LL + while None::<()>.is_none() {} + | -error: redundant pattern matching, consider using `is_some()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_option.rs:55:15 | LL | while let Some(_) = v.pop() { - | ----------^^^^^^^---------- help: try: `while v.pop().is_some()` + | ^^^^^^^ + | +help: consider using `is_some()` + | +LL - while let Some(_) = v.pop() { +LL + while v.pop().is_some() { + | -error: redundant pattern matching, consider using `is_some()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_option.rs:64:5 | LL | / match Some(42) { @@ -63,9 +116,19 @@ LL | | LL | | Some(_) => true, LL | | None => false, LL | | }; - | |_____^ help: try: `Some(42).is_some()` + | |_____^ + | +help: consider using `is_some()` + | +LL - match Some(42) { +LL - +LL - Some(_) => true, +LL - None => false, +LL - }; +LL + Some(42).is_some(); + | -error: redundant pattern matching, consider using `is_none()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_option.rs:70:5 | LL | / match None::<()> { @@ -73,9 +136,19 @@ LL | | LL | | Some(_) => false, LL | | None => true, LL | | }; - | |_____^ help: try: `None::<()>.is_none()` + | |_____^ + | +help: consider using `is_none()` + | +LL - match None::<()> { +LL - +LL - Some(_) => false, +LL - None => true, +LL - }; +LL + None::<()>.is_none(); + | -error: redundant pattern matching, consider using `is_none()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_option.rs:76:13 | LL | let _ = match None::<()> { @@ -84,57 +157,115 @@ LL | | LL | | Some(_) => false, LL | | None => true, LL | | }; - | |_____^ help: try: `None::<()>.is_none()` + | |_____^ + | +help: consider using `is_none()` + | +LL - let _ = match None::<()> { +LL - +LL - Some(_) => false, +LL - None => true, +LL - }; +LL + let _ = None::<()>.is_none(); + | -error: redundant pattern matching, consider using `is_some()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_option.rs:83:20 | LL | let _ = if let Some(_) = opt { true } else { false }; - | -------^^^^^^^------ help: try: `if opt.is_some()` + | ^^^^^^^ + | +help: consider using `is_some()` + | +LL - let _ = if let Some(_) = opt { true } else { false }; +LL + let _ = if opt.is_some() { true } else { false }; + | -error: redundant pattern matching, consider using `is_some()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_option.rs:90:20 | LL | let _ = if let Some(_) = gen_opt() { - | -------^^^^^^^------------ help: try: `if gen_opt().is_some()` + | ^^^^^^^ + | +help: consider using `is_some()` + | +LL - let _ = if let Some(_) = gen_opt() { +LL + let _ = if gen_opt().is_some() { + | -error: redundant pattern matching, consider using `is_none()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_option.rs:93:19 | LL | } else if let None = gen_opt() { - | -------^^^^------------ help: try: `if gen_opt().is_none()` + | ^^^^ + | +help: consider using `is_none()` + | +LL - } else if let None = gen_opt() { +LL + } else if gen_opt().is_none() { + | -error: redundant pattern matching, consider using `is_some()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_option.rs:100:12 | LL | if let Some(..) = gen_opt() {} - | -------^^^^^^^^------------ help: try: `if gen_opt().is_some()` + | ^^^^^^^^ + | +help: consider using `is_some()` + | +LL - if let Some(..) = gen_opt() {} +LL + if gen_opt().is_some() {} + | -error: redundant pattern matching, consider using `is_some()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_option.rs:116:12 | LL | if let Some(_) = Some(42) {} - | -------^^^^^^^----------- help: try: `if Some(42).is_some()` + | ^^^^^^^ + | +help: consider using `is_some()` + | +LL - if let Some(_) = Some(42) {} +LL + if Some(42).is_some() {} + | -error: redundant pattern matching, consider using `is_none()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_option.rs:119:12 | LL | if let None = None::<()> {} - | -------^^^^------------- help: try: `if None::<()>.is_none()` + | ^^^^ + | +help: consider using `is_none()` + | +LL - if let None = None::<()> {} +LL + if None::<()>.is_none() {} + | -error: redundant pattern matching, consider using `is_some()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_option.rs:122:15 | LL | while let Some(_) = Some(42) {} - | ----------^^^^^^^----------- help: try: `while Some(42).is_some()` + | ^^^^^^^ + | +help: consider using `is_some()` + | +LL - while let Some(_) = Some(42) {} +LL + while Some(42).is_some() {} + | -error: redundant pattern matching, consider using `is_none()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_option.rs:125:15 | LL | while let None = None::<()> {} - | ----------^^^^------------- help: try: `while None::<()>.is_none()` + | ^^^^ + | +help: consider using `is_none()` + | +LL - while let None = None::<()> {} +LL + while None::<()>.is_none() {} + | -error: redundant pattern matching, consider using `is_some()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_option.rs:128:5 | LL | / match Some(42) { @@ -142,9 +273,19 @@ LL | | LL | | Some(_) => true, LL | | None => false, LL | | }; - | |_____^ help: try: `Some(42).is_some()` + | |_____^ + | +help: consider using `is_some()` + | +LL - match Some(42) { +LL - +LL - Some(_) => true, +LL - None => false, +LL - }; +LL + Some(42).is_some(); + | -error: redundant pattern matching, consider using `is_none()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_option.rs:134:5 | LL | / match None::<()> { @@ -152,21 +293,43 @@ LL | | LL | | Some(_) => false, LL | | None => true, LL | | }; - | |_____^ help: try: `None::<()>.is_none()` + | |_____^ + | +help: consider using `is_none()` + | +LL - match None::<()> { +LL - +LL - Some(_) => false, +LL - None => true, +LL - }; +LL + None::<()>.is_none(); + | -error: redundant pattern matching, consider using `is_none()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_option.rs:143:12 | LL | if let None = *(&None::<()>) {} - | -------^^^^----------------- help: try: `if (&None::<()>).is_none()` + | ^^^^ + | +help: consider using `is_none()` + | +LL - if let None = *(&None::<()>) {} +LL + if (&None::<()>).is_none() {} + | -error: redundant pattern matching, consider using `is_none()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_option.rs:145:12 | LL | if let None = *&None::<()> {} - | -------^^^^--------------- help: try: `if (&None::<()>).is_none()` + | ^^^^ + | +help: consider using `is_none()` + | +LL - if let None = *&None::<()> {} +LL + if (&None::<()>).is_none() {} + | -error: redundant pattern matching, consider using `is_some()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_option.rs:152:5 | LL | / match x { @@ -174,9 +337,19 @@ LL | | LL | | Some(_) => true, LL | | _ => false, LL | | }; - | |_____^ help: try: `x.is_some()` + | |_____^ + | +help: consider using `is_some()` + | +LL - match x { +LL - +LL - Some(_) => true, +LL - _ => false, +LL - }; +LL + x.is_some(); + | -error: redundant pattern matching, consider using `is_none()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_option.rs:158:5 | LL | / match x { @@ -184,9 +357,19 @@ LL | | LL | | None => true, LL | | _ => false, LL | | }; - | |_____^ help: try: `x.is_none()` + | |_____^ + | +help: consider using `is_none()` + | +LL - match x { +LL - +LL - None => true, +LL - _ => false, +LL - }; +LL + x.is_none(); + | -error: redundant pattern matching, consider using `is_none()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_option.rs:164:5 | LL | / match x { @@ -194,9 +377,19 @@ LL | | LL | | Some(_) => false, LL | | _ => true, LL | | }; - | |_____^ help: try: `x.is_none()` + | |_____^ + | +help: consider using `is_none()` + | +LL - match x { +LL - +LL - Some(_) => false, +LL - _ => true, +LL - }; +LL + x.is_none(); + | -error: redundant pattern matching, consider using `is_some()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_option.rs:170:5 | LL | / match x { @@ -204,49 +397,101 @@ LL | | LL | | None => false, LL | | _ => true, LL | | }; - | |_____^ help: try: `x.is_some()` + | |_____^ + | +help: consider using `is_some()` + | +LL - match x { +LL - +LL - None => false, +LL - _ => true, +LL - }; +LL + x.is_some(); + | -error: redundant pattern matching, consider using `is_some()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_option.rs:186:13 | LL | let _ = matches!(x, Some(_)); - | ^^^^^^^^^^^^^^^^^^^^ help: try: `x.is_some()` + | ^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `is_some()` + | +LL - let _ = matches!(x, Some(_)); +LL + let _ = x.is_some(); + | -error: redundant pattern matching, consider using `is_none()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_option.rs:189:13 | LL | let _ = matches!(x, None); - | ^^^^^^^^^^^^^^^^^ help: try: `x.is_none()` + | ^^^^^^^^^^^^^^^^^ + | +help: consider using `is_none()` + | +LL - let _ = matches!(x, None); +LL + let _ = x.is_none(); + | -error: redundant pattern matching, consider using `is_none()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_option.rs:200:17 | LL | let _ = matches!(*p, None); - | ^^^^^^^^^^^^^^^^^^ help: try: `(*p).is_none()` + | ^^^^^^^^^^^^^^^^^^ + | +help: consider using `is_none()` + | +LL - let _ = matches!(*p, None); +LL + let _ = (*p).is_none(); + | -error: redundant pattern matching, consider using `is_some()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_option.rs:208:16 | LL | if let Some(_) = x? { - | -------^^^^^^^----- help: try: `if x?.is_some()` + | ^^^^^^^ + | +help: consider using `is_some()` + | +LL - if let Some(_) = x? { +LL + if x?.is_some() { + | -error: redundant pattern matching, consider using `is_some()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_option.rs:228:16 | LL | if let Some(_) = x.await { - | -------^^^^^^^---------- help: try: `if x.await.is_some()` + | ^^^^^^^ + | +help: consider using `is_some()` + | +LL - if let Some(_) = x.await { +LL + if x.await.is_some() { + | -error: redundant pattern matching, consider using `is_some()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_option.rs:241:12 | LL | if let Some(_) = (x! {}) {}; - | -------^^^^^^^---------- help: try: `if x! {}.is_some()` + | ^^^^^^^ + | +help: consider using `is_some()` + | +LL - if let Some(_) = (x! {}) {}; +LL + if x! {}.is_some() {}; + | -error: redundant pattern matching, consider using `is_some()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_option.rs:243:15 | LL | while let Some(_) = (x! {}) {} - | ----------^^^^^^^---------- help: try: `while x! {}.is_some()` + | ^^^^^^^ + | +help: consider using `is_some()` + | +LL - while let Some(_) = (x! {}) {} +LL + while x! {}.is_some() {} + | error: aborting due to 35 previous errors diff --git a/tests/ui/redundant_pattern_matching_poll.stderr b/tests/ui/redundant_pattern_matching_poll.stderr index 5cd9d9636e466..5b94965c06daa 100644 --- a/tests/ui/redundant_pattern_matching_poll.stderr +++ b/tests/ui/redundant_pattern_matching_poll.stderr @@ -1,55 +1,102 @@ -error: redundant pattern matching, consider using `is_pending()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_poll.rs:13:12 | LL | if let Pending = Pending::<()> {} - | -------^^^^^^^---------------- help: try: `if Pending::<()>.is_pending()` + | ^^^^^^^ | = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::redundant_pattern_matching)]` +help: consider using `is_pending()` + | +LL - if let Pending = Pending::<()> {} +LL + if Pending::<()>.is_pending() {} + | -error: redundant pattern matching, consider using `is_ready()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_poll.rs:16:12 | LL | if let Ready(_) = Ready(42) {} - | -------^^^^^^^^------------ help: try: `if Ready(42).is_ready()` + | ^^^^^^^^ + | +help: consider using `is_ready()` + | +LL - if let Ready(_) = Ready(42) {} +LL + if Ready(42).is_ready() {} + | -error: redundant pattern matching, consider using `is_ready()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_poll.rs:19:12 | LL | if let Ready(_) = Ready(42) { - | -------^^^^^^^^------------ help: try: `if Ready(42).is_ready()` + | ^^^^^^^^ + | +help: consider using `is_ready()` + | +LL - if let Ready(_) = Ready(42) { +LL + if Ready(42).is_ready() { + | -error: redundant pattern matching, consider using `is_ready()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_poll.rs:27:8 | LL | if matches!(Ready(42), Ready(_)) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Ready(42).is_ready()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `is_ready()` + | +LL - if matches!(Ready(42), Ready(_)) {} +LL + if Ready(42).is_ready() {} + | -error: redundant pattern matching, consider using `is_pending()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_poll.rs:31:8 | LL | if matches!(Pending::<()>, Pending) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Pending::<()>.is_pending()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `is_pending()` + | +LL - if matches!(Pending::<()>, Pending) {} +LL + if Pending::<()>.is_pending() {} + | -error: redundant pattern matching, consider using `is_ready()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_poll.rs:34:15 | LL | while let Ready(_) = Ready(42) {} - | ----------^^^^^^^^------------ help: try: `while Ready(42).is_ready()` + | ^^^^^^^^ + | +help: consider using `is_ready()` + | +LL - while let Ready(_) = Ready(42) {} +LL + while Ready(42).is_ready() {} + | -error: redundant pattern matching, consider using `is_pending()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_poll.rs:37:15 | LL | while let Pending = Ready(42) {} - | ----------^^^^^^^------------ help: try: `while Ready(42).is_pending()` + | ^^^^^^^ + | +help: consider using `is_pending()` + | +LL - while let Pending = Ready(42) {} +LL + while Ready(42).is_pending() {} + | -error: redundant pattern matching, consider using `is_pending()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_poll.rs:40:15 | LL | while let Pending = Pending::<()> {} - | ----------^^^^^^^---------------- help: try: `while Pending::<()>.is_pending()` + | ^^^^^^^ + | +help: consider using `is_pending()` + | +LL - while let Pending = Pending::<()> {} +LL + while Pending::<()>.is_pending() {} + | -error: redundant pattern matching, consider using `is_ready()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_poll.rs:47:5 | LL | / match Ready(42) { @@ -57,9 +104,19 @@ LL | | LL | | Ready(_) => true, LL | | Pending => false, LL | | }; - | |_____^ help: try: `Ready(42).is_ready()` + | |_____^ + | +help: consider using `is_ready()` + | +LL - match Ready(42) { +LL - +LL - Ready(_) => true, +LL - Pending => false, +LL - }; +LL + Ready(42).is_ready(); + | -error: redundant pattern matching, consider using `is_pending()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_poll.rs:53:5 | LL | / match Pending::<()> { @@ -67,9 +124,19 @@ LL | | LL | | Ready(_) => false, LL | | Pending => true, LL | | }; - | |_____^ help: try: `Pending::<()>.is_pending()` + | |_____^ + | +help: consider using `is_pending()` + | +LL - match Pending::<()> { +LL - +LL - Ready(_) => false, +LL - Pending => true, +LL - }; +LL + Pending::<()>.is_pending(); + | -error: redundant pattern matching, consider using `is_pending()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_poll.rs:59:13 | LL | let _ = match Pending::<()> { @@ -78,51 +145,103 @@ LL | | LL | | Ready(_) => false, LL | | Pending => true, LL | | }; - | |_____^ help: try: `Pending::<()>.is_pending()` + | |_____^ + | +help: consider using `is_pending()` + | +LL - let _ = match Pending::<()> { +LL - +LL - Ready(_) => false, +LL - Pending => true, +LL - }; +LL + let _ = Pending::<()>.is_pending(); + | -error: redundant pattern matching, consider using `is_ready()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_poll.rs:66:20 | LL | let _ = if let Ready(_) = poll { true } else { false }; - | -------^^^^^^^^------- help: try: `if poll.is_ready()` + | ^^^^^^^^ + | +help: consider using `is_ready()` + | +LL - let _ = if let Ready(_) = poll { true } else { false }; +LL + let _ = if poll.is_ready() { true } else { false }; + | -error: redundant pattern matching, consider using `is_ready()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_poll.rs:71:20 | LL | let _ = if let Ready(_) = gen_poll() { - | -------^^^^^^^^------------- help: try: `if gen_poll().is_ready()` + | ^^^^^^^^ + | +help: consider using `is_ready()` + | +LL - let _ = if let Ready(_) = gen_poll() { +LL + let _ = if gen_poll().is_ready() { + | -error: redundant pattern matching, consider using `is_pending()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_poll.rs:74:19 | LL | } else if let Pending = gen_poll() { - | -------^^^^^^^------------- help: try: `if gen_poll().is_pending()` + | ^^^^^^^ + | +help: consider using `is_pending()` + | +LL - } else if let Pending = gen_poll() { +LL + } else if gen_poll().is_pending() { + | -error: redundant pattern matching, consider using `is_ready()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_poll.rs:91:12 | LL | if let Ready(_) = Ready(42) {} - | -------^^^^^^^^------------ help: try: `if Ready(42).is_ready()` + | ^^^^^^^^ + | +help: consider using `is_ready()` + | +LL - if let Ready(_) = Ready(42) {} +LL + if Ready(42).is_ready() {} + | -error: redundant pattern matching, consider using `is_pending()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_poll.rs:94:12 | LL | if let Pending = Pending::<()> {} - | -------^^^^^^^---------------- help: try: `if Pending::<()>.is_pending()` + | ^^^^^^^ + | +help: consider using `is_pending()` + | +LL - if let Pending = Pending::<()> {} +LL + if Pending::<()>.is_pending() {} + | -error: redundant pattern matching, consider using `is_ready()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_poll.rs:97:15 | LL | while let Ready(_) = Ready(42) {} - | ----------^^^^^^^^------------ help: try: `while Ready(42).is_ready()` + | ^^^^^^^^ + | +help: consider using `is_ready()` + | +LL - while let Ready(_) = Ready(42) {} +LL + while Ready(42).is_ready() {} + | -error: redundant pattern matching, consider using `is_pending()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_poll.rs:100:15 | LL | while let Pending = Pending::<()> {} - | ----------^^^^^^^---------------- help: try: `while Pending::<()>.is_pending()` + | ^^^^^^^ + | +help: consider using `is_pending()` + | +LL - while let Pending = Pending::<()> {} +LL + while Pending::<()>.is_pending() {} + | -error: redundant pattern matching, consider using `is_ready()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_poll.rs:103:5 | LL | / match Ready(42) { @@ -130,9 +249,19 @@ LL | | LL | | Ready(_) => true, LL | | Pending => false, LL | | }; - | |_____^ help: try: `Ready(42).is_ready()` + | |_____^ + | +help: consider using `is_ready()` + | +LL - match Ready(42) { +LL - +LL - Ready(_) => true, +LL - Pending => false, +LL - }; +LL + Ready(42).is_ready(); + | -error: redundant pattern matching, consider using `is_pending()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_poll.rs:109:5 | LL | / match Pending::<()> { @@ -140,7 +269,17 @@ LL | | LL | | Ready(_) => false, LL | | Pending => true, LL | | }; - | |_____^ help: try: `Pending::<()>.is_pending()` + | |_____^ + | +help: consider using `is_pending()` + | +LL - match Pending::<()> { +LL - +LL - Ready(_) => false, +LL - Pending => true, +LL - }; +LL + Pending::<()>.is_pending(); + | error: aborting due to 20 previous errors diff --git a/tests/ui/redundant_pattern_matching_result.stderr b/tests/ui/redundant_pattern_matching_result.stderr index dda203b753c3e..ef44731a59a40 100644 --- a/tests/ui/redundant_pattern_matching_result.stderr +++ b/tests/ui/redundant_pattern_matching_result.stderr @@ -1,37 +1,66 @@ -error: redundant pattern matching, consider using `is_ok()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_result.rs:14:12 | LL | if let Ok(_) = &result {} - | -------^^^^^---------- help: try: `if result.is_ok()` + | ^^^^^ | = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::redundant_pattern_matching)]` +help: consider using `is_ok()` + | +LL - if let Ok(_) = &result {} +LL + if result.is_ok() {} + | -error: redundant pattern matching, consider using `is_ok()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_result.rs:17:12 | LL | if let Ok(_) = Ok::(42) {} - | -------^^^^^--------------------- help: try: `if Ok::(42).is_ok()` + | ^^^^^ + | +help: consider using `is_ok()` + | +LL - if let Ok(_) = Ok::(42) {} +LL + if Ok::(42).is_ok() {} + | -error: redundant pattern matching, consider using `is_err()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_result.rs:20:12 | LL | if let Err(_) = Err::(42) {} - | -------^^^^^^---------------------- help: try: `if Err::(42).is_err()` + | ^^^^^^ + | +help: consider using `is_err()` + | +LL - if let Err(_) = Err::(42) {} +LL + if Err::(42).is_err() {} + | -error: redundant pattern matching, consider using `is_ok()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_result.rs:23:15 | LL | while let Ok(_) = Ok::(10) {} - | ----------^^^^^--------------------- help: try: `while Ok::(10).is_ok()` + | ^^^^^ + | +help: consider using `is_ok()` + | +LL - while let Ok(_) = Ok::(10) {} +LL + while Ok::(10).is_ok() {} + | -error: redundant pattern matching, consider using `is_err()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_result.rs:26:15 | LL | while let Err(_) = Ok::(10) {} - | ----------^^^^^^--------------------- help: try: `while Ok::(10).is_err()` + | ^^^^^^ + | +help: consider using `is_err()` + | +LL - while let Err(_) = Ok::(10) {} +LL + while Ok::(10).is_err() {} + | -error: redundant pattern matching, consider using `is_ok()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_result.rs:37:5 | LL | / match Ok::(42) { @@ -39,9 +68,19 @@ LL | | LL | | Ok(_) => true, LL | | Err(_) => false, LL | | }; - | |_____^ help: try: `Ok::(42).is_ok()` + | |_____^ + | +help: consider using `is_ok()` + | +LL - match Ok::(42) { +LL - +LL - Ok(_) => true, +LL - Err(_) => false, +LL - }; +LL + Ok::(42).is_ok(); + | -error: redundant pattern matching, consider using `is_err()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_result.rs:43:5 | LL | / match Ok::(42) { @@ -49,9 +88,19 @@ LL | | LL | | Ok(_) => false, LL | | Err(_) => true, LL | | }; - | |_____^ help: try: `Ok::(42).is_err()` + | |_____^ + | +help: consider using `is_err()` + | +LL - match Ok::(42) { +LL - +LL - Ok(_) => false, +LL - Err(_) => true, +LL - }; +LL + Ok::(42).is_err(); + | -error: redundant pattern matching, consider using `is_err()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_result.rs:49:5 | LL | / match Err::(42) { @@ -59,9 +108,19 @@ LL | | LL | | Ok(_) => false, LL | | Err(_) => true, LL | | }; - | |_____^ help: try: `Err::(42).is_err()` + | |_____^ + | +help: consider using `is_err()` + | +LL - match Err::(42) { +LL - +LL - Ok(_) => false, +LL - Err(_) => true, +LL - }; +LL + Err::(42).is_err(); + | -error: redundant pattern matching, consider using `is_ok()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_result.rs:55:5 | LL | / match Err::(42) { @@ -69,75 +128,151 @@ LL | | LL | | Ok(_) => true, LL | | Err(_) => false, LL | | }; - | |_____^ help: try: `Err::(42).is_ok()` + | |_____^ + | +help: consider using `is_ok()` + | +LL - match Err::(42) { +LL - +LL - Ok(_) => true, +LL - Err(_) => false, +LL - }; +LL + Err::(42).is_ok(); + | -error: redundant pattern matching, consider using `is_ok()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_result.rs:61:20 | LL | let _ = if let Ok(_) = Ok::(4) { true } else { false }; - | -------^^^^^--------------------- help: try: `if Ok::(4).is_ok()` + | ^^^^^ + | +help: consider using `is_ok()` + | +LL - let _ = if let Ok(_) = Ok::(4) { true } else { false }; +LL + let _ = if Ok::(4).is_ok() { true } else { false }; + | -error: redundant pattern matching, consider using `is_ok()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_result.rs:70:20 | LL | let _ = if let Ok(_) = gen_res() { - | -------^^^^^------------ help: try: `if gen_res().is_ok()` + | ^^^^^ + | +help: consider using `is_ok()` + | +LL - let _ = if let Ok(_) = gen_res() { +LL + let _ = if gen_res().is_ok() { + | -error: redundant pattern matching, consider using `is_err()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_result.rs:73:19 | LL | } else if let Err(_) = gen_res() { - | -------^^^^^^------------ help: try: `if gen_res().is_err()` + | ^^^^^^ + | +help: consider using `is_err()` + | +LL - } else if let Err(_) = gen_res() { +LL + } else if gen_res().is_err() { + | -error: redundant pattern matching, consider using `is_some()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_result.rs:97:19 | LL | while let Some(_) = r#try!(result_opt()) {} - | ----------^^^^^^^----------------------- help: try: `while r#try!(result_opt()).is_some()` + | ^^^^^^^ + | +help: consider using `is_some()` + | +LL - while let Some(_) = r#try!(result_opt()) {} +LL + while r#try!(result_opt()).is_some() {} + | -error: redundant pattern matching, consider using `is_some()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_result.rs:99:16 | LL | if let Some(_) = r#try!(result_opt()) {} - | -------^^^^^^^----------------------- help: try: `if r#try!(result_opt()).is_some()` + | ^^^^^^^ + | +help: consider using `is_some()` + | +LL - if let Some(_) = r#try!(result_opt()) {} +LL + if r#try!(result_opt()).is_some() {} + | -error: redundant pattern matching, consider using `is_some()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_result.rs:106:12 | LL | if let Some(_) = m!() {} - | -------^^^^^^^------- help: try: `if m!().is_some()` + | ^^^^^^^ + | +help: consider using `is_some()` + | +LL - if let Some(_) = m!() {} +LL + if m!().is_some() {} + | -error: redundant pattern matching, consider using `is_some()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_result.rs:108:15 | LL | while let Some(_) = m!() {} - | ----------^^^^^^^------- help: try: `while m!().is_some()` + | ^^^^^^^ + | +help: consider using `is_some()` + | +LL - while let Some(_) = m!() {} +LL + while m!().is_some() {} + | -error: redundant pattern matching, consider using `is_ok()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_result.rs:127:12 | LL | if let Ok(_) = Ok::(42) {} - | -------^^^^^--------------------- help: try: `if Ok::(42).is_ok()` + | ^^^^^ + | +help: consider using `is_ok()` + | +LL - if let Ok(_) = Ok::(42) {} +LL + if Ok::(42).is_ok() {} + | -error: redundant pattern matching, consider using `is_err()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_result.rs:130:12 | LL | if let Err(_) = Err::(42) {} - | -------^^^^^^---------------------- help: try: `if Err::(42).is_err()` + | ^^^^^^ + | +help: consider using `is_err()` + | +LL - if let Err(_) = Err::(42) {} +LL + if Err::(42).is_err() {} + | -error: redundant pattern matching, consider using `is_ok()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_result.rs:133:15 | LL | while let Ok(_) = Ok::(10) {} - | ----------^^^^^--------------------- help: try: `while Ok::(10).is_ok()` + | ^^^^^ + | +help: consider using `is_ok()` + | +LL - while let Ok(_) = Ok::(10) {} +LL + while Ok::(10).is_ok() {} + | -error: redundant pattern matching, consider using `is_err()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_result.rs:136:15 | LL | while let Err(_) = Ok::(10) {} - | ----------^^^^^^--------------------- help: try: `while Ok::(10).is_err()` + | ^^^^^^ + | +help: consider using `is_err()` + | +LL - while let Err(_) = Ok::(10) {} +LL + while Ok::(10).is_err() {} + | -error: redundant pattern matching, consider using `is_ok()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_result.rs:139:5 | LL | / match Ok::(42) { @@ -145,9 +280,19 @@ LL | | LL | | Ok(_) => true, LL | | Err(_) => false, LL | | }; - | |_____^ help: try: `Ok::(42).is_ok()` + | |_____^ + | +help: consider using `is_ok()` + | +LL - match Ok::(42) { +LL - +LL - Ok(_) => true, +LL - Err(_) => false, +LL - }; +LL + Ok::(42).is_ok(); + | -error: redundant pattern matching, consider using `is_err()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_result.rs:145:5 | LL | / match Err::(42) { @@ -155,9 +300,19 @@ LL | | LL | | Ok(_) => false, LL | | Err(_) => true, LL | | }; - | |_____^ help: try: `Err::(42).is_err()` + | |_____^ + | +help: consider using `is_err()` + | +LL - match Err::(42) { +LL - +LL - Ok(_) => false, +LL - Err(_) => true, +LL - }; +LL + Err::(42).is_err(); + | -error: redundant pattern matching, consider using `is_ok()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_result.rs:156:5 | LL | / match x { @@ -165,9 +320,19 @@ LL | | LL | | Ok(_) => true, LL | | _ => false, LL | | }; - | |_____^ help: try: `x.is_ok()` + | |_____^ + | +help: consider using `is_ok()` + | +LL - match x { +LL - +LL - Ok(_) => true, +LL - _ => false, +LL - }; +LL + x.is_ok(); + | -error: redundant pattern matching, consider using `is_err()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_result.rs:162:5 | LL | / match x { @@ -175,9 +340,19 @@ LL | | LL | | Ok(_) => false, LL | | _ => true, LL | | }; - | |_____^ help: try: `x.is_err()` + | |_____^ + | +help: consider using `is_err()` + | +LL - match x { +LL - +LL - Ok(_) => false, +LL - _ => true, +LL - }; +LL + x.is_err(); + | -error: redundant pattern matching, consider using `is_err()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_result.rs:168:5 | LL | / match x { @@ -185,9 +360,19 @@ LL | | LL | | Err(_) => true, LL | | _ => false, LL | | }; - | |_____^ help: try: `x.is_err()` + | |_____^ + | +help: consider using `is_err()` + | +LL - match x { +LL - +LL - Err(_) => true, +LL - _ => false, +LL - }; +LL + x.is_err(); + | -error: redundant pattern matching, consider using `is_ok()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_result.rs:174:5 | LL | / match x { @@ -195,21 +380,43 @@ LL | | LL | | Err(_) => false, LL | | _ => true, LL | | }; - | |_____^ help: try: `x.is_ok()` + | |_____^ + | +help: consider using `is_ok()` + | +LL - match x { +LL - +LL - Err(_) => false, +LL - _ => true, +LL - }; +LL + x.is_ok(); + | -error: redundant pattern matching, consider using `is_ok()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_result.rs:196:13 | LL | let _ = matches!(x, Ok(_)); - | ^^^^^^^^^^^^^^^^^^ help: try: `x.is_ok()` + | ^^^^^^^^^^^^^^^^^^ + | +help: consider using `is_ok()` + | +LL - let _ = matches!(x, Ok(_)); +LL + let _ = x.is_ok(); + | -error: redundant pattern matching, consider using `is_err()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_result.rs:199:13 | LL | let _ = matches!(x, Err(_)); - | ^^^^^^^^^^^^^^^^^^^ help: try: `x.is_err()` + | ^^^^^^^^^^^^^^^^^^^ + | +help: consider using `is_err()` + | +LL - let _ = matches!(x, Err(_)); +LL + let _ = x.is_err(); + | -error: redundant pattern matching, consider using `is_ok()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_result.rs:216:13 | LL | let _ = match test_expr!(42) { @@ -218,13 +425,29 @@ LL | | LL | | Ok(_) => true, LL | | Err(_) => false, LL | | }; - | |_____^ help: try: `test_expr!(42).is_ok()` + | |_____^ + | +help: consider using `is_ok()` + | +LL - let _ = match test_expr!(42) { +LL - +LL - Ok(_) => true, +LL - Err(_) => false, +LL - }; +LL + let _ = test_expr!(42).is_ok(); + | -error: redundant pattern matching, consider using `is_ok()` +error: redundant pattern matching --> tests/ui/redundant_pattern_matching_result.rs:229:13 | LL | let _ = matches!(x, Ok(_) if test_guard!(42)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `x.is_ok() && test_guard!(42)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `is_ok()` + | +LL - let _ = matches!(x, Ok(_) if test_guard!(42)); +LL + let _ = x.is_ok() && test_guard!(42); + | error: aborting due to 30 previous errors diff --git a/tests/ui/renamed_builtin_attr.fixed b/tests/ui/renamed_builtin_attr.fixed index 1ad7d8702bc00..3768ff1976ffc 100644 --- a/tests/ui/renamed_builtin_attr.fixed +++ b/tests/ui/renamed_builtin_attr.fixed @@ -1,5 +1,3 @@ -//@compile-flags: -Zdeduplicate-diagnostics=yes - #[clippy::cognitive_complexity = "1"] //~^ ERROR: usage of deprecated attribute fn main() {} diff --git a/tests/ui/renamed_builtin_attr.rs b/tests/ui/renamed_builtin_attr.rs index 0fb43b7f49016..232e2d4920e8c 100644 --- a/tests/ui/renamed_builtin_attr.rs +++ b/tests/ui/renamed_builtin_attr.rs @@ -1,5 +1,3 @@ -//@compile-flags: -Zdeduplicate-diagnostics=yes - #[clippy::cyclomatic_complexity = "1"] //~^ ERROR: usage of deprecated attribute fn main() {} diff --git a/tests/ui/renamed_builtin_attr.stderr b/tests/ui/renamed_builtin_attr.stderr index 0ebc43739d6b7..5f3f9fdcc32a0 100644 --- a/tests/ui/renamed_builtin_attr.stderr +++ b/tests/ui/renamed_builtin_attr.stderr @@ -1,5 +1,5 @@ error: usage of deprecated attribute - --> tests/ui/renamed_builtin_attr.rs:3:3 + --> tests/ui/renamed_builtin_attr.rs:1:3 | LL | #[clippy::cyclomatic_complexity = "1"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `clippy::cognitive_complexity` diff --git a/tests/ui/result_large_err.rs b/tests/ui/result_large_err.rs index b4ad050df3b79..0056c54ff5d42 100644 --- a/tests/ui/result_large_err.rs +++ b/tests/ui/result_large_err.rs @@ -150,3 +150,17 @@ fn issue16249() { let closure = || Ok::<(), Large>(()); //~^ result_large_err } + +pub async fn async_large_err() -> Result<(), [u8; 512]> { + //~^ result_large_err + Ok(()) +} + +pub async fn async_small_err() -> Result<(), u128> { + Ok(()) +} + +pub async fn async_struct_error() -> Result<(), FullyDefinedLargeError> { + //~^ result_large_err + Ok(()) +} diff --git a/tests/ui/result_large_err.stderr b/tests/ui/result_large_err.stderr index fd39179c61cb5..653b7e354f431 100644 --- a/tests/ui/result_large_err.stderr +++ b/tests/ui/result_large_err.stderr @@ -120,5 +120,21 @@ LL | let closure = || Ok::<(), Large>(()); | = help: try reducing the size of `[u8; 1024]`, for example by boxing large elements or replacing it with `Box<[u8; 1024]>` -error: aborting due to 14 previous errors +error: the `Err`-variant returned from this function is very large + --> tests/ui/result_large_err.rs:154:35 + | +LL | pub async fn async_large_err() -> Result<(), [u8; 512]> { + | ^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 512 bytes + | + = help: try reducing the size of `[u8; 512]`, for example by boxing large elements or replacing it with `Box<[u8; 512]>` + +error: the `Err`-variant returned from this function is very large + --> tests/ui/result_large_err.rs:163:38 + | +LL | pub async fn async_struct_error() -> Result<(), FullyDefinedLargeError> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 240 bytes + | + = help: try reducing the size of `FullyDefinedLargeError`, for example by boxing large elements or replacing it with `Box` + +error: aborting due to 16 previous errors diff --git a/tests/ui/result_unit_error.rs b/tests/ui/result_unit_error.rs index ddbe0eb556c85..fdf155ff291d5 100644 --- a/tests/ui/result_unit_error.rs +++ b/tests/ui/result_unit_error.rs @@ -62,4 +62,16 @@ pub mod issue_6546 { } } +pub mod issue_17070 { + pub async fn returns_unit_error_async() -> Result { + //~^ result_unit_err + + Err(()) + } + + async fn private_unit_errors_async() -> Result { + Err(()) + } +} + fn main() {} diff --git a/tests/ui/result_unit_error.stderr b/tests/ui/result_unit_error.stderr index d6c0924d88689..02ef9f3a1b7ea 100644 --- a/tests/ui/result_unit_error.stderr +++ b/tests/ui/result_unit_error.stderr @@ -40,5 +40,13 @@ LL | pub fn should_lint() -> ResInv<(), usize> { | = help: use a custom `Error` type instead -error: aborting due to 5 previous errors +error: this returns a `Result<_, ()>` + --> tests/ui/result_unit_error.rs:66:5 + | +LL | pub async fn returns_unit_error_async() -> Result { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use a custom `Error` type instead + +error: aborting due to 6 previous errors diff --git a/tests/ui/single_range_in_vec_init.1.fixed b/tests/ui/single_range_in_vec_init.1.fixed index 0af91907ad05f..e0c1dba073d86 100644 --- a/tests/ui/single_range_in_vec_init.1.fixed +++ b/tests/ui/single_range_in_vec_init.1.fixed @@ -82,3 +82,10 @@ fn issue16044() { let input = (0..as_i32!(10)).collect::>(); //~^ single_range_in_vec_init } + +fn issue16508() { + (0..=10).collect::>(); + //~^ single_range_in_vec_init + (0..=10).collect::>(); + //~^ single_range_in_vec_init +} diff --git a/tests/ui/single_range_in_vec_init.2.fixed b/tests/ui/single_range_in_vec_init.2.fixed index fd6b91360aeb2..5784702661926 100644 --- a/tests/ui/single_range_in_vec_init.2.fixed +++ b/tests/ui/single_range_in_vec_init.2.fixed @@ -82,3 +82,10 @@ fn issue16044() { let input = (0..as_i32!(10)).collect::>(); //~^ single_range_in_vec_init } + +fn issue16508() { + (0..=10).collect::>(); + //~^ single_range_in_vec_init + (0..=10).collect::>(); + //~^ single_range_in_vec_init +} diff --git a/tests/ui/single_range_in_vec_init.rs b/tests/ui/single_range_in_vec_init.rs index 1cc2b894c0348..3ff07c386d218 100644 --- a/tests/ui/single_range_in_vec_init.rs +++ b/tests/ui/single_range_in_vec_init.rs @@ -82,3 +82,10 @@ fn issue16044() { let input = vec![0..as_i32!(10)]; //~^ single_range_in_vec_init } + +fn issue16508() { + [0..=10]; + //~^ single_range_in_vec_init + vec![0..=10]; + //~^ single_range_in_vec_init +} diff --git a/tests/ui/single_range_in_vec_init.stderr b/tests/ui/single_range_in_vec_init.stderr index d93379777d39c..1fec5119d8155 100644 --- a/tests/ui/single_range_in_vec_init.stderr +++ b/tests/ui/single_range_in_vec_init.stderr @@ -172,5 +172,29 @@ LL - let input = vec![0..as_i32!(10)]; LL + let input = (0..as_i32!(10)).collect::>(); | -error: aborting due to 11 previous errors +error: an array of `RangeInclusive` that is only one element + --> tests/ui/single_range_in_vec_init.rs:87:5 + | +LL | [0..=10]; + | ^^^^^^^^ + | +help: if you wanted a `Vec` that contains the entire range, try + | +LL - [0..=10]; +LL + (0..=10).collect::>(); + | + +error: a `Vec` of `RangeInclusive` that is only one element + --> tests/ui/single_range_in_vec_init.rs:89:5 + | +LL | vec![0..=10]; + | ^^^^^^^^^^^^ + | +help: if you wanted a `Vec` that contains the entire range, try + | +LL - vec![0..=10]; +LL + (0..=10).collect::>(); + | + +error: aborting due to 13 previous errors diff --git a/tests/ui/single_range_in_vec_init_unfixable.rs b/tests/ui/single_range_in_vec_init_unfixable.rs index 33378b386f344..5574c51155ec9 100644 --- a/tests/ui/single_range_in_vec_init_unfixable.rs +++ b/tests/ui/single_range_in_vec_init_unfixable.rs @@ -10,3 +10,26 @@ fn issue16306(v: &[i32]) { takes_range_slice(&[0..len as i64]); //~^ single_range_in_vec_init } + +#[allow(clippy::no_effect, clippy::useless_vec)] +fn issue16508_open_ended() { + [..10]; + //~^ single_range_in_vec_init + vec![..10]; + //~^ single_range_in_vec_init + + [10..]; + //~^ single_range_in_vec_init + vec![10..]; + //~^ single_range_in_vec_init + + [..=10]; + //~^ single_range_in_vec_init + vec![..=10]; + //~^ single_range_in_vec_init + + [..]; + //~^ single_range_in_vec_init + vec![..]; + //~^ single_range_in_vec_init +} diff --git a/tests/ui/single_range_in_vec_init_unfixable.stderr b/tests/ui/single_range_in_vec_init_unfixable.stderr index b10af21ed21c2..32caefb4f3dde 100644 --- a/tests/ui/single_range_in_vec_init_unfixable.stderr +++ b/tests/ui/single_range_in_vec_init_unfixable.stderr @@ -12,5 +12,53 @@ LL - takes_range_slice(&[0..len as i64]); LL + takes_range_slice(&(0..len as i64).collect::>()); | -error: aborting due to 1 previous error +error: an array of `RangeTo` that is only one element + --> tests/ui/single_range_in_vec_init_unfixable.rs:16:5 + | +LL | [..10]; + | ^^^^^^ + +error: a `Vec` of `RangeTo` that is only one element + --> tests/ui/single_range_in_vec_init_unfixable.rs:18:5 + | +LL | vec![..10]; + | ^^^^^^^^^^ + +error: an array of `RangeFrom` that is only one element + --> tests/ui/single_range_in_vec_init_unfixable.rs:21:5 + | +LL | [10..]; + | ^^^^^^ + +error: a `Vec` of `RangeFrom` that is only one element + --> tests/ui/single_range_in_vec_init_unfixable.rs:23:5 + | +LL | vec![10..]; + | ^^^^^^^^^^ + +error: an array of `RangeToInclusive` that is only one element + --> tests/ui/single_range_in_vec_init_unfixable.rs:26:5 + | +LL | [..=10]; + | ^^^^^^^ + +error: a `Vec` of `RangeToInclusive` that is only one element + --> tests/ui/single_range_in_vec_init_unfixable.rs:28:5 + | +LL | vec![..=10]; + | ^^^^^^^^^^^ + +error: an array of `RangeFull` that is only one element + --> tests/ui/single_range_in_vec_init_unfixable.rs:31:5 + | +LL | [..]; + | ^^^^ + +error: a `Vec` of `RangeFull` that is only one element + --> tests/ui/single_range_in_vec_init_unfixable.rs:33:5 + | +LL | vec![..]; + | ^^^^^^^^ + +error: aborting due to 9 previous errors diff --git a/tests/ui/ty_fn_sig.rs b/tests/ui/ty_fn_sig.rs index 60767bfad135c..d7aa8f9a2c4d9 100644 --- a/tests/ui/ty_fn_sig.rs +++ b/tests/ui/ty_fn_sig.rs @@ -2,7 +2,7 @@ // Regression test pub fn retry(f: F) { - for _i in 0.. { + for _i in 0..=i32::MAX { f(); } } diff --git a/tests/ui/unknown_attribute.rs b/tests/ui/unknown_attribute.rs index 3241742b5d464..932f284d5b713 100644 --- a/tests/ui/unknown_attribute.rs +++ b/tests/ui/unknown_attribute.rs @@ -1,5 +1,3 @@ -//@compile-flags: -Zdeduplicate-diagnostics=yes - #[clippy::unknown] //~^ ERROR: usage of unknown attribute #[clippy::cognitive_complexity = "1"] diff --git a/tests/ui/unknown_attribute.stderr b/tests/ui/unknown_attribute.stderr index 1d4d50ffc02a4..17c592b3aa078 100644 --- a/tests/ui/unknown_attribute.stderr +++ b/tests/ui/unknown_attribute.stderr @@ -1,5 +1,5 @@ error: usage of unknown attribute - --> tests/ui/unknown_attribute.rs:3:3 + --> tests/ui/unknown_attribute.rs:1:3 | LL | #[clippy::unknown] | ^^^^^^^^^^^^^^^ diff --git a/tests/ui/unused_async_trait_impl.fixed b/tests/ui/unused_async_trait_impl.fixed index 384bb3449f90b..d8a96afdf1be5 100644 --- a/tests/ui/unused_async_trait_impl.fixed +++ b/tests/ui/unused_async_trait_impl.fixed @@ -107,3 +107,36 @@ mod macros { } } } + +mod issue17179 { + struct Test; + + impl crate::HasAsyncMethod for Test { + fn do_something() -> impl Future { + //~^ unused_async_trait_impl + + // Test that local functions are not touched by the suggestion. + fn local_func() -> u32 { + if 5 == 2 { + return 1; + } + 2 + } + + // Test that we do not change the tail expr or return in a (unrelated) closure. + let f = || { + if 5 == 2 { + return 1; + } + 2 + }; + + // However the following return statement and tail expression should be changed. + if f() == 5 { + return std::future::ready(3); + } + + std::future::ready(5) + } + } +} diff --git a/tests/ui/unused_async_trait_impl.rs b/tests/ui/unused_async_trait_impl.rs index 0a93635c264f5..f2b69eb46428f 100644 --- a/tests/ui/unused_async_trait_impl.rs +++ b/tests/ui/unused_async_trait_impl.rs @@ -107,3 +107,36 @@ mod macros { } } } + +mod issue17179 { + struct Test; + + impl crate::HasAsyncMethod for Test { + async fn do_something() -> u32 { + //~^ unused_async_trait_impl + + // Test that local functions are not touched by the suggestion. + fn local_func() -> u32 { + if 5 == 2 { + return 1; + } + 2 + } + + // Test that we do not change the tail expr or return in a (unrelated) closure. + let f = || { + if 5 == 2 { + return 1; + } + 2 + }; + + // However the following return statement and tail expression should be changed. + if f() == 5 { + return 3; + } + + 5 + } + } +} diff --git a/tests/ui/unused_async_trait_impl.stderr b/tests/ui/unused_async_trait_impl.stderr index 7265dc2dd0595..b1da2e2e351a1 100644 --- a/tests/ui/unused_async_trait_impl.stderr +++ b/tests/ui/unused_async_trait_impl.stderr @@ -90,5 +90,27 @@ LL | LL ~ std::future::ready(vec![]) | -error: aborting due to 5 previous errors +error: unused `async` for async trait impl function with no `.await` statements + --> tests/ui/unused_async_trait_impl.rs:115:9 + | +LL | / async fn do_something() -> u32 { +... | +LL | | 5 +LL | | } + | |_________^ + | + = note: `std::future::ready` creates a `Future` which returns the value immediately when `poll`ed +help: consider removing the `async` from this function and returning `impl Future` instead + | +LL ~ fn do_something() -> impl Future { +LL | +... +LL | if f() == 5 { +LL ~ return std::future::ready(3); +LL | } +LL | +LL ~ std::future::ready(5) + | + +error: aborting due to 6 previous errors diff --git a/tests/ui/with_capacity_zero.fixed b/tests/ui/with_capacity_zero.fixed new file mode 100644 index 0000000000000..6da614d000248 --- /dev/null +++ b/tests/ui/with_capacity_zero.fixed @@ -0,0 +1,50 @@ +#![warn(clippy::with_capacity_zero)] +#![allow(unused)] +#![allow(clippy::eq_op)] + +use std::collections::{BinaryHeap, HashMap, HashSet, VecDeque}; +use std::ffi::OsString; +use std::io::BufReader; +use std::path::PathBuf; + +struct MyStruct; +impl MyStruct { + fn with_capacity(cap: usize) -> Self { + MyStruct + } +} + +fn main() { + // Positive cases + let v: Vec = Vec::new(); + //~^ ERROR: calling `with_capacity(0)` is equivalent to `new()` + let s = String::new(); + //~^ ERROR: calling `with_capacity(0)` is equivalent to `new()` + let v2 = std::vec::Vec::::new(); + //~^ ERROR: calling `with_capacity(0)` is equivalent to `new()` + let map = HashMap::::new(); + //~^ ERROR: calling `with_capacity(0)` is equivalent to `new()` + let set = HashSet::::new(); + //~^ ERROR: calling `with_capacity(0)` is equivalent to `new()` + let deque = VecDeque::::new(); + //~^ ERROR: calling `with_capacity(0)` is equivalent to `new()` + let heap = BinaryHeap::::new(); + //~^ ERROR: calling `with_capacity(0)` is equivalent to `new()` + let path = PathBuf::new(); + //~^ ERROR: calling `with_capacity(0)` is equivalent to `new()` + let os_str = OsString::new(); + //~^ ERROR: calling `with_capacity(0)` is equivalent to `new()` + + // Negative cases + let v_non_zero = Vec::::with_capacity(10); + let s_non_zero = String::with_capacity(5); + + let cap = 0; + let v_variable = Vec::::with_capacity(cap); + + // Custom struct with with_capacity method + let custom = MyStruct::with_capacity(0); + + // Two-argument capacity call (BufReader) + let reader = BufReader::with_capacity(0, std::io::empty()); +} diff --git a/tests/ui/with_capacity_zero.rs b/tests/ui/with_capacity_zero.rs new file mode 100644 index 0000000000000..0f8bfb12c34f5 --- /dev/null +++ b/tests/ui/with_capacity_zero.rs @@ -0,0 +1,50 @@ +#![warn(clippy::with_capacity_zero)] +#![allow(unused)] +#![allow(clippy::eq_op)] + +use std::collections::{BinaryHeap, HashMap, HashSet, VecDeque}; +use std::ffi::OsString; +use std::io::BufReader; +use std::path::PathBuf; + +struct MyStruct; +impl MyStruct { + fn with_capacity(cap: usize) -> Self { + MyStruct + } +} + +fn main() { + // Positive cases + let v: Vec = Vec::with_capacity(0); + //~^ ERROR: calling `with_capacity(0)` is equivalent to `new()` + let s = String::with_capacity(0); + //~^ ERROR: calling `with_capacity(0)` is equivalent to `new()` + let v2 = std::vec::Vec::::with_capacity(0); + //~^ ERROR: calling `with_capacity(0)` is equivalent to `new()` + let map = HashMap::::with_capacity(0); + //~^ ERROR: calling `with_capacity(0)` is equivalent to `new()` + let set = HashSet::::with_capacity(0); + //~^ ERROR: calling `with_capacity(0)` is equivalent to `new()` + let deque = VecDeque::::with_capacity(0); + //~^ ERROR: calling `with_capacity(0)` is equivalent to `new()` + let heap = BinaryHeap::::with_capacity(0); + //~^ ERROR: calling `with_capacity(0)` is equivalent to `new()` + let path = PathBuf::with_capacity(0); + //~^ ERROR: calling `with_capacity(0)` is equivalent to `new()` + let os_str = OsString::with_capacity(0); + //~^ ERROR: calling `with_capacity(0)` is equivalent to `new()` + + // Negative cases + let v_non_zero = Vec::::with_capacity(10); + let s_non_zero = String::with_capacity(5); + + let cap = 0; + let v_variable = Vec::::with_capacity(cap); + + // Custom struct with with_capacity method + let custom = MyStruct::with_capacity(0); + + // Two-argument capacity call (BufReader) + let reader = BufReader::with_capacity(0, std::io::empty()); +} diff --git a/tests/ui/with_capacity_zero.stderr b/tests/ui/with_capacity_zero.stderr new file mode 100644 index 0000000000000..5fce9d90e0360 --- /dev/null +++ b/tests/ui/with_capacity_zero.stderr @@ -0,0 +1,112 @@ +error: calling `with_capacity(0)` is equivalent to `new()` + --> tests/ui/with_capacity_zero.rs:19:23 + | +LL | let v: Vec = Vec::with_capacity(0); + | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::with-capacity-zero` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::with_capacity_zero)]` +help: use `new()` instead + | +LL - let v: Vec = Vec::with_capacity(0); +LL + let v: Vec = Vec::new(); + | + +error: calling `with_capacity(0)` is equivalent to `new()` + --> tests/ui/with_capacity_zero.rs:21:13 + | +LL | let s = String::with_capacity(0); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `new()` instead + | +LL - let s = String::with_capacity(0); +LL + let s = String::new(); + | + +error: calling `with_capacity(0)` is equivalent to `new()` + --> tests/ui/with_capacity_zero.rs:23:14 + | +LL | let v2 = std::vec::Vec::::with_capacity(0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `new()` instead + | +LL - let v2 = std::vec::Vec::::with_capacity(0); +LL + let v2 = std::vec::Vec::::new(); + | + +error: calling `with_capacity(0)` is equivalent to `new()` + --> tests/ui/with_capacity_zero.rs:25:15 + | +LL | let map = HashMap::::with_capacity(0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `new()` instead + | +LL - let map = HashMap::::with_capacity(0); +LL + let map = HashMap::::new(); + | + +error: calling `with_capacity(0)` is equivalent to `new()` + --> tests/ui/with_capacity_zero.rs:27:15 + | +LL | let set = HashSet::::with_capacity(0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `new()` instead + | +LL - let set = HashSet::::with_capacity(0); +LL + let set = HashSet::::new(); + | + +error: calling `with_capacity(0)` is equivalent to `new()` + --> tests/ui/with_capacity_zero.rs:29:17 + | +LL | let deque = VecDeque::::with_capacity(0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `new()` instead + | +LL - let deque = VecDeque::::with_capacity(0); +LL + let deque = VecDeque::::new(); + | + +error: calling `with_capacity(0)` is equivalent to `new()` + --> tests/ui/with_capacity_zero.rs:31:16 + | +LL | let heap = BinaryHeap::::with_capacity(0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `new()` instead + | +LL - let heap = BinaryHeap::::with_capacity(0); +LL + let heap = BinaryHeap::::new(); + | + +error: calling `with_capacity(0)` is equivalent to `new()` + --> tests/ui/with_capacity_zero.rs:33:16 + | +LL | let path = PathBuf::with_capacity(0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `new()` instead + | +LL - let path = PathBuf::with_capacity(0); +LL + let path = PathBuf::new(); + | + +error: calling `with_capacity(0)` is equivalent to `new()` + --> tests/ui/with_capacity_zero.rs:35:18 + | +LL | let os_str = OsString::with_capacity(0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `new()` instead + | +LL - let os_str = OsString::with_capacity(0); +LL + let os_str = OsString::new(); + | + +error: aborting due to 9 previous errors + diff --git a/triagebot.toml b/triagebot.toml index e357c528ed65f..667468474b3c1 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -94,6 +94,7 @@ users_on_vacation = [ "Alexendoo", "y21", "blyxyas", + "ada4a" ] [assign.owners] From 6ccea6c7fb880adc6c1fe9cac306fb8b5b753d30 Mon Sep 17 00:00:00 2001 From: khyperia <953151+khyperia@users.noreply.github.com> Date: Thu, 11 Jun 2026 13:48:00 +0200 Subject: [PATCH 14/77] remove AliasTerm::def_id() --- clippy_utils/src/ty/mod.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/clippy_utils/src/ty/mod.rs b/clippy_utils/src/ty/mod.rs index a944e91db0c0e..60d19ecf68bb5 100644 --- a/clippy_utils/src/ty/mod.rs +++ b/clippy_utils/src/ty/mod.rs @@ -712,7 +712,7 @@ fn sig_from_bounds<'tcx>( inputs = Some(i); }, ty::ClauseKind::Projection(p) - if Some(p.projection_term.def_id()) == lang_items.fn_once_output() + if Some(p.projection_term.expect_projection_def_id()) == lang_items.fn_once_output() && p.projection_term.self_ty() == ty => { if output.is_some() { @@ -753,7 +753,9 @@ fn sig_for_projection<'tcx>(cx: &LateContext<'tcx>, ty: AliasTy<'tcx>) -> Option } inputs = Some(i); }, - ty::ClauseKind::Projection(p) if Some(p.projection_term.def_id()) == lang_items.fn_once_output() => { + ty::ClauseKind::Projection(p) + if Some(p.projection_term.expect_projection_def_id()) == lang_items.fn_once_output() => + { if output.is_some() { // Multiple different fn trait impls. Is this even allowed? return None; From 5076a6b5589db7e8182c0b17fb46e6444c21bcce Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Thu, 11 Jun 2026 10:46:08 -0400 Subject: [PATCH 15/77] Refactor `drain_collect` and clarify the lint messages. --- clippy_lints/src/methods/drain_collect.rs | 78 +++++++---------------- clippy_lints/src/methods/mod.rs | 6 +- tests/ui/drain_collect.stderr | 40 ++++++------ tests/ui/drain_collect_nostd.stderr | 4 +- 4 files changed, 50 insertions(+), 78 deletions(-) diff --git a/clippy_lints/src/methods/drain_collect.rs b/clippy_lints/src/methods/drain_collect.rs index 6c222640e2601..b9d8a0d26cc7e 100644 --- a/clippy_lints/src/methods/drain_collect.rs +++ b/clippy_lints/src/methods/drain_collect.rs @@ -4,64 +4,34 @@ use clippy_utils::res::MaybeDef; use clippy_utils::source::snippet; use clippy_utils::{is_range_full, std_or_core, sym}; use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind, LangItem, Path, QPath}; +use rustc_hir::{Expr, ExprKind, QPath}; use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_middle::ty::Ty; -use rustc_span::Symbol; -/// Checks if both types match the given diagnostic item, e.g.: -/// -/// `vec![1,2].drain(..).collect::>()` -/// ^^^^^^^^^ ^^^^^^ true -/// `vec![1,2].drain(..).collect::>()` -/// ^^^^^^^^^ ^^^^^^^^^^ false -fn types_match_diagnostic_item(cx: &LateContext<'_>, expr: Ty<'_>, recv: Ty<'_>, sym: Symbol) -> bool { - if let Some(expr_adt) = expr.ty_adt_def() - && let Some(recv_adt) = recv.ty_adt_def() - { - cx.tcx.is_diagnostic_item(sym, expr_adt.did()) && cx.tcx.is_diagnostic_item(sym, recv_adt.did()) - } else { - false - } -} - -/// Checks `std::{vec::Vec, collections::VecDeque}`. -fn check_vec(cx: &LateContext<'_>, args: &[Expr<'_>], expr: Ty<'_>, recv: Ty<'_>, recv_path: &Path<'_>) -> bool { - (types_match_diagnostic_item(cx, expr, recv, sym::Vec) - || types_match_diagnostic_item(cx, expr, recv, sym::VecDeque)) - && matches!(args, [arg] if is_range_full(cx, arg, Some(recv_path))) -} - -/// Checks `std::string::String` -fn check_string(cx: &LateContext<'_>, args: &[Expr<'_>], expr: Ty<'_>, recv: Ty<'_>, recv_path: &Path<'_>) -> bool { - expr.is_lang_item(cx, LangItem::String) - && recv.is_lang_item(cx, LangItem::String) - && matches!(args, [arg] if is_range_full(cx, arg, Some(recv_path))) -} - -/// Checks `std::collections::{HashSet, HashMap, BinaryHeap}`. -fn check_collections(cx: &LateContext<'_>, expr: Ty<'_>, recv: Ty<'_>) -> Option<&'static str> { - types_match_diagnostic_item(cx, expr, recv, sym::HashSet) - .then_some("HashSet") - .or_else(|| types_match_diagnostic_item(cx, expr, recv, sym::HashMap).then_some("HashMap")) - .or_else(|| types_match_diagnostic_item(cx, expr, recv, sym::BinaryHeap).then_some("BinaryHeap")) -} - -pub(super) fn check(cx: &LateContext<'_>, args: &[Expr<'_>], expr: &Expr<'_>, recv: &Expr<'_>) { - let expr_ty = cx.typeck_results().expr_ty(expr); - let recv_ty = cx.typeck_results().expr_ty(recv); - let recv_ty_no_refs = recv_ty.peel_refs(); - - if let ExprKind::Path(QPath::Resolved(_, recv_path)) = recv.kind - && let Some(typename) = check_vec(cx, args, expr_ty, recv_ty_no_refs, recv_path) - .then_some("Vec") - .or_else(|| check_string(cx, args, expr_ty, recv_ty_no_refs, recv_path).then_some("String")) - .or_else(|| check_collections(cx, expr_ty, recv_ty_no_refs)) +pub(super) fn check(cx: &LateContext<'_>, arg: Option<&Expr<'_>>, expr: &Expr<'_>, recv: &Expr<'_>) { + let ty = cx.typeck_results().expr_ty(recv); + let (is_ref, ty) = match *ty.kind() { + ty::Ref(_, ty, _) => (true, ty), + _ => (false, ty), + }; + if cx.typeck_results().expr_ty(expr) == ty + && let Some(did) = ty.opt_def_id() + && (cx.tcx.lang_items().string() == Some(did) + || matches!( + ty.opt_diag_name(cx), + Some(sym::HashMap | sym::HashSet | sym::BinaryHeap | sym::Vec | sym::VecDeque) + )) + && arg.is_none_or(|arg| { + if let ExprKind::Path(QPath::Resolved(None, path)) = recv.kind { + is_range_full(cx, arg, Some(path)) + } else { + false + } + }) && let Some(exec_context) = std_or_core(cx) { let recv = snippet(cx, recv.span, ""); - let sugg = if let ty::Ref(..) = recv_ty.kind() { + let sugg = if is_ref { format!("{exec_context}::mem::take({recv})") } else { format!("{exec_context}::mem::take(&mut {recv})") @@ -71,8 +41,8 @@ pub(super) fn check(cx: &LateContext<'_>, args: &[Expr<'_>], expr: &Expr<'_>, re cx, DRAIN_COLLECT, expr.span, - format!("you seem to be trying to move all elements into a new `{typename}`"), - "consider using `mem::take`", + "draining all elements of a collection into a new collection of the same type", + "use `mem::take` to avoid creating a new allocation", sugg, Applicability::MachineApplicable, ); diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index b01cd49739431..2ccab8685a7c6 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -5277,8 +5277,10 @@ impl Methods { manual_str_repeat::check(cx, expr, recv, take_self_arg, take_arg); } }, - Some((sym::drain, recv, args, ..)) => { - drain_collect::check(cx, args, expr, recv); + Some((sym::drain, recv, args, ..)) => match args { + [arg] => drain_collect::check(cx, Some(arg), expr, recv), + [] => drain_collect::check(cx, None, expr, recv), + _ => {}, }, _ => {}, } diff --git a/tests/ui/drain_collect.stderr b/tests/ui/drain_collect.stderr index 46da4e799d2e8..7c1008aebe58a 100644 --- a/tests/ui/drain_collect.stderr +++ b/tests/ui/drain_collect.stderr @@ -1,8 +1,8 @@ -error: you seem to be trying to move all elements into a new `BinaryHeap` +error: draining all elements of a collection into a new collection of the same type --> tests/ui/drain_collect.rs:6:5 | LL | b.drain().collect() - | ^^^^^^^^^^^^^^^^^^^ help: consider using `mem::take`: `std::mem::take(b)` + | ^^^^^^^^^^^^^^^^^^^ help: use `mem::take` to avoid creating a new allocation: `std::mem::take(b)` | note: the lint level is defined here --> tests/ui/drain_collect.rs:1:9 @@ -10,59 +10,59 @@ note: the lint level is defined here LL | #![deny(clippy::drain_collect)] | ^^^^^^^^^^^^^^^^^^^^^ -error: you seem to be trying to move all elements into a new `HashMap` +error: draining all elements of a collection into a new collection of the same type --> tests/ui/drain_collect.rs:15:5 | LL | b.drain().collect() - | ^^^^^^^^^^^^^^^^^^^ help: consider using `mem::take`: `std::mem::take(b)` + | ^^^^^^^^^^^^^^^^^^^ help: use `mem::take` to avoid creating a new allocation: `std::mem::take(b)` -error: you seem to be trying to move all elements into a new `HashSet` +error: draining all elements of a collection into a new collection of the same type --> tests/ui/drain_collect.rs:24:5 | LL | b.drain().collect() - | ^^^^^^^^^^^^^^^^^^^ help: consider using `mem::take`: `std::mem::take(b)` + | ^^^^^^^^^^^^^^^^^^^ help: use `mem::take` to avoid creating a new allocation: `std::mem::take(b)` -error: you seem to be trying to move all elements into a new `Vec` +error: draining all elements of a collection into a new collection of the same type --> tests/ui/drain_collect.rs:33:5 | LL | b.drain(..).collect() - | ^^^^^^^^^^^^^^^^^^^^^ help: consider using `mem::take`: `std::mem::take(b)` + | ^^^^^^^^^^^^^^^^^^^^^ help: use `mem::take` to avoid creating a new allocation: `std::mem::take(b)` -error: you seem to be trying to move all elements into a new `Vec` +error: draining all elements of a collection into a new collection of the same type --> tests/ui/drain_collect.rs:42:5 | LL | b.drain(..).collect() - | ^^^^^^^^^^^^^^^^^^^^^ help: consider using `mem::take`: `std::mem::take(b)` + | ^^^^^^^^^^^^^^^^^^^^^ help: use `mem::take` to avoid creating a new allocation: `std::mem::take(b)` -error: you seem to be trying to move all elements into a new `Vec` +error: draining all elements of a collection into a new collection of the same type --> tests/ui/drain_collect.rs:47:5 | LL | b.drain(0..).collect() - | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using `mem::take`: `std::mem::take(b)` + | ^^^^^^^^^^^^^^^^^^^^^^ help: use `mem::take` to avoid creating a new allocation: `std::mem::take(b)` -error: you seem to be trying to move all elements into a new `Vec` +error: draining all elements of a collection into a new collection of the same type --> tests/ui/drain_collect.rs:52:5 | LL | b.drain(..b.len()).collect() - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `mem::take`: `std::mem::take(b)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `mem::take` to avoid creating a new allocation: `std::mem::take(b)` -error: you seem to be trying to move all elements into a new `Vec` +error: draining all elements of a collection into a new collection of the same type --> tests/ui/drain_collect.rs:57:5 | LL | b.drain(0..b.len()).collect() - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `mem::take`: `std::mem::take(b)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `mem::take` to avoid creating a new allocation: `std::mem::take(b)` -error: you seem to be trying to move all elements into a new `Vec` +error: draining all elements of a collection into a new collection of the same type --> tests/ui/drain_collect.rs:63:5 | LL | b.drain(..).collect() - | ^^^^^^^^^^^^^^^^^^^^^ help: consider using `mem::take`: `std::mem::take(&mut b)` + | ^^^^^^^^^^^^^^^^^^^^^ help: use `mem::take` to avoid creating a new allocation: `std::mem::take(&mut b)` -error: you seem to be trying to move all elements into a new `String` +error: draining all elements of a collection into a new collection of the same type --> tests/ui/drain_collect.rs:72:5 | LL | b.drain(..).collect() - | ^^^^^^^^^^^^^^^^^^^^^ help: consider using `mem::take`: `std::mem::take(b)` + | ^^^^^^^^^^^^^^^^^^^^^ help: use `mem::take` to avoid creating a new allocation: `std::mem::take(b)` error: aborting due to 10 previous errors diff --git a/tests/ui/drain_collect_nostd.stderr b/tests/ui/drain_collect_nostd.stderr index 91b38932fee79..77fcae84d570e 100644 --- a/tests/ui/drain_collect_nostd.stderr +++ b/tests/ui/drain_collect_nostd.stderr @@ -1,8 +1,8 @@ -error: you seem to be trying to move all elements into a new `Vec` +error: draining all elements of a collection into a new collection of the same type --> tests/ui/drain_collect_nostd.rs:7:5 | LL | v.drain(..).collect() - | ^^^^^^^^^^^^^^^^^^^^^ help: consider using `mem::take`: `core::mem::take(v)` + | ^^^^^^^^^^^^^^^^^^^^^ help: use `mem::take` to avoid creating a new allocation: `core::mem::take(v)` | = note: `-D clippy::drain-collect` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::drain_collect)]` From a71d1184a526b96b0df48b7580eb65667b6390e1 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Thu, 11 Jun 2026 10:46:25 -0400 Subject: [PATCH 16/77] Replace `is_range_full` with `is_full_collection_range`. --- clippy_lints/src/methods/clear_with_drain.rs | 9 ++- clippy_lints/src/methods/drain_collect.rs | 14 ++--- clippy_lints/src/methods/iter_with_drain.rs | 8 +-- clippy_utils/src/lib.rs | 59 ++++------------- tests/ui/clear_with_drain.fixed | 30 --------- tests/ui/clear_with_drain.rs | 30 --------- tests/ui/clear_with_drain.stderr | 66 +++++--------------- 7 files changed, 38 insertions(+), 178 deletions(-) diff --git a/clippy_lints/src/methods/clear_with_drain.rs b/clippy_lints/src/methods/clear_with_drain.rs index cd6b39b15a1b9..0b6ead0747a80 100644 --- a/clippy_lints/src/methods/clear_with_drain.rs +++ b/clippy_lints/src/methods/clear_with_drain.rs @@ -1,8 +1,8 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::res::MaybeDef; -use clippy_utils::{is_range_full, sym}; +use clippy_utils::res::{MaybeDef, MaybeResPath}; +use clippy_utils::{is_full_collection_range, sym}; use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind, LangItem, QPath}; +use rustc_hir::{Expr, LangItem}; use rustc_lint::LateContext; use rustc_span::Span; @@ -16,8 +16,7 @@ const ACCEPTABLE_TYPES_WITHOUT_ARG: [rustc_span::Symbol; 3] = [sym::BinaryHeap, pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span: Span, arg: Option<&Expr<'_>>) { if let Some(arg) = arg { if match_acceptable_type(cx, recv, &ACCEPTABLE_TYPES_WITH_ARG) - && let ExprKind::Path(QPath::Resolved(None, container_path)) = recv.kind - && is_range_full(cx, arg, Some(container_path)) + && is_full_collection_range(cx, recv.res_local_id(), arg) { suggest(cx, expr, recv, span); } diff --git a/clippy_lints/src/methods/drain_collect.rs b/clippy_lints/src/methods/drain_collect.rs index b9d8a0d26cc7e..2b4b200904b2e 100644 --- a/clippy_lints/src/methods/drain_collect.rs +++ b/clippy_lints/src/methods/drain_collect.rs @@ -1,10 +1,10 @@ use crate::methods::DRAIN_COLLECT; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::res::MaybeDef; +use clippy_utils::res::{MaybeDef, MaybeResPath}; use clippy_utils::source::snippet; -use clippy_utils::{is_range_full, std_or_core, sym}; +use clippy_utils::{is_full_collection_range, std_or_core, sym}; use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind, QPath}; +use rustc_hir::Expr; use rustc_lint::LateContext; use rustc_middle::ty; @@ -21,13 +21,7 @@ pub(super) fn check(cx: &LateContext<'_>, arg: Option<&Expr<'_>>, expr: &Expr<'_ ty.opt_diag_name(cx), Some(sym::HashMap | sym::HashSet | sym::BinaryHeap | sym::Vec | sym::VecDeque) )) - && arg.is_none_or(|arg| { - if let ExprKind::Path(QPath::Resolved(None, path)) = recv.kind { - is_range_full(cx, arg, Some(path)) - } else { - false - } - }) + && arg.is_none_or(|arg| is_full_collection_range(cx, recv.res_local_id(), arg)) && let Some(exec_context) = std_or_core(cx) { let recv = snippet(cx, recv.span, ""); diff --git a/clippy_lints/src/methods/iter_with_drain.rs b/clippy_lints/src/methods/iter_with_drain.rs index 8d1585baac451..2ef09fa3f8d2c 100644 --- a/clippy_lints/src/methods/iter_with_drain.rs +++ b/clippy_lints/src/methods/iter_with_drain.rs @@ -1,7 +1,8 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::{is_range_full, sym}; +use clippy_utils::res::MaybeResPath; +use clippy_utils::{is_full_collection_range, sym}; use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind, QPath}; +use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; use rustc_span::Span; @@ -12,8 +13,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span && let Some(adt) = cx.typeck_results().expr_ty(recv).ty_adt_def() && let Some(ty_name) = cx.tcx.get_diagnostic_name(adt.did()) && matches!(ty_name, sym::Vec | sym::VecDeque) - && let ExprKind::Path(QPath::Resolved(None, container_path)) = recv.kind - && is_range_full(cx, arg, Some(container_path)) + && is_full_collection_range(cx, recv.res_local_id(), arg) { span_lint_and_sugg( cx, diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index c208b8b97506f..39c00337c6f77 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -120,7 +120,6 @@ use source::{SpanRangeExt, walk_span_to_context}; use visitors::{Visitable, for_each_unconsumed_temporary}; use crate::ast_utils::unordered_over; -use crate::consts::ConstEvalCtxt; use crate::higher::Range; use crate::msrvs::Msrv; use crate::res::{MaybeDef, MaybeQPath, MaybeResPath}; @@ -1329,59 +1328,23 @@ pub fn is_else_clause_in_let_else(tcx: TyCtxt<'_>, expr: &Expr<'_>) -> bool { }) } -/// Checks whether the given `Expr` is a range equivalent to a `RangeFull`. -/// -/// For the lower bound, this means that: -/// - either there is none -/// - or it is the smallest value that can be represented by the range's integer type -/// -/// For the upper bound, this means that: -/// - either there is none -/// - or it is the largest value that can be represented by the range's integer type and is -/// inclusive -/// - or it is a call to some container's `len` method and is exclusive, and the range is passed to -/// a method call on that same container (e.g. `v.drain(..v.len())`) -/// -/// If the given `Expr` is not some kind of range, the function returns `false`. -pub fn is_range_full(cx: &LateContext<'_>, expr: &Expr<'_>, container_path: Option<&Path<'_>>) -> bool { - let ty = cx.typeck_results().expr_ty(expr); +/// Checks whether the given `Expr` is a range over the entire container. +pub fn is_full_collection_range(cx: &LateContext<'_>, container: Option, expr: &Expr<'_>) -> bool { if let Some(Range { start, end, limits, .. }) = Range::hir(cx, expr) { - let start_is_none_or_min = start.is_none_or(|start| { - if let rustc_ty::Adt(_, subst) = ty.kind() - && let bnd_ty = subst.type_at(0) - && let Some(start_const) = ConstEvalCtxt::new(cx).eval(start) - { - start_const.is_numeric_min(cx.tcx, bnd_ty) - } else { - false - } - }); - let end_is_none_or_max = end.is_none_or(|end| match limits { - RangeLimits::Closed => { - if let rustc_ty::Adt(_, subst) = ty.kind() - && let bnd_ty = subst.type_at(0) - && let Some(end_const) = ConstEvalCtxt::new(cx).eval(end) + start.is_none_or(|start| is_integer_literal(start, 0)) + && end.is_none_or(|end| { + if limits == RangeLimits::HalfOpen + && let Some(container) = container + && let ExprKind::MethodCall(seg, recv, [], _) = end.kind { - end_const.is_numeric_max(cx.tcx, bnd_ty) + seg.ident.name == sym::len && recv.res_local_id() == Some(container) } else { false } - }, - RangeLimits::HalfOpen => { - if let Some(container_path) = container_path - && let ExprKind::MethodCall(name, self_arg, [], _) = end.kind - && name.ident.name == sym::len - && let ExprKind::Path(QPath::Resolved(None, path)) = self_arg.kind - { - container_path.res == path.res - } else { - false - } - }, - }); - return start_is_none_or_min && end_is_none_or_max; + }) + } else { + false } - false } /// Checks whether the given expression is a constant literal of the given value. diff --git a/tests/ui/clear_with_drain.fixed b/tests/ui/clear_with_drain.fixed index aaaec700cc9d2..5f8441c0470dc 100644 --- a/tests/ui/clear_with_drain.fixed +++ b/tests/ui/clear_with_drain.fixed @@ -20,11 +20,6 @@ fn vec_range() { let mut v = vec![1, 2, 3]; v.clear(); //~^ clear_with_drain - - // Do lint - let mut v = vec![1, 2, 3]; - v.clear(); - //~^ clear_with_drain } fn vec_range_from() { @@ -45,11 +40,6 @@ fn vec_range_from() { let mut v = vec![1, 2, 3]; v.clear(); //~^ clear_with_drain - - // Do lint - let mut v = vec![1, 2, 3]; - v.clear(); - //~^ clear_with_drain } fn vec_range_full() { @@ -124,11 +114,6 @@ fn vec_deque_range() { let mut deque = VecDeque::from([1, 2, 3]); deque.clear(); //~^ clear_with_drain - - // Do lint - let mut deque = VecDeque::from([1, 2, 3]); - deque.clear(); - //~^ clear_with_drain } fn vec_deque_range_from() { @@ -149,11 +134,6 @@ fn vec_deque_range_from() { let mut deque = VecDeque::from([1, 2, 3]); deque.clear(); //~^ clear_with_drain - - // Do lint - let mut deque = VecDeque::from([1, 2, 3]); - deque.clear(); - //~^ clear_with_drain } fn vec_deque_range_full() { @@ -228,11 +208,6 @@ fn string_range() { let mut s = String::from("Hello, world!"); s.clear(); //~^ clear_with_drain - - // Do lint - let mut s = String::from("Hello, world!"); - s.clear(); - //~^ clear_with_drain } fn string_range_from() { @@ -253,11 +228,6 @@ fn string_range_from() { let mut s = String::from("Hello, world!"); s.clear(); //~^ clear_with_drain - - // Do lint - let mut s = String::from("Hello, world!"); - s.clear(); - //~^ clear_with_drain } fn string_range_full() { diff --git a/tests/ui/clear_with_drain.rs b/tests/ui/clear_with_drain.rs index e36384e09c693..59024dcfe93d8 100644 --- a/tests/ui/clear_with_drain.rs +++ b/tests/ui/clear_with_drain.rs @@ -20,11 +20,6 @@ fn vec_range() { let mut v = vec![1, 2, 3]; v.drain(0..v.len()); //~^ clear_with_drain - - // Do lint - let mut v = vec![1, 2, 3]; - v.drain(usize::MIN..v.len()); - //~^ clear_with_drain } fn vec_range_from() { @@ -45,11 +40,6 @@ fn vec_range_from() { let mut v = vec![1, 2, 3]; v.drain(0..); //~^ clear_with_drain - - // Do lint - let mut v = vec![1, 2, 3]; - v.drain(usize::MIN..); - //~^ clear_with_drain } fn vec_range_full() { @@ -124,11 +114,6 @@ fn vec_deque_range() { let mut deque = VecDeque::from([1, 2, 3]); deque.drain(0..deque.len()); //~^ clear_with_drain - - // Do lint - let mut deque = VecDeque::from([1, 2, 3]); - deque.drain(usize::MIN..deque.len()); - //~^ clear_with_drain } fn vec_deque_range_from() { @@ -149,11 +134,6 @@ fn vec_deque_range_from() { let mut deque = VecDeque::from([1, 2, 3]); deque.drain(0..); //~^ clear_with_drain - - // Do lint - let mut deque = VecDeque::from([1, 2, 3]); - deque.drain(usize::MIN..); - //~^ clear_with_drain } fn vec_deque_range_full() { @@ -228,11 +208,6 @@ fn string_range() { let mut s = String::from("Hello, world!"); s.drain(0..s.len()); //~^ clear_with_drain - - // Do lint - let mut s = String::from("Hello, world!"); - s.drain(usize::MIN..s.len()); - //~^ clear_with_drain } fn string_range_from() { @@ -253,11 +228,6 @@ fn string_range_from() { let mut s = String::from("Hello, world!"); s.drain(0..); //~^ clear_with_drain - - // Do lint - let mut s = String::from("Hello, world!"); - s.drain(usize::MIN..); - //~^ clear_with_drain } fn string_range_full() { diff --git a/tests/ui/clear_with_drain.stderr b/tests/ui/clear_with_drain.stderr index 8b09c26e46af2..b4c71bf60be7f 100644 --- a/tests/ui/clear_with_drain.stderr +++ b/tests/ui/clear_with_drain.stderr @@ -8,124 +8,88 @@ LL | v.drain(0..v.len()); = help: to override `-D warnings` add `#[allow(clippy::clear_with_drain)]` error: `drain` used to clear a `Vec` - --> tests/ui/clear_with_drain.rs:26:7 - | -LL | v.drain(usize::MIN..v.len()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `clear()` - -error: `drain` used to clear a `Vec` - --> tests/ui/clear_with_drain.rs:46:7 + --> tests/ui/clear_with_drain.rs:41:7 | LL | v.drain(0..); | ^^^^^^^^^^ help: try: `clear()` error: `drain` used to clear a `Vec` - --> tests/ui/clear_with_drain.rs:51:7 - | -LL | v.drain(usize::MIN..); - | ^^^^^^^^^^^^^^^^^^^ help: try: `clear()` - -error: `drain` used to clear a `Vec` - --> tests/ui/clear_with_drain.rs:68:7 + --> tests/ui/clear_with_drain.rs:58:7 | LL | v.drain(..); | ^^^^^^^^^ help: try: `clear()` error: `drain` used to clear a `Vec` - --> tests/ui/clear_with_drain.rs:86:7 + --> tests/ui/clear_with_drain.rs:76:7 | LL | v.drain(..v.len()); | ^^^^^^^^^^^^^^^^ help: try: `clear()` error: `drain` used to clear a `VecDeque` - --> tests/ui/clear_with_drain.rs:125:11 + --> tests/ui/clear_with_drain.rs:115:11 | LL | deque.drain(0..deque.len()); | ^^^^^^^^^^^^^^^^^^^^^ help: try: `clear()` error: `drain` used to clear a `VecDeque` - --> tests/ui/clear_with_drain.rs:130:11 - | -LL | deque.drain(usize::MIN..deque.len()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `clear()` - -error: `drain` used to clear a `VecDeque` - --> tests/ui/clear_with_drain.rs:150:11 + --> tests/ui/clear_with_drain.rs:135:11 | LL | deque.drain(0..); | ^^^^^^^^^^ help: try: `clear()` error: `drain` used to clear a `VecDeque` - --> tests/ui/clear_with_drain.rs:155:11 - | -LL | deque.drain(usize::MIN..); - | ^^^^^^^^^^^^^^^^^^^ help: try: `clear()` - -error: `drain` used to clear a `VecDeque` - --> tests/ui/clear_with_drain.rs:172:11 + --> tests/ui/clear_with_drain.rs:152:11 | LL | deque.drain(..); | ^^^^^^^^^ help: try: `clear()` error: `drain` used to clear a `VecDeque` - --> tests/ui/clear_with_drain.rs:190:11 + --> tests/ui/clear_with_drain.rs:170:11 | LL | deque.drain(..deque.len()); | ^^^^^^^^^^^^^^^^^^^^ help: try: `clear()` error: `drain` used to clear a `String` - --> tests/ui/clear_with_drain.rs:229:7 + --> tests/ui/clear_with_drain.rs:209:7 | LL | s.drain(0..s.len()); | ^^^^^^^^^^^^^^^^^ help: try: `clear()` error: `drain` used to clear a `String` - --> tests/ui/clear_with_drain.rs:234:7 - | -LL | s.drain(usize::MIN..s.len()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `clear()` - -error: `drain` used to clear a `String` - --> tests/ui/clear_with_drain.rs:254:7 + --> tests/ui/clear_with_drain.rs:229:7 | LL | s.drain(0..); | ^^^^^^^^^^ help: try: `clear()` error: `drain` used to clear a `String` - --> tests/ui/clear_with_drain.rs:259:7 - | -LL | s.drain(usize::MIN..); - | ^^^^^^^^^^^^^^^^^^^ help: try: `clear()` - -error: `drain` used to clear a `String` - --> tests/ui/clear_with_drain.rs:276:7 + --> tests/ui/clear_with_drain.rs:246:7 | LL | s.drain(..); | ^^^^^^^^^ help: try: `clear()` error: `drain` used to clear a `String` - --> tests/ui/clear_with_drain.rs:294:7 + --> tests/ui/clear_with_drain.rs:264:7 | LL | s.drain(..s.len()); | ^^^^^^^^^^^^^^^^ help: try: `clear()` error: `drain` used to clear a `HashSet` - --> tests/ui/clear_with_drain.rs:333:9 + --> tests/ui/clear_with_drain.rs:303:9 | LL | set.drain(); | ^^^^^^^ help: try: `clear()` error: `drain` used to clear a `HashMap` - --> tests/ui/clear_with_drain.rs:353:9 + --> tests/ui/clear_with_drain.rs:323:9 | LL | map.drain(); | ^^^^^^^ help: try: `clear()` error: `drain` used to clear a `BinaryHeap` - --> tests/ui/clear_with_drain.rs:373:10 + --> tests/ui/clear_with_drain.rs:343:10 | LL | heap.drain(); | ^^^^^^^ help: try: `clear()` -error: aborting due to 21 previous errors +error: aborting due to 15 previous errors From 372057a78f0068766e547a993932ddf0daeeaba4 Mon Sep 17 00:00:00 2001 From: Mahdi Ali-Raihan Date: Thu, 11 Jun 2026 13:47:09 -0400 Subject: [PATCH 17/77] Added PhantomPinned diagnostic item and prevented dead field warning on PhantomPinned --- clippy_lints/src/missing_fields_in_debug.rs | 1 + clippy_lints/src/pub_underscore_fields.rs | 4 +++- clippy_utils/src/sym.rs | 1 + .../pub_underscore_fields.all_pub_fields.stderr | 12 ++++++------ .../pub_underscore_fields/pub_underscore_fields.rs | 4 +++- tests/ui/missing_fields_in_debug.rs | 12 +++++++----- 6 files changed, 21 insertions(+), 13 deletions(-) diff --git a/clippy_lints/src/missing_fields_in_debug.rs b/clippy_lints/src/missing_fields_in_debug.rs index 332c19e140b3e..634745422204f 100644 --- a/clippy_lints/src/missing_fields_in_debug.rs +++ b/clippy_lints/src/missing_fields_in_debug.rs @@ -185,6 +185,7 @@ fn check_struct<'tcx>( .filter_map(|field| { if field_accesses.contains(&field.ident.name) || field.ty.basic_res().is_lang_item(cx, LangItem::PhantomData) + || field.ty.basic_res().is_diag_item(cx, sym::PhantomPinned) { None } else { diff --git a/clippy_lints/src/pub_underscore_fields.rs b/clippy_lints/src/pub_underscore_fields.rs index 64724f7d01d00..92d1bf505bfaf 100644 --- a/clippy_lints/src/pub_underscore_fields.rs +++ b/clippy_lints/src/pub_underscore_fields.rs @@ -3,6 +3,7 @@ use clippy_config::types::PubUnderscoreFieldsBehaviour; use clippy_utils::attrs::is_doc_hidden; use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::res::{MaybeDef, MaybeResPath}; +use clippy_utils::sym::PhantomPinned; use rustc_hir::{FieldDef, Item, ItemKind, LangItem}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; @@ -75,8 +76,9 @@ impl<'tcx> LateLintPass<'tcx> for PubUnderscoreFields { if field.ident.as_str().starts_with('_') && is_visible(field) // We ignore fields that have `#[doc(hidden)]`. && !is_doc_hidden(cx.tcx.hir_attrs(field.hir_id)) - // We ignore fields that are `PhantomData`. + // We ignore fields that are `PhantomData` and `PhantomPinned`. && !field.ty.basic_res().is_lang_item(cx, LangItem::PhantomData) + && !field.ty.basic_res().is_diag_item(cx, PhantomPinned) { span_lint_hir_and_then( cx, diff --git a/clippy_utils/src/sym.rs b/clippy_utils/src/sym.rs index f414c0ac47fa4..59e98cdc7bef8 100644 --- a/clippy_utils/src/sym.rs +++ b/clippy_utils/src/sym.rs @@ -100,6 +100,7 @@ generate! { Path, PathBuf, PathLookup, + PhantomPinned, RangeBounds, RefCellRef, RefCellRefMut, diff --git a/tests/ui-toml/pub_underscore_fields/pub_underscore_fields.all_pub_fields.stderr b/tests/ui-toml/pub_underscore_fields/pub_underscore_fields.all_pub_fields.stderr index 40112fbf4c743..4632c06f095a3 100644 --- a/tests/ui-toml/pub_underscore_fields/pub_underscore_fields.all_pub_fields.stderr +++ b/tests/ui-toml/pub_underscore_fields/pub_underscore_fields.all_pub_fields.stderr @@ -9,7 +9,7 @@ LL | pub _b: u8, = help: to override `-D warnings` add `#[allow(clippy::pub_underscore_fields)]` error: field marked as public but also inferred as unused because it's prefixed with `_` - --> tests/ui-toml/pub_underscore_fields/pub_underscore_fields.rs:23:13 + --> tests/ui-toml/pub_underscore_fields/pub_underscore_fields.rs:24:13 | LL | pub(in crate::inner) _f: Option<()>, | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -17,7 +17,7 @@ LL | pub(in crate::inner) _f: Option<()>, = help: consider removing the underscore, or making the field private error: field marked as public but also inferred as unused because it's prefixed with `_` - --> tests/ui-toml/pub_underscore_fields/pub_underscore_fields.rs:28:13 + --> tests/ui-toml/pub_underscore_fields/pub_underscore_fields.rs:29:13 | LL | pub _g: String, | ^^^^^^ @@ -25,7 +25,7 @@ LL | pub _g: String, = help: consider removing the underscore, or making the field private error: field marked as public but also inferred as unused because it's prefixed with `_` - --> tests/ui-toml/pub_underscore_fields/pub_underscore_fields.rs:36:9 + --> tests/ui-toml/pub_underscore_fields/pub_underscore_fields.rs:37:9 | LL | pub _a: usize, | ^^^^^^ @@ -33,7 +33,7 @@ LL | pub _a: usize, = help: consider removing the underscore, or making the field private error: field marked as public but also inferred as unused because it's prefixed with `_` - --> tests/ui-toml/pub_underscore_fields/pub_underscore_fields.rs:44:9 + --> tests/ui-toml/pub_underscore_fields/pub_underscore_fields.rs:45:9 | LL | pub _c: i64, | ^^^^^^ @@ -41,7 +41,7 @@ LL | pub _c: i64, = help: consider removing the underscore, or making the field private error: field marked as public but also inferred as unused because it's prefixed with `_` - --> tests/ui-toml/pub_underscore_fields/pub_underscore_fields.rs:48:9 + --> tests/ui-toml/pub_underscore_fields/pub_underscore_fields.rs:49:9 | LL | pub _e: Option, | ^^^^^^ @@ -49,7 +49,7 @@ LL | pub _e: Option, = help: consider removing the underscore, or making the field private error: field marked as public but also inferred as unused because it's prefixed with `_` - --> tests/ui-toml/pub_underscore_fields/pub_underscore_fields.rs:62:9 + --> tests/ui-toml/pub_underscore_fields/pub_underscore_fields.rs:63:9 | LL | pub(crate) _b: Option, | ^^^^^^^^^^^^^ diff --git a/tests/ui-toml/pub_underscore_fields/pub_underscore_fields.rs b/tests/ui-toml/pub_underscore_fields/pub_underscore_fields.rs index 807469e2d8c5a..5a52cf78821b6 100644 --- a/tests/ui-toml/pub_underscore_fields/pub_underscore_fields.rs +++ b/tests/ui-toml/pub_underscore_fields/pub_underscore_fields.rs @@ -4,7 +4,7 @@ #![warn(clippy::pub_underscore_fields)] -use std::marker::PhantomData; +use std::marker::{PhantomData, PhantomPinned}; pub mod inner { use std::marker; @@ -15,6 +15,7 @@ pub mod inner { //~^ pub_underscore_fields _c: i32, pub _mark: marker::PhantomData, + pub _pinned: marker::PhantomPinned, } mod inner2 { @@ -68,6 +69,7 @@ fn main() { r#pub: bool, _pub: String, pub(crate) _mark: PhantomData, + pub(crate) _pinned: PhantomPinned, } // shouldn't warn when `#[allow]` is used on field level diff --git a/tests/ui/missing_fields_in_debug.rs b/tests/ui/missing_fields_in_debug.rs index 14803b5485a11..b206f4d8f8ce3 100644 --- a/tests/ui/missing_fields_in_debug.rs +++ b/tests/ui/missing_fields_in_debug.rs @@ -2,7 +2,7 @@ #![warn(clippy::missing_fields_in_debug)] use std::fmt; -use std::marker::PhantomData; +use std::marker::{PhantomData, PhantomPinned}; use std::ops::Deref; use std::thread::LocalKey; @@ -179,16 +179,18 @@ mod comment1175473620 { } // https://github.com/rust-lang/rust-clippy/pull/10616#discussion_r1175488757 -// PhantomData is an exception and does not need to be included -struct WithPD { +// https://github.com/rust-lang/rust/issues/154888 +// PhantomData & PhantomPinned are exceptions and do not need to be included +struct WithPDPP { a: u8, b: u8, c: PhantomData, + d: PhantomPinned, } -impl fmt::Debug for WithPD { +impl fmt::Debug for WithPDPP { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("WithPD") + f.debug_struct("WithPDPP") .field("a", &self.a) .field("b", &self.b) .finish() From ebedc9bd33913fb5bb473ccfbeba204271ef9c66 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Fri, 12 Jun 2026 13:17:07 -0700 Subject: [PATCH 18/77] unnecessary_lazy_evaluations: handle closure `->` Instead of bailing, this changes the lint to handle the return type and write out the correct result. If the function we're translating into can handle it, we use a turbofish, since that will influence type inference but not cause integer truncation. But, if that can't be done, it'll use `as` and let a future lint take care of that. --- clippy_lints/src/methods/mod.rs | 12 ++-- .../src/methods/unnecessary_lazy_eval.rs | 45 ++++++++---- tests/ui/unnecessary_lazy_eval.fixed | 12 ++++ tests/ui/unnecessary_lazy_eval.rs | 12 ++++ tests/ui/unnecessary_lazy_eval.stderr | 72 ++++++++++++------- tests/ui/unnecessary_lazy_eval_unfixable.rs | 6 -- .../ui/unnecessary_lazy_eval_unfixable.stderr | 14 +--- 7 files changed, 111 insertions(+), 62 deletions(-) diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index a7043d1359fa4..91cd6bff2fe66 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -5238,7 +5238,7 @@ impl Methods { let biom_option_linted = bind_instead_of_map::check_and_then_some(cx, expr, recv, arg); let biom_result_linted = bind_instead_of_map::check_and_then_ok(cx, expr, recv, arg); if !biom_option_linted && !biom_result_linted { - let ule_and_linted = unnecessary_lazy_eval::check(cx, expr, recv, arg, "and"); + let ule_and_linted = unnecessary_lazy_eval::check(cx, expr, recv, arg, "and", true); if !ule_and_linted { return_and_then::check(cx, expr, recv, arg); } @@ -5474,7 +5474,7 @@ impl Methods { get_last_with_len::check(cx, expr, recv, arg); }, (sym::get_or_insert_with, [arg]) => { - unnecessary_lazy_eval::check(cx, expr, recv, arg, "get_or_insert"); + unnecessary_lazy_eval::check(cx, expr, recv, arg, "get_or_insert", false); }, (sym::hash, [arg]) => { unit_hash::check(cx, expr, recv, arg); @@ -5629,14 +5629,14 @@ impl Methods { ptr_offset_by_literal::check(cx, expr, self.msrv); }, (sym::ok_or_else, [arg]) => { - unnecessary_lazy_eval::check(cx, expr, recv, arg, "ok_or"); + unnecessary_lazy_eval::check(cx, expr, recv, arg, "ok_or", true); }, (sym::open, [_]) => { open_options::check(cx, expr, recv); }, (sym::or_else, [arg]) => { if !bind_instead_of_map::check_or_else_err(cx, expr, recv, arg) { - unnecessary_lazy_eval::check(cx, expr, recv, arg, "or"); + unnecessary_lazy_eval::check(cx, expr, recv, arg, "or", false); } }, (sym::peek, []) => { @@ -5737,7 +5737,7 @@ impl Methods { if !self.msrv.meets(cx, msrvs::BOOL_THEN_SOME) { return; } - unnecessary_lazy_eval::check(cx, expr, recv, arg, "then_some"); + unnecessary_lazy_eval::check(cx, expr, recv, arg, "then_some", true); }, (sym::try_into, []) if cx.ty_based_def(expr).opt_parent(cx).is_diag_item(cx, sym::TryInto) => { unnecessary_fallible_conversions::check_method(cx, expr); @@ -5827,7 +5827,7 @@ impl Methods { ); }, _ => { - unnecessary_lazy_eval::check(cx, expr, recv, u_arg, "unwrap_or"); + unnecessary_lazy_eval::check(cx, expr, recv, u_arg, "unwrap_or", false); }, } unnecessary_literal_unwrap::check(cx, expr, recv, name, args); diff --git a/clippy_lints/src/methods/unnecessary_lazy_eval.rs b/clippy_lints/src/methods/unnecessary_lazy_eval.rs index 2869547650f31..8db54a0a28b8b 100644 --- a/clippy_lints/src/methods/unnecessary_lazy_eval.rs +++ b/clippy_lints/src/methods/unnecessary_lazy_eval.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::res::MaybeDef; -use clippy_utils::source::snippet; +use clippy_utils::source::{snippet, snippet_with_applicability}; use clippy_utils::{eager_or_lazy, is_from_proc_macro, usage}; use hir::FnRetTy; use rustc_errors::Applicability; @@ -18,6 +18,7 @@ pub(super) fn check<'tcx>( recv: &'tcx hir::Expr<'_>, arg: &'tcx hir::Expr<'_>, simplify_using: &str, + use_turbofish: bool, ) -> bool { let is_option = cx.typeck_results().expr_ty(recv).is_diag_item(cx, sym::Option); let is_result = cx.typeck_results().expr_ty(recv).is_diag_item(cx, sym::Result); @@ -46,23 +47,38 @@ pub(super) fn check<'tcx>( } else { "unnecessary closure used with `bool::then`" }; - let applicability = if body + let mut applicability = Applicability::MachineApplicable; + let (ascription, turbofish) = if body .params .iter() // bindings are checked to be unused above .all(|param| matches!(param.pat.kind, hir::PatKind::Binding(..) | hir::PatKind::Wild)) - && matches!( - fn_decl.output, + { + match fn_decl.output { FnRetTy::DefaultReturn(_) - | FnRetTy::Return(hir::Ty { - kind: hir::TyKind::Infer(()), - .. - }) - ) { - Applicability::MachineApplicable + | FnRetTy::Return(hir::Ty { + kind: hir::TyKind::Infer(()), + .. + }) => { + // type ascription is definitely not needed here + (String::new(), String::new()) + }, + FnRetTy::Return(ty) => { + // explicit type was given on the closure + // try to use turbofish for this, since it's less dangerous, + // but, failing that, use `as` + let ty = snippet_with_applicability(cx, ty.span, "_", &mut applicability); + if use_turbofish { + (String::new(), format!("::<{ty}>")) + } else { + (format!(" as {ty}"), String::new()) + } + }, + } } else { - // replacing the lambda may break type inference - Applicability::MaybeIncorrect + // can't infer the actual type + applicability = Applicability::MaybeIncorrect; + (String::new(), String::new()) }; // This is a duplicate of what's happening in clippy_lints::methods::method_call, @@ -73,7 +89,10 @@ pub(super) fn check<'tcx>( diag.span_suggestion_verbose( span, format!("use `{simplify_using}` instead"), - format!("{simplify_using}({})", snippet(cx, body_expr.span, "..")), + format!( + "{simplify_using}{turbofish}({}{ascription})", + snippet(cx, body_expr.span, "..") + ), applicability, ); }); diff --git a/tests/ui/unnecessary_lazy_eval.fixed b/tests/ui/unnecessary_lazy_eval.fixed index 409a8efbfeb95..c8d6b1832a710 100644 --- a/tests/ui/unnecessary_lazy_eval.fixed +++ b/tests/ui/unnecessary_lazy_eval.fixed @@ -240,6 +240,18 @@ fn main() { let _: Result = res.or_else(|err| Ok(err)); } +fn issue11672() { + // needs turbofish to disambiguate + let _ = true.then_some::<&[u8]>({ &[] }); + //~^ unnecessary_lazy_evaluations +} + +fn issue11672_as() { + // Return type annotation helps type inference and removing it can break code + let _ = None.get_or_insert({ &[] } as &[u8]); + //~^ unnecessary_lazy_evaluations +} + #[allow(unused)] fn issue9485() { // should not lint, is in proc macro diff --git a/tests/ui/unnecessary_lazy_eval.rs b/tests/ui/unnecessary_lazy_eval.rs index 54735023a935d..87e903c5bbb8c 100644 --- a/tests/ui/unnecessary_lazy_eval.rs +++ b/tests/ui/unnecessary_lazy_eval.rs @@ -240,6 +240,18 @@ fn main() { let _: Result = res.or_else(|err| Ok(err)); } +fn issue11672() { + // needs turbofish to disambiguate + let _ = true.then(|| -> &[u8] { &[] }); + //~^ unnecessary_lazy_evaluations +} + +fn issue11672_as() { + // Return type annotation helps type inference and removing it can break code + let _ = None.get_or_insert_with(|| -> &[u8] { &[] }); + //~^ unnecessary_lazy_evaluations +} + #[allow(unused)] fn issue9485() { // should not lint, is in proc macro diff --git a/tests/ui/unnecessary_lazy_eval.stderr b/tests/ui/unnecessary_lazy_eval.stderr index 75a06a419c71b..9b91b22f80d3a 100644 --- a/tests/ui/unnecessary_lazy_eval.stderr +++ b/tests/ui/unnecessary_lazy_eval.stderr @@ -484,7 +484,31 @@ LL + or(Ok(ext_str.some_field)); | error: unnecessary closure used with `bool::then` - --> tests/ui/unnecessary_lazy_eval.rs:259:14 + --> tests/ui/unnecessary_lazy_eval.rs:245:13 + | +LL | let _ = true.then(|| -> &[u8] { &[] }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `then_some` instead + | +LL - let _ = true.then(|| -> &[u8] { &[] }); +LL + let _ = true.then_some::<&[u8]>({ &[] }); + | + +error: unnecessary closure used to substitute value for `Option::None` + --> tests/ui/unnecessary_lazy_eval.rs:251:13 + | +LL | let _ = None.get_or_insert_with(|| -> &[u8] { &[] }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `get_or_insert` instead + | +LL - let _ = None.get_or_insert_with(|| -> &[u8] { &[] }); +LL + let _ = None.get_or_insert({ &[] } as &[u8]); + | + +error: unnecessary closure used with `bool::then` + --> tests/ui/unnecessary_lazy_eval.rs:271:14 | LL | let _x = false.then(|| i32::MAX + 1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -496,7 +520,7 @@ LL + let _x = false.then_some(i32::MAX + 1); | error: unnecessary closure used with `bool::then` - --> tests/ui/unnecessary_lazy_eval.rs:261:14 + --> tests/ui/unnecessary_lazy_eval.rs:273:14 | LL | let _x = false.then(|| i32::MAX * 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -508,7 +532,7 @@ LL + let _x = false.then_some(i32::MAX * 2); | error: unnecessary closure used with `bool::then` - --> tests/ui/unnecessary_lazy_eval.rs:263:14 + --> tests/ui/unnecessary_lazy_eval.rs:275:14 | LL | let _x = false.then(|| i32::MAX - 1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -520,7 +544,7 @@ LL + let _x = false.then_some(i32::MAX - 1); | error: unnecessary closure used with `bool::then` - --> tests/ui/unnecessary_lazy_eval.rs:265:14 + --> tests/ui/unnecessary_lazy_eval.rs:277:14 | LL | let _x = false.then(|| i32::MIN - 1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -532,7 +556,7 @@ LL + let _x = false.then_some(i32::MIN - 1); | error: unnecessary closure used with `bool::then` - --> tests/ui/unnecessary_lazy_eval.rs:267:14 + --> tests/ui/unnecessary_lazy_eval.rs:279:14 | LL | let _x = false.then(|| (1 + 2 * 3 - 2 / 3 + 9) << 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -544,7 +568,7 @@ LL + let _x = false.then_some((1 + 2 * 3 - 2 / 3 + 9) << 2); | error: unnecessary closure used with `bool::then` - --> tests/ui/unnecessary_lazy_eval.rs:269:14 + --> tests/ui/unnecessary_lazy_eval.rs:281:14 | LL | let _x = false.then(|| 255u8 << 7); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -556,7 +580,7 @@ LL + let _x = false.then_some(255u8 << 7); | error: unnecessary closure used with `bool::then` - --> tests/ui/unnecessary_lazy_eval.rs:271:14 + --> tests/ui/unnecessary_lazy_eval.rs:283:14 | LL | let _x = false.then(|| 255u8 << 8); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -568,7 +592,7 @@ LL + let _x = false.then_some(255u8 << 8); | error: unnecessary closure used with `bool::then` - --> tests/ui/unnecessary_lazy_eval.rs:273:14 + --> tests/ui/unnecessary_lazy_eval.rs:285:14 | LL | let _x = false.then(|| 255u8 >> 8); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -580,7 +604,7 @@ LL + let _x = false.then_some(255u8 >> 8); | error: unnecessary closure used with `bool::then` - --> tests/ui/unnecessary_lazy_eval.rs:276:14 + --> tests/ui/unnecessary_lazy_eval.rs:288:14 | LL | let _x = false.then(|| i32::MAX + -1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -592,7 +616,7 @@ LL + let _x = false.then_some(i32::MAX + -1); | error: unnecessary closure used with `bool::then` - --> tests/ui/unnecessary_lazy_eval.rs:278:14 + --> tests/ui/unnecessary_lazy_eval.rs:290:14 | LL | let _x = false.then(|| -i32::MAX); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -604,7 +628,7 @@ LL + let _x = false.then_some(-i32::MAX); | error: unnecessary closure used with `bool::then` - --> tests/ui/unnecessary_lazy_eval.rs:280:14 + --> tests/ui/unnecessary_lazy_eval.rs:292:14 | LL | let _x = false.then(|| -i32::MIN); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -616,7 +640,7 @@ LL + let _x = false.then_some(-i32::MIN); | error: unnecessary closure used with `bool::then` - --> tests/ui/unnecessary_lazy_eval.rs:283:14 + --> tests/ui/unnecessary_lazy_eval.rs:295:14 | LL | let _x = false.then(|| 255 >> -7); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -628,7 +652,7 @@ LL + let _x = false.then_some(255 >> -7); | error: unnecessary closure used with `bool::then` - --> tests/ui/unnecessary_lazy_eval.rs:285:14 + --> tests/ui/unnecessary_lazy_eval.rs:297:14 | LL | let _x = false.then(|| 255 << -1); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -640,7 +664,7 @@ LL + let _x = false.then_some(255 << -1); | error: unnecessary closure used with `bool::then` - --> tests/ui/unnecessary_lazy_eval.rs:287:14 + --> tests/ui/unnecessary_lazy_eval.rs:299:14 | LL | let _x = false.then(|| 1 / 0); | ^^^^^^^^^^^^^^^^^^^^ @@ -652,7 +676,7 @@ LL + let _x = false.then_some(1 / 0); | error: unnecessary closure used with `bool::then` - --> tests/ui/unnecessary_lazy_eval.rs:289:14 + --> tests/ui/unnecessary_lazy_eval.rs:301:14 | LL | let _x = false.then(|| x << -1); | ^^^^^^^^^^^^^^^^^^^^^^ @@ -664,7 +688,7 @@ LL + let _x = false.then_some(x << -1); | error: unnecessary closure used with `bool::then` - --> tests/ui/unnecessary_lazy_eval.rs:291:14 + --> tests/ui/unnecessary_lazy_eval.rs:303:14 | LL | let _x = false.then(|| x << 2); | ^^^^^^^^^^^^^^^^^^^^^ @@ -676,7 +700,7 @@ LL + let _x = false.then_some(x << 2); | error: unnecessary closure used with `bool::then` - --> tests/ui/unnecessary_lazy_eval.rs:301:14 + --> tests/ui/unnecessary_lazy_eval.rs:313:14 | LL | let _x = false.then(|| x / 0); | ^^^^^^^^^^^^^^^^^^^^ @@ -688,7 +712,7 @@ LL + let _x = false.then_some(x / 0); | error: unnecessary closure used with `bool::then` - --> tests/ui/unnecessary_lazy_eval.rs:303:14 + --> tests/ui/unnecessary_lazy_eval.rs:315:14 | LL | let _x = false.then(|| x % 0); | ^^^^^^^^^^^^^^^^^^^^ @@ -700,7 +724,7 @@ LL + let _x = false.then_some(x % 0); | error: unnecessary closure used with `bool::then` - --> tests/ui/unnecessary_lazy_eval.rs:306:14 + --> tests/ui/unnecessary_lazy_eval.rs:318:14 | LL | let _x = false.then(|| 1 / -1); | ^^^^^^^^^^^^^^^^^^^^^ @@ -712,7 +736,7 @@ LL + let _x = false.then_some(1 / -1); | error: unnecessary closure used with `bool::then` - --> tests/ui/unnecessary_lazy_eval.rs:308:14 + --> tests/ui/unnecessary_lazy_eval.rs:320:14 | LL | let _x = false.then(|| i32::MIN / -1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -724,7 +748,7 @@ LL + let _x = false.then_some(i32::MIN / -1); | error: unnecessary closure used with `bool::then` - --> tests/ui/unnecessary_lazy_eval.rs:311:14 + --> tests/ui/unnecessary_lazy_eval.rs:323:14 | LL | let _x = false.then(|| i32::MIN / 0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -736,7 +760,7 @@ LL + let _x = false.then_some(i32::MIN / 0); | error: unnecessary closure used with `bool::then` - --> tests/ui/unnecessary_lazy_eval.rs:313:14 + --> tests/ui/unnecessary_lazy_eval.rs:325:14 | LL | let _x = false.then(|| 4 / 2); | ^^^^^^^^^^^^^^^^^^^^ @@ -748,7 +772,7 @@ LL + let _x = false.then_some(4 / 2); | error: unnecessary closure used with `bool::then` - --> tests/ui/unnecessary_lazy_eval.rs:321:14 + --> tests/ui/unnecessary_lazy_eval.rs:333:14 | LL | let _x = false.then(|| f1 + f2); | ^^^^^^^^^^^^^^^^^^^^^^ @@ -759,5 +783,5 @@ LL - let _x = false.then(|| f1 + f2); LL + let _x = false.then_some(f1 + f2); | -error: aborting due to 63 previous errors +error: aborting due to 65 previous errors diff --git a/tests/ui/unnecessary_lazy_eval_unfixable.rs b/tests/ui/unnecessary_lazy_eval_unfixable.rs index 6d28d544dfe0b..adb386bd31623 100644 --- a/tests/ui/unnecessary_lazy_eval_unfixable.rs +++ b/tests/ui/unnecessary_lazy_eval_unfixable.rs @@ -26,9 +26,3 @@ fn main() { let arr = [(Some(1),)]; Some(&0).and_then(|&i| arr[i].0); } - -fn issue11672() { - // Return type annotation helps type inference and removing it can break code - let _ = true.then(|| -> &[u8] { &[] }); - //~^ unnecessary_lazy_evaluations -} diff --git a/tests/ui/unnecessary_lazy_eval_unfixable.stderr b/tests/ui/unnecessary_lazy_eval_unfixable.stderr index 5174acc1e9f95..35e68957ca394 100644 --- a/tests/ui/unnecessary_lazy_eval_unfixable.stderr +++ b/tests/ui/unnecessary_lazy_eval_unfixable.stderr @@ -36,17 +36,5 @@ LL - let _ = Ok(1).unwrap_or_else(|SomeStruct { .. }| 2); LL + let _ = Ok(1).unwrap_or(2); | -error: unnecessary closure used with `bool::then` - --> tests/ui/unnecessary_lazy_eval_unfixable.rs:32:13 - | -LL | let _ = true.then(|| -> &[u8] { &[] }); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: use `then_some` instead - | -LL - let _ = true.then(|| -> &[u8] { &[] }); -LL + let _ = true.then_some({ &[] }); - | - -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors From 934018e8c72e817b98b4e9d41ae6b45c98749b20 Mon Sep 17 00:00:00 2001 From: xmakro Date: Fri, 12 Jun 2026 15:09:44 -0700 Subject: [PATCH 19/77] perf: skip doc_markdown text collection and word scan when the lint is allowed --- clippy_lints/src/doc/mod.rs | 43 +++++++++++++++++++++++++------------ 1 file changed, 29 insertions(+), 14 deletions(-) diff --git a/clippy_lints/src/doc/mod.rs b/clippy_lints/src/doc/mod.rs index 81da571bdd601..c5816cb8b2d63 100644 --- a/clippy_lints/src/doc/mod.rs +++ b/clippy_lints/src/doc/mod.rs @@ -1124,6 +1124,9 @@ fn check_doc<'a, Events: Iterator, Range, Range, Range Date: Fri, 12 Jun 2026 15:48:48 -0700 Subject: [PATCH 20/77] perf: check is_in_test last in incompatible_msrv --- clippy_lints/src/incompatible_msrv.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/incompatible_msrv.rs b/clippy_lints/src/incompatible_msrv.rs index 1ae8198a432dd..99e7d202fe46f 100644 --- a/clippy_lints/src/incompatible_msrv.rs +++ b/clippy_lints/src/incompatible_msrv.rs @@ -193,10 +193,11 @@ impl IncompatibleMsrv { } } - if (self.check_in_tests || !is_in_test(cx.tcx, node)) - && let Some(current) = self.msrv.current(cx) + // Check `is_in_test` last as it walks the HIR parent chain. + if let Some(current) = self.msrv.current(cx) && let Availability::Since(version) = self.get_def_id_availability(cx.tcx, def_id, needs_const) && version > current + && (self.check_in_tests || !is_in_test(cx.tcx, node)) { span_lint_and_then( cx, From 81c4ee5d01a08abed69b1d2002b53e6a3f72e750 Mon Sep 17 00:00:00 2001 From: xmakro Date: Fri, 12 Jun 2026 20:29:50 -0700 Subject: [PATCH 21/77] perf: check the token kind before extracting source in early literal lints --- clippy_lints/src/literal_representation.rs | 6 +++++- clippy_lints/src/misc_early/mod.rs | 14 +++++++++----- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/clippy_lints/src/literal_representation.rs b/clippy_lints/src/literal_representation.rs index 2ec046c8d6ba4..db99f601c8932 100644 --- a/clippy_lints/src/literal_representation.rs +++ b/clippy_lints/src/literal_representation.rs @@ -207,7 +207,9 @@ pub struct LiteralDigitGrouping { impl EarlyLintPass for LiteralDigitGrouping { fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { + // `NumericLiteral::from_lit_kind` only accepts integer and float literals. if let ExprKind::Lit(lit) = expr.kind + && matches!(lit.kind, token::LitKind::Integer | token::LitKind::Float) && !expr.span.in_external_macro(cx.sess().source_map()) { self.check_lit(cx, lit, expr.span); @@ -418,7 +420,9 @@ pub struct DecimalLiteralRepresentation { impl EarlyLintPass for DecimalLiteralRepresentation { fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { + // Only integer tokens can produce `LitKind::Int`. if let ExprKind::Lit(lit) = expr.kind + && lit.kind == token::LitKind::Integer && !expr.span.in_external_macro(cx.sess().source_map()) { self.check_lit(cx, lit, expr.span); @@ -436,10 +440,10 @@ impl DecimalLiteralRepresentation { // Lint integral literals. if let Ok(lit_kind) = LitKind::from_token_lit(lit) && let LitKind::Int(val, _) = lit_kind + && val >= u128::from(self.threshold) && let Some(src) = span.get_source_text(cx) && let Some(num_lit) = NumericLiteral::from_lit_kind(&src, &lit_kind) && num_lit.radix == Radix::Decimal - && val >= u128::from(self.threshold) { let hex = format!("{val:#X}"); let num_lit = NumericLiteral::new(&hex, num_lit.suffix, false); diff --git a/clippy_lints/src/misc_early/mod.rs b/clippy_lints/src/misc_early/mod.rs index 314004621ce05..79e56b7de41f8 100644 --- a/clippy_lints/src/misc_early/mod.rs +++ b/clippy_lints/src/misc_early/mod.rs @@ -333,11 +333,15 @@ impl EarlyLintPass for MiscEarlyLints { } fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { - if expr.span.in_external_macro(cx.sess().source_map()) { - return; - } - - if let ExprKind::Lit(lit) = expr.kind { + // `check_lit` only lints integer literals and suffixed float literals. + if let ExprKind::Lit(lit) = expr.kind + && match lit.kind { + token::LitKind::Integer => true, + token::LitKind::Float => lit.suffix.is_some(), + _ => false, + } + && !expr.span.in_external_macro(cx.sess().source_map()) + { MiscEarlyLints::check_lit(cx, lit, expr.span); } } From aa783f197ece05f2d1b13928119ef44d747be0c1 Mon Sep 17 00:00:00 2001 From: xmakro Date: Fri, 12 Jun 2026 15:56:16 -0700 Subject: [PATCH 22/77] perf: match expression shape before MSRV check in cloned_ref_to_slice_refs --- clippy_lints/src/cloned_ref_to_slice_refs.rs | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/clippy_lints/src/cloned_ref_to_slice_refs.rs b/clippy_lints/src/cloned_ref_to_slice_refs.rs index 4f663f4aa9098..980584e9a1eec 100644 --- a/clippy_lints/src/cloned_ref_to_slice_refs.rs +++ b/clippy_lints/src/cloned_ref_to_slice_refs.rs @@ -64,15 +64,8 @@ impl<'a> ClonedRefToSliceRefs<'a> { impl<'tcx> LateLintPass<'tcx> for ClonedRefToSliceRefs<'_> { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) { - if self.msrv.meets(cx, { - if is_in_const_context(cx) { - msrvs::CONST_SLICE_FROM_REF - } else { - msrvs::SLICE_FROM_REF - } - }) - // `&[foo.clone()]` expressions - && let ExprKind::AddrOf(_, mutability, arr) = &expr.kind + // `&[foo.clone()]` expressions + if let ExprKind::AddrOf(_, mutability, arr) = &expr.kind // mutable references would have a different meaning && mutability.is_not() @@ -81,6 +74,14 @@ impl<'tcx> LateLintPass<'tcx> for ClonedRefToSliceRefs<'_> { // check for clones && let ExprKind::MethodCall(path, recv, _, _) = item.kind + + && self.msrv.meets(cx, { + if is_in_const_context(cx) { + msrvs::CONST_SLICE_FROM_REF + } else { + msrvs::SLICE_FROM_REF + } + }) && let Some(adjustment) = is_needless_clone_or_equivalent(cx, recv, path.ident.name, item.hir_id) // check for immutability or purity From 75b49dfb9cc46fdd4521556bb052c613e63642fe Mon Sep 17 00:00:00 2001 From: xmakro Date: Fri, 12 Jun 2026 15:19:46 -0700 Subject: [PATCH 23/77] perf: compare method names before type queries in three lint passes --- clippy_lints/src/minmax.rs | 11 ++++++----- clippy_lints/src/string_patterns.rs | 4 ++-- clippy_lints/src/useless_conversion.rs | 8 ++++---- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/clippy_lints/src/minmax.rs b/clippy_lints/src/minmax.rs index ba62853c74571..74da699e3c006 100644 --- a/clippy_lints/src/minmax.rs +++ b/clippy_lints/src/minmax.rs @@ -79,14 +79,15 @@ fn min_max<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<(MinMax, Cons } }, ExprKind::MethodCall(path, receiver, args @ [_], _) => { + let m = match path.ident.name { + sym::max => MinMax::Max, + sym::min => MinMax::Min, + _ => return None, + }; if cx.typeck_results().expr_ty(receiver).is_floating_point() || cx.ty_based_def(expr).opt_parent(cx).is_diag_item(cx, sym::Ord) { - match path.ident.name { - sym::max => fetch_const(cx, expr.span.ctxt(), Some(receiver), args, MinMax::Max), - sym::min => fetch_const(cx, expr.span.ctxt(), Some(receiver), args, MinMax::Min), - _ => None, - } + fetch_const(cx, expr.span.ctxt(), Some(receiver), args, m) } else { None } diff --git a/clippy_lints/src/string_patterns.rs b/clippy_lints/src/string_patterns.rs index b4eb8977bf0fb..7ddd6b1b89499 100644 --- a/clippy_lints/src/string_patterns.rs +++ b/clippy_lints/src/string_patterns.rs @@ -230,13 +230,13 @@ impl<'tcx> LateLintPass<'tcx> for StringPatterns { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if !expr.span.from_expansion() && let ExprKind::MethodCall(method, receiver, args, _) = expr.kind - && let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty_adjusted(receiver).kind() - && ty.is_str() && let method_name = method.ident.name && let Some(&(_, pos)) = PATTERN_METHODS .iter() .find(|(array_method_name, _)| *array_method_name == method_name) && let Some(arg) = args.get(pos) + && let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty_adjusted(receiver).kind() + && ty.is_str() { check_single_char_pattern_lint(cx, arg); diff --git a/clippy_lints/src/useless_conversion.rs b/clippy_lints/src/useless_conversion.rs index d6db088ba76c0..766659f426aea 100644 --- a/clippy_lints/src/useless_conversion.rs +++ b/clippy_lints/src/useless_conversion.rs @@ -132,8 +132,8 @@ fn into_iter_bound<'tcx>( /// Extracts the receiver of a `.into_iter()` method call. fn into_iter_call<'hir>(cx: &LateContext<'_>, expr: &'hir Expr<'hir>) -> Option<&'hir Expr<'hir>> { if let ExprKind::MethodCall(name, recv, [], _) = expr.kind - && cx.ty_based_def(expr).opt_parent(cx).is_diag_item(cx, sym::IntoIterator) && name.ident.name == sym::into_iter + && cx.ty_based_def(expr).opt_parent(cx).is_diag_item(cx, sym::IntoIterator) { Some(recv) } else { @@ -208,7 +208,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { }, ExprKind::MethodCall(name, recv, [], _) => { - if cx.ty_based_def(e).opt_parent(cx).is_diag_item(cx, sym::Into) && name.ident.name == sym::into { + if name.ident.name == sym::into && cx.ty_based_def(e).opt_parent(cx).is_diag_item(cx, sym::Into) { let a = cx.typeck_results().expr_ty(e); let b = cx.typeck_results().expr_ty(recv); if same_type_modulo_regions(a, b) { @@ -393,8 +393,8 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { ); } } - if cx.ty_based_def(e).opt_parent(cx).is_diag_item(cx, sym::TryInto) - && name.ident.name == sym::try_into + if name.ident.name == sym::try_into + && cx.ty_based_def(e).opt_parent(cx).is_diag_item(cx, sym::TryInto) && let a = cx.typeck_results().expr_ty(e) && let b = cx.typeck_results().expr_ty(recv) && a.is_diag_item(cx, sym::Result) From 49bb992983166ac8940dcca691d81fd3ec449ca2 Mon Sep 17 00:00:00 2001 From: xmakro Date: Fri, 12 Jun 2026 15:07:34 -0700 Subject: [PATCH 24/77] perf: check the method name first in or_fun_call --- clippy_lints/src/methods/or_fun_call.rs | 29 ++++++++++++++++++++----- 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/clippy_lints/src/methods/or_fun_call.rs b/clippy_lints/src/methods/or_fun_call.rs index a07cd5a8925ae..0d2f57ce334e7 100644 --- a/clippy_lints/src/methods/or_fun_call.rs +++ b/clippy_lints/src/methods/or_fun_call.rs @@ -30,6 +30,23 @@ pub(super) fn check<'tcx>( args: &'tcx [hir::Expr<'_>], msrv: Msrv, ) { + // Bail out early unless the method is one that `check_unwrap_or_default` or + // `check_or_fn_call` can lint, to avoid walking the argument of every method call. + if !matches!( + name, + sym::unwrap_or + | sym::unwrap_or_else + | sym::or_insert + | sym::or_insert_with + | sym::get_or_insert + | sym::map_or + | sym::ok_or + | sym::or + | sym::and + ) { + return; + } + if let [arg] = args { let inner_arg = peel_blocks(arg); for_each_expr(cx, inner_arg, |ex| { @@ -112,6 +129,12 @@ fn check_unwrap_or_default( method_span: Span, msrv: Msrv, ) -> bool { + let sugg = match (name, call_expr.is_some()) { + (sym::unwrap_or, true) | (sym::unwrap_or_else, false) => sym::unwrap_or_default, + (sym::or_insert, true) | (sym::or_insert_with, false) => sym::or_default, + _ => return false, + }; + let receiver_ty = cx.typeck_results().expr_ty_adjusted(receiver).peel_refs(); // Check MSRV, but only for `Result::unwrap_or_default` @@ -150,12 +173,6 @@ fn check_unwrap_or_default( } }; - let sugg = match (name, call_expr.is_some()) { - (sym::unwrap_or, true) | (sym::unwrap_or_else, false) => sym::unwrap_or_default, - (sym::or_insert, true) | (sym::or_insert_with, false) => sym::or_default, - _ => return false, - }; - let Some(suggested_method_def_id) = receiver_ty.ty_adt_def().and_then(|adt_def| { cx.tcx .inherent_impls(adt_def.did()) From a972a8856bfb3618efe63beadada579d933af279 Mon Sep 17 00:00:00 2001 From: xmakro Date: Fri, 12 Jun 2026 15:44:22 -0700 Subject: [PATCH 25/77] perf: skip single_component_path_imports module walk when nothing to lint --- .../src/single_component_path_imports.rs | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/clippy_lints/src/single_component_path_imports.rs b/clippy_lints/src/single_component_path_imports.rs index aba51114c533a..67c8710b80ec8 100644 --- a/clippy_lints/src/single_component_path_imports.rs +++ b/clippy_lints/src/single_component_path_imports.rs @@ -146,16 +146,24 @@ impl SingleComponentPathImports { // ``` let mut macros = Vec::new(); - let mut import_usage_visitor = ImportUsageVisitor::default(); for item in items { self.track_uses(item, &mut imports_reused_with_self, &mut single_use_usages, &mut macros); + } + + // Only walk the module's AST in search of `self::xxx` paths when there are single + // component imports left to lint, as the visitor recurses into every nested item. + single_use_usages.retain(|usage| !imports_reused_with_self.contains(&usage.name)); + if single_use_usages.is_empty() { + return; + } + + let mut import_usage_visitor = ImportUsageVisitor::default(); + for item in items { import_usage_visitor.visit_item(item); } for usage in single_use_usages { - if !imports_reused_with_self.contains(&usage.name) - && !import_usage_visitor.imports_referenced_with_self.contains(&usage.name) - { + if !import_usage_visitor.imports_referenced_with_self.contains(&usage.name) { self.found.entry(usage.item_id).or_default().push(usage); } } From 2027f8ad957061d69858ecf453579f9edd2276b8 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Fri, 12 Jun 2026 21:56:43 -0700 Subject: [PATCH 26/77] Address nits - make the comments more specific and useful - add return-type ascription even if there are params that still prevent this from being a machine applicable lint --- .../src/methods/unnecessary_lazy_eval.rs | 57 ++++++++++--------- tests/ui/unnecessary_lazy_eval_unfixable.rs | 2 + .../ui/unnecessary_lazy_eval_unfixable.stderr | 18 +++++- 3 files changed, 48 insertions(+), 29 deletions(-) diff --git a/clippy_lints/src/methods/unnecessary_lazy_eval.rs b/clippy_lints/src/methods/unnecessary_lazy_eval.rs index 8db54a0a28b8b..0b3c8146b9f76 100644 --- a/clippy_lints/src/methods/unnecessary_lazy_eval.rs +++ b/clippy_lints/src/methods/unnecessary_lazy_eval.rs @@ -47,38 +47,43 @@ pub(super) fn check<'tcx>( } else { "unnecessary closure used with `bool::then`" }; + let mut applicability = Applicability::MachineApplicable; - let (ascription, turbofish) = if body + if body .params .iter() // bindings are checked to be unused above - .all(|param| matches!(param.pat.kind, hir::PatKind::Binding(..) | hir::PatKind::Wild)) + .any(|param| !matches!(param.pat.kind, hir::PatKind::Binding(..) | hir::PatKind::Wild)) { - match fn_decl.output { - FnRetTy::DefaultReturn(_) - | FnRetTy::Return(hir::Ty { - kind: hir::TyKind::Infer(()), - .. - }) => { - // type ascription is definitely not needed here - (String::new(), String::new()) - }, - FnRetTy::Return(ty) => { - // explicit type was given on the closure - // try to use turbofish for this, since it's less dangerous, - // but, failing that, use `as` - let ty = snippet_with_applicability(cx, ty.span, "_", &mut applicability); - if use_turbofish { - (String::new(), format!("::<{ty}>")) - } else { - (format!(" as {ty}"), String::new()) - } - }, - } - } else { - // can't infer the actual type + // If the closure parameters have a pattern, + // it might be required for type inferrence. applicability = Applicability::MaybeIncorrect; - (String::new(), String::new()) + } + let (ascription, turbofish) = match fn_decl.output { + FnRetTy::DefaultReturn(_) + | FnRetTy::Return(hir::Ty { + kind: hir::TyKind::Infer(()), + .. + }) => { + // if the closure has no explicit return type, + // then there's nothing to preserve + (String::new(), String::new()) + }, + FnRetTy::Return(ty) => { + // explicit return type was given on the closure + // + // we can preserve this information using `as`, but `as` is + // a somewhat dangerous feature, because it can be used to + // truncate integers + // + // if possible, use turbofish to preserve the type information + let ty = snippet_with_applicability(cx, ty.span, "_", &mut applicability); + if use_turbofish { + (String::new(), format!("::<{ty}>")) + } else { + (format!(" as {ty}"), String::new()) + } + }, }; // This is a duplicate of what's happening in clippy_lints::methods::method_call, diff --git a/tests/ui/unnecessary_lazy_eval_unfixable.rs b/tests/ui/unnecessary_lazy_eval_unfixable.rs index adb386bd31623..7ceda40597942 100644 --- a/tests/ui/unnecessary_lazy_eval_unfixable.rs +++ b/tests/ui/unnecessary_lazy_eval_unfixable.rs @@ -12,6 +12,8 @@ fn main() { // fix will break type inference let _ = Ok(1).unwrap_or_else(|()| 2); //~^ unnecessary_lazy_evaluations + let _ = Ok(1).unwrap_or_else(|()| -> i32 { 2 }); + //~^ unnecessary_lazy_evaluations mod e { pub struct E; diff --git a/tests/ui/unnecessary_lazy_eval_unfixable.stderr b/tests/ui/unnecessary_lazy_eval_unfixable.stderr index 35e68957ca394..97e9ef621cee0 100644 --- a/tests/ui/unnecessary_lazy_eval_unfixable.stderr +++ b/tests/ui/unnecessary_lazy_eval_unfixable.stderr @@ -13,7 +13,19 @@ LL + let _ = Ok(1).unwrap_or(2); | error: unnecessary closure used to substitute value for `Result::Err` - --> tests/ui/unnecessary_lazy_eval_unfixable.rs:19:13 + --> tests/ui/unnecessary_lazy_eval_unfixable.rs:15:13 + | +LL | let _ = Ok(1).unwrap_or_else(|()| -> i32 { 2 }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `unwrap_or` instead + | +LL - let _ = Ok(1).unwrap_or_else(|()| -> i32 { 2 }); +LL + let _ = Ok(1).unwrap_or({ 2 } as i32); + | + +error: unnecessary closure used to substitute value for `Result::Err` + --> tests/ui/unnecessary_lazy_eval_unfixable.rs:21:13 | LL | let _ = Ok(1).unwrap_or_else(|e::E| 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -25,7 +37,7 @@ LL + let _ = Ok(1).unwrap_or(2); | error: unnecessary closure used to substitute value for `Result::Err` - --> tests/ui/unnecessary_lazy_eval_unfixable.rs:22:13 + --> tests/ui/unnecessary_lazy_eval_unfixable.rs:24:13 | LL | let _ = Ok(1).unwrap_or_else(|SomeStruct { .. }| 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -36,5 +48,5 @@ LL - let _ = Ok(1).unwrap_or_else(|SomeStruct { .. }| 2); LL + let _ = Ok(1).unwrap_or(2); | -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors From c749c60a5428ca214cc46bbb30a9d19b95739ccf Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Sat, 13 Jun 2026 10:28:57 +0200 Subject: [PATCH 27/77] Be less assertive about the gains obtained through `mul_add` --- .../src/floating_point_arithmetic/mul_add.rs | 3 +- tests/ui/floating_point_mul_add.stderr | 41 ++++++++++--------- 2 files changed, 23 insertions(+), 21 deletions(-) diff --git a/clippy_lints/src/floating_point_arithmetic/mul_add.rs b/clippy_lints/src/floating_point_arithmetic/mul_add.rs index 888d5b7b762a0..eb96e65638445 100644 --- a/clippy_lints/src/floating_point_arithmetic/mul_add.rs +++ b/clippy_lints/src/floating_point_arithmetic/mul_add.rs @@ -91,7 +91,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) { cx, SUBOPTIMAL_FLOPS, expr.span, - "multiply and add expressions can be calculated more efficiently and accurately", + "multiply and add expressions may be calculated more efficiently and accurately", |diag| { let maybe_neg_sugg = |expr, app: &mut _| { let sugg = Sugg::hir_with_applicability(cx, expr, "_", app); @@ -120,6 +120,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) { }, app, ); + diag.note_once("the performance gain from `mul_add` may vary depending on the target architecture"); }, ); } diff --git a/tests/ui/floating_point_mul_add.stderr b/tests/ui/floating_point_mul_add.stderr index 3f2ca76826f45..b14d0585f2c96 100644 --- a/tests/ui/floating_point_mul_add.stderr +++ b/tests/ui/floating_point_mul_add.stderr @@ -1,121 +1,122 @@ -error: multiply and add expressions can be calculated more efficiently and accurately +error: multiply and add expressions may be calculated more efficiently and accurately --> tests/ui/floating_point_mul_add.rs:19:13 | LL | let _ = a * b + c; | ^^^^^^^^^ help: consider using: `a.mul_add(b, c)` | + = note: the performance gain from `mul_add` may vary depending on the target architecture = note: `-D clippy::suboptimal-flops` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::suboptimal_flops)]` -error: multiply and add expressions can be calculated more efficiently and accurately +error: multiply and add expressions may be calculated more efficiently and accurately --> tests/ui/floating_point_mul_add.rs:21:13 | LL | let _ = a * b - c; | ^^^^^^^^^ help: consider using: `a.mul_add(b, -c)` -error: multiply and add expressions can be calculated more efficiently and accurately +error: multiply and add expressions may be calculated more efficiently and accurately --> tests/ui/floating_point_mul_add.rs:23:13 | LL | let _ = c + a * b; | ^^^^^^^^^ help: consider using: `a.mul_add(b, c)` -error: multiply and add expressions can be calculated more efficiently and accurately +error: multiply and add expressions may be calculated more efficiently and accurately --> tests/ui/floating_point_mul_add.rs:25:13 | LL | let _ = c - a * b; | ^^^^^^^^^ help: consider using: `a.mul_add(-b, c)` -error: multiply and add expressions can be calculated more efficiently and accurately +error: multiply and add expressions may be calculated more efficiently and accurately --> tests/ui/floating_point_mul_add.rs:27:13 | LL | let _ = a + 2.0 * 4.0; | ^^^^^^^^^^^^^ help: consider using: `2.0f64.mul_add(4.0, a)` -error: multiply and add expressions can be calculated more efficiently and accurately +error: multiply and add expressions may be calculated more efficiently and accurately --> tests/ui/floating_point_mul_add.rs:29:13 | LL | let _ = a + 2. * 4.; | ^^^^^^^^^^^ help: consider using: `2.0f64.mul_add(4., a)` -error: multiply and add expressions can be calculated more efficiently and accurately +error: multiply and add expressions may be calculated more efficiently and accurately --> tests/ui/floating_point_mul_add.rs:32:13 | LL | let _ = (a * b) + c; | ^^^^^^^^^^^ help: consider using: `a.mul_add(b, c)` -error: multiply and add expressions can be calculated more efficiently and accurately +error: multiply and add expressions may be calculated more efficiently and accurately --> tests/ui/floating_point_mul_add.rs:34:13 | LL | let _ = c + (a * b); | ^^^^^^^^^^^ help: consider using: `a.mul_add(b, c)` -error: multiply and add expressions can be calculated more efficiently and accurately +error: multiply and add expressions may be calculated more efficiently and accurately --> tests/ui/floating_point_mul_add.rs:36:13 | LL | let _ = a * b * c + d; | ^^^^^^^^^^^^^ help: consider using: `(a * b).mul_add(c, d)` -error: multiply and add expressions can be calculated more efficiently and accurately +error: multiply and add expressions may be calculated more efficiently and accurately --> tests/ui/floating_point_mul_add.rs:39:13 | LL | let _ = a.mul_add(b, c) * a.mul_add(b, c) + a.mul_add(b, c) + c; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `a.mul_add(b, c).mul_add(a.mul_add(b, c), a.mul_add(b, c))` -error: multiply and add expressions can be calculated more efficiently and accurately +error: multiply and add expressions may be calculated more efficiently and accurately --> tests/ui/floating_point_mul_add.rs:41:13 | LL | let _ = 1234.567_f64 * 45.67834_f64 + 0.0004_f64; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1234.567_f64.mul_add(45.67834_f64, 0.0004_f64)` -error: multiply and add expressions can be calculated more efficiently and accurately +error: multiply and add expressions may be calculated more efficiently and accurately --> tests/ui/floating_point_mul_add.rs:44:13 | LL | let _ = (a * a + b).sqrt(); | ^^^^^^^^^^^ help: consider using: `a.mul_add(a, b)` -error: multiply and add expressions can be calculated more efficiently and accurately +error: multiply and add expressions may be calculated more efficiently and accurately --> tests/ui/floating_point_mul_add.rs:48:13 | LL | let _ = a - (b * u as f64); | ^^^^^^^^^^^^^^^^^^ help: consider using: `b.mul_add(-(u as f64), a)` -error: multiply and add expressions can be calculated more efficiently and accurately +error: multiply and add expressions may be calculated more efficiently and accurately --> tests/ui/floating_point_mul_add.rs:102:13 | LL | let _ = 0.5 + 2.0 * x; | ^^^^^^^^^^^^^ help: consider using: `2.0f64.mul_add(x, 0.5)` -error: multiply and add expressions can be calculated more efficiently and accurately +error: multiply and add expressions may be calculated more efficiently and accurately --> tests/ui/floating_point_mul_add.rs:104:13 | LL | let _ = 2.0 * x + 0.5; | ^^^^^^^^^^^^^ help: consider using: `2.0f64.mul_add(x, 0.5)` -error: multiply and add expressions can be calculated more efficiently and accurately +error: multiply and add expressions may be calculated more efficiently and accurately --> tests/ui/floating_point_mul_add.rs:107:13 | LL | let _ = x + 2.0 * 4.0; | ^^^^^^^^^^^^^ help: consider using: `2.0f64.mul_add(4.0, x)` -error: multiply and add expressions can be calculated more efficiently and accurately +error: multiply and add expressions may be calculated more efficiently and accurately --> tests/ui/floating_point_mul_add.rs:111:13 | LL | let _ = y * 2.0 + 0.5; | ^^^^^^^^^^^^^ help: consider using: `y.mul_add(2.0, 0.5)` -error: multiply and add expressions can be calculated more efficiently and accurately +error: multiply and add expressions may be calculated more efficiently and accurately --> tests/ui/floating_point_mul_add.rs:113:13 | LL | let _ = 1.0 * 2.0 + 0.5; | ^^^^^^^^^^^^^^^ help: consider using: `1.0f64.mul_add(2.0, 0.5)` -error: multiply and add expressions can be calculated more efficiently and accurately +error: multiply and add expressions may be calculated more efficiently and accurately --> tests/ui/floating_point_mul_add.rs:122:5 | LL | a += b * c; | ^^^^^^^^^^ help: consider using: `a = b.mul_add(c, a)` -error: multiply and add expressions can be calculated more efficiently and accurately +error: multiply and add expressions may be calculated more efficiently and accurately --> tests/ui/floating_point_mul_add.rs:125:5 | LL | a -= b * c; From 97057829063d6be372b29dfee719057f83cd9f45 Mon Sep 17 00:00:00 2001 From: cyphercodes Date: Sat, 13 Jun 2026 22:46:17 +0300 Subject: [PATCH 28/77] fix: defer adjusted unwrap_or type lookup --- clippy_lints/src/methods/map_unwrap_or.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/clippy_lints/src/methods/map_unwrap_or.rs b/clippy_lints/src/methods/map_unwrap_or.rs index a12687c63736c..ec6dccd4fe543 100644 --- a/clippy_lints/src/methods/map_unwrap_or.rs +++ b/clippy_lints/src/methods/map_unwrap_or.rs @@ -35,7 +35,6 @@ pub(super) fn check<'tcx>( }; let unwrap_arg_ty = cx.typeck_results().expr_ty(unwrap_arg); - let unwrap_arg_ty_adjusted = cx.typeck_results().expr_ty_adjusted(unwrap_arg); if !is_copy(cx, unwrap_arg_ty) { // Replacing `.map().unwrap_or()` with `.map_or(, )` can sometimes lead to // borrowck errors, see #10579 for one such instance. @@ -129,7 +128,7 @@ pub(super) fn check<'tcx>( (SuggestedKind::AndThen, _) => "and_then", (SuggestedKind::IsVariantAnd, sym::Result) => "is_ok_and", (SuggestedKind::IsVariantAnd, sym::Option) => "is_some_and", - (SuggestedKind::Other, _) if unwrap_arg_ty != unwrap_arg_ty_adjusted => { + (SuggestedKind::Other, _) if unwrap_arg_ty != cx.typeck_results().expr_ty_adjusted(unwrap_arg) => { // If the `unwrap_or` argument needs an adjustment, moving it into `map_or`'s // first argument can make type inference pick the unadjusted type and reject // the closure return type. Keep the lint, but don't emit a rustfix. From 3d5b7a6cb5f142b952d1299b545b2072dd27302b Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Thu, 1 May 2025 22:59:40 -0400 Subject: [PATCH 29/77] Change `HasSession` to `HasSourceMap` --- clippy_lints/src/collapsible_if.rs | 6 +- clippy_lints/src/double_parens.rs | 4 +- clippy_lints/src/if_not_else.rs | 23 ++- clippy_lints/src/inline_trait_bounds.rs | 4 +- clippy_lints/src/large_stack_frames.rs | 6 +- clippy_lints/src/needless_pass_by_ref_mut.rs | 3 +- clippy_lints/src/redundant_pub_crate.rs | 3 +- .../missing_transmute_annotations.rs | 6 +- clippy_lints/src/unused_async.rs | 4 +- clippy_utils/src/consts.rs | 2 +- clippy_utils/src/lib.rs | 18 +- clippy_utils/src/source.rs | 179 ++++++++++-------- 12 files changed, 135 insertions(+), 123 deletions(-) diff --git a/clippy_lints/src/collapsible_if.rs b/clippy_lints/src/collapsible_if.rs index baa13b2133277..c7aa5f02ef1aa 100644 --- a/clippy_lints/src/collapsible_if.rs +++ b/clippy_lints/src/collapsible_if.rs @@ -1,7 +1,7 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::msrvs::Msrv; -use clippy_utils::source::{HasSession, IntoSpan as _, SpanRangeExt, snippet, snippet_block_with_applicability}; +use clippy_utils::source::{IntoSpan as _, SpanRangeExt, snippet, snippet_block_with_applicability}; use clippy_utils::{can_use_if_let_chains, span_contains_cfg, span_contains_non_whitespace, sym, tokenize_with_text}; use rustc_ast::{BinOpKind, MetaItemInner}; use rustc_errors::Applicability; @@ -319,7 +319,7 @@ pub(super) fn parens_around(expr: &Expr<'_>) -> Vec<(Span, String)> { } } -fn span_extract_keyword(cx: &impl HasSession, span: Span, keyword: &str) -> Option { +fn span_extract_keyword(cx: &LateContext<'_>, span: Span, keyword: &str) -> Option { span.with_source_text(cx, |snippet| { tokenize_with_text(snippet) .filter(|(t, s, _)| matches!(t, TokenKind::Ident if *s == keyword)) @@ -335,7 +335,7 @@ fn span_extract_keyword(cx: &impl HasSession, span: Span, keyword: &str) -> Opti } /// Peel the parentheses from an `if` expression, e.g. `((if true {} else {}))`. -pub(super) fn peel_parens(cx: &impl HasSession, mut span: Span) -> (Span, Span, Span) { +pub(super) fn peel_parens(cx: &LateContext<'_>, mut span: Span) -> (Span, Span, Span) { use crate::rustc_span::Pos; let start = span.shrink_to_lo(); diff --git a/clippy_lints/src/double_parens.rs b/clippy_lints/src/double_parens.rs index acc3e4936e440..cc897f41ca230 100644 --- a/clippy_lints/src/double_parens.rs +++ b/clippy_lints/src/double_parens.rs @@ -1,8 +1,8 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::{HasSession, SpanRangeExt, snippet_with_applicability, snippet_with_context}; +use clippy_utils::source::{SpanRangeExt, snippet_with_applicability, snippet_with_context}; use rustc_ast::ast::{Expr, ExprKind, MethodCall}; use rustc_errors::Applicability; -use rustc_lint::{EarlyContext, EarlyLintPass}; +use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_session::declare_lint_pass; declare_clippy_lint! { diff --git a/clippy_lints/src/if_not_else.rs b/clippy_lints/src/if_not_else.rs index ff22ba4fcd0d6..ea1992d471312 100644 --- a/clippy_lints/src/if_not_else.rs +++ b/clippy_lints/src/if_not_else.rs @@ -1,7 +1,7 @@ use clippy_utils::consts::is_zero_integer_const; use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg}; use clippy_utils::is_else_clause; -use clippy_utils::source::{HasSession, indent_of, reindent_multiline, snippet_with_context}; +use clippy_utils::source::{indent_of, reindent_multiline, snippet_with_context}; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; @@ -104,28 +104,27 @@ impl LateLintPass<'_> for IfNotElse { } } -fn make_sugg<'a>( - sess: &impl HasSession, +fn make_sugg( + cx: &LateContext<'_>, expr_span: Span, - cond_kind: &'a ExprKind<'a>, + cond_kind: &ExprKind<'_>, cond_inner: Span, els_span: Span, - default: &'a str, + default: &str, applicability: &mut Applicability, ) -> String { - let (cond_inner_snip, _) = snippet_with_context(sess, cond_inner, expr_span.ctxt(), default, applicability); - let (els_snip, _) = snippet_with_context(sess, els_span, expr_span.ctxt(), default, applicability); - let indent = indent_of(sess, expr_span); - + let (cond_inner_snip, _) = snippet_with_context(cx, cond_inner, expr_span.ctxt(), default, applicability); + let (els_snip, _) = snippet_with_context(cx, els_span, expr_span.ctxt(), default, applicability); + let indent = indent_of(cx, expr_span); let suggestion = match cond_kind { ExprKind::Unary(UnOp::Not, cond_rest) => { let (cond_rest_snip, _) = - snippet_with_context(sess, cond_rest.span, expr_span.ctxt(), default, applicability); + snippet_with_context(cx, cond_rest.span, expr_span.ctxt(), default, applicability); format!("if {cond_rest_snip} {els_snip} else {cond_inner_snip}") }, ExprKind::Binary(_, lhs, rhs) => { - let (lhs_snip, _) = snippet_with_context(sess, lhs.span, expr_span.ctxt(), default, applicability); - let (rhs_snip, _) = snippet_with_context(sess, rhs.span, expr_span.ctxt(), default, applicability); + let (lhs_snip, _) = snippet_with_context(cx, lhs.span, expr_span.ctxt(), default, applicability); + let (rhs_snip, _) = snippet_with_context(cx, rhs.span, expr_span.ctxt(), default, applicability); format!("if {lhs_snip} == {rhs_snip} {els_snip} else {cond_inner_snip}") }, diff --git a/clippy_lints/src/inline_trait_bounds.rs b/clippy_lints/src/inline_trait_bounds.rs index 3ffa23dcd6046..87e63e8732fe8 100644 --- a/clippy_lints/src/inline_trait_bounds.rs +++ b/clippy_lints/src/inline_trait_bounds.rs @@ -1,11 +1,11 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::{HasSession, snippet}; +use clippy_utils::source::snippet; use clippy_utils::sym; use rustc_ast::ast::{Fn, FnRetTy, GenericParam, GenericParamKind}; use rustc_ast::visit::{FnCtxt, FnKind}; use rustc_ast::{HasAttrs as _, NodeId}; use rustc_errors::Applicability; -use rustc_lint::{EarlyContext, EarlyLintPass}; +use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_session::impl_lint_pass; use rustc_span::Span; diff --git a/clippy_lints/src/large_stack_frames.rs b/clippy_lints/src/large_stack_frames.rs index 7cf594384b5a2..10377584ef690 100644 --- a/clippy_lints/src/large_stack_frames.rs +++ b/clippy_lints/src/large_stack_frames.rs @@ -2,7 +2,7 @@ use std::{fmt, ops}; use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::{HasSession, SpanRangeExt}; +use clippy_utils::source::SpanRangeExt; use clippy_utils::{fn_has_unsatisfiable_preds, is_entrypoint_fn, is_in_test}; use rustc_errors::Diag; use rustc_hir::def_id::LocalDefId; @@ -228,11 +228,11 @@ impl<'tcx> LateLintPass<'tcx> for LargeStackFrames { if fn_span.from_expansion() { // Don't lint on the main function generated by `--test` target - if cx.sess().is_test_crate() && is_entrypoint_fn(cx, local_def_id.to_def_id()) { + if cx.tcx.sess.is_test_crate() && is_entrypoint_fn(cx, local_def_id.to_def_id()) { return; } - let is_from_external_macro = fn_span.in_external_macro(cx.sess().source_map()); + let is_from_external_macro = fn_span.in_external_macro(cx.tcx.sess.source_map()); span_lint_and_then( cx, LARGE_STACK_FRAMES, diff --git a/clippy_lints/src/needless_pass_by_ref_mut.rs b/clippy_lints/src/needless_pass_by_ref_mut.rs index 91358ef77fa1e..dea88e592f2a5 100644 --- a/clippy_lints/src/needless_pass_by_ref_mut.rs +++ b/clippy_lints/src/needless_pass_by_ref_mut.rs @@ -1,7 +1,6 @@ use super::needless_pass_by_value::requires_exact_signature; use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_hir_and_then; -use clippy_utils::source::HasSession as _; use clippy_utils::visitors::for_each_expr; use clippy_utils::{inherits_cfg, is_from_proc_macro, is_self}; use core::ops::ControlFlow; @@ -269,7 +268,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> { // If the argument is never used mutably, we emit the warning. let sp = input.span; if let rustc_hir::TyKind::Ref(_, inner_ty) = input.kind { - let Some(after_mut_span) = cx.sess().source_map().span_extend_to_prev_str( + let Some(after_mut_span) = cx.tcx.sess.source_map().span_extend_to_prev_str( inner_ty.ty.span.shrink_to_lo(), "mut", true, diff --git a/clippy_lints/src/redundant_pub_crate.rs b/clippy_lints/src/redundant_pub_crate.rs index 7ebf7ccb7571e..c7f7b47403376 100644 --- a/clippy_lints/src/redundant_pub_crate.rs +++ b/clippy_lints/src/redundant_pub_crate.rs @@ -1,5 +1,4 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::HasSession; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{Item, ItemKind, UseKind}; @@ -49,7 +48,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantPubCrate { && !cx.effective_visibilities.is_exported(item.owner_id.def_id) && self.is_exported.last() == Some(&false) && !is_ignorable_export(item) - && !item.span.in_external_macro(cx.sess().source_map()) + && !item.span.in_external_macro(cx.tcx.sess.source_map()) { let span = item .kind diff --git a/clippy_lints/src/transmute/missing_transmute_annotations.rs b/clippy_lints/src/transmute/missing_transmute_annotations.rs index 42f3e06b7d6f5..ec1c34fec1780 100644 --- a/clippy_lints/src/transmute/missing_transmute_annotations.rs +++ b/clippy_lints/src/transmute/missing_transmute_annotations.rs @@ -1,7 +1,7 @@ use std::borrow::Cow; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::{HasSession, SpanRangeExt as _}; +use clippy_utils::source::SpanRangeExt as _; use rustc_errors::Applicability; use rustc_hir::{Expr, GenericArg, HirId, LetStmt, Node, Path, TyKind}; use rustc_lint::LateContext; @@ -114,8 +114,8 @@ fn ty_cannot_be_named(ty: Ty<'_>) -> bool { ) } -fn maybe_name_by_expr<'a>(sess: &impl HasSession, span: Span, default: &'a str) -> Cow<'a, str> { - span.with_source_text(sess, |name| { +fn maybe_name_by_expr<'a>(cx: &LateContext<'_>, span: Span, default: &'a str) -> Cow<'a, str> { + span.with_source_text(cx, |name| { (name.len() + 9 < default.len()).then_some(format!("`{name}`'s type").into()) }) .flatten() diff --git a/clippy_lints/src/unused_async.rs b/clippy_lints/src/unused_async.rs index bfbfd0903bbe8..0a6f3f5992ece 100644 --- a/clippy_lints/src/unused_async.rs +++ b/clippy_lints/src/unused_async.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then}; use clippy_utils::is_def_id_trait_method; -use clippy_utils::source::{HasSession, snippet_with_applicability, walk_span_to_context}; +use clippy_utils::source::{snippet_with_applicability, walk_span_to_context}; use clippy_utils::usage::is_todo_unimplemented_stub; use rustc_errors::Applicability; use rustc_hir::def::DefKind; @@ -303,7 +303,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedAsync { // evaluate the expression, to immediately evaluate the expression. let mut app = Applicability::MaybeIncorrect; - let async_span = cx.sess().source_map().span_extend_while_whitespace(async_span); + let async_span = cx.tcx.sess.source_map().span_extend_while_whitespace(async_span); let signature_snippet = snippet_with_applicability(cx, signature_span, "_", &mut app); let tail_snippet = snippet_with_applicability(cx, tail_span, "_", &mut app).to_string(); diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs index 098be98f3672c..3cb9febb5003c 100644 --- a/clippy_utils/src/consts.rs +++ b/clippy_utils/src/consts.rs @@ -934,7 +934,7 @@ impl<'tcx> ConstEvalCtxt<'tcx> { if let Some(expr_span) = walk_span_to_context(expr.span, span.ctxt) && let expr_lo = expr_span.lo() && expr_lo >= span.lo - && let Some(src) = (span.lo..expr_lo).get_source_range(&self.tcx) + && let Some(src) = (span.lo..expr_lo).get_source_range(self.tcx) && let Some(src) = src.as_str() { use rustc_lexer::TokenKind::{BlockComment, LineComment, OpenBrace, Semi, Whitespace}; diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index c208b8b97506f..203962c05d86e 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -124,6 +124,7 @@ use crate::consts::ConstEvalCtxt; use crate::higher::Range; use crate::msrvs::Msrv; use crate::res::{MaybeDef, MaybeQPath, MaybeResPath}; +use crate::source::HasSourceMap; use crate::ty::{adt_and_variant_of_res, can_partially_move_ty, expr_sig, is_copy, is_recursively_primitive_type}; use crate::visitors::for_each_expr_without_closures; @@ -2880,8 +2881,8 @@ pub fn tokenize_with_text(s: &str) -> impl Iterator bool { - span.check_source_text(cx, |snippet| { +pub fn span_contains_comment<'sm>(sm: impl HasSourceMap<'sm>, span: Span) -> bool { + span.check_source_text(sm, |snippet| { tokenize(snippet, FrontmatterAllowed::No).any(|token| { matches!( token.kind, @@ -2895,8 +2896,8 @@ pub fn span_contains_comment(cx: &impl source::HasSession, span: Span) -> bool { /// token, including comments unless `skip_comments` is set. /// This is useful to determine if there are any actual code tokens in the span that are omitted in /// the late pass, such as platform-specific code. -pub fn span_contains_non_whitespace(cx: &impl source::HasSession, span: Span, skip_comments: bool) -> bool { - span.check_source_text(cx, |snippet| { +pub fn span_contains_non_whitespace<'sm>(sm: impl HasSourceMap<'sm>, span: Span, skip_comments: bool) -> bool { + span.check_source_text(sm, |snippet| { tokenize_with_text(snippet).any(|(token, _, _)| match token { TokenKind::Whitespace => false, TokenKind::BlockComment { .. } | TokenKind::LineComment { .. } => !skip_comments, @@ -2904,18 +2905,19 @@ pub fn span_contains_non_whitespace(cx: &impl source::HasSession, span: Span, sk }) }) } + /// Returns all the comments a given span contains /// /// Comments are returned wrapped with their relevant delimiters -pub fn span_extract_comment(cx: &impl source::HasSession, span: Span) -> String { - span_extract_comments(cx, span).join("\n") +pub fn span_extract_comment<'sm>(sm: impl HasSourceMap<'sm>, span: Span) -> String { + span_extract_comments(sm, span).join("\n") } /// Returns all the comments a given span contains. /// /// Comments are returned wrapped with their relevant delimiters. -pub fn span_extract_comments(cx: &impl source::HasSession, span: Span) -> Vec { - span.with_source_text(cx, |snippet| { +pub fn span_extract_comments<'sm>(sm: impl HasSourceMap<'sm>, span: Span) -> Vec { + span.with_source_text(sm, |snippet| { tokenize_with_text(snippet) .filter(|(t, ..)| matches!(t, TokenKind::BlockComment { .. } | TokenKind::LineComment { .. })) .map(|(_, s, _)| s.to_string()) diff --git a/clippy_utils/src/source.rs b/clippy_utils/src/source.rs index 02d502f8b67f8..923d3a9cdb0d1 100644 --- a/clippy_utils/src/source.rs +++ b/clippy_utils/src/source.rs @@ -20,27 +20,38 @@ use std::borrow::Cow; use std::fmt; use std::ops::{Deref, Index, Range}; -pub trait HasSession { - fn sess(&self) -> &Session; +pub trait HasSourceMap<'sm>: Copy { + #[must_use] + fn source_map(self) -> &'sm SourceMap; } -impl HasSession for Session { - fn sess(&self) -> &Session { +impl<'sm> HasSourceMap<'sm> for &'sm SourceMap { + #[inline] + fn source_map(self) -> &'sm SourceMap { self } } -impl HasSession for TyCtxt<'_> { - fn sess(&self) -> &Session { - self.sess +impl<'sm> HasSourceMap<'sm> for &'sm Session { + #[inline] + fn source_map(self) -> &'sm SourceMap { + self.source_map() } } -impl HasSession for EarlyContext<'_> { - fn sess(&self) -> &Session { - ::rustc_lint::LintContext::sess(self) +impl<'sm> HasSourceMap<'sm> for TyCtxt<'sm> { + #[inline] + fn source_map(self) -> &'sm SourceMap { + self.sess.source_map() } } -impl HasSession for LateContext<'_> { - fn sess(&self) -> &Session { - self.tcx.sess() +impl<'sm> HasSourceMap<'sm> for &'sm EarlyContext<'_> { + #[inline] + fn source_map(self) -> &'sm SourceMap { + ::rustc_lint::LintContext::sess(self).source_map() + } +} +impl<'sm> HasSourceMap<'sm> for &LateContext<'sm> { + #[inline] + fn source_map(self) -> &'sm SourceMap { + self.tcx.sess.source_map() } } @@ -98,36 +109,36 @@ impl IntoSpan for Range { pub trait SpanRangeExt: SpanRange { /// Attempts to get a handle to the source text. Returns `None` if either the span is malformed, /// or the source text is not accessible. - fn get_source_text(self, cx: &impl HasSession) -> Option { - get_source_range(cx.sess().source_map(), self.into_range()).and_then(SourceText::new) + fn get_source_text<'sm>(self, sm: impl HasSourceMap<'sm>) -> Option { + get_source_range(sm.source_map(), self.into_range()).and_then(SourceText::new) } /// Gets the source file, and range in the file, of the given span. Returns `None` if the span /// extends through multiple files, or is malformed. - fn get_source_range(self, cx: &impl HasSession) -> Option { - get_source_range(cx.sess().source_map(), self.into_range()) + fn get_source_range<'sm>(self, sm: impl HasSourceMap<'sm>) -> Option { + get_source_range(sm.source_map(), self.into_range()) } /// Calls the given function with the source text referenced and returns the value. Returns /// `None` if the source text cannot be retrieved. - fn with_source_text(self, cx: &impl HasSession, f: impl for<'a> FnOnce(&'a str) -> T) -> Option { - with_source_text(cx.sess().source_map(), self.into_range(), f) + fn with_source_text<'sm, T>(self, sm: impl HasSourceMap<'sm>, f: impl for<'a> FnOnce(&'a str) -> T) -> Option { + with_source_text(sm.source_map(), self.into_range(), f) } /// Checks if the referenced source text satisfies the given predicate. Returns `false` if the /// source text cannot be retrieved. - fn check_source_text(self, cx: &impl HasSession, pred: impl for<'a> FnOnce(&'a str) -> bool) -> bool { - self.with_source_text(cx, pred).unwrap_or(false) + fn check_source_text<'sm>(self, sm: impl HasSourceMap<'sm>, pred: impl for<'a> FnOnce(&'a str) -> bool) -> bool { + self.with_source_text(sm, pred).unwrap_or(false) } /// Calls the given function with the both the text of the source file and the referenced range, /// and returns the value. Returns `None` if the source text cannot be retrieved. - fn with_source_text_and_range( + fn with_source_text_and_range<'sm, T>( self, - cx: &impl HasSession, + sm: impl HasSourceMap<'sm>, f: impl for<'a> FnOnce(&'a str, Range) -> T, ) -> Option { - with_source_text_and_range(cx.sess().source_map(), self.into_range(), f) + with_source_text_and_range(sm.source_map(), self.into_range(), f) } /// Calls the given function with the both the text of the source file and the referenced range, @@ -135,12 +146,12 @@ pub trait SpanRangeExt: SpanRange { /// retrieved, or no result is returned. /// /// The new range must reside within the same source file. - fn map_range( + fn map_range<'sm>( self, - cx: &impl HasSession, + sm: impl HasSourceMap<'sm>, f: impl for<'a> FnOnce(&'a SourceFile, &'a str, Range) -> Option>, ) -> Option> { - map_range(cx.sess().source_map(), self.into_range(), f) + map_range(sm.source_map(), self.into_range(), f) } /// Extends the range to include all preceding whitespace characters. @@ -156,13 +167,13 @@ pub trait SpanRangeExt: SpanRange { /// /// When the range points to `foo`, suggesting to remove the range after it's been extended will /// cause the `)` to be placed inside the line comment as `( // Some comment)`. - fn with_leading_whitespace(self, cx: &impl HasSession) -> Range { - with_leading_whitespace(cx.sess().source_map(), self.into_range()) + fn with_leading_whitespace<'sm>(self, sm: impl HasSourceMap<'sm>) -> Range { + with_leading_whitespace(sm.source_map(), self.into_range()) } /// Trims the leading whitespace from the range. - fn trim_start(self, cx: &impl HasSession) -> Range { - trim_start(cx.sess().source_map(), self.into_range()) + fn trim_start<'sm>(self, sm: impl HasSourceMap<'sm>) -> Range { + trim_start(sm.source_map(), self.into_range()) } } impl SpanRangeExt for T {} @@ -353,15 +364,15 @@ impl SourceFileRange { } /// Like [`snippet_block`], but add braces if the expr is not an `ExprKind::Block` with no label. -pub fn expr_block( - sess: &impl HasSession, +pub fn expr_block<'sm>( + sm: impl HasSourceMap<'sm>, expr: &Expr<'_>, outer: SyntaxContext, default: &str, indent_relative_to: Option, app: &mut Applicability, ) -> String { - let (code, from_macro) = snippet_block_with_context(sess, expr.span, outer, default, indent_relative_to, app); + let (code, from_macro) = snippet_block_with_context(sm, expr.span, outer, default, indent_relative_to, app); if !from_macro && let ExprKind::Block(block, None) = expr.kind && block.rules != BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided) @@ -386,13 +397,13 @@ pub fn expr_block( /// let x = (); /// // ^^^^^^^^^^ /// ``` -pub fn first_line_of_span(sess: &impl HasSession, span: Span) -> Span { - first_char_in_first_line(sess, span).map_or(span, |first_char_pos| span.with_lo(first_char_pos)) +pub fn first_line_of_span<'sm>(sm: impl HasSourceMap<'sm>, span: Span) -> Span { + first_char_in_first_line(sm, span).map_or(span, |first_char_pos| span.with_lo(first_char_pos)) } -fn first_char_in_first_line(sess: &impl HasSession, span: Span) -> Option { - let line_span = line_span(sess, span); - snippet_opt(sess, line_span).and_then(|snip| { +fn first_char_in_first_line<'sm>(sm: impl HasSourceMap<'sm>, span: Span) -> Option { + let line_span = line_span(sm, span); + snippet_opt(sm, line_span).and_then(|snip| { snip.find(|c: char| !c.is_whitespace()) .map(|pos| line_span.lo() + BytePos::from_usize(pos)) }) @@ -407,9 +418,9 @@ fn first_char_in_first_line(sess: &impl HasSession, span: Span) -> Option Span { +fn line_span<'sm>(sm: impl HasSourceMap<'sm>, span: Span) -> Span { let span = original_sp(span, DUMMY_SP); - let SourceFileAndLine { sf, line } = sess.sess().source_map().lookup_line(span.lo()).unwrap(); + let SourceFileAndLine { sf, line } = sm.source_map().lookup_line(span.lo()).unwrap(); let line_start = sf.lines()[line]; let line_start = sf.absolute_position(line_start); span.with_lo(line_start) @@ -423,13 +434,13 @@ fn line_span(sess: &impl HasSession, span: Span) -> Span { /// let x = (); /// // ^^ -- will return 4 /// ``` -pub fn indent_of(sess: &impl HasSession, span: Span) -> Option { - snippet_opt(sess, line_span(sess, span)).and_then(|snip| snip.find(|c: char| !c.is_whitespace())) +pub fn indent_of<'sm>(sm: impl HasSourceMap<'sm>, span: Span) -> Option { + snippet_opt(sm, line_span(sm, span)).and_then(|snip| snip.find(|c: char| !c.is_whitespace())) } /// Gets a snippet of the indentation of the line of a span -pub fn snippet_indent(sess: &impl HasSession, span: Span) -> Option { - snippet_opt(sess, line_span(sess, span)).map(|mut s| { +pub fn snippet_indent<'sm>(sm: impl HasSourceMap<'sm>, span: Span) -> Option { + snippet_opt(sm, line_span(sm, span)).map(|mut s| { let len = s.len() - s.trim_start().len(); s.truncate(len); s @@ -441,8 +452,8 @@ pub fn snippet_indent(sess: &impl HasSession, span: Span) -> Option { // sources that the user has no control over. // For some reason these attributes don't have any expansion info on them, so // we have to check it this way until there is a better way. -pub fn is_present_in_source(sess: &impl HasSession, span: Span) -> bool { - if let Some(snippet) = snippet_opt(sess, span) +pub fn is_present_in_source<'sm>(sm: impl HasSourceMap<'sm>, span: Span) -> bool { + if let Some(snippet) = snippet_opt(sm, span) && snippet.is_empty() { return false; @@ -534,8 +545,8 @@ fn reindent_multiline_inner(s: &str, ignore_first: bool, indent: Option, /// snippet(cx, span1, "..") // -> "value" /// snippet(cx, span2, "..") // -> "Vec::new()" /// ``` -pub fn snippet<'a>(sess: &impl HasSession, span: Span, default: &'a str) -> Cow<'a, str> { - snippet_opt(sess, span).map_or_else(|| Cow::Borrowed(default), From::from) +pub fn snippet<'a, 'sm>(sm: impl HasSourceMap<'sm>, span: Span, default: &'a str) -> Cow<'a, str> { + snippet_opt(sm, span).map_or_else(|| Cow::Borrowed(default), From::from) } /// Same as [`snippet`], but it adapts the applicability level by following rules: @@ -547,17 +558,17 @@ pub fn snippet<'a>(sess: &impl HasSession, span: Span, default: &'a str) -> Cow< /// /// If the span might realistically contain a macro call (e.g. `vec![]`), consider using /// [`snippet_with_context`] instead. -pub fn snippet_with_applicability<'a>( - sess: &impl HasSession, +pub fn snippet_with_applicability<'a, 'sm>( + sm: impl HasSourceMap<'sm>, span: Span, default: &'a str, applicability: &mut Applicability, ) -> Cow<'a, str> { - snippet_with_applicability_sess(sess.sess(), span, default, applicability) + snippet_with_applicability_sm(sm.source_map(), span, default, applicability) } -fn snippet_with_applicability_sess<'a>( - sess: &Session, +fn snippet_with_applicability_sm<'a>( + sm: &SourceMap, span: Span, default: &'a str, applicability: &mut Applicability, @@ -565,7 +576,7 @@ fn snippet_with_applicability_sess<'a>( if *applicability != Applicability::Unspecified && span.from_expansion() { *applicability = Applicability::MaybeIncorrect; } - if let Some(t) = snippet_opt(sess, span) { + if let Some(t) = snippet_opt(sm, span) { Cow::Owned(t) } else { if *applicability == Applicability::MachineApplicable { @@ -576,8 +587,8 @@ fn snippet_with_applicability_sess<'a>( } /// Converts a span to a code snippet. Returns `None` if not available. -pub fn snippet_opt(sess: &impl HasSession, span: Span) -> Option { - sess.sess().source_map().span_to_snippet(span).ok() +pub fn snippet_opt<'sm>(sm: impl HasSourceMap<'sm>, span: Span) -> Option { + sm.source_map().span_to_snippet(span).ok() } /// Converts a span (from a block) to a code snippet if available, otherwise use default. @@ -614,37 +625,42 @@ pub fn snippet_opt(sess: &impl HasSession, span: Span) -> Option { /// } // aligned with `if` /// ``` /// Note that the first line of the snippet always has 0 indentation. -pub fn snippet_block(sess: &impl HasSession, span: Span, default: &str, indent_relative_to: Option) -> String { - let snip = snippet(sess, span, default); - let indent = indent_relative_to.and_then(|s| indent_of(sess, s)); +pub fn snippet_block<'sm>( + sm: impl HasSourceMap<'sm>, + span: Span, + default: &str, + indent_relative_to: Option, +) -> String { + let snip = snippet(sm, span, default); + let indent = indent_relative_to.and_then(|s| indent_of(sm, s)); reindent_multiline(&snip, true, indent) } /// Same as [`snippet_block`], but adapts the applicability level by the rules of /// [`snippet_with_applicability`]. -pub fn snippet_block_with_applicability( - sess: &impl HasSession, +pub fn snippet_block_with_applicability<'sm>( + sm: impl HasSourceMap<'sm>, span: Span, default: &str, indent_relative_to: Option, applicability: &mut Applicability, ) -> String { - let snip = snippet_with_applicability(sess, span, default, applicability); - let indent = indent_relative_to.and_then(|s| indent_of(sess, s)); + let snip = snippet_with_applicability(sm, span, default, applicability); + let indent = indent_relative_to.and_then(|s| indent_of(sm, s)); reindent_multiline(&snip, true, indent) } /// Combination of [`snippet_block`] and [`snippet_with_context`]. -pub fn snippet_block_with_context( - sess: &impl HasSession, +pub fn snippet_block_with_context<'sm>( + sm: impl HasSourceMap<'sm>, span: Span, outer: SyntaxContext, default: &str, indent_relative_to: Option, app: &mut Applicability, ) -> (String, bool) { - let (snip, from_macro) = snippet_with_context(sess, span, outer, default, app); - let indent = indent_relative_to.and_then(|s| indent_of(sess, s)); + let (snip, from_macro) = snippet_with_context(sm, span, outer, default, app); + let indent = indent_relative_to.and_then(|s| indent_of(sm, s)); (reindent_multiline(&snip, true, indent), from_macro) } @@ -658,18 +674,18 @@ pub fn snippet_block_with_context( /// correctly get a snippet of `vec![]`. /// /// This will also return whether or not the snippet is a macro call. -pub fn snippet_with_context<'a>( - sess: &impl HasSession, +pub fn snippet_with_context<'a, 'sm>( + sm: impl HasSourceMap<'sm>, span: Span, outer: SyntaxContext, default: &'a str, applicability: &mut Applicability, ) -> (Cow<'a, str>, bool) { - snippet_with_context_sess(sess.sess(), span, outer, default, applicability) + snippet_with_context_sm(sm.source_map(), span, outer, default, applicability) } -fn snippet_with_context_sess<'a>( - sess: &Session, +fn snippet_with_context_sm<'a>( + sm: &SourceMap, span: Span, outer: SyntaxContext, default: &'a str, @@ -677,10 +693,7 @@ fn snippet_with_context_sess<'a>( ) -> (Cow<'a, str>, bool) { // If it is just range desugaring, use the desugaring span since it may include parenthesis. if span.desugaring_kind() == Some(DesugaringKind::RangeExpr) && span.parent_callsite().unwrap().ctxt() == outer { - return ( - snippet_with_applicability_sess(sess, span, default, applicability), - false, - ); + return (snippet_with_applicability_sm(sm, span, default, applicability), false); } let (span, is_macro_call) = walk_span_to_context(span, outer).map_or_else( @@ -696,7 +709,7 @@ fn snippet_with_context_sess<'a>( ); ( - snippet_with_applicability_sess(sess, span, default, applicability), + snippet_with_applicability_sm(sm, span, default, applicability), is_macro_call, ) } @@ -759,15 +772,15 @@ pub fn trim_span(sm: &SourceMap, span: Span) -> Span { /// writeln!(o, "") -> writeln!(o, "") /// ^^ ^^^^ /// ``` -pub fn expand_past_previous_comma(sess: &impl HasSession, span: Span) -> Span { - let extended = sess.sess().source_map().span_extend_to_prev_char(span, ',', true); +pub fn expand_past_previous_comma<'sm>(sm: impl HasSourceMap<'sm>, span: Span) -> Span { + let extended = sm.source_map().span_extend_to_prev_char(span, ',', true); extended.with_lo(extended.lo() - BytePos(1)) } /// Converts `expr` to a `char` literal if it's a `str` literal containing a single /// character (or a single byte with `ascii_only`) -pub fn str_literal_to_char_literal( - sess: &impl HasSession, +pub fn str_literal_to_char_literal<'sm>( + sm: impl HasSourceMap<'sm>, expr: &Expr<'_>, applicability: &mut Applicability, ascii_only: bool, @@ -782,7 +795,7 @@ pub fn str_literal_to_char_literal( } && len == 1 { - let snip = snippet_with_applicability(sess, expr.span, string, applicability); + let snip = snippet_with_applicability(sm, expr.span, string, applicability); let ch = if let StrStyle::Raw(nhash) = style { let nhash = nhash as usize; // for raw string: r##"a"## From c5f215e7eea9ff2dd72f0fadf528e16d285b7265 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Thu, 1 May 2025 23:53:16 -0400 Subject: [PATCH 30/77] Rename `SpanRangeExt` to `SpanExt` --- clippy_lints/src/attrs/non_minimal_cfg.rs | 2 +- clippy_lints/src/attrs/unnecessary_clippy_cfg.rs | 2 +- clippy_lints/src/attrs/useless_attribute.rs | 2 +- clippy_lints/src/booleans.rs | 2 +- clippy_lints/src/borrow_deref_ref.rs | 2 +- clippy_lints/src/casts/as_ptr_cast_mut.rs | 2 +- clippy_lints/src/casts/cast_lossless.rs | 2 +- clippy_lints/src/casts/manual_dangling_ptr.rs | 2 +- clippy_lints/src/casts/unnecessary_cast.rs | 2 +- clippy_lints/src/casts/zero_ptr.rs | 2 +- clippy_lints/src/cognitive_complexity.rs | 2 +- clippy_lints/src/collapsible_if.rs | 2 +- clippy_lints/src/default_constructed_unit_structs.rs | 2 +- clippy_lints/src/double_parens.rs | 2 +- clippy_lints/src/empty_line_after.rs | 2 +- clippy_lints/src/empty_with_brackets.rs | 4 ++-- clippy_lints/src/format.rs | 2 +- clippy_lints/src/format_args.rs | 2 +- clippy_lints/src/four_forward_slashes.rs | 2 +- clippy_lints/src/from_over_into.rs | 2 +- clippy_lints/src/functions/too_many_lines.rs | 2 +- clippy_lints/src/ifs/branches_sharing_code.rs | 2 +- clippy_lints/src/implicit_hasher.rs | 2 +- clippy_lints/src/ineffective_open_options.rs | 2 +- clippy_lints/src/items_after_test_module.rs | 2 +- clippy_lints/src/large_stack_frames.rs | 2 +- clippy_lints/src/legacy_numeric_constants.rs | 2 +- clippy_lints/src/len_zero.rs | 2 +- clippy_lints/src/let_with_type_underscore.rs | 2 +- clippy_lints/src/literal_representation.rs | 2 +- clippy_lints/src/loops/unused_enumerate_index.rs | 2 +- clippy_lints/src/manual_async_fn.rs | 2 +- clippy_lints/src/manual_float_methods.rs | 2 +- clippy_lints/src/manual_hash_one.rs | 2 +- clippy_lints/src/manual_range_patterns.rs | 2 +- clippy_lints/src/matches/collapsible_match.rs | 2 +- clippy_lints/src/matches/manual_unwrap_or.rs | 2 +- clippy_lints/src/matches/match_same_arms.rs | 2 +- clippy_lints/src/matches/match_wild_enum.rs | 2 +- clippy_lints/src/matches/single_match.rs | 2 +- .../src/methods/case_sensitive_file_extension_comparisons.rs | 2 +- clippy_lints/src/methods/filter_map_bool_then.rs | 2 +- clippy_lints/src/methods/manual_inspect.rs | 2 +- clippy_lints/src/methods/manual_ok_or.rs | 2 +- clippy_lints/src/methods/manual_try_fold.rs | 2 +- clippy_lints/src/methods/map_all_any_identity.rs | 2 +- clippy_lints/src/methods/needless_character_iteration.rs | 2 +- clippy_lints/src/methods/needless_option_as_deref.rs | 2 +- clippy_lints/src/methods/ptr_offset_by_literal.rs | 2 +- clippy_lints/src/methods/range_zip_with_len.rs | 2 +- clippy_lints/src/methods/string_lit_chars_any.rs | 2 +- clippy_lints/src/methods/unnecessary_first_then_check.rs | 2 +- clippy_lints/src/methods/unnecessary_get_then_check.rs | 2 +- clippy_lints/src/methods/unnecessary_iter_cloned.rs | 2 +- clippy_lints/src/methods/unnecessary_to_owned.rs | 2 +- clippy_lints/src/misc_early/unneeded_field_pattern.rs | 2 +- clippy_lints/src/missing_enforced_import_rename.rs | 2 +- clippy_lints/src/multiple_bound_locations.rs | 2 +- clippy_lints/src/mutex_atomic.rs | 2 +- clippy_lints/src/needless_else.rs | 2 +- clippy_lints/src/needless_ifs.rs | 2 +- clippy_lints/src/needless_late_init.rs | 2 +- clippy_lints/src/needless_pass_by_value.rs | 2 +- clippy_lints/src/no_effect.rs | 2 +- clippy_lints/src/non_octal_unix_permissions.rs | 2 +- clippy_lints/src/nonstandard_macro_braces.rs | 2 +- clippy_lints/src/octal_escapes.rs | 2 +- clippy_lints/src/operators/assign_op_pattern.rs | 2 +- clippy_lints/src/operators/decimal_bitwise_operands.rs | 2 +- clippy_lints/src/operators/misrefactored_assign_op.rs | 2 +- clippy_lints/src/pathbuf_init_then_push.rs | 2 +- clippy_lints/src/ptr/ptr_arg.rs | 2 +- clippy_lints/src/ranges.rs | 2 +- clippy_lints/src/raw_strings.rs | 2 +- clippy_lints/src/redundant_clone.rs | 2 +- clippy_lints/src/regex.rs | 2 +- clippy_lints/src/semicolon_block.rs | 2 +- clippy_lints/src/single_range_in_vec_init.rs | 2 +- clippy_lints/src/trait_bounds.rs | 2 +- clippy_lints/src/transmute/missing_transmute_annotations.rs | 2 +- clippy_lints/src/unit_types/unit_arg.rs | 2 +- clippy_lints/src/unnecessary_mut_passed.rs | 2 +- clippy_lints/src/unused_unit.rs | 2 +- clippy_lints/src/useless_vec.rs | 2 +- clippy_lints/src/utils/format_args_collector.rs | 2 +- clippy_lints/src/visibility.rs | 2 +- clippy_lints/src/write/literal.rs | 2 +- clippy_lints/src/write/with_newline.rs | 2 +- clippy_utils/src/attrs.rs | 2 +- clippy_utils/src/consts.rs | 2 +- clippy_utils/src/hir_utils.rs | 2 +- clippy_utils/src/lib.rs | 2 +- clippy_utils/src/source.rs | 4 ++-- 93 files changed, 95 insertions(+), 95 deletions(-) diff --git a/clippy_lints/src/attrs/non_minimal_cfg.rs b/clippy_lints/src/attrs/non_minimal_cfg.rs index 7eff5eccfa138..a76bdcfdfb3e5 100644 --- a/clippy_lints/src/attrs/non_minimal_cfg.rs +++ b/clippy_lints/src/attrs/non_minimal_cfg.rs @@ -1,6 +1,6 @@ use super::{Attribute, NON_MINIMAL_CFG}; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use rustc_ast::{MetaItemInner, MetaItemKind}; use rustc_errors::Applicability; use rustc_lint::EarlyContext; diff --git a/clippy_lints/src/attrs/unnecessary_clippy_cfg.rs b/clippy_lints/src/attrs/unnecessary_clippy_cfg.rs index 6efc931df2429..b4742e4da7503 100644 --- a/clippy_lints/src/attrs/unnecessary_clippy_cfg.rs +++ b/clippy_lints/src/attrs/unnecessary_clippy_cfg.rs @@ -1,6 +1,6 @@ use super::{Attribute, UNNECESSARY_CLIPPY_CFG}; use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_sugg}; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use itertools::Itertools; use rustc_ast::AttrStyle; use rustc_errors::Applicability; diff --git a/clippy_lints/src/attrs/useless_attribute.rs b/clippy_lints/src/attrs/useless_attribute.rs index 2d56086a96024..7c0bfd9edb415 100644 --- a/clippy_lints/src/attrs/useless_attribute.rs +++ b/clippy_lints/src/attrs/useless_attribute.rs @@ -1,7 +1,7 @@ use super::USELESS_ATTRIBUTE; use super::utils::{is_lint_level, is_word, namespace_and_lint}; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::{SpanRangeExt, first_line_of_span}; +use clippy_utils::source::{SpanExt, first_line_of_span}; use clippy_utils::sym; use rustc_ast::{Attribute, Item, ItemKind}; use rustc_errors::Applicability; diff --git a/clippy_lints/src/booleans.rs b/clippy_lints/src/booleans.rs index 2f2382d9a50ed..4a3ff6c63705e 100644 --- a/clippy_lints/src/booleans.rs +++ b/clippy_lints/src/booleans.rs @@ -3,7 +3,7 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then}; use clippy_utils::higher::has_let_expr; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::res::MaybeDef; -use clippy_utils::source::{SpanRangeExt, snippet_with_context}; +use clippy_utils::source::{SpanExt, snippet_with_context}; use clippy_utils::sugg::Sugg; use clippy_utils::ty::implements_trait; use clippy_utils::{eq_expr_value, sym}; diff --git a/clippy_lints/src/borrow_deref_ref.rs b/clippy_lints/src/borrow_deref_ref.rs index 947b99696bb1f..1d5ea5ae88f72 100644 --- a/clippy_lints/src/borrow_deref_ref.rs +++ b/clippy_lints/src/borrow_deref_ref.rs @@ -1,6 +1,6 @@ use crate::reference::DEREF_ADDROF; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use clippy_utils::ty::implements_trait; use clippy_utils::{ get_enclosing_closure, get_parent_expr, is_expr_temporary_value, is_from_proc_macro, is_lint_allowed, is_mutable, diff --git a/clippy_lints/src/casts/as_ptr_cast_mut.rs b/clippy_lints/src/casts/as_ptr_cast_mut.rs index adc43e282fc5c..0222dd96a6904 100644 --- a/clippy_lints/src/casts/as_ptr_cast_mut.rs +++ b/clippy_lints/src/casts/as_ptr_cast_mut.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use clippy_utils::sym; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; diff --git a/clippy_lints/src/casts/cast_lossless.rs b/clippy_lints/src/casts/cast_lossless.rs index c924fba6b5c85..bcfb59028201e 100644 --- a/clippy_lints/src/casts/cast_lossless.rs +++ b/clippy_lints/src/casts/cast_lossless.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_in_const_context; use clippy_utils::msrvs::{self, Msrv}; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use clippy_utils::sugg::Sugg; use clippy_utils::ty::is_isize_or_usize; use rustc_errors::Applicability; diff --git a/clippy_lints/src/casts/manual_dangling_ptr.rs b/clippy_lints/src/casts/manual_dangling_ptr.rs index 55b0945f0962b..fe31de69a1545 100644 --- a/clippy_lints/src/casts/manual_dangling_ptr.rs +++ b/clippy_lints/src/casts/manual_dangling_ptr.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::res::{MaybeDef, MaybeResPath}; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use clippy_utils::{expr_or_init, std_or_core, sym}; use rustc_ast::LitKind; use rustc_errors::Applicability; diff --git a/clippy_lints/src/casts/unnecessary_cast.rs b/clippy_lints/src/casts/unnecessary_cast.rs index 333f31ba00eac..c320da98b4d61 100644 --- a/clippy_lints/src/casts/unnecessary_cast.rs +++ b/clippy_lints/src/casts/unnecessary_cast.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::numeric_literal::NumericLiteral; use clippy_utils::res::MaybeResPath as _; -use clippy_utils::source::{SpanRangeExt, snippet, snippet_with_applicability}; +use clippy_utils::source::{SpanExt, snippet, snippet_with_applicability}; use clippy_utils::sugg::has_enclosing_paren; use clippy_utils::visitors::{Visitable, for_each_expr_without_closures}; use clippy_utils::{get_parent_expr, is_hir_ty_cfg_dependant, is_ty_alias, sym}; diff --git a/clippy_lints/src/casts/zero_ptr.rs b/clippy_lints/src/casts/zero_ptr.rs index f4738e7b0d51d..d33d08230d1a3 100644 --- a/clippy_lints/src/casts/zero_ptr.rs +++ b/clippy_lints/src/casts/zero_ptr.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::msrvs::{self, Msrv}; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use clippy_utils::{is_in_const_context, is_integer_literal, std_or_core}; use rustc_errors::Applicability; use rustc_hir::{Expr, Mutability, Ty, TyKind}; diff --git a/clippy_lints/src/cognitive_complexity.rs b/clippy_lints/src/cognitive_complexity.rs index 95b99c1d2435f..c330ed3d5a0a4 100644 --- a/clippy_lints/src/cognitive_complexity.rs +++ b/clippy_lints/src/cognitive_complexity.rs @@ -1,7 +1,7 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::res::MaybeDef; -use clippy_utils::source::{IntoSpan, SpanRangeExt}; +use clippy_utils::source::{IntoSpan, SpanExt}; use clippy_utils::visitors::for_each_expr_without_closures; use clippy_utils::{LimitStack, get_async_fn_body, sym}; use core::ops::ControlFlow; diff --git a/clippy_lints/src/collapsible_if.rs b/clippy_lints/src/collapsible_if.rs index c7aa5f02ef1aa..6def41b775d1d 100644 --- a/clippy_lints/src/collapsible_if.rs +++ b/clippy_lints/src/collapsible_if.rs @@ -1,7 +1,7 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::msrvs::Msrv; -use clippy_utils::source::{IntoSpan as _, SpanRangeExt, snippet, snippet_block_with_applicability}; +use clippy_utils::source::{IntoSpan as _, SpanExt, snippet, snippet_block_with_applicability}; use clippy_utils::{can_use_if_let_chains, span_contains_cfg, span_contains_non_whitespace, sym, tokenize_with_text}; use rustc_ast::{BinOpKind, MetaItemInner}; use rustc_errors::Applicability; diff --git a/clippy_lints/src/default_constructed_unit_structs.rs b/clippy_lints/src/default_constructed_unit_structs.rs index c831f96443c60..dc930e83dfa50 100644 --- a/clippy_lints/src/default_constructed_unit_structs.rs +++ b/clippy_lints/src/default_constructed_unit_structs.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_ty_alias; -use clippy_utils::source::SpanRangeExt as _; +use clippy_utils::source::SpanExt as _; use hir::ExprKind; use hir::def::Res; use rustc_errors::Applicability; diff --git a/clippy_lints/src/double_parens.rs b/clippy_lints/src/double_parens.rs index cc897f41ca230..daf65e090f6ac 100644 --- a/clippy_lints/src/double_parens.rs +++ b/clippy_lints/src/double_parens.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::{SpanRangeExt, snippet_with_applicability, snippet_with_context}; +use clippy_utils::source::{SpanExt, snippet_with_applicability, snippet_with_context}; use rustc_ast::ast::{Expr, ExprKind, MethodCall}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; diff --git a/clippy_lints/src/empty_line_after.rs b/clippy_lints/src/empty_line_after.rs index 9df1919867e2e..3978ba65f59b8 100644 --- a/clippy_lints/src/empty_line_after.rs +++ b/clippy_lints/src/empty_line_after.rs @@ -1,7 +1,7 @@ use std::borrow::Cow; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::{SpanRangeExt, snippet_indent}; +use clippy_utils::source::{SpanExt, snippet_indent}; use clippy_utils::tokenize_with_text; use itertools::Itertools; use rustc_ast::token::CommentKind; diff --git a/clippy_lints/src/empty_with_brackets.rs b/clippy_lints/src/empty_with_brackets.rs index ee1be48417222..b01745008510c 100644 --- a/clippy_lints/src/empty_with_brackets.rs +++ b/clippy_lints/src/empty_with_brackets.rs @@ -1,6 +1,6 @@ use clippy_utils::attrs::span_contains_cfg; use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then}; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use clippy_utils::span_contains_non_whitespace; use rustc_data_structures::fx::{FxIndexMap, IndexEntry}; use rustc_errors::Applicability; @@ -192,7 +192,7 @@ impl LateLintPass<'_> for EmptyWithBrackets { // Span of the parentheses in variant definition let span = variant.span.with_lo(variant.ident.span.hi()); let span_inner = span - .with_lo(SpanRangeExt::trim_start(span, cx).start + BytePos(1)) + .with_lo(SpanExt::trim_start(span, cx).start + BytePos(1)) .with_hi(span.hi() - BytePos(1)); if span_contains_non_whitespace(cx, span_inner, false) { continue; diff --git a/clippy_lints/src/format.rs b/clippy_lints/src/format.rs index 2691fb4766397..18fefd4b5a550 100644 --- a/clippy_lints/src/format.rs +++ b/clippy_lints/src/format.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::macros::{FormatArgsStorage, find_format_arg_expr, first_node_in_macro, matching_root_macro_call}; -use clippy_utils::source::{SpanRangeExt, snippet_with_context}; +use clippy_utils::source::{SpanExt, snippet_with_context}; use clippy_utils::sugg::Sugg; use rustc_ast::{FormatArgsPiece, FormatOptions, FormatTrait}; use rustc_errors::Applicability; diff --git a/clippy_lints/src/format_args.rs b/clippy_lints/src/format_args.rs index 05145456071c0..bfc9c41c9dbd6 100644 --- a/clippy_lints/src/format_args.rs +++ b/clippy_lints/src/format_args.rs @@ -10,7 +10,7 @@ use clippy_utils::macros::{ }; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::res::MaybeDef; -use clippy_utils::source::{SpanRangeExt, snippet, snippet_opt}; +use clippy_utils::source::{SpanExt, snippet, snippet_opt}; use clippy_utils::ty::implements_trait; use clippy_utils::{is_from_proc_macro, is_in_test, peel_hir_expr_while, sym, trait_ref_of_method}; use itertools::Itertools; diff --git a/clippy_lints/src/four_forward_slashes.rs b/clippy_lints/src/four_forward_slashes.rs index 57c1dd2eb72b0..f05626268fc21 100644 --- a/clippy_lints/src/four_forward_slashes.rs +++ b/clippy_lints/src/four_forward_slashes.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::SpanRangeExt as _; +use clippy_utils::source::SpanExt as _; use itertools::Itertools; use rustc_errors::Applicability; use rustc_hir::Item; diff --git a/clippy_lints/src/from_over_into.rs b/clippy_lints/src/from_over_into.rs index 433d591418798..73250c2952bc1 100644 --- a/clippy_lints/src/from_over_into.rs +++ b/clippy_lints/src/from_over_into.rs @@ -5,7 +5,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::macros::span_is_local; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::res::MaybeResPath; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use rustc_errors::Applicability; use rustc_hir::intravisit::{Visitor, walk_path}; use rustc_hir::{ diff --git a/clippy_lints/src/functions/too_many_lines.rs b/clippy_lints/src/functions/too_many_lines.rs index 33eede8e65ac9..da3ad2287c319 100644 --- a/clippy_lints/src/functions/too_many_lines.rs +++ b/clippy_lints/src/functions/too_many_lines.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::FnKind; diff --git a/clippy_lints/src/ifs/branches_sharing_code.rs b/clippy_lints/src/ifs/branches_sharing_code.rs index 06ebd3ac7f5fd..2701cdaa394da 100644 --- a/clippy_lints/src/ifs/branches_sharing_code.rs +++ b/clippy_lints/src/ifs/branches_sharing_code.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::res::MaybeResPath; -use clippy_utils::source::{IntoSpan, SpanRangeExt, first_line_of_span, indent_of, reindent_multiline, snippet}; +use clippy_utils::source::{IntoSpan, SpanExt, first_line_of_span, indent_of, reindent_multiline, snippet}; use clippy_utils::ty::needs_ordered_drop; use clippy_utils::visitors::for_each_expr_without_closures; use clippy_utils::{ diff --git a/clippy_lints/src/implicit_hasher.rs b/clippy_lints/src/implicit_hasher.rs index 70176c62772b7..bf2c7a007644c 100644 --- a/clippy_lints/src/implicit_hasher.rs +++ b/clippy_lints/src/implicit_hasher.rs @@ -13,7 +13,7 @@ use rustc_session::declare_lint_pass; use rustc_span::Span; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::{IntoSpan, SpanRangeExt, snippet, snippet_with_context}; +use clippy_utils::source::{IntoSpan, SpanExt, snippet, snippet_with_context}; use clippy_utils::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/ineffective_open_options.rs b/clippy_lints/src/ineffective_open_options.rs index bc57d9e85478a..aae847031bf64 100644 --- a/clippy_lints/src/ineffective_open_options.rs +++ b/clippy_lints/src/ineffective_open_options.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::res::MaybeDef; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use clippy_utils::{peel_blocks, peel_hir_expr_while, sym}; use rustc_ast::LitKind; use rustc_errors::Applicability; diff --git a/clippy_lints/src/items_after_test_module.rs b/clippy_lints/src/items_after_test_module.rs index dd63de288b87f..3ab4be1442515 100644 --- a/clippy_lints/src/items_after_test_module.rs +++ b/clippy_lints/src/items_after_test_module.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use clippy_utils::{fulfill_or_allowed, is_cfg_test, is_from_proc_macro}; use rustc_errors::{Applicability, SuggestionStyle}; use rustc_hir::{HirId, Item, ItemKind, Mod}; diff --git a/clippy_lints/src/large_stack_frames.rs b/clippy_lints/src/large_stack_frames.rs index 10377584ef690..88216d188f8e5 100644 --- a/clippy_lints/src/large_stack_frames.rs +++ b/clippy_lints/src/large_stack_frames.rs @@ -2,7 +2,7 @@ use std::{fmt, ops}; use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use clippy_utils::{fn_has_unsatisfiable_preds, is_entrypoint_fn, is_in_test}; use rustc_errors::Diag; use rustc_hir::def_id::LocalDefId; diff --git a/clippy_lints/src/legacy_numeric_constants.rs b/clippy_lints/src/legacy_numeric_constants.rs index 838abc81ce449..b53355150f6ab 100644 --- a/clippy_lints/src/legacy_numeric_constants.rs +++ b/clippy_lints/src/legacy_numeric_constants.rs @@ -1,7 +1,7 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::msrvs::{self, Msrv}; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use clippy_utils::{is_from_proc_macro, sym}; use hir::def_id::DefId; use rustc_errors::Applicability; diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index 53ee157dd6d70..4d1a8bacbfff2 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -2,7 +2,7 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::msrvs::Msrv; use clippy_utils::res::{MaybeDef, MaybeTypeckRes}; -use clippy_utils::source::{SpanRangeExt, snippet_with_context}; +use clippy_utils::source::{SpanExt, snippet_with_context}; use clippy_utils::sugg::{Sugg, has_enclosing_paren}; use clippy_utils::ty::implements_trait; use clippy_utils::{parent_item_name, peel_ref_operators, sym}; diff --git a/clippy_lints/src/let_with_type_underscore.rs b/clippy_lints/src/let_with_type_underscore.rs index 7f2687664c686..3f4b59382ca15 100644 --- a/clippy_lints/src/let_with_type_underscore.rs +++ b/clippy_lints/src/let_with_type_underscore.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_from_proc_macro; -use clippy_utils::source::{IntoSpan, SpanRangeExt}; +use clippy_utils::source::{IntoSpan, SpanExt}; use rustc_ast::{Local, TyKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; diff --git a/clippy_lints/src/literal_representation.rs b/clippy_lints/src/literal_representation.rs index db99f601c8932..6b908e32ee3e0 100644 --- a/clippy_lints/src/literal_representation.rs +++ b/clippy_lints/src/literal_representation.rs @@ -1,7 +1,7 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::numeric_literal::{NumericLiteral, Radix}; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use rustc_ast::ast::{Expr, ExprKind, LitKind}; use rustc_ast::token; use rustc_errors::Applicability; diff --git a/clippy_lints/src/loops/unused_enumerate_index.rs b/clippy_lints/src/loops/unused_enumerate_index.rs index 4ecfadbf9d494..b80efdae9294c 100644 --- a/clippy_lints/src/loops/unused_enumerate_index.rs +++ b/clippy_lints/src/loops/unused_enumerate_index.rs @@ -1,7 +1,7 @@ use super::UNUSED_ENUMERATE_INDEX; use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::res::MaybeDef; -use clippy_utils::source::{SpanRangeExt, walk_span_to_context}; +use clippy_utils::source::{SpanExt, walk_span_to_context}; use clippy_utils::{expr_or_init, pat_is_wild, sym}; use rustc_errors::Applicability; use rustc_hir::{Closure, Expr, ExprKind, Pat, PatKind, TyKind}; diff --git a/clippy_lints/src/manual_async_fn.rs b/clippy_lints/src/manual_async_fn.rs index bee3b19b597c0..dff324d132a0e 100644 --- a/clippy_lints/src/manual_async_fn.rs +++ b/clippy_lints/src/manual_async_fn.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::{SpanRangeExt, position_before_rarrow, snippet_block}; +use clippy_utils::source::{SpanExt, position_before_rarrow, snippet_block}; use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; use rustc_hir::{ diff --git a/clippy_lints/src/manual_float_methods.rs b/clippy_lints/src/manual_float_methods.rs index 4a2784caf4c74..87fc28b39ce7e 100644 --- a/clippy_lints/src/manual_float_methods.rs +++ b/clippy_lints/src/manual_float_methods.rs @@ -4,7 +4,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_from_proc_macro; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::res::MaybeResPath; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use rustc_errors::Applicability; use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; diff --git a/clippy_lints/src/manual_hash_one.rs b/clippy_lints/src/manual_hash_one.rs index 96d69003934fc..475ee2191a850 100644 --- a/clippy_lints/src/manual_hash_one.rs +++ b/clippy_lints/src/manual_hash_one.rs @@ -2,7 +2,7 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::res::{MaybeDef, MaybeResPath, MaybeTypeckRes}; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use clippy_utils::sym; use clippy_utils::visitors::{is_local_used, local_used_once}; use rustc_errors::Applicability; diff --git a/clippy_lints/src/manual_range_patterns.rs b/clippy_lints/src/manual_range_patterns.rs index f60b2a1a6729f..e1b353b4911ad 100644 --- a/clippy_lints/src/manual_range_patterns.rs +++ b/clippy_lints/src/manual_range_patterns.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use rustc_ast::LitKind; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; diff --git a/clippy_lints/src/matches/collapsible_match.rs b/clippy_lints/src/matches/collapsible_match.rs index 67685f803841c..2eb15928f25aa 100644 --- a/clippy_lints/src/matches/collapsible_match.rs +++ b/clippy_lints/src/matches/collapsible_match.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::higher::{If, IfLetOrMatch}; use clippy_utils::msrvs::Msrv; use clippy_utils::res::{MaybeDef, MaybeResPath}; -use clippy_utils::source::{IntoSpan, SpanRangeExt, snippet}; +use clippy_utils::source::{IntoSpan, SpanExt, snippet}; use clippy_utils::usage::mutated_variables; use clippy_utils::visitors::is_local_used; use clippy_utils::{SpanlessEq, get_ref_operators, is_unit_expr, peel_blocks_with_stmt, peel_ref_operators}; diff --git a/clippy_lints/src/matches/manual_unwrap_or.rs b/clippy_lints/src/matches/manual_unwrap_or.rs index e3a112d1f7802..38017335f5a11 100644 --- a/clippy_lints/src/matches/manual_unwrap_or.rs +++ b/clippy_lints/src/matches/manual_unwrap_or.rs @@ -1,6 +1,6 @@ use clippy_utils::consts::ConstEvalCtxt; use clippy_utils::res::{MaybeDef, MaybeQPath, MaybeResPath}; -use clippy_utils::source::{SpanRangeExt as _, indent_of, reindent_multiline}; +use clippy_utils::source::{SpanExt as _, indent_of, reindent_multiline}; use rustc_ast::{BindingMode, ByRef}; use rustc_errors::Applicability; use rustc_hir::def::Res; diff --git a/clippy_lints/src/matches/match_same_arms.rs b/clippy_lints/src/matches/match_same_arms.rs index caef6a0b36377..35b9e5617ca1b 100644 --- a/clippy_lints/src/matches/match_same_arms.rs +++ b/clippy_lints/src/matches/match_same_arms.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::res::MaybeResPath; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use clippy_utils::{SpanlessEq, fulfill_or_allowed, hash_expr, is_lint_allowed, search_same}; use core::cmp::Ordering; use core::{iter, slice}; diff --git a/clippy_lints/src/matches/match_wild_enum.rs b/clippy_lints/src/matches/match_wild_enum.rs index 6b46791eb117a..b175ed2acf9af 100644 --- a/clippy_lints/src/matches/match_wild_enum.rs +++ b/clippy_lints/src/matches/match_wild_enum.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::res::MaybeDef; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use clippy_utils::{is_refutable, peel_hir_pat_refs, recurse_or_patterns}; use rustc_errors::Applicability; use rustc_hir::def::{CtorKind, DefKind, Res}; diff --git a/clippy_lints/src/matches/single_match.rs b/clippy_lints/src/matches/single_match.rs index b96c869b5151a..414932199d2e4 100644 --- a/clippy_lints/src/matches/single_match.rs +++ b/clippy_lints/src/matches/single_match.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::{ - SpanRangeExt, expr_block, snippet, snippet_block_with_context, snippet_with_applicability, snippet_with_context, + SpanExt, expr_block, snippet, snippet_block_with_context, snippet_with_applicability, snippet_with_context, }; use clippy_utils::ty::{implements_trait, peel_and_count_ty_refs}; use clippy_utils::{is_lint_allowed, is_unit_expr, peel_blocks, peel_hir_pat_refs, peel_n_hir_expr_refs, sym}; diff --git a/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs b/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs index 15f4d91e4bd9e..43508edd42630 100644 --- a/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs +++ b/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::res::MaybeDef; -use clippy_utils::source::{SpanRangeExt, indent_of, reindent_multiline}; +use clippy_utils::source::{SpanExt, indent_of, reindent_multiline}; use clippy_utils::sym; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; diff --git a/clippy_lints/src/methods/filter_map_bool_then.rs b/clippy_lints/src/methods/filter_map_bool_then.rs index 8e5b271212e67..2c16a444adea3 100644 --- a/clippy_lints/src/methods/filter_map_bool_then.rs +++ b/clippy_lints/src/methods/filter_map_bool_then.rs @@ -1,7 +1,7 @@ use super::FILTER_MAP_BOOL_THEN; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::res::{MaybeDef, MaybeTypeckRes}; -use clippy_utils::source::{SpanRangeExt, snippet_with_context}; +use clippy_utils::source::{SpanExt, snippet_with_context}; use clippy_utils::ty::is_copy; use clippy_utils::{CaptureKind, can_move_expr_to_closure, contains_return, is_from_proc_macro, peel_blocks, sym}; use rustc_ast::Mutability; diff --git a/clippy_lints/src/methods/manual_inspect.rs b/clippy_lints/src/methods/manual_inspect.rs index a89a656a6bc7e..bcda19e32e097 100644 --- a/clippy_lints/src/methods/manual_inspect.rs +++ b/clippy_lints/src/methods/manual_inspect.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::res::{MaybeDef, MaybeResPath}; -use clippy_utils::source::{IntoSpan, SpanRangeExt}; +use clippy_utils::source::{IntoSpan, SpanExt}; use clippy_utils::ty::get_field_by_name; use clippy_utils::visitors::{for_each_expr, for_each_expr_without_closures}; use clippy_utils::{ExprUseNode, get_expr_use_site, sym}; diff --git a/clippy_lints/src/methods/manual_ok_or.rs b/clippy_lints/src/methods/manual_ok_or.rs index 48f2c10f97cc6..a50da461719e0 100644 --- a/clippy_lints/src/methods/manual_ok_or.rs +++ b/clippy_lints/src/methods/manual_ok_or.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::res::{MaybeDef, MaybeQPath, MaybeResPath}; -use clippy_utils::source::{SpanRangeExt, indent_of, reindent_multiline}; +use clippy_utils::source::{SpanExt, indent_of, reindent_multiline}; use rustc_errors::Applicability; use rustc_hir::LangItem::{ResultErr, ResultOk}; use rustc_hir::{Expr, ExprKind, PatKind}; diff --git a/clippy_lints/src/methods/manual_try_fold.rs b/clippy_lints/src/methods/manual_try_fold.rs index 5f5944d5d4230..4ec4f41d2b8e3 100644 --- a/clippy_lints/src/methods/manual_try_fold.rs +++ b/clippy_lints/src/methods/manual_try_fold.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::is_from_proc_macro; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::res::{MaybeDef, MaybeTypeckRes}; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use clippy_utils::ty::implements_trait; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; diff --git a/clippy_lints/src/methods/map_all_any_identity.rs b/clippy_lints/src/methods/map_all_any_identity.rs index ad950f75f8130..91118c6fb1c47 100644 --- a/clippy_lints/src/methods/map_all_any_identity.rs +++ b/clippy_lints/src/methods/map_all_any_identity.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_expr_identity_function; use clippy_utils::res::{MaybeDef, MaybeTypeckRes}; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use rustc_errors::Applicability; use rustc_hir::Expr; use rustc_lint::LateContext; diff --git a/clippy_lints/src/methods/needless_character_iteration.rs b/clippy_lints/src/methods/needless_character_iteration.rs index 948ed8a25746e..ba62382da6b0c 100644 --- a/clippy_lints/src/methods/needless_character_iteration.rs +++ b/clippy_lints/src/methods/needless_character_iteration.rs @@ -8,7 +8,7 @@ use rustc_span::Span; use super::NEEDLESS_CHARACTER_ITERATION; use super::utils::get_last_chain_binding_hir_id; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use clippy_utils::{peel_blocks, sym}; fn peels_expr_ref<'a, 'tcx>(mut expr: &'a Expr<'tcx>) -> &'a Expr<'tcx> { diff --git a/clippy_lints/src/methods/needless_option_as_deref.rs b/clippy_lints/src/methods/needless_option_as_deref.rs index 06e6a3c70b87d..0e510a88015ec 100644 --- a/clippy_lints/src/methods/needless_option_as_deref.rs +++ b/clippy_lints/src/methods/needless_option_as_deref.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::res::{MaybeDef, MaybeResPath}; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use clippy_utils::sym; use clippy_utils::usage::local_used_after_expr; use rustc_errors::Applicability; diff --git a/clippy_lints/src/methods/ptr_offset_by_literal.rs b/clippy_lints/src/methods/ptr_offset_by_literal.rs index b5d2add65cf19..129d39c1e9f46 100644 --- a/clippy_lints/src/methods/ptr_offset_by_literal.rs +++ b/clippy_lints/src/methods/ptr_offset_by_literal.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::msrvs::{self, Msrv}; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use clippy_utils::sym; use rustc_ast::LitKind; use rustc_errors::Applicability; diff --git a/clippy_lints/src/methods/range_zip_with_len.rs b/clippy_lints/src/methods/range_zip_with_len.rs index 5fec0c5f2cf7d..51b3db52bd27f 100644 --- a/clippy_lints/src/methods/range_zip_with_len.rs +++ b/clippy_lints/src/methods/range_zip_with_len.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::res::{MaybeDef, MaybeTypeckRes}; -use clippy_utils::source::{SpanRangeExt as _, snippet_with_applicability}; +use clippy_utils::source::{SpanExt as _, snippet_with_applicability}; use clippy_utils::{SpanlessEq, get_parent_expr, higher, is_integer_literal, sym}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, Node, Pat, PatKind, QPath}; diff --git a/clippy_lints/src/methods/string_lit_chars_any.rs b/clippy_lints/src/methods/string_lit_chars_any.rs index 48e89c2998efa..27c324f863285 100644 --- a/clippy_lints/src/methods/string_lit_chars_any.rs +++ b/clippy_lints/src/methods/string_lit_chars_any.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_from_proc_macro; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::res::{MaybeDef, MaybeResPath, MaybeTypeckRes}; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use itertools::Itertools; use rustc_ast::LitKind; use rustc_errors::Applicability; diff --git a/clippy_lints/src/methods/unnecessary_first_then_check.rs b/clippy_lints/src/methods/unnecessary_first_then_check.rs index d322909bef359..9c5768dfb6f53 100644 --- a/clippy_lints/src/methods/unnecessary_first_then_check.rs +++ b/clippy_lints/src/methods/unnecessary_first_then_check.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; diff --git a/clippy_lints/src/methods/unnecessary_get_then_check.rs b/clippy_lints/src/methods/unnecessary_get_then_check.rs index b2413bb77aa73..f0054bd3a897a 100644 --- a/clippy_lints/src/methods/unnecessary_get_then_check.rs +++ b/clippy_lints/src/methods/unnecessary_get_then_check.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::res::MaybeDef; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use clippy_utils::sym; use rustc_errors::Applicability; diff --git a/clippy_lints/src/methods/unnecessary_iter_cloned.rs b/clippy_lints/src/methods/unnecessary_iter_cloned.rs index 444d0a1d72422..9232547355f68 100644 --- a/clippy_lints/src/methods/unnecessary_iter_cloned.rs +++ b/clippy_lints/src/methods/unnecessary_iter_cloned.rs @@ -2,7 +2,7 @@ use super::utils::clone_or_copy_needed; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::higher::ForLoop; use clippy_utils::res::MaybeResPath; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use clippy_utils::ty::{get_iterator_item_ty, implements_trait}; use clippy_utils::visitors::for_each_expr_without_closures; use clippy_utils::{can_mut_borrow_both, fn_def_id, get_parent_expr}; diff --git a/clippy_lints/src/methods/unnecessary_to_owned.rs b/clippy_lints/src/methods/unnecessary_to_owned.rs index a56dcd894b6aa..d26d8f5b42e0d 100644 --- a/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -3,7 +3,7 @@ use super::unnecessary_iter_cloned::{self, is_into_iter}; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::res::MaybeDef; -use clippy_utils::source::{SpanRangeExt, snippet, snippet_with_context}; +use clippy_utils::source::{SpanExt, snippet, snippet_with_context}; use clippy_utils::ty::{get_iterator_item_ty, implements_trait, is_copy, peel_and_count_ty_refs}; use clippy_utils::visitors::find_all_ret_expressions; use clippy_utils::{fn_def_id, get_parent_expr, is_expr_temporary_value, return_ty, sym}; diff --git a/clippy_lints/src/misc_early/unneeded_field_pattern.rs b/clippy_lints/src/misc_early/unneeded_field_pattern.rs index 33ab94e00a5c6..b2ee3f0c24f10 100644 --- a/clippy_lints/src/misc_early/unneeded_field_pattern.rs +++ b/clippy_lints/src/misc_early/unneeded_field_pattern.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use itertools::Itertools; use rustc_ast::ast::{Pat, PatKind}; use rustc_lint::EarlyContext; diff --git a/clippy_lints/src/missing_enforced_import_rename.rs b/clippy_lints/src/missing_enforced_import_rename.rs index 7dbe39bb099d6..2b99ab81816b6 100644 --- a/clippy_lints/src/missing_enforced_import_rename.rs +++ b/clippy_lints/src/missing_enforced_import_rename.rs @@ -1,7 +1,7 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::paths::{PathNS, lookup_path_str}; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use rustc_errors::Applicability; use rustc_hir::def::Res; use rustc_hir::def_id::DefIdMap; diff --git a/clippy_lints/src/multiple_bound_locations.rs b/clippy_lints/src/multiple_bound_locations.rs index 8b02c4865d138..a78f53188ba8b 100644 --- a/clippy_lints/src/multiple_bound_locations.rs +++ b/clippy_lints/src/multiple_bound_locations.rs @@ -6,7 +6,7 @@ use rustc_session::declare_lint_pass; use rustc_span::Span; use clippy_utils::diagnostics::span_lint; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/mutex_atomic.rs b/clippy_lints/src/mutex_atomic.rs index ad44d65b4d663..6d9950579fb24 100644 --- a/clippy_lints/src/mutex_atomic.rs +++ b/clippy_lints/src/mutex_atomic.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::res::MaybeDef; -use clippy_utils::source::{IntoSpan, SpanRangeExt}; +use clippy_utils::source::{IntoSpan, SpanExt}; use clippy_utils::sugg::Sugg; use clippy_utils::ty::ty_from_hir_ty; use rustc_errors::{Applicability, Diag}; diff --git a/clippy_lints/src/needless_else.rs b/clippy_lints/src/needless_else.rs index 807c4cf5da8e1..0a25ab37603e2 100644 --- a/clippy_lints/src/needless_else.rs +++ b/clippy_lints/src/needless_else.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::{IntoSpan, SpanRangeExt}; +use clippy_utils::source::{IntoSpan, SpanExt}; use rustc_ast::ast::{Expr, ExprKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; diff --git a/clippy_lints/src/needless_ifs.rs b/clippy_lints/src/needless_ifs.rs index cdf9bd91339c6..0356fc2696215 100644 --- a/clippy_lints/src/needless_ifs.rs +++ b/clippy_lints/src/needless_ifs.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::higher::If; use clippy_utils::is_from_proc_macro; -use clippy_utils::source::{SpanRangeExt, walk_span_to_context}; +use clippy_utils::source::{SpanExt, walk_span_to_context}; use rustc_errors::Applicability; use rustc_hir::{ExprKind, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; diff --git a/clippy_lints/src/needless_late_init.rs b/clippy_lints/src/needless_late_init.rs index bc4f6ca401710..e4dcaad69026c 100644 --- a/clippy_lints/src/needless_late_init.rs +++ b/clippy_lints/src/needless_late_init.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::res::MaybeResPath; -use clippy_utils::source::{SourceText, SpanRangeExt, snippet}; +use clippy_utils::source::{SourceText, SpanExt, snippet}; use clippy_utils::ty::needs_ordered_drop; use clippy_utils::visitors::{for_each_expr, for_each_expr_without_closures, is_local_used}; use core::ops::ControlFlow; diff --git a/clippy_lints/src/needless_pass_by_value.rs b/clippy_lints/src/needless_pass_by_value.rs index 4ff5b0b0b3c39..b531eb00edc68 100644 --- a/clippy_lints/src/needless_pass_by_value.rs +++ b/clippy_lints/src/needless_pass_by_value.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::res::{MaybeDef, MaybeResPath}; -use clippy_utils::source::{SpanRangeExt, snippet}; +use clippy_utils::source::{SpanExt, snippet}; use clippy_utils::ty::{implements_trait, implements_trait_with_env_from_iter, is_copy}; use clippy_utils::visitors::{Descend, for_each_expr_without_closures}; use clippy_utils::{is_self, peel_hir_ty_options, strip_pat_refs, sym}; diff --git a/clippy_lints/src/no_effect.rs b/clippy_lints/src/no_effect.rs index f2a54b99170e9..af64f71ba3e24 100644 --- a/clippy_lints/src/no_effect.rs +++ b/clippy_lints/src/no_effect.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::{span_lint_hir, span_lint_hir_and_then}; use clippy_utils::res::MaybeResPath; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use clippy_utils::ty::{expr_type_is_certain, has_drop}; use clippy_utils::{in_automatically_derived, is_inside_always_const_context, is_lint_allowed, peel_blocks}; use rustc_errors::Applicability; diff --git a/clippy_lints/src/non_octal_unix_permissions.rs b/clippy_lints/src/non_octal_unix_permissions.rs index cb934466bd890..72ebe13562be4 100644 --- a/clippy_lints/src/non_octal_unix_permissions.rs +++ b/clippy_lints/src/non_octal_unix_permissions.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::{SpanRangeExt, snippet_with_applicability}; +use clippy_utils::source::{SpanExt, snippet_with_applicability}; use clippy_utils::sym; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; diff --git a/clippy_lints/src/nonstandard_macro_braces.rs b/clippy_lints/src/nonstandard_macro_braces.rs index b449681ae2e14..eae2c22ef1eb4 100644 --- a/clippy_lints/src/nonstandard_macro_braces.rs +++ b/clippy_lints/src/nonstandard_macro_braces.rs @@ -1,7 +1,7 @@ use clippy_config::Conf; use clippy_config::types::MacroMatcher; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::{SourceText, SpanRangeExt}; +use clippy_utils::source::{SourceText, SpanExt}; use rustc_ast::ast; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::Applicability; diff --git a/clippy_lints/src/octal_escapes.rs b/clippy_lints/src/octal_escapes.rs index 6e7ee727965db..2ac9e010c69cf 100644 --- a/clippy_lints/src/octal_escapes.rs +++ b/clippy_lints/src/octal_escapes.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use rustc_ast::token::LitKind; use rustc_ast::{Expr, ExprKind}; use rustc_errors::Applicability; diff --git a/clippy_lints/src/operators/assign_op_pattern.rs b/clippy_lints/src/operators/assign_op_pattern.rs index 5695779425f4a..8064a77d43486 100644 --- a/clippy_lints/src/operators/assign_op_pattern.rs +++ b/clippy_lints/src/operators/assign_op_pattern.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::msrvs::Msrv; use clippy_utils::qualify_min_const_fn::is_stable_const_fn; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use clippy_utils::ty::implements_trait; use clippy_utils::visitors::for_each_expr_without_closures; use clippy_utils::{binop_traits, eq_expr_value, is_in_const_context, trait_ref_of_method}; diff --git a/clippy_lints/src/operators/decimal_bitwise_operands.rs b/clippy_lints/src/operators/decimal_bitwise_operands.rs index 8511f2151342d..c5050ca9d4fd5 100644 --- a/clippy_lints/src/operators/decimal_bitwise_operands.rs +++ b/clippy_lints/src/operators/decimal_bitwise_operands.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::numeric_literal; use clippy_utils::numeric_literal::NumericLiteral; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use rustc_ast::LitKind; use rustc_data_structures::packed::Pu128; use rustc_hir::{BinOpKind, Expr, ExprKind}; diff --git a/clippy_lints/src/operators/misrefactored_assign_op.rs b/clippy_lints/src/operators/misrefactored_assign_op.rs index f0b6407a141bd..610f252332f52 100644 --- a/clippy_lints/src/operators/misrefactored_assign_op.rs +++ b/clippy_lints/src/operators/misrefactored_assign_op.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use clippy_utils::{eq_expr_value, sugg}; use rustc_errors::Applicability; use rustc_hir as hir; diff --git a/clippy_lints/src/pathbuf_init_then_push.rs b/clippy_lints/src/pathbuf_init_then_push.rs index a5e57d97301e3..d26aa25778165 100644 --- a/clippy_lints/src/pathbuf_init_then_push.rs +++ b/clippy_lints/src/pathbuf_init_then_push.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::res::{MaybeDef, MaybeResPath}; -use clippy_utils::source::{SpanRangeExt, snippet}; +use clippy_utils::source::{SpanExt, snippet}; use clippy_utils::sym; use rustc_ast::{LitKind, StrStyle}; use rustc_errors::Applicability; diff --git a/clippy_lints/src/ptr/ptr_arg.rs b/clippy_lints/src/ptr/ptr_arg.rs index 40bc42dcdcb36..4f2105b8dc147 100644 --- a/clippy_lints/src/ptr/ptr_arg.rs +++ b/clippy_lints/src/ptr/ptr_arg.rs @@ -1,7 +1,7 @@ use super::PTR_ARG; use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::res::MaybeResPath; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use clippy_utils::{VEC_METHODS_SHADOWING_SLICE_METHODS, get_expr_use_or_unification_node, is_lint_allowed, sym}; use hir::LifetimeKind; use rustc_abi::ExternAbi; diff --git a/clippy_lints/src/ranges.rs b/clippy_lints/src/ranges.rs index 71965ee1e29f9..48456f809c42c 100644 --- a/clippy_lints/src/ranges.rs +++ b/clippy_lints/src/ranges.rs @@ -3,7 +3,7 @@ use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then}; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::res::MaybeResPath; -use clippy_utils::source::{SpanRangeExt, snippet, snippet_with_applicability}; +use clippy_utils::source::{SpanExt, snippet, snippet_with_applicability}; use clippy_utils::sugg::Sugg; use clippy_utils::ty::implements_trait; use clippy_utils::{ diff --git a/clippy_lints/src/raw_strings.rs b/clippy_lints/src/raw_strings.rs index d8aa88d48b09d..5916828b2e8a9 100644 --- a/clippy_lints/src/raw_strings.rs +++ b/clippy_lints/src/raw_strings.rs @@ -1,6 +1,6 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::{SpanRangeExt, snippet_opt}; +use clippy_utils::source::{SpanExt, snippet_opt}; use rustc_ast::ast::{Expr, ExprKind}; use rustc_ast::token::LitKind; use rustc_errors::Applicability; diff --git a/clippy_lints/src/redundant_clone.rs b/clippy_lints/src/redundant_clone.rs index bfb704dd21719..f04e3480a9c63 100644 --- a/clippy_lints/src/redundant_clone.rs +++ b/clippy_lints/src/redundant_clone.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::{span_lint_hir, span_lint_hir_and_then}; use clippy_utils::mir::{LocalUsage, PossibleBorrowerMap, visit_local_usage}; use clippy_utils::res::MaybeDef; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use clippy_utils::ty::{has_drop, is_copy, peel_and_count_ty_refs}; use clippy_utils::{fn_has_unsatisfiable_preds, sym}; use rustc_errors::Applicability; diff --git a/clippy_lints/src/regex.rs b/clippy_lints/src/regex.rs index 80696f0a81b15..53f8a453d275f 100644 --- a/clippy_lints/src/regex.rs +++ b/clippy_lints/src/regex.rs @@ -5,7 +5,7 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; use clippy_utils::paths; use clippy_utils::paths::PathLookup; use clippy_utils::res::MaybeQPath; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use rustc_ast::ast::{LitKind, StrStyle}; use rustc_hir::def_id::DefIdMap; use rustc_hir::{BorrowKind, Expr, ExprKind, OwnerId}; diff --git a/clippy_lints/src/semicolon_block.rs b/clippy_lints/src/semicolon_block.rs index e806123596b85..cde9d16fc6066 100644 --- a/clippy_lints/src/semicolon_block.rs +++ b/clippy_lints/src/semicolon_block.rs @@ -1,6 +1,6 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use rustc_errors::Applicability; use rustc_hir::{Block, Expr, ExprKind, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; diff --git a/clippy_lints/src/single_range_in_vec_init.rs b/clippy_lints/src/single_range_in_vec_init.rs index fc5702a358bbc..eaef8d111a991 100644 --- a/clippy_lints/src/single_range_in_vec_init.rs +++ b/clippy_lints/src/single_range_in_vec_init.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::higher::{Range, VecArgs}; use clippy_utils::macros::root_macro_call_first_node; -use clippy_utils::source::{SpanRangeExt, snippet_with_context}; +use clippy_utils::source::{SpanExt, snippet_with_context}; use clippy_utils::ty::implements_trait; use clippy_utils::{is_no_std_crate, sym}; use rustc_ast::{LitIntType, LitKind, RangeLimits, UintTy}; diff --git a/clippy_lints/src/trait_bounds.rs b/clippy_lints/src/trait_bounds.rs index 7b690b7eb136c..b3a63ed814cb5 100644 --- a/clippy_lints/src/trait_bounds.rs +++ b/clippy_lints/src/trait_bounds.rs @@ -1,7 +1,7 @@ use clippy_config::Conf; use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg}; use clippy_utils::msrvs::{self, Msrv}; -use clippy_utils::source::{SpanRangeExt, snippet, snippet_with_applicability}; +use clippy_utils::source::{SpanExt, snippet, snippet_with_applicability}; use clippy_utils::{SpanlessEq, SpanlessHash, is_from_proc_macro}; use core::hash::{Hash, Hasher}; use itertools::Itertools; diff --git a/clippy_lints/src/transmute/missing_transmute_annotations.rs b/clippy_lints/src/transmute/missing_transmute_annotations.rs index ec1c34fec1780..d121c5385b3c7 100644 --- a/clippy_lints/src/transmute/missing_transmute_annotations.rs +++ b/clippy_lints/src/transmute/missing_transmute_annotations.rs @@ -1,7 +1,7 @@ use std::borrow::Cow; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::SpanRangeExt as _; +use clippy_utils::source::SpanExt as _; use rustc_errors::Applicability; use rustc_hir::{Expr, GenericArg, HirId, LetStmt, Node, Path, TyKind}; use rustc_lint::LateContext; diff --git a/clippy_lints/src/unit_types/unit_arg.rs b/clippy_lints/src/unit_types/unit_arg.rs index 6df3e7baa1bca..ac86a457b5374 100644 --- a/clippy_lints/src/unit_types/unit_arg.rs +++ b/clippy_lints/src/unit_types/unit_arg.rs @@ -1,7 +1,7 @@ use std::iter; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::{SpanRangeExt, indent_of, reindent_multiline}; +use clippy_utils::source::{SpanExt, indent_of, reindent_multiline}; use clippy_utils::sugg::Sugg; use clippy_utils::ty::expr_type_is_certain; use clippy_utils::{is_empty_block, is_expr_default, is_from_proc_macro}; diff --git a/clippy_lints/src/unnecessary_mut_passed.rs b/clippy_lints/src/unnecessary_mut_passed.rs index 75b0b7b10687a..60a6688927ab5 100644 --- a/clippy_lints/src/unnecessary_mut_passed.rs +++ b/clippy_lints/src/unnecessary_mut_passed.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use rustc_errors::Applicability; use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/unused_unit.rs b/clippy_lints/src/unused_unit.rs index d503bd3379b08..bb2ad9f92157c 100644 --- a/clippy_lints/src/unused_unit.rs +++ b/clippy_lints/src/unused_unit.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::{SpanRangeExt, position_before_rarrow}; +use clippy_utils::source::{SpanExt, position_before_rarrow}; use clippy_utils::{is_never_expr, is_unit_expr}; use rustc_ast::{Block, StmtKind}; use rustc_errors::Applicability; diff --git a/clippy_lints/src/useless_vec.rs b/clippy_lints/src/useless_vec.rs index 7b6122213d608..0cd7426cfe0f6 100644 --- a/clippy_lints/src/useless_vec.rs +++ b/clippy_lints/src/useless_vec.rs @@ -7,7 +7,7 @@ use clippy_config::Conf; use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::msrvs::{self, Msrv}; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use clippy_utils::ty::is_copy; use clippy_utils::visitors::for_each_local_use_after_expr; use clippy_utils::{VEC_METHODS_SHADOWING_SLICE_METHODS, get_parent_expr, higher, is_in_test, span_contains_comment}; diff --git a/clippy_lints/src/utils/format_args_collector.rs b/clippy_lints/src/utils/format_args_collector.rs index 6629a67f78bd4..8f5014d1e3add 100644 --- a/clippy_lints/src/utils/format_args_collector.rs +++ b/clippy_lints/src/utils/format_args_collector.rs @@ -1,5 +1,5 @@ use clippy_utils::macros::FormatArgsStorage; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use itertools::Itertools; use rustc_ast::{Crate, Expr, ExprKind, FormatArgs}; use rustc_data_structures::fx::FxHashMap; diff --git a/clippy_lints/src/visibility.rs b/clippy_lints/src/visibility.rs index 74ffeb629d2be..875041da780c1 100644 --- a/clippy_lints/src/visibility.rs +++ b/clippy_lints/src/visibility.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use rustc_ast::ast::{Item, VisibilityKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; diff --git a/clippy_lints/src/write/literal.rs b/clippy_lints/src/write/literal.rs index 699ac7ea7a5cd..9711410ef8853 100644 --- a/clippy_lints/src/write/literal.rs +++ b/clippy_lints/src/write/literal.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::macros::format_arg_removal_span; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use clippy_utils::sym; use rustc_ast::token::LitKind; use rustc_ast::{ diff --git a/clippy_lints/src/write/with_newline.rs b/clippy_lints/src/write/with_newline.rs index e4b51da3cadcf..53109f4014c81 100644 --- a/clippy_lints/src/write/with_newline.rs +++ b/clippy_lints/src/write/with_newline.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::macros::MacroCall; -use clippy_utils::source::{SpanRangeExt, expand_past_previous_comma}; +use clippy_utils::source::{SpanExt, expand_past_previous_comma}; use clippy_utils::sym; use rustc_ast::{FormatArgs, FormatArgsPiece}; use rustc_errors::Applicability; diff --git a/clippy_utils/src/attrs.rs b/clippy_utils/src/attrs.rs index 8df82489d6a3f..119836fda46c3 100644 --- a/clippy_utils/src/attrs.rs +++ b/clippy_utils/src/attrs.rs @@ -1,6 +1,6 @@ //! Utility functions for attributes, including Clippy's built-in ones -use crate::source::SpanRangeExt; +use crate::source::SpanExt; use crate::{sym, tokenize_with_text}; use rustc_ast::attr::AttributeExt; use rustc_errors::Applicability; diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs index 3cb9febb5003c..26aef9c1fc910 100644 --- a/clippy_utils/src/consts.rs +++ b/clippy_utils/src/consts.rs @@ -5,7 +5,7 @@ #![expect(clippy::float_cmp)] use crate::res::MaybeDef; -use crate::source::{SpanRangeExt, walk_span_to_context}; +use crate::source::{SpanExt, walk_span_to_context}; use crate::{clip, is_direct_expn_of, sext, sym, unsext}; use rustc_abi::Size; diff --git a/clippy_utils/src/hir_utils.rs b/clippy_utils/src/hir_utils.rs index 38724a1053f65..53352ddc7f83a 100644 --- a/clippy_utils/src/hir_utils.rs +++ b/clippy_utils/src/hir_utils.rs @@ -1,6 +1,6 @@ use crate::consts::ConstEvalCtxt; use crate::macros::macro_backtrace; -use crate::source::{SpanRange, SpanRangeExt, walk_span_to_context}; +use crate::source::{SpanExt, SpanRange, walk_span_to_context}; use crate::{sym, tokenize_with_text}; use core::mem; use rustc_ast::ast; diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 203962c05d86e..366ace799612c 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -116,7 +116,7 @@ use rustc_span::hygiene::{ExpnKind, MacroKind}; use rustc_span::source_map::SourceMap; use rustc_span::symbol::{Ident, Symbol, kw}; use rustc_span::{InnerSpan, Span, SyntaxContext}; -use source::{SpanRangeExt, walk_span_to_context}; +use source::{SpanExt, walk_span_to_context}; use visitors::{Visitable, for_each_unconsumed_temporary}; use crate::ast_utils::unordered_over; diff --git a/clippy_utils/src/source.rs b/clippy_utils/src/source.rs index 923d3a9cdb0d1..036f1346ce625 100644 --- a/clippy_utils/src/source.rs +++ b/clippy_utils/src/source.rs @@ -106,7 +106,7 @@ impl IntoSpan for Range { } } -pub trait SpanRangeExt: SpanRange { +pub trait SpanExt: SpanRange { /// Attempts to get a handle to the source text. Returns `None` if either the span is malformed, /// or the source text is not accessible. fn get_source_text<'sm>(self, sm: impl HasSourceMap<'sm>) -> Option { @@ -176,7 +176,7 @@ pub trait SpanRangeExt: SpanRange { trim_start(sm.source_map(), self.into_range()) } } -impl SpanRangeExt for T {} +impl SpanExt for T {} /// Handle to a range of text in a source file. pub struct SourceText(SourceFileRange); From 9c88e494d50f6a5f878e691327aa0c34922fb9f5 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Tue, 18 Nov 2025 23:49:16 -0500 Subject: [PATCH 31/77] Rename `get_source_text` and `check_source_text` to `get_text` and `check_text`. --- clippy_lints/src/attrs/non_minimal_cfg.rs | 2 +- .../src/attrs/unnecessary_clippy_cfg.rs | 4 +-- clippy_lints/src/attrs/useless_attribute.rs | 2 +- clippy_lints/src/booleans.rs | 29 +++++++------------ clippy_lints/src/borrow_deref_ref.rs | 2 +- clippy_lints/src/casts/as_ptr_cast_mut.rs | 2 +- clippy_lints/src/casts/cast_lossless.rs | 2 +- clippy_lints/src/casts/manual_dangling_ptr.rs | 2 +- clippy_lints/src/casts/unnecessary_cast.rs | 4 +-- clippy_lints/src/casts/zero_ptr.rs | 2 +- .../src/default_constructed_unit_structs.rs | 2 +- clippy_lints/src/empty_line_after.rs | 2 +- clippy_lints/src/format.rs | 2 +- clippy_lints/src/format_args.rs | 4 +-- clippy_lints/src/four_forward_slashes.rs | 2 +- clippy_lints/src/from_over_into.rs | 4 +-- clippy_lints/src/functions/too_many_lines.rs | 2 +- clippy_lints/src/items_after_test_module.rs | 2 +- clippy_lints/src/large_stack_frames.rs | 2 +- clippy_lints/src/legacy_numeric_constants.rs | 2 +- clippy_lints/src/len_zero.rs | 2 +- clippy_lints/src/literal_representation.rs | 4 +-- clippy_lints/src/manual_async_fn.rs | 6 ++-- clippy_lints/src/manual_float_methods.rs | 2 +- clippy_lints/src/manual_hash_one.rs | 4 +-- clippy_lints/src/manual_range_patterns.rs | 4 +-- clippy_lints/src/matches/manual_unwrap_or.rs | 2 +- clippy_lints/src/matches/match_same_arms.rs | 2 +- clippy_lints/src/matches/match_wild_enum.rs | 2 +- clippy_lints/src/matches/single_match.rs | 2 +- ...se_sensitive_file_extension_comparisons.rs | 2 +- .../src/methods/filter_map_bool_then.rs | 2 +- clippy_lints/src/methods/manual_ok_or.rs | 4 +-- clippy_lints/src/methods/manual_try_fold.rs | 6 ++-- .../src/methods/map_all_any_identity.rs | 2 +- .../methods/needless_character_iteration.rs | 4 +-- .../src/methods/needless_option_as_deref.rs | 2 +- .../src/methods/ptr_offset_by_literal.rs | 2 +- .../src/methods/range_zip_with_len.rs | 4 +-- .../src/methods/string_lit_chars_any.rs | 2 +- .../methods/unnecessary_first_then_check.rs | 4 +-- .../src/methods/unnecessary_get_then_check.rs | 8 ++--- .../src/methods/unnecessary_iter_cloned.rs | 4 +-- .../src/methods/unnecessary_to_owned.rs | 8 ++--- .../src/misc_early/unneeded_field_pattern.rs | 2 +- .../src/missing_enforced_import_rename.rs | 2 +- clippy_lints/src/needless_else.rs | 2 +- clippy_lints/src/needless_ifs.rs | 4 +-- clippy_lints/src/needless_late_init.rs | 2 +- clippy_lints/src/needless_pass_by_value.rs | 4 +-- clippy_lints/src/no_effect.rs | 6 ++-- .../src/non_octal_unix_permissions.rs | 4 +-- clippy_lints/src/nonstandard_macro_braces.rs | 2 +- clippy_lints/src/octal_escapes.rs | 2 +- .../src/operators/assign_op_pattern.rs | 4 +-- .../src/operators/decimal_bitwise_operands.rs | 2 +- .../src/operators/misrefactored_assign_op.rs | 4 +-- clippy_lints/src/pathbuf_init_then_push.rs | 6 ++-- clippy_lints/src/ptr/ptr_arg.rs | 6 ++-- clippy_lints/src/ranges.rs | 2 +- clippy_lints/src/raw_strings.rs | 4 +-- clippy_lints/src/redundant_clone.rs | 2 +- clippy_lints/src/regex.rs | 2 +- clippy_lints/src/semicolon_block.rs | 2 +- clippy_lints/src/single_range_in_vec_init.rs | 2 +- clippy_lints/src/trait_bounds.rs | 7 ++--- clippy_lints/src/unit_types/unit_arg.rs | 4 +-- clippy_lints/src/useless_vec.rs | 4 +-- .../src/utils/format_args_collector.rs | 2 +- clippy_lints/src/visibility.rs | 2 +- clippy_lints/src/write/literal.rs | 4 +-- clippy_lints/src/write/with_newline.rs | 2 +- clippy_utils/src/attrs.rs | 2 +- clippy_utils/src/hir_utils.rs | 2 +- clippy_utils/src/lib.rs | 4 +-- clippy_utils/src/source.rs | 4 +-- 76 files changed, 125 insertions(+), 137 deletions(-) diff --git a/clippy_lints/src/attrs/non_minimal_cfg.rs b/clippy_lints/src/attrs/non_minimal_cfg.rs index a76bdcfdfb3e5..91e2689a14731 100644 --- a/clippy_lints/src/attrs/non_minimal_cfg.rs +++ b/clippy_lints/src/attrs/non_minimal_cfg.rs @@ -29,7 +29,7 @@ fn check_nested_cfg(cx: &EarlyContext<'_>, items: &[MetaItemInner]) { meta.span, "unneeded sub `cfg` when there is only one condition", |diag| { - if let Some(snippet) = list[0].span().get_source_text(cx) { + if let Some(snippet) = list[0].span().get_text(cx) { diag.span_suggestion( meta.span, "try", diff --git a/clippy_lints/src/attrs/unnecessary_clippy_cfg.rs b/clippy_lints/src/attrs/unnecessary_clippy_cfg.rs index b4742e4da7503..4c97c03471aa9 100644 --- a/clippy_lints/src/attrs/unnecessary_clippy_cfg.rs +++ b/clippy_lints/src/attrs/unnecessary_clippy_cfg.rs @@ -32,7 +32,7 @@ pub(super) fn check( return; } if nb_items == clippy_lints.len() { - if let Some(snippet) = behind_cfg_attr.span.get_source_text(cx) { + if let Some(snippet) = behind_cfg_attr.span.get_text(cx) { span_lint_and_sugg( cx, UNNECESSARY_CLIPPY_CFG, @@ -48,7 +48,7 @@ pub(super) fn check( ); } } else { - let snippet = clippy_lints.iter().filter_map(|sp| sp.get_source_text(cx)).join(","); + let snippet = clippy_lints.iter().filter_map(|sp| sp.get_text(cx)).join(","); span_lint_and_note( cx, UNNECESSARY_CLIPPY_CFG, diff --git a/clippy_lints/src/attrs/useless_attribute.rs b/clippy_lints/src/attrs/useless_attribute.rs index 7c0bfd9edb415..60cdcd4a85817 100644 --- a/clippy_lints/src/attrs/useless_attribute.rs +++ b/clippy_lints/src/attrs/useless_attribute.rs @@ -74,7 +74,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, item: &Item, attrs: &[Attribute]) { } let line_span = first_line_of_span(cx, attr.span); - if let Some(src) = line_span.get_source_text(cx) + if let Some(src) = line_span.get_text(cx) && src.contains("#[") { #[expect(clippy::collapsible_span_lint_calls)] diff --git a/clippy_lints/src/booleans.rs b/clippy_lints/src/booleans.rs index 4a3ff6c63705e..efd453b3276cc 100644 --- a/clippy_lints/src/booleans.rs +++ b/clippy_lints/src/booleans.rs @@ -157,30 +157,30 @@ fn check_inverted_bool_in_condition( let suggestion = match (left.kind, right.kind) { (ExprKind::Unary(UnOp::Not, left_sub), ExprKind::Unary(UnOp::Not, right_sub)) => { - let Some(left) = left_sub.span.get_source_text(cx) else { + let Some(left) = left_sub.span.get_text(cx) else { return; }; - let Some(right) = right_sub.span.get_source_text(cx) else { + let Some(right) = right_sub.span.get_text(cx) else { return; }; let Some(op) = bin_op_eq_str(op) else { return }; format!("{left} {op} {right}") }, (ExprKind::Unary(UnOp::Not, left_sub), _) => { - let Some(left) = left_sub.span.get_source_text(cx) else { + let Some(left) = left_sub.span.get_text(cx) else { return; }; - let Some(right) = right.span.get_source_text(cx) else { + let Some(right) = right.span.get_text(cx) else { return; }; let Some(op) = inverted_bin_op_eq_str(op) else { return }; format!("{left} {op} {right}") }, (_, ExprKind::Unary(UnOp::Not, right_sub)) => { - let Some(left) = left.span.get_source_text(cx) else { + let Some(left) = left.span.get_text(cx) else { return; }; - let Some(right) = right_sub.span.get_source_text(cx) else { + let Some(right) = right_sub.span.get_text(cx) else { return; }; let Some(op) = inverted_bin_op_eq_str(op) else { return }; @@ -392,12 +392,8 @@ impl SuggestContext<'_, '_, '_> { } }, &Term(n) => { - self.output.push_str( - &self.terminals[n as usize] - .span - .source_callsite() - .get_source_text(self.cx)?, - ); + self.output + .push_str(&self.terminals[n as usize].span.source_callsite().get_text(self.cx)?); }, } Some(()) @@ -452,10 +448,7 @@ fn simplify_not(cx: &LateContext<'_>, curr_msrv: Msrv, expr: &Expr<'_>) -> Optio .map(|arg| simplify_not(cx, curr_msrv, arg)) .collect::>>()? .join(", "); - Some(format!( - "{}.{neg_method}({negated_args})", - receiver.span.get_source_text(cx)? - )) + Some(format!("{}.{neg_method}({negated_args})", receiver.span.get_text(cx)?)) }) }, ExprKind::Closure(closure) => { @@ -463,13 +456,13 @@ fn simplify_not(cx: &LateContext<'_>, curr_msrv: Msrv, expr: &Expr<'_>) -> Optio let params = body .params .iter() - .map(|param| param.span.get_source_text(cx).map(|t| t.to_string())) + .map(|param| param.span.get_text(cx).map(|t| t.to_string())) .collect::>>()? .join(", "); let negated = simplify_not(cx, curr_msrv, body.value)?; Some(format!("|{params}| {negated}")) }, - ExprKind::Unary(UnOp::Not, expr) => expr.span.get_source_text(cx).map(|t| t.to_string()), + ExprKind::Unary(UnOp::Not, expr) => expr.span.get_text(cx).map(|t| t.to_string()), _ => None, } } diff --git a/clippy_lints/src/borrow_deref_ref.rs b/clippy_lints/src/borrow_deref_ref.rs index 1d5ea5ae88f72..13ae80868d9b5 100644 --- a/clippy_lints/src/borrow_deref_ref.rs +++ b/clippy_lints/src/borrow_deref_ref.rs @@ -82,7 +82,7 @@ impl<'tcx> LateLintPass<'tcx> for BorrowDerefRef { // If the new borrow might be itself borrowed mutably and the original reference is not a temporary // value, do not propose to use it directly. && (is_expr_temporary_value(cx, deref_target) || !potentially_bound_to_mutable_ref(cx, e)) - && let Some(deref_text) = deref_target.span.get_source_text(cx) + && let Some(deref_text) = deref_target.span.get_text(cx) { // `&*x` can be needed to shorten the borrow of `x`. Replacing it with `x` can be // incorrect when `x` is a closure-captured upvar (e.g. a closure returning another diff --git a/clippy_lints/src/casts/as_ptr_cast_mut.rs b/clippy_lints/src/casts/as_ptr_cast_mut.rs index 0222dd96a6904..f23e789cf5d64 100644 --- a/clippy_lints/src/casts/as_ptr_cast_mut.rs +++ b/clippy_lints/src/casts/as_ptr_cast_mut.rs @@ -20,7 +20,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, && let as_ptr_sig = cx.tcx.fn_sig(as_ptr_did).instantiate_identity().skip_norm_wip() && let Some(first_param_ty) = as_ptr_sig.skip_binder().inputs().iter().next() && let ty::Ref(_, _, Mutability::Not) = first_param_ty.kind() - && let Some(recv) = receiver.span.get_source_text(cx) + && let Some(recv) = receiver.span.get_text(cx) { // `as_mut_ptr` might not exist let applicability = Applicability::MaybeIncorrect; diff --git a/clippy_lints/src/casts/cast_lossless.rs b/clippy_lints/src/casts/cast_lossless.rs index bcfb59028201e..d2bf6db751320 100644 --- a/clippy_lints/src/casts/cast_lossless.rs +++ b/clippy_lints/src/casts/cast_lossless.rs @@ -40,7 +40,7 @@ pub(super) fn check( diag.help("an `as` cast can become silently lossy if the types change in the future"); let mut applicability = Applicability::MachineApplicable; let from_sugg = Sugg::hir_with_context(cx, cast_from_expr, expr.span.ctxt(), "", &mut applicability); - let Some(ty) = hygiene::walk_chain(cast_to_hir.span, expr.span.ctxt()).get_source_text(cx) else { + let Some(ty) = hygiene::walk_chain(cast_to_hir.span, expr.span.ctxt()).get_text(cx) else { return; }; match cast_to_hir.kind { diff --git a/clippy_lints/src/casts/manual_dangling_ptr.rs b/clippy_lints/src/casts/manual_dangling_ptr.rs index fe31de69a1545..36d63ce63195b 100644 --- a/clippy_lints/src/casts/manual_dangling_ptr.rs +++ b/clippy_lints/src/casts/manual_dangling_ptr.rs @@ -25,7 +25,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, from: &Expr<'_>, to: let sugg = if let TyKind::Infer(()) = ptr_ty.ty.kind { format!("{std_or_core}::{sugg_fn}()") - } else if let Some(mut_ty_snip) = ptr_ty.ty.span.get_source_text(cx) { + } else if let Some(mut_ty_snip) = ptr_ty.ty.span.get_text(cx) { format!("{std_or_core}::{sugg_fn}::<{mut_ty_snip}>()") } else { return; diff --git a/clippy_lints/src/casts/unnecessary_cast.rs b/clippy_lints/src/casts/unnecessary_cast.rs index c320da98b4d61..83a6cab01f9d9 100644 --- a/clippy_lints/src/casts/unnecessary_cast.rs +++ b/clippy_lints/src/casts/unnecessary_cast.rs @@ -113,7 +113,7 @@ pub(super) fn check<'tcx>( let literal_str = &cast_str; if let LitKind::Int(n, _) = lit.node - && let Some(src) = cast_expr.span.get_source_text(cx) + && let Some(src) = cast_expr.span.get_text(cx) && cast_to.is_floating_point() && let Some(num_lit) = NumericLiteral::from_lit_kind(&src, &lit.node) && let from_nbits = 128 - n.get().leading_zeros() @@ -140,7 +140,7 @@ pub(super) fn check<'tcx>( | LitKind::Float(_, LitFloatType::Suffixed(_)) if cast_from.kind() == cast_to.kind() => { - if let Some(src) = cast_expr.span.get_source_text(cx) + if let Some(src) = cast_expr.span.get_text(cx) && let Some(num_lit) = NumericLiteral::from_lit_kind(&src, &lit.node) { lint_unnecessary_cast(cx, expr, num_lit.integer, cast_from, cast_to); diff --git a/clippy_lints/src/casts/zero_ptr.rs b/clippy_lints/src/casts/zero_ptr.rs index d33d08230d1a3..90290caf10bf7 100644 --- a/clippy_lints/src/casts/zero_ptr.rs +++ b/clippy_lints/src/casts/zero_ptr.rs @@ -21,7 +21,7 @@ pub fn check(cx: &LateContext<'_>, expr: &Expr<'_>, from: &Expr<'_>, to: &Ty<'_> let sugg = if let TyKind::Infer(()) = mut_ty.ty.kind { format!("{std_or_core}::{sugg_fn}()") - } else if let Some(mut_ty_snip) = mut_ty.ty.span.get_source_text(cx) { + } else if let Some(mut_ty_snip) = mut_ty.ty.span.get_text(cx) { format!("{std_or_core}::{sugg_fn}::<{mut_ty_snip}>()") } else { return; diff --git a/clippy_lints/src/default_constructed_unit_structs.rs b/clippy_lints/src/default_constructed_unit_structs.rs index dc930e83dfa50..9e141bd945db0 100644 --- a/clippy_lints/src/default_constructed_unit_structs.rs +++ b/clippy_lints/src/default_constructed_unit_structs.rs @@ -78,7 +78,7 @@ impl LateLintPass<'_> for DefaultConstructedUnitStructs { && !base.is_suggestable_infer_ty() { let mut removals = vec![(expr.span.with_lo(qpath.qself_span().hi()), String::new())]; - if expr.span.check_source_text(cx, |s| s.starts_with('<')) { + if expr.span.check_text(cx, |s| s.starts_with('<')) { // Remove `<`, '>` has already been removed by the existing removal expression. removals.push((expr.span.with_hi(qpath.qself_span().lo()), String::new())); } diff --git a/clippy_lints/src/empty_line_after.rs b/clippy_lints/src/empty_line_after.rs index 3978ba65f59b8..f076c6d29138d 100644 --- a/clippy_lints/src/empty_line_after.rs +++ b/clippy_lints/src/empty_line_after.rs @@ -288,7 +288,7 @@ impl<'a> Gap<'a> { let prev_stop = prev_chunk.last()?; let next_stop = next_chunk.first()?; let gap_span = prev_stop.span.between(next_stop.span); - let gap_snippet = gap_span.get_source_text(cx)?; + let gap_snippet = gap_span.get_text(cx)?; let mut has_comment = false; let mut empty_lines = Vec::new(); diff --git a/clippy_lints/src/format.rs b/clippy_lints/src/format.rs index 18fefd4b5a550..f13278d91ce7f 100644 --- a/clippy_lints/src/format.rs +++ b/clippy_lints/src/format.rs @@ -69,7 +69,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessFormat { ([], []) => span_useless_format_empty(cx, call_site, "String::new()".to_owned(), applicability), ([], [_]) => { // Simulate macro expansion, converting {{ and }} to { and }. - let Some(snippet) = format_args.span.get_source_text(cx) else { + let Some(snippet) = format_args.span.get_text(cx) else { return; }; let s_expand = snippet.replace("{{", "{").replace("}}", "}"); diff --git a/clippy_lints/src/format_args.rs b/clippy_lints/src/format_args.rs index bfc9c41c9dbd6..9014302fb8ea6 100644 --- a/clippy_lints/src/format_args.rs +++ b/clippy_lints/src/format_args.rs @@ -380,7 +380,7 @@ impl<'tcx> FormatArgsExpr<'_, 'tcx> { /// Check if there is a comma after the last format macro arg. fn check_trailing_comma(&self) { let span = self.macro_call.span; - if let Some(src) = span.get_source_text(self.cx) + if let Some(src) = span.get_text(self.cx) && let Some(src) = src.strip_suffix([')', ']', '}']) && let src = src.trim_end_matches(|c: char| c.is_whitespace() && c != '\n') && let Some(src) = src.strip_suffix(',') @@ -694,7 +694,7 @@ impl<'tcx> FormatArgsExpr<'_, 'tcx> { count_needed_derefs(receiver_ty, cx.typeck_results().expr_adjustments(receiver).iter()) && implements_trait(cx, target, display_trait_id, &[]) && let Some(sized_trait_id) = cx.tcx.lang_items().sized_trait() - && let Some(receiver_snippet) = receiver.span.source_callsite().get_source_text(cx) + && let Some(receiver_snippet) = receiver.span.source_callsite().get_text(cx) { let needs_ref = !implements_trait(cx, receiver_ty, sized_trait_id, &[]); if n_needed_derefs == 0 && !needs_ref { diff --git a/clippy_lints/src/four_forward_slashes.rs b/clippy_lints/src/four_forward_slashes.rs index f05626268fc21..c64e742592080 100644 --- a/clippy_lints/src/four_forward_slashes.rs +++ b/clippy_lints/src/four_forward_slashes.rs @@ -86,7 +86,7 @@ impl<'tcx> LateLintPass<'tcx> for FourForwardSlashes { // If the comment contains a bare CR (not followed by a LF), do not propose an auto-fix // as bare CR are not allowed in doc comments. - if span.check_source_text(cx, contains_bare_cr) { + if span.check_text(cx, contains_bare_cr) { diag.help(msg) .note("bare CR characters are not allowed in doc comments"); return; diff --git a/clippy_lints/src/from_over_into.rs b/clippy_lints/src/from_over_into.rs index 73250c2952bc1..fb09cac1fe702 100644 --- a/clippy_lints/src/from_over_into.rs +++ b/clippy_lints/src/from_over_into.rs @@ -197,8 +197,8 @@ fn convert_to_from( return None; }; - let from = self_ty.span.get_source_text(cx)?; - let into = target_ty.span.get_source_text(cx)?; + let from = self_ty.span.get_text(cx)?; + let into = target_ty.span.get_text(cx)?; let mut suggestions = vec![ // impl Into for U -> impl From for U diff --git a/clippy_lints/src/functions/too_many_lines.rs b/clippy_lints/src/functions/too_many_lines.rs index da3ad2287c319..a5fed9f03a620 100644 --- a/clippy_lints/src/functions/too_many_lines.rs +++ b/clippy_lints/src/functions/too_many_lines.rs @@ -23,7 +23,7 @@ pub(super) fn check_fn( } let mut line_count: u64 = 0; - let too_many = body.value.span.check_source_text(cx, |src| { + let too_many = body.value.span.check_text(cx, |src| { let mut in_comment = false; let mut code_in_line; diff --git a/clippy_lints/src/items_after_test_module.rs b/clippy_lints/src/items_after_test_module.rs index 3ab4be1442515..f83bcb3cf4076 100644 --- a/clippy_lints/src/items_after_test_module.rs +++ b/clippy_lints/src/items_after_test_module.rs @@ -99,7 +99,7 @@ impl LateLintPass<'_> for ItemsAfterTestModule { if let Some(prev) = mod_pos.checked_sub(1) && let prev = cx.tcx.hir_item(module.item_ids[prev]) && let items_span = last.span.with_lo(test_mod.span.hi()) - && let Some(items) = items_span.get_source_text(cx) + && let Some(items) = items_span.get_text(cx) { diag.multipart_suggestion_with_style( "move the items to before the test module was defined", diff --git a/clippy_lints/src/large_stack_frames.rs b/clippy_lints/src/large_stack_frames.rs index 88216d188f8e5..dec3f3bcae895 100644 --- a/clippy_lints/src/large_stack_frames.rs +++ b/clippy_lints/src/large_stack_frames.rs @@ -197,7 +197,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeStackFrames { // TODO: Is there a cleaner, robust way to ask this question? // The obvious `LocalDecl::is_user_variable()` panics on "unwrapping cross-crate data", // and that doesn't get us the true name in scope rather than the span text either. - if let Some(name) = local_span.get_source_text(cx) + if let Some(name) = local_span.get_text(cx) && is_ident(&name) { // If the local is an ordinary named variable, diff --git a/clippy_lints/src/legacy_numeric_constants.rs b/clippy_lints/src/legacy_numeric_constants.rs index b53355150f6ab..48e1414defadf 100644 --- a/clippy_lints/src/legacy_numeric_constants.rs +++ b/clippy_lints/src/legacy_numeric_constants.rs @@ -121,7 +121,7 @@ impl<'tcx> LateLintPass<'tcx> for LegacyNumericConstants { && let QPath::TypeRelative(ty, last_segment) = qpath && let Some(def_id) = cx.qpath_res(qpath, func.hir_id).opt_def_id() && is_integer_method(cx, def_id) - && let Some(mod_name) = ty.span.get_source_text(cx) + && let Some(mod_name) = ty.span.get_text(cx) && ty.span.eq_ctxt(last_segment.ident.span) { let name = last_segment.ident.name.as_str()[..=2].to_ascii_uppercase(); diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index 4d1a8bacbfff2..a84db8929713e 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -261,7 +261,7 @@ impl LenZero { } fn span_without_enclosing_paren(cx: &LateContext<'_>, span: Span) -> Span { - let Some(snippet) = span.get_source_text(cx) else { + let Some(snippet) = span.get_text(cx) else { return span; }; if has_enclosing_paren(snippet) { diff --git a/clippy_lints/src/literal_representation.rs b/clippy_lints/src/literal_representation.rs index 6b908e32ee3e0..4e7ff879ae590 100644 --- a/clippy_lints/src/literal_representation.rs +++ b/clippy_lints/src/literal_representation.rs @@ -228,7 +228,7 @@ impl LiteralDigitGrouping { } fn check_lit(&self, cx: &EarlyContext<'_>, lit: token::Lit, span: Span) { - if let Some(src) = span.get_source_text(cx) + if let Some(src) = span.get_text(cx) && let Ok(lit_kind) = LitKind::from_token_lit(lit) && let Some(mut num_lit) = NumericLiteral::from_lit_kind(&src, &lit_kind) { @@ -441,7 +441,7 @@ impl DecimalLiteralRepresentation { if let Ok(lit_kind) = LitKind::from_token_lit(lit) && let LitKind::Int(val, _) = lit_kind && val >= u128::from(self.threshold) - && let Some(src) = span.get_source_text(cx) + && let Some(src) = span.get_text(cx) && let Some(num_lit) = NumericLiteral::from_lit_kind(&src, &lit_kind) && num_lit.radix == Radix::Decimal { diff --git a/clippy_lints/src/manual_async_fn.rs b/clippy_lints/src/manual_async_fn.rs index dff324d132a0e..161834914b309 100644 --- a/clippy_lints/src/manual_async_fn.rs +++ b/clippy_lints/src/manual_async_fn.rs @@ -76,8 +76,8 @@ impl<'tcx> LateLintPass<'tcx> for ManualAsyncFn { "this function can be simplified using the `async fn` syntax", |diag| { if let Some(vis_span) = vis_span_opt - && let Some(vis_snip) = vis_span.get_source_text(cx) - && let Some(header_snip) = header_span.get_source_text(cx) + && let Some(vis_snip) = vis_span.get_text(cx) + && let Some(header_snip) = header_span.get_text(cx) && let Some(ret_pos) = position_before_rarrow(&header_snip) && let Some((_, ret_snip)) = suggested_ret(cx, output) { @@ -185,6 +185,6 @@ fn suggested_ret(cx: &LateContext<'_>, output: &Ty<'_>) -> Option<(&'static str, Some((sugg, String::new())) } else { let sugg = "return the output of the future directly"; - output.span.get_source_text(cx).map(|src| (sugg, format!(" -> {src}"))) + output.span.get_text(cx).map(|src| (sugg, format!(" -> {src}"))) } } diff --git a/clippy_lints/src/manual_float_methods.rs b/clippy_lints/src/manual_float_methods.rs index 87fc28b39ce7e..acd47fcd279db 100644 --- a/clippy_lints/src/manual_float_methods.rs +++ b/clippy_lints/src/manual_float_methods.rs @@ -157,7 +157,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualFloatMethods { // case somebody does that for some reason && (const_1.is_pos_infinity() && const_2.is_neg_infinity() || const_1.is_neg_infinity() && const_2.is_pos_infinity()) - && let Some(local_snippet) = first.span.get_source_text(cx) + && let Some(local_snippet) = first.span.get_text(cx) { let variant = match (kind.node, lhs_kind.node, rhs_kind.node) { (BinOpKind::Or, BinOpKind::Eq, BinOpKind::Eq) => Variant::ManualIsInfinite, diff --git a/clippy_lints/src/manual_hash_one.rs b/clippy_lints/src/manual_hash_one.rs index 475ee2191a850..33370194d4e7c 100644 --- a/clippy_lints/src/manual_hash_one.rs +++ b/clippy_lints/src/manual_hash_one.rs @@ -105,8 +105,8 @@ impl LateLintPass<'_> for ManualHashOne { finish_expr.span, "manual implementation of `BuildHasher::hash_one`", |diag| { - if let Some(build_hasher) = build_hasher.span.get_source_text(cx) - && let Some(hashed_value) = hashed_value.span.get_source_text(cx) + if let Some(build_hasher) = build_hasher.span.get_text(cx) + && let Some(hashed_value) = hashed_value.span.get_text(cx) { diag.multipart_suggestion( "try", diff --git a/clippy_lints/src/manual_range_patterns.rs b/clippy_lints/src/manual_range_patterns.rs index e1b353b4911ad..94a3f2b1f15f9 100644 --- a/clippy_lints/src/manual_range_patterns.rs +++ b/clippy_lints/src/manual_range_patterns.rs @@ -143,8 +143,8 @@ impl LateLintPass<'_> for ManualRangePatterns { pat.span, "this OR pattern can be rewritten using a range", |diag| { - if let Some(min) = min.span.get_source_text(cx) - && let Some(max) = max.span.get_source_text(cx) + if let Some(min) = min.span.get_text(cx) + && let Some(max) = max.span.get_text(cx) { diag.span_suggestion( pat.span, diff --git a/clippy_lints/src/matches/manual_unwrap_or.rs b/clippy_lints/src/matches/manual_unwrap_or.rs index 38017335f5a11..e317056e29809 100644 --- a/clippy_lints/src/matches/manual_unwrap_or.rs +++ b/clippy_lints/src/matches/manual_unwrap_or.rs @@ -160,7 +160,7 @@ fn handle( ); } else if let Some(ty_name) = find_type_name(cx, cx.typeck_results().expr_ty(condition)) && cx.typeck_results().expr_adjustments(body_some).is_empty() - && let Some(or_body_snippet) = peel_blocks(body_none).span.get_source_text(cx) + && let Some(or_body_snippet) = peel_blocks(body_none).span.get_text(cx) && let Some(indent) = indent_of(cx, expr.span) && ConstEvalCtxt::new(cx).eval_local(body_none, expr.span.ctxt()).is_some() { diff --git a/clippy_lints/src/matches/match_same_arms.rs b/clippy_lints/src/matches/match_same_arms.rs index 35b9e5617ca1b..f500f21246bdb 100644 --- a/clippy_lints/src/matches/match_same_arms.rs +++ b/clippy_lints/src/matches/match_same_arms.rs @@ -152,7 +152,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>]) { if let Some(((_, dest), src)) = split && let Some(pat_snippets) = group .iter() - .map(|(_, arm)| arm.pat.span.get_source_text(cx)) + .map(|(_, arm)| arm.pat.span.get_text(cx)) .collect::>>() { let suggs = src diff --git a/clippy_lints/src/matches/match_wild_enum.rs b/clippy_lints/src/matches/match_wild_enum.rs index b175ed2acf9af..98530b7808076 100644 --- a/clippy_lints/src/matches/match_wild_enum.rs +++ b/clippy_lints/src/matches/match_wild_enum.rs @@ -119,7 +119,7 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) { wildcard_ident.map_or(String::new(), |ident| { ident .span - .get_source_text(cx) + .get_text(cx) .map_or_else(|| format!("{} @ ", ident.name), |s| format!("{s} @ ")) }), if let CommonPrefixSearcher::Path(path_prefix) = path_prefix { diff --git a/clippy_lints/src/matches/single_match.rs b/clippy_lints/src/matches/single_match.rs index 414932199d2e4..7c740ababb060 100644 --- a/clippy_lints/src/matches/single_match.rs +++ b/clippy_lints/src/matches/single_match.rs @@ -22,7 +22,7 @@ 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_source_text(cx, |text| text.as_bytes().windows(2).any(|w| w == b"//" || w == b"/*")) + span.check_text(cx, |text| text.as_bytes().windows(2).any(|w| w == b"//" || w == b"/*")) } pub(crate) fn check<'tcx>( diff --git a/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs b/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs index 43508edd42630..b6694ad5148ba 100644 --- a/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs +++ b/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs @@ -51,7 +51,7 @@ pub(super) fn check<'tcx>( "case-sensitive file extension comparison", |diag| { diag.help("consider using a case-insensitive comparison instead"); - if let Some(recv_source) = recv.span.get_source_text(cx) { + if let Some(recv_source) = recv.span.get_text(cx) { let recv_source = if cx.typeck_results().expr_ty(recv).is_ref() { recv_source.to_owned() } else { diff --git a/clippy_lints/src/methods/filter_map_bool_then.rs b/clippy_lints/src/methods/filter_map_bool_then.rs index 2c16a444adea3..419a7e0ed877d 100644 --- a/clippy_lints/src/methods/filter_map_bool_then.rs +++ b/clippy_lints/src/methods/filter_map_bool_then.rs @@ -43,7 +43,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, arg: & .iter() .filter(|adj| matches!(adj.kind, Adjust::Deref(_))) .count() - && let Some(param_snippet) = param.span.get_source_text(cx) + && let Some(param_snippet) = param.span.get_text(cx) { let mut applicability = Applicability::MachineApplicable; let (filter, _) = snippet_with_context(cx, recv.span, expr.span.ctxt(), "..", &mut applicability); diff --git a/clippy_lints/src/methods/manual_ok_or.rs b/clippy_lints/src/methods/manual_ok_or.rs index a50da461719e0..050b28b3babd7 100644 --- a/clippy_lints/src/methods/manual_ok_or.rs +++ b/clippy_lints/src/methods/manual_ok_or.rs @@ -27,8 +27,8 @@ pub(super) fn check<'tcx>( && let ExprKind::Call(err_path, [err_arg]) = or_expr.kind && err_path.res(cx).ctor_parent(cx).is_lang_item(cx, ResultErr) && is_ok_wrapping(cx, map_expr) - && let Some(recv_snippet) = recv.span.get_source_text(cx) - && let Some(err_arg_snippet) = err_arg.span.get_source_text(cx) + && let Some(recv_snippet) = recv.span.get_text(cx) + && let Some(err_arg_snippet) = err_arg.span.get_text(cx) && let Some(indent) = indent_of(cx, expr.span) { let reindented_err_arg_snippet = reindent_multiline(err_arg_snippet.as_str(), true, Some(indent + 4)); diff --git a/clippy_lints/src/methods/manual_try_fold.rs b/clippy_lints/src/methods/manual_try_fold.rs index 4ec4f41d2b8e3..6ef7abffb0b2f 100644 --- a/clippy_lints/src/methods/manual_try_fold.rs +++ b/clippy_lints/src/methods/manual_try_fold.rs @@ -31,14 +31,12 @@ pub(super) fn check<'tcx>( && let ExprKind::Closure(closure) = acc.kind && msrv.meets(cx, msrvs::ITERATOR_TRY_FOLD) && !is_from_proc_macro(cx, expr) - && let Some(args_snip) = closure - .fn_arg_span - .and_then(|fn_arg_span| fn_arg_span.get_source_text(cx)) + && let Some(args_snip) = closure.fn_arg_span.and_then(|fn_arg_span| fn_arg_span.get_text(cx)) { let init_snip = rest .is_empty() .then_some(first.span) - .and_then(|span| span.get_source_text(cx)) + .and_then(|span| span.get_text(cx)) .map_or_else(|| "...".to_owned(), |src| src.to_owned()); span_lint_and_sugg( diff --git a/clippy_lints/src/methods/map_all_any_identity.rs b/clippy_lints/src/methods/map_all_any_identity.rs index 91118c6fb1c47..14a9752d3bded 100644 --- a/clippy_lints/src/methods/map_all_any_identity.rs +++ b/clippy_lints/src/methods/map_all_any_identity.rs @@ -24,7 +24,7 @@ pub(super) fn check( && cx.ty_based_def(recv).opt_parent(cx).is_diag_item(cx, sym::Iterator) && is_expr_identity_function(cx, any_arg) && let map_any_call_span = map_call_span.with_hi(any_call_span.hi()) - && let Some(map_arg) = map_arg.span.get_source_text(cx) + && let Some(map_arg) = map_arg.span.get_text(cx) { span_lint_and_then( cx, diff --git a/clippy_lints/src/methods/needless_character_iteration.rs b/clippy_lints/src/methods/needless_character_iteration.rs index ba62382da6b0c..20468784aae7a 100644 --- a/clippy_lints/src/methods/needless_character_iteration.rs +++ b/clippy_lints/src/methods/needless_character_iteration.rs @@ -36,7 +36,7 @@ fn handle_expr( && receiver.res_local_id() == Some(first_param) && let char_arg_ty = cx.typeck_results().expr_ty_adjusted(receiver).peel_refs() && *char_arg_ty.kind() == ty::Char - && let Some(snippet) = before_chars.get_source_text(cx) + && let Some(snippet) = before_chars.get_text(cx) { span_lint_and_sugg( cx, @@ -78,7 +78,7 @@ fn handle_expr( if revert != is_all && fn_path.ty_rel_def(cx).is_diag_item(cx, sym::char_is_ascii) && peels_expr_ref(arg).res_local_id() == Some(first_param) - && let Some(snippet) = before_chars.get_source_text(cx) + && let Some(snippet) = before_chars.get_text(cx) { span_lint_and_sugg( cx, diff --git a/clippy_lints/src/methods/needless_option_as_deref.rs b/clippy_lints/src/methods/needless_option_as_deref.rs index 0e510a88015ec..7626cdb5a5fe8 100644 --- a/clippy_lints/src/methods/needless_option_as_deref.rs +++ b/clippy_lints/src/methods/needless_option_as_deref.rs @@ -32,7 +32,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, name expr.span, "derefed type is same as origin", "try", - recv.span.get_source_text(cx).unwrap().to_owned(), + recv.span.get_text(cx).unwrap().to_owned(), Applicability::MachineApplicable, ); } diff --git a/clippy_lints/src/methods/ptr_offset_by_literal.rs b/clippy_lints/src/methods/ptr_offset_by_literal.rs index 129d39c1e9f46..17f81f547aeb0 100644 --- a/clippy_lints/src/methods/ptr_offset_by_literal.rs +++ b/clippy_lints/src/methods/ptr_offset_by_literal.rs @@ -92,7 +92,7 @@ fn expr_as_literal<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Opti } fn format_isize_literal<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option { - let text = expr.span.get_source_text(cx)?; + let text = expr.span.get_text(cx)?; let text = peel_parens_str(&text); Some(text.trim_end_matches("isize").trim_end_matches('_').to_string()) } diff --git a/clippy_lints/src/methods/range_zip_with_len.rs b/clippy_lints/src/methods/range_zip_with_len.rs index 51b3db52bd27f..b01adbf4d58af 100644 --- a/clippy_lints/src/methods/range_zip_with_len.rs +++ b/clippy_lints/src/methods/range_zip_with_len.rs @@ -49,8 +49,8 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, recv: &' ), )]; if let Some((left, right)) = invert_bindings - && let Some(snip_left) = left.get_source_text(cx) - && let Some(snip_right) = right.get_source_text(cx) + && let Some(snip_left) = left.get_text(cx) + && let Some(snip_right) = right.get_text(cx) { suggestions.extend([(left, snip_right.to_string()), (right, snip_left.to_string())]); } else { diff --git a/clippy_lints/src/methods/string_lit_chars_any.rs b/clippy_lints/src/methods/string_lit_chars_any.rs index 27c324f863285..53c695e378476 100644 --- a/clippy_lints/src/methods/string_lit_chars_any.rs +++ b/clippy_lints/src/methods/string_lit_chars_any.rs @@ -35,7 +35,7 @@ pub(super) fn check<'tcx>( } && msrv.meets(cx, msrvs::MATCHES_MACRO) && !is_from_proc_macro(cx, expr) - && let Some(scrutinee_snip) = scrutinee.span.get_source_text(cx) + && let Some(scrutinee_snip) = scrutinee.span.get_text(cx) { // Normalize the char using `map` so `join` doesn't use `Display`, if we don't then // something like `r"\"` will become `'\'`, which is of course invalid diff --git a/clippy_lints/src/methods/unnecessary_first_then_check.rs b/clippy_lints/src/methods/unnecessary_first_then_check.rs index 9c5768dfb6f53..43dac249f7440 100644 --- a/clippy_lints/src/methods/unnecessary_first_then_check.rs +++ b/clippy_lints/src/methods/unnecessary_first_then_check.rs @@ -29,8 +29,8 @@ pub(super) fn check( }; let both_calls_span = first_call_span.with_hi(call_span.hi()); - if let Some(both_calls_snippet) = both_calls_span.get_source_text(cx) - && let Some(first_caller_snippet) = first_caller.span.get_source_text(cx) + if let Some(both_calls_snippet) = both_calls_span.get_text(cx) + && let Some(first_caller_snippet) = first_caller.span.get_text(cx) { let (sugg_span, suggestion) = if is_some { ( diff --git a/clippy_lints/src/methods/unnecessary_get_then_check.rs b/clippy_lints/src/methods/unnecessary_get_then_check.rs index f0054bd3a897a..b622a219f35dc 100644 --- a/clippy_lints/src/methods/unnecessary_get_then_check.rs +++ b/clippy_lints/src/methods/unnecessary_get_then_check.rs @@ -39,11 +39,11 @@ pub(super) fn check( return; }; let both_calls_span = get_call_span.with_hi(call_span.hi()); - if let Some(snippet) = both_calls_span.get_source_text(cx) - && let Some(arg_snippet) = arg.span.get_source_text(cx) + if let Some(snippet) = both_calls_span.get_text(cx) + && let Some(arg_snippet) = arg.span.get_text(cx) { let generics_snippet = if let Some(generics) = path.args - && let Some(generics_snippet) = generics.span_ext.get_source_text(cx) + && let Some(generics_snippet) = generics.span_ext.get_text(cx) { format!("::{generics_snippet}") } else { @@ -64,7 +64,7 @@ pub(super) fn check( suggestion, Applicability::MaybeIncorrect, ); - } else if let Some(caller_snippet) = get_caller.span.get_source_text(cx) { + } else if let Some(caller_snippet) = get_caller.span.get_text(cx) { let full_span = get_caller.span.with_hi(call_span.hi()); span_lint_and_then( diff --git a/clippy_lints/src/methods/unnecessary_iter_cloned.rs b/clippy_lints/src/methods/unnecessary_iter_cloned.rs index 9232547355f68..5b19c43f1b32f 100644 --- a/clippy_lints/src/methods/unnecessary_iter_cloned.rs +++ b/clippy_lints/src/methods/unnecessary_iter_cloned.rs @@ -42,7 +42,7 @@ pub fn check_for_loop_iter( && let Some(ForLoop { pat, body, .. }) = ForLoop::hir(grandparent) && let (clone_or_copy_needed, references_to_binding) = clone_or_copy_needed(cx, pat, body) && !clone_or_copy_needed - && let Some(receiver_snippet) = receiver.span.get_source_text(cx) + && let Some(receiver_snippet) = receiver.span.get_text(cx) { // Issue 12098 // https://github.com/rust-lang/rust-clippy/issues/12098 @@ -102,7 +102,7 @@ pub fn check_for_loop_iter( && implements_trait(cx, collection_ty, into_iterator_trait_id, &[]) && let Some(into_iter_item_ty) = cx.get_associated_type(collection_ty, into_iterator_trait_id, sym::Item) && iter_item_ty == into_iter_item_ty - && let Some(collection_snippet) = collection.span.get_source_text(cx) + && let Some(collection_snippet) = collection.span.get_text(cx) { collection_snippet } else { diff --git a/clippy_lints/src/methods/unnecessary_to_owned.rs b/clippy_lints/src/methods/unnecessary_to_owned.rs index d26d8f5b42e0d..35ae44591c188 100644 --- a/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -217,7 +217,7 @@ fn check_into_iter_call_arg( && let parent_ty = cx.typeck_results().expr_ty(parent) && implements_trait(cx, parent_ty, iterator_trait_id, &[]) && let Some(item_ty) = get_iterator_item_ty(cx, parent_ty) - && let Some(receiver_snippet) = receiver.span.get_source_text(cx) + && let Some(receiver_snippet) = receiver.span.get_text(cx) // If the receiver is a `Cow`, we can't remove the `into_owned` generally, see https://github.com/rust-lang/rust-clippy/issues/13624. && !cx.typeck_results().expr_ty(receiver).is_diag_item(cx, sym::Cow) // Calling `iter()` on a temporary object can lead to false positives. #14242 @@ -313,8 +313,8 @@ fn check_string_from_utf8<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, fn check_split_call_arg(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol, receiver: &Expr<'_>) -> bool { if let Some(parent) = get_parent_expr(cx, expr) && let Some((sym::split, argument_expr)) = get_fn_name_and_arg(cx, parent) - && let Some(receiver_snippet) = receiver.span.get_source_text(cx) - && let Some(arg_snippet) = argument_expr.span.get_source_text(cx) + && let Some(receiver_snippet) = receiver.span.get_text(cx) + && let Some(arg_snippet) = argument_expr.span.get_text(cx) { // We may end-up here because of an expression like `x.to_string().split(…)` where the type of `x` // implements `AsRef` but does not implement `Deref`. In this case, we have to @@ -712,7 +712,7 @@ fn check_if_applicable_to_argument<'tcx>(cx: &LateContext<'tcx>, arg: &Expr<'tcx && let arg_ty = arg_ty.peel_refs() // For now we limit this lint to `String` and `Vec`. && (is_str_and_string(cx, arg_ty, original_arg_ty) || is_slice_and_vec(cx, arg_ty, original_arg_ty)) - && let Some(snippet) = caller.span.get_source_text(cx) + && let Some(snippet) = caller.span.get_text(cx) { span_lint_and_sugg( cx, diff --git a/clippy_lints/src/misc_early/unneeded_field_pattern.rs b/clippy_lints/src/misc_early/unneeded_field_pattern.rs index b2ee3f0c24f10..5bc437cf24f4c 100644 --- a/clippy_lints/src/misc_early/unneeded_field_pattern.rs +++ b/clippy_lints/src/misc_early/unneeded_field_pattern.rs @@ -59,7 +59,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, pat: &Pat) { .iter() .filter_map(|f| match f.pat.kind { PatKind::Wild => None, - _ => f.span.get_source_text(cx), + _ => f.span.get_text(cx), }) .format(", "), )); diff --git a/clippy_lints/src/missing_enforced_import_rename.rs b/clippy_lints/src/missing_enforced_import_rename.rs index 2b99ab81816b6..36a2a7f4b406c 100644 --- a/clippy_lints/src/missing_enforced_import_rename.rs +++ b/clippy_lints/src/missing_enforced_import_rename.rs @@ -78,7 +78,7 @@ impl LateLintPass<'_> for ImportRename { && let Some(name) = self.renames.get(&id) // Remove semicolon since it is not present for nested imports && let span_without_semi = cx.sess().source_map().span_until_char(item.span, ';') - && let Some(snip) = span_without_semi.get_source_text(cx) + && let Some(snip) = span_without_semi.get_text(cx) && let Some(import) = match snip.split_once(" as ") { None => Some(snip.as_str()), Some((import, rename)) => { diff --git a/clippy_lints/src/needless_else.rs b/clippy_lints/src/needless_else.rs index 0a25ab37603e2..299860ac1e037 100644 --- a/clippy_lints/src/needless_else.rs +++ b/clippy_lints/src/needless_else.rs @@ -43,7 +43,7 @@ impl EarlyLintPass for NeedlessElse { && !else_clause.span.from_expansion() && block.stmts.is_empty() && let range = (then_block.span.hi()..expr.span.hi()).trim_start(cx) - && range.clone().check_source_text(cx, |src| { + && range.clone().check_text(cx, |src| { // Ignore else blocks that contain comments or #[cfg]s !src.contains(['/', '#']) }) diff --git a/clippy_lints/src/needless_ifs.rs b/clippy_lints/src/needless_ifs.rs index 0356fc2696215..48d15056f7291 100644 --- a/clippy_lints/src/needless_ifs.rs +++ b/clippy_lints/src/needless_ifs.rs @@ -48,7 +48,7 @@ impl LateLintPass<'_> for NeedlessIfs { && block.stmts.is_empty() && block.expr.is_none() && !expr.span.in_external_macro(cx.sess().source_map()) - && then.span.check_source_text(cx, |src| { + && then.span.check_text(cx, |src| { // Ignore // - empty macro expansions // - empty reptitions in macro expansions @@ -58,7 +58,7 @@ impl LateLintPass<'_> for NeedlessIfs { .all(|ch| matches!(ch, b'{' | b'}') || ch.is_ascii_whitespace() || ch == b'\x0b') }) && let Some(cond_span) = walk_span_to_context(cond.span, expr.span.ctxt()) - && let Some(cond_snippet) = cond_span.get_source_text(cx) + && let Some(cond_snippet) = cond_span.get_text(cx) && !is_from_proc_macro(cx, expr) { span_lint_and_sugg( diff --git a/clippy_lints/src/needless_late_init.rs b/clippy_lints/src/needless_late_init.rs index e4dcaad69026c..a2206102f053d 100644 --- a/clippy_lints/src/needless_late_init.rs +++ b/clippy_lints/src/needless_late_init.rs @@ -249,7 +249,7 @@ fn local_snippet_without_semicolon(cx: &LateContext<'_>, local: &LetStmt<'_>) -> None => local.pat.span.hi(), }); - span.get_source_text(cx) + span.get_text(cx) } fn check<'tcx>( diff --git a/clippy_lints/src/needless_pass_by_value.rs b/clippy_lints/src/needless_pass_by_value.rs index b531eb00edc68..a2ad531751288 100644 --- a/clippy_lints/src/needless_pass_by_value.rs +++ b/clippy_lints/src/needless_pass_by_value.rs @@ -248,7 +248,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { for (span, suggestion) in clone_spans { diag.span_suggestion( span, - span.get_source_text(cx).map_or_else( + span.get_text(cx).map_or_else( || "change the call to".to_owned(), |src| format!("change `{src}` to"), ), @@ -275,7 +275,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { for (span, suggestion) in clone_spans { diag.span_suggestion( span, - span.get_source_text(cx).map_or_else( + span.get_text(cx).map_or_else( || "change the call to".to_owned(), |src| format!("change `{src}` to"), ), diff --git a/clippy_lints/src/no_effect.rs b/clippy_lints/src/no_effect.rs index af64f71ba3e24..99ab839f28eda 100644 --- a/clippy_lints/src/no_effect.rs +++ b/clippy_lints/src/no_effect.rs @@ -285,8 +285,8 @@ fn check_unnecessary_operation(cx: &LateContext<'_>, stmt: &Stmt<'_>) { if let ExprKind::Index(..) = &expr.kind { if !is_inside_always_const_context(cx.tcx, expr.hir_id) && let [arr, func] = &*reduced - && let Some(arr) = arr.span.get_source_text(cx) - && let Some(func) = func.span.get_source_text(cx) + && let Some(arr) = arr.span.get_text(cx) + && let Some(func) = func.span.get_text(cx) { span_lint_hir_and_then( cx, @@ -307,7 +307,7 @@ fn check_unnecessary_operation(cx: &LateContext<'_>, stmt: &Stmt<'_>) { } else { let mut snippet = String::new(); for e in reduced { - if let Some(snip) = e.span.get_source_text(cx) { + if let Some(snip) = e.span.get_text(cx) { snippet.push_str(&snip); snippet.push_str("; "); } else { diff --git a/clippy_lints/src/non_octal_unix_permissions.rs b/clippy_lints/src/non_octal_unix_permissions.rs index 72ebe13562be4..cf19cd9fc81d5 100644 --- a/clippy_lints/src/non_octal_unix_permissions.rs +++ b/clippy_lints/src/non_octal_unix_permissions.rs @@ -52,7 +52,7 @@ impl<'tcx> LateLintPass<'tcx> for NonOctalUnixPermissions { && param.span.eq_ctxt(expr.span) && param .span - .check_source_text(cx, |src| !matches!(src.as_bytes(), [b'0', b'o' | b'b', ..])) + .check_text(cx, |src| !matches!(src.as_bytes(), [b'0', b'o' | b'b', ..])) { show_error(cx, param); } @@ -65,7 +65,7 @@ impl<'tcx> LateLintPass<'tcx> for NonOctalUnixPermissions { && param.span.eq_ctxt(expr.span) && param .span - .check_source_text(cx, |src| !matches!(src.as_bytes(), [b'0', b'o' | b'b', ..])) + .check_text(cx, |src| !matches!(src.as_bytes(), [b'0', b'o' | b'b', ..])) { show_error(cx, param); } diff --git a/clippy_lints/src/nonstandard_macro_braces.rs b/clippy_lints/src/nonstandard_macro_braces.rs index eae2c22ef1eb4..e601d54cc4eda 100644 --- a/clippy_lints/src/nonstandard_macro_braces.rs +++ b/clippy_lints/src/nonstandard_macro_braces.rs @@ -129,7 +129,7 @@ fn is_offending_macro(cx: &EarlyContext<'_>, span: Span, mac_braces: &MacroBrace if let ExpnKind::Macro(MacroKind::Bang, mac_name) = expn_data.kind && let name = mac_name.as_str() && let Some(&braces) = mac_braces.macro_braces.get(name) - && let Some(snip) = expn_data.call_site.get_source_text(cx) + && let Some(snip) = expn_data.call_site.get_text(cx) // we must check only invocation sites // https://github.com/rust-lang/rust-clippy/issues/7422 && let Some(macro_args_str) = snip.strip_prefix(name).and_then(|snip| snip.strip_prefix('!')) diff --git a/clippy_lints/src/octal_escapes.rs b/clippy_lints/src/octal_escapes.rs index 2ac9e010c69cf..5735c23a62ac8 100644 --- a/clippy_lints/src/octal_escapes.rs +++ b/clippy_lints/src/octal_escapes.rs @@ -86,7 +86,7 @@ impl EarlyLintPass for OctalEscapes { // Last check to make sure the source text matches what we read from the string. // Macros are involved somehow if this doesn't match. - if span.check_source_text(cx, |src| match *src.as_bytes() { + if span.check_text(cx, |src| match *src.as_bytes() { [b'\\', b'0', lo] => lo == c_lo, [b'\\', b'0', hi, lo] => hi == c_hi && lo == c_lo, _ => false, diff --git a/clippy_lints/src/operators/assign_op_pattern.rs b/clippy_lints/src/operators/assign_op_pattern.rs index 8064a77d43486..fa391fad589fe 100644 --- a/clippy_lints/src/operators/assign_op_pattern.rs +++ b/clippy_lints/src/operators/assign_op_pattern.rs @@ -74,8 +74,8 @@ pub(super) fn check<'tcx>( expr.span, "manual implementation of an assign operation", |diag| { - if let Some(snip_a) = assignee.span.get_source_text(cx) - && let Some(snip_r) = rhs.span.get_source_text(cx) + if let Some(snip_a) = assignee.span.get_text(cx) + && let Some(snip_r) = rhs.span.get_text(cx) { diag.span_suggestion( expr.span, diff --git a/clippy_lints/src/operators/decimal_bitwise_operands.rs b/clippy_lints/src/operators/decimal_bitwise_operands.rs index c5050ca9d4fd5..08e56e4516c52 100644 --- a/clippy_lints/src/operators/decimal_bitwise_operands.rs +++ b/clippy_lints/src/operators/decimal_bitwise_operands.rs @@ -40,7 +40,7 @@ fn check_expr(cx: &LateContext<'_>, expr: &Expr<'_>) { if let LitKind::Int(Pu128(val), _) = lit.node && !is_single_digit(val) && !is_power_of_twoish(val) - && let Some(src) = lit.span.get_source_text(cx) + && let Some(src) = lit.span.get_text(cx) && let Some(num_lit) = NumericLiteral::from_lit_kind(&src, &lit.node) && num_lit.is_decimal() { diff --git a/clippy_lints/src/operators/misrefactored_assign_op.rs b/clippy_lints/src/operators/misrefactored_assign_op.rs index 610f252332f52..8a2cdf430927b 100644 --- a/clippy_lints/src/operators/misrefactored_assign_op.rs +++ b/clippy_lints/src/operators/misrefactored_assign_op.rs @@ -43,8 +43,8 @@ fn lint_misrefactored_assign_op( expr.span, "variable appears on both sides of an assignment operation", |diag| { - if let Some(snip_a) = assignee.span.get_source_text(cx) - && let Some(snip_r) = rhs_other.span.get_source_text(cx) + if let Some(snip_a) = assignee.span.get_text(cx) + && let Some(snip_r) = rhs_other.span.get_text(cx) { let a = &sugg::Sugg::hir(cx, assignee, ".."); let r = &sugg::Sugg::hir(cx, rhs, ".."); diff --git a/clippy_lints/src/pathbuf_init_then_push.rs b/clippy_lints/src/pathbuf_init_then_push.rs index d26aa25778165..473718c5419f1 100644 --- a/clippy_lints/src/pathbuf_init_then_push.rs +++ b/clippy_lints/src/pathbuf_init_then_push.rs @@ -73,7 +73,7 @@ impl PathbufPushSearcher<'_> { && let Some(arg) = self.arg && let ExprKind::Lit(x) = arg.kind && let LitKind::Str(_, StrStyle::Cooked) = x.node - && let Some(s) = arg.span.get_source_text(cx) + && let Some(s) = arg.span.get_text(cx) { Some(format!(" = PathBuf::from({s});")) } else { @@ -83,8 +83,8 @@ impl PathbufPushSearcher<'_> { fn gen_pathbuf_join(&self, cx: &LateContext<'_>) -> Option { let arg = self.arg?; - let arg_str = arg.span.get_source_text(cx)?; - let init_val = self.init_val.span.get_source_text(cx)?; + let arg_str = arg.span.get_text(cx)?; + let init_val = self.init_val.span.get_text(cx)?; Some(format!(" = {init_val}.join({arg_str});")) } diff --git a/clippy_lints/src/ptr/ptr_arg.rs b/clippy_lints/src/ptr/ptr_arg.rs index 4f2105b8dc147..200ab8f8418f1 100644 --- a/clippy_lints/src/ptr/ptr_arg.rs +++ b/clippy_lints/src/ptr/ptr_arg.rs @@ -55,7 +55,7 @@ pub(super) fn check_body<'tcx>( .chain(result.replacements.iter().map(|r| { ( r.expr_span, - format!("{}{}", r.self_span.get_source_text(cx).unwrap(), r.replacement), + format!("{}{}", r.self_span.get_text(cx).unwrap(), r.replacement), ) })) .collect(), @@ -156,7 +156,7 @@ impl fmt::Display for DerefTyDisplay<'_, '_> { DerefTy::Path => f.write_str("Path"), DerefTy::Slice(hir_ty, ty) => { f.write_char('[')?; - match hir_ty.and_then(|s| s.get_source_text(self.0)) { + match hir_ty.and_then(|s| s.get_text(self.0)) { Some(s) => f.write_str(&s)?, None => ty.fmt(f)?, } @@ -279,7 +279,7 @@ fn check_fn_args<'cx, 'tcx: 'cx>( diag.span_suggestion( hir_ty.span, "change this to", - match ty.span().get_source_text(cx) { + match ty.span().get_text(cx) { Some(s) => format!("&{}{s}", mutability.prefix_str()), None => format!("&{}{}", mutability.prefix_str(), args.type_at(1)), }, diff --git a/clippy_lints/src/ranges.rs b/clippy_lints/src/ranges.rs index 48456f809c42c..051e2894e2606 100644 --- a/clippy_lints/src/ranges.rs +++ b/clippy_lints/src/ranges.rs @@ -300,7 +300,7 @@ fn check_possible_range_contains( if let ExprKind::Binary(ref lhs_op, _left, new_lhs) = left.kind && op == lhs_op.node && let new_span = Span::new(new_lhs.span.lo(), right.span.hi(), expr.span.ctxt(), expr.span.parent()) - && new_span.check_source_text(cx, |src| { + && new_span.check_text(cx, |src| { // Do not continue if we have mismatched number of parens, otherwise the suggestion is wrong src.matches('(').count() == src.matches(')').count() }) diff --git a/clippy_lints/src/raw_strings.rs b/clippy_lints/src/raw_strings.rs index 5916828b2e8a9..31c90c591b7c2 100644 --- a/clippy_lints/src/raw_strings.rs +++ b/clippy_lints/src/raw_strings.rs @@ -74,7 +74,7 @@ impl EarlyLintPass for RawStrings { fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { if let ExprKind::FormatArgs(format_args) = &expr.kind && !format_args.span.in_external_macro(cx.sess().source_map()) - && format_args.span.check_source_text(cx, |src| src.starts_with('r')) + && format_args.span.check_text(cx, |src| src.starts_with('r')) && let Some(str) = snippet_opt(cx.sess(), format_args.span) && let count_hash = str.bytes().skip(1).take_while(|b| *b == b'#').count() && let Some(str) = str.get(count_hash + 2..str.len() - count_hash - 1) @@ -97,7 +97,7 @@ impl EarlyLintPass for RawStrings { _ => return, } && !expr.span.in_external_macro(cx.sess().source_map()) - && expr.span.check_source_text(cx, |src| src.starts_with(prefix)) + && expr.span.check_text(cx, |src| src.starts_with(prefix)) { self.check_raw_string(cx, lit.symbol.as_str(), expr.span, prefix, max, lit.kind.descr()); } diff --git a/clippy_lints/src/redundant_clone.rs b/clippy_lints/src/redundant_clone.rs index f04e3480a9c63..db3be9e64f147 100644 --- a/clippy_lints/src/redundant_clone.rs +++ b/clippy_lints/src/redundant_clone.rs @@ -214,7 +214,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClone { .unwrap_crate_local() .lint_root; - if let Some(snip) = span.get_source_text(cx) + if let Some(snip) = span.get_text(cx) && let Some(dot) = snip.rfind('.') { let sugg_span = span.with_lo(span.lo() + BytePos(u32::try_from(dot).unwrap())); diff --git a/clippy_lints/src/regex.rs b/clippy_lints/src/regex.rs index 53f8a453d275f..837c29c08851b 100644 --- a/clippy_lints/src/regex.rs +++ b/clippy_lints/src/regex.rs @@ -190,7 +190,7 @@ fn lint_syntax_error(cx: &LateContext<'_>, error: ®ex_syntax::Error, unescape }; if let Some((primary, auxiliary, kind)) = parts - && let Some(literal_snippet) = base.get_source_text(cx) + && let Some(literal_snippet) = base.get_text(cx) && let Some(inner) = literal_snippet.get(offset as usize..) // Only convert to native rustc spans if the parsed regex matches the // source snippet exactly, to ensure the span offsets are correct diff --git a/clippy_lints/src/semicolon_block.rs b/clippy_lints/src/semicolon_block.rs index cde9d16fc6066..7fdc03891a889 100644 --- a/clippy_lints/src/semicolon_block.rs +++ b/clippy_lints/src/semicolon_block.rs @@ -94,7 +94,7 @@ impl SemicolonBlock { // ({ 0 }); // if we remove this `;`, this will parse as a `({ 0 })(5);` function call // (5); // } - if remove_span.check_source_text(cx, |src| src.contains(')')) { + if remove_span.check_text(cx, |src| src.contains(')')) { return; } diff --git a/clippy_lints/src/single_range_in_vec_init.rs b/clippy_lints/src/single_range_in_vec_init.rs index eaef8d111a991..3d5de785b790c 100644 --- a/clippy_lints/src/single_range_in_vec_init.rs +++ b/clippy_lints/src/single_range_in_vec_init.rs @@ -91,7 +91,7 @@ impl LateLintPass<'_> for SingleRangeInVecInit { return; }; - let Some(snippet) = span.get_source_text(cx) else { + let Some(snippet) = span.get_text(cx) else { return; }; // `is_from_proc_macro` will skip any `vec![]`. Let's not! diff --git a/clippy_lints/src/trait_bounds.rs b/clippy_lints/src/trait_bounds.rs index b3a63ed814cb5..16cf0ecbc0bc7 100644 --- a/clippy_lints/src/trait_bounds.rs +++ b/clippy_lints/src/trait_bounds.rs @@ -212,10 +212,7 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds { bounds_span = bounds_span.to(bound.span); } - let fixed_trait_snippet = unique_traits - .iter() - .filter_map(|b| b.span.get_source_text(cx)) - .join(" + "); + let fixed_trait_snippet = unique_traits.iter().filter_map(|b| b.span.get_text(cx)).join(" + "); span_lint_and_sugg( cx, @@ -451,7 +448,7 @@ fn rollup_traits<'cx, 'tcx>( let traits = comparable_bounds .iter() - .filter_map(|&(_, span)| span.get_source_text(cx)) + .filter_map(|&(_, span)| span.get_text(cx)) .join(" + "); span_lint_and_sugg( diff --git a/clippy_lints/src/unit_types/unit_arg.rs b/clippy_lints/src/unit_types/unit_arg.rs index ac86a457b5374..b9d6c81a152b3 100644 --- a/clippy_lints/src/unit_types/unit_arg.rs +++ b/clippy_lints/src/unit_types/unit_arg.rs @@ -85,7 +85,7 @@ fn lint_unit_args<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, args_to_ && block.expr.is_none() && let Some(last_stmt) = block.stmts.iter().last() && let StmtKind::Semi(last_expr) = last_stmt.kind - && let Some(snip) = last_expr.span.get_source_text(cx) + && let Some(snip) = last_expr.span.get_text(cx) { Some((last_stmt.span, snip)) } else { @@ -117,7 +117,7 @@ fn lint_unit_args<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, args_to_ .filter_map(|arg| get_expr_snippet_with_type_certainty(cx, arg)) .collect(); - if let Some(call_snippet) = expr.span.get_source_text(cx) { + if let Some(call_snippet) = expr.span.get_text(cx) { if arg_snippets_without_redundant_exprs.is_empty() && let suggestions = args_to_recover .iter() diff --git a/clippy_lints/src/useless_vec.rs b/clippy_lints/src/useless_vec.rs index 0cd7426cfe0f6..cdb757ed89e23 100644 --- a/clippy_lints/src/useless_vec.rs +++ b/clippy_lints/src/useless_vec.rs @@ -285,10 +285,10 @@ impl SuggestedType { assert!(args_span.is_none_or(|s| !s.from_expansion())); assert!(len_span.is_none_or(|s| !s.from_expansion())); - let maybe_args = args_span.map(|sp| sp.get_source_text(cx).expect("spans are always crate-local")); + let maybe_args = args_span.map(|sp| sp.get_text(cx).expect("spans are always crate-local")); let maybe_args = maybe_args.as_deref().unwrap_or_default(); let maybe_len = len_span - .map(|sp| sp.get_source_text(cx).expect("spans are always crate-local")) + .map(|sp| sp.get_text(cx).expect("spans are always crate-local")) .map(|st| format!("; {st}")) .unwrap_or_default(); diff --git a/clippy_lints/src/utils/format_args_collector.rs b/clippy_lints/src/utils/format_args_collector.rs index 8f5014d1e3add..ee1729750f2e5 100644 --- a/clippy_lints/src/utils/format_args_collector.rs +++ b/clippy_lints/src/utils/format_args_collector.rs @@ -80,7 +80,7 @@ fn has_span_from_proc_macro(cx: &EarlyContext<'_>, args: &FormatArgs) -> bool { .tuple_windows() .map(|(start, end)| start.between(end)) .all(|sp| { - sp.check_source_text(cx, |src| { + sp.check_text(cx, |src| { // text should be either `, name` or `, name =` let mut iter = tokenize(src, FrontmatterAllowed::No).filter(|t| { !matches!( diff --git a/clippy_lints/src/visibility.rs b/clippy_lints/src/visibility.rs index 875041da780c1..9cefc54598b78 100644 --- a/clippy_lints/src/visibility.rs +++ b/clippy_lints/src/visibility.rs @@ -152,5 +152,5 @@ impl EarlyLintPass for Visibility { } fn is_from_proc_macro(cx: &EarlyContext<'_>, span: Span) -> bool { - !span.check_source_text(cx, |src| src.starts_with("pub")) + !span.check_text(cx, |src| src.starts_with("pub")) } diff --git a/clippy_lints/src/write/literal.rs b/clippy_lints/src/write/literal.rs index 9711410ef8853..df31fad8615ed 100644 --- a/clippy_lints/src/write/literal.rs +++ b/clippy_lints/src/write/literal.rs @@ -48,7 +48,7 @@ pub(super) fn check(cx: &LateContext<'_>, format_args: &FormatArgs, name: &str) && let Some(arg) = format_args.arguments.by_index(index) && let rustc_ast::ExprKind::Lit(lit) = &arg.expr.kind && !arg.expr.span.from_expansion() - && let Some(value_string) = arg.expr.span.get_source_text(cx) + && let Some(value_string) = arg.expr.span.get_text(cx) { let (replacement, replace_raw) = match lit.kind { LitKind::Str | LitKind::StrRaw(_) => match extract_str_literal(&value_string) { @@ -71,7 +71,7 @@ pub(super) fn check(cx: &LateContext<'_>, format_args: &FormatArgs, name: &str) _ => continue, }; - let Some(format_string_snippet) = format_args.span.get_source_text(cx) else { + let Some(format_string_snippet) = format_args.span.get_text(cx) else { continue; }; let format_string_is_raw = format_string_snippet.starts_with('r'); diff --git a/clippy_lints/src/write/with_newline.rs b/clippy_lints/src/write/with_newline.rs index 53109f4014c81..15cc29818aec4 100644 --- a/clippy_lints/src/write/with_newline.rs +++ b/clippy_lints/src/write/with_newline.rs @@ -48,7 +48,7 @@ pub(super) fn check(cx: &LateContext<'_>, format_args: &FormatArgs, macro_call: format!("using `{name}!()` with a format string that ends in a single newline"), |diag| { let name_span = cx.sess().source_map().span_until_char(macro_call.span, '!'); - let Some(format_snippet) = format_string_span.get_source_text(cx) else { + let Some(format_snippet) = format_string_span.get_text(cx) else { return; }; diff --git a/clippy_utils/src/attrs.rs b/clippy_utils/src/attrs.rs index 119836fda46c3..2341007cd49e8 100644 --- a/clippy_utils/src/attrs.rs +++ b/clippy_utils/src/attrs.rs @@ -107,7 +107,7 @@ pub fn has_non_exhaustive_attr(tcx: TyCtxt<'_>, adt: AdtDef<'_>) -> bool { /// Checks whether the given span contains a `#[cfg(..)]` attribute pub fn span_contains_cfg(cx: &LateContext<'_>, s: Span) -> bool { - s.check_source_text(cx, |src| { + s.check_text(cx, |src| { let mut iter = tokenize_with_text(src); // Search for the token sequence [`#`, `[`, `cfg`] diff --git a/clippy_utils/src/hir_utils.rs b/clippy_utils/src/hir_utils.rs index 53352ddc7f83a..050e43344d0c4 100644 --- a/clippy_utils/src/hir_utils.rs +++ b/clippy_utils/src/hir_utils.rs @@ -1036,7 +1036,7 @@ fn reduce_exprkind<'hir>( // `{}` => `()` ([], None) if block.span.ctxt() != eval_ctxt - || block.span.check_source_text(cx, |src| { + || block.span.check_text(cx, |src| { tokenize(src, FrontmatterAllowed::No) .map(|t| t.kind) .filter(|t| { diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 366ace799612c..a067e55595692 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -2882,7 +2882,7 @@ pub fn tokenize_with_text(s: &str) -> impl Iterator(sm: impl HasSourceMap<'sm>, span: Span) -> bool { - span.check_source_text(sm, |snippet| { + span.check_text(sm, |snippet| { tokenize(snippet, FrontmatterAllowed::No).any(|token| { matches!( token.kind, @@ -2897,7 +2897,7 @@ pub fn span_contains_comment<'sm>(sm: impl HasSourceMap<'sm>, span: Span) -> boo /// This is useful to determine if there are any actual code tokens in the span that are omitted in /// the late pass, such as platform-specific code. pub fn span_contains_non_whitespace<'sm>(sm: impl HasSourceMap<'sm>, span: Span, skip_comments: bool) -> bool { - span.check_source_text(sm, |snippet| { + span.check_text(sm, |snippet| { tokenize_with_text(snippet).any(|(token, _, _)| match token { TokenKind::Whitespace => false, TokenKind::BlockComment { .. } | TokenKind::LineComment { .. } => !skip_comments, diff --git a/clippy_utils/src/source.rs b/clippy_utils/src/source.rs index 036f1346ce625..171276f997d39 100644 --- a/clippy_utils/src/source.rs +++ b/clippy_utils/src/source.rs @@ -109,7 +109,7 @@ impl IntoSpan for Range { pub trait SpanExt: SpanRange { /// Attempts to get a handle to the source text. Returns `None` if either the span is malformed, /// or the source text is not accessible. - fn get_source_text<'sm>(self, sm: impl HasSourceMap<'sm>) -> Option { + fn get_text<'sm>(self, sm: impl HasSourceMap<'sm>) -> Option { get_source_range(sm.source_map(), self.into_range()).and_then(SourceText::new) } @@ -127,7 +127,7 @@ pub trait SpanExt: SpanRange { /// Checks if the referenced source text satisfies the given predicate. Returns `false` if the /// source text cannot be retrieved. - fn check_source_text<'sm>(self, sm: impl HasSourceMap<'sm>, pred: impl for<'a> FnOnce(&'a str) -> bool) -> bool { + fn check_text<'sm>(self, sm: impl HasSourceMap<'sm>, pred: impl for<'a> FnOnce(&'a str) -> bool) -> bool { self.with_source_text(sm, pred).unwrap_or(false) } From 345dafc68a37d1765f80b97e0e6de9bf5933e9b8 Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Sat, 13 Jun 2026 23:58:44 +0200 Subject: [PATCH 32/77] extract the tests out of `methods.rs` Among other things, this duplicates the repro for issue10029 for `.next_back()` --- tests/ui/filter_next.fixed | 50 ++++++++++++++++++ tests/ui/filter_next.rs | 50 ++++++++++++++++++ ...hods_fixable.stderr => filter_next.stderr} | 6 +-- tests/ui/filter_next_unfixable.rs | 35 +++++++++++++ tests/ui/filter_next_unfixable.stderr | 51 +++++++++++++++++++ tests/ui/methods.rs | 47 ----------------- tests/ui/methods.stderr | 29 +---------- tests/ui/methods_fixable.fixed | 25 --------- tests/ui/methods_fixable.rs | 25 --------- tests/ui/methods_unfixable.rs | 9 ---- tests/ui/methods_unfixable.stderr | 16 ------ 11 files changed, 191 insertions(+), 152 deletions(-) create mode 100644 tests/ui/filter_next.fixed create mode 100644 tests/ui/filter_next.rs rename tests/ui/{methods_fixable.stderr => filter_next.stderr} (90%) create mode 100644 tests/ui/filter_next_unfixable.rs create mode 100644 tests/ui/filter_next_unfixable.stderr delete mode 100644 tests/ui/methods_fixable.fixed delete mode 100644 tests/ui/methods_fixable.rs delete mode 100644 tests/ui/methods_unfixable.rs delete mode 100644 tests/ui/methods_unfixable.stderr diff --git a/tests/ui/filter_next.fixed b/tests/ui/filter_next.fixed new file mode 100644 index 0000000000000..e982c9233d28e --- /dev/null +++ b/tests/ui/filter_next.fixed @@ -0,0 +1,50 @@ +//@aux-build:option_helpers.rs +#![warn(clippy::filter_next)] +#![expect(clippy::disallowed_names)] +#![allow(clippy::useless_vec)] + +extern crate option_helpers; + +use option_helpers::{IteratorFalsePositives, IteratorMethodFalsePositives}; + +fn main() {} + +fn filter_next() { + let v = [3, 2, 1, 0, -1, -2, -3]; + + // Single-line case. + let _ = v.iter().find(|&x| *x < 0); + //~^ filter_next + + let _ = v.iter().rfind(|&x| *x < 0); + //~^ filter_next + + // Check that we don't lint if the caller is not an `Iterator`. + let foo = IteratorFalsePositives { foo: 0 }; + let _ = foo.filter().next(); + + let foo = IteratorMethodFalsePositives {}; + let _ = foo.filter(42).next(); +} + +fn filter_next_back() { + let v = [3, 2, 1, 0, -1, -2, -3]; + + // Check that we don't lint if the caller is not an `Iterator`. + let foo = IteratorFalsePositives { foo: 0 }; + let _ = foo.filter().next_back(); + + let foo = IteratorMethodFalsePositives {}; + let _ = foo.filter(42).next_back(); +} + +#[clippy::msrv = "1.27"] +fn msrv_1_27() { + let _ = vec![1].into_iter().rfind(|&x| x < 0); + //~^ filter_next +} + +#[clippy::msrv = "1.26"] +fn msrv_1_26() { + let _ = vec![1].into_iter().filter(|&x| x < 0).next_back(); +} diff --git a/tests/ui/filter_next.rs b/tests/ui/filter_next.rs new file mode 100644 index 0000000000000..c6575de8f95c8 --- /dev/null +++ b/tests/ui/filter_next.rs @@ -0,0 +1,50 @@ +//@aux-build:option_helpers.rs +#![warn(clippy::filter_next)] +#![expect(clippy::disallowed_names)] +#![allow(clippy::useless_vec)] + +extern crate option_helpers; + +use option_helpers::{IteratorFalsePositives, IteratorMethodFalsePositives}; + +fn main() {} + +fn filter_next() { + let v = [3, 2, 1, 0, -1, -2, -3]; + + // Single-line case. + let _ = v.iter().filter(|&x| *x < 0).next(); + //~^ filter_next + + let _ = v.iter().filter(|&x| *x < 0).next_back(); + //~^ filter_next + + // Check that we don't lint if the caller is not an `Iterator`. + let foo = IteratorFalsePositives { foo: 0 }; + let _ = foo.filter().next(); + + let foo = IteratorMethodFalsePositives {}; + let _ = foo.filter(42).next(); +} + +fn filter_next_back() { + let v = [3, 2, 1, 0, -1, -2, -3]; + + // Check that we don't lint if the caller is not an `Iterator`. + let foo = IteratorFalsePositives { foo: 0 }; + let _ = foo.filter().next_back(); + + let foo = IteratorMethodFalsePositives {}; + let _ = foo.filter(42).next_back(); +} + +#[clippy::msrv = "1.27"] +fn msrv_1_27() { + let _ = vec![1].into_iter().filter(|&x| x < 0).next_back(); + //~^ filter_next +} + +#[clippy::msrv = "1.26"] +fn msrv_1_26() { + let _ = vec![1].into_iter().filter(|&x| x < 0).next_back(); +} diff --git a/tests/ui/methods_fixable.stderr b/tests/ui/filter_next.stderr similarity index 90% rename from tests/ui/methods_fixable.stderr rename to tests/ui/filter_next.stderr index d26b5e9ac271e..3c5ef757b07fd 100644 --- a/tests/ui/methods_fixable.stderr +++ b/tests/ui/filter_next.stderr @@ -1,5 +1,5 @@ error: called `filter(..).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(..)` instead - --> tests/ui/methods_fixable.rs:9:13 + --> tests/ui/filter_next.rs:16:13 | LL | let _ = v.iter().filter(|&x| *x < 0).next(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `v.iter().find(|&x| *x < 0)` @@ -8,13 +8,13 @@ LL | let _ = v.iter().filter(|&x| *x < 0).next(); = help: to override `-D warnings` add `#[allow(clippy::filter_next)]` error: called `filter(..).next_back()` on an `DoubleEndedIterator`. This is more succinctly expressed by calling `.rfind(..)` instead - --> tests/ui/methods_fixable.rs:12:13 + --> tests/ui/filter_next.rs:19:13 | LL | let _ = v.iter().filter(|&x| *x < 0).next_back(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `v.iter().rfind(|&x| *x < 0)` error: called `filter(..).next_back()` on an `DoubleEndedIterator`. This is more succinctly expressed by calling `.rfind(..)` instead - --> tests/ui/methods_fixable.rs:18:13 + --> tests/ui/filter_next.rs:43:13 | LL | let _ = vec![1].into_iter().filter(|&x| x < 0).next_back(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec![1].into_iter().rfind(|&x| x < 0)` diff --git a/tests/ui/filter_next_unfixable.rs b/tests/ui/filter_next_unfixable.rs new file mode 100644 index 0000000000000..ae70931ddf3b5 --- /dev/null +++ b/tests/ui/filter_next_unfixable.rs @@ -0,0 +1,35 @@ +//@no-rustfix +#![warn(clippy::filter_next)] + +#[rustfmt::skip] +fn main() { + let v = [3, 2, 1, 0, -1, -2, -3]; + + // Multi-line case -- only a note is emitted + let _ = v.iter().filter(|&x| { + //~^ filter_next + *x < 0 + } + ).next(); + + let _ = v.iter().filter(|&x| { + //~^ filter_next + *x < 0 + } + ).next_back(); +} + +// The fixed version doesn't compile, as `iter` isn't `mut`. +// We do emit a note suggesting adding it, but not an autofix +pub fn issue10029() { + { + let iter = (0..10); + let _ = iter.filter(|_| true).next(); + //~^ filter_next + } + { + let iter = (0..10); + let _ = iter.filter(|_| true).next_back(); + //~^ filter_next + } +} diff --git a/tests/ui/filter_next_unfixable.stderr b/tests/ui/filter_next_unfixable.stderr new file mode 100644 index 0000000000000..1a31f1f17ca1d --- /dev/null +++ b/tests/ui/filter_next_unfixable.stderr @@ -0,0 +1,51 @@ +error: called `filter(..).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(..)` instead + --> tests/ui/filter_next_unfixable.rs:9:13 + | +LL | let _ = v.iter().filter(|&x| { + | _____________^ +LL | | +LL | | *x < 0 +LL | | } +LL | | ).next(); + | |___________________________^ + | + = note: `-D clippy::filter-next` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::filter_next)]` + +error: called `filter(..).next_back()` on an `DoubleEndedIterator`. This is more succinctly expressed by calling `.rfind(..)` instead + --> tests/ui/filter_next_unfixable.rs:15:13 + | +LL | let _ = v.iter().filter(|&x| { + | _____________^ +LL | | +LL | | *x < 0 +LL | | } +LL | | ).next_back(); + | |________________________________^ + +error: called `filter(..).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(..)` instead + --> tests/ui/filter_next_unfixable.rs:27:17 + | +LL | let _ = iter.filter(|_| true).next(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `iter.find(|_| true)` + | +help: you will also need to make `iter` mutable, because `find` takes `&mut self` + --> tests/ui/filter_next_unfixable.rs:26:13 + | +LL | let iter = (0..10); + | ^^^^ + +error: called `filter(..).next_back()` on an `DoubleEndedIterator`. This is more succinctly expressed by calling `.rfind(..)` instead + --> tests/ui/filter_next_unfixable.rs:32:17 + | +LL | let _ = iter.filter(|_| true).next_back(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `iter.rfind(|_| true)` + | +help: you will also need to make `iter` mutable, because `rfind` takes `&mut self` + --> tests/ui/filter_next_unfixable.rs:31:13 + | +LL | let iter = (0..10); + | ^^^^ + +error: aborting due to 4 previous errors + diff --git a/tests/ui/methods.rs b/tests/ui/methods.rs index b45b7dcd56a43..10f0934bede74 100644 --- a/tests/ui/methods.rs +++ b/tests/ui/methods.rs @@ -1,18 +1,10 @@ -//@aux-build:option_helpers.rs - #![warn(clippy::filter_next, clippy::new_ret_no_self)] -#![expect(clippy::disallowed_names, clippy::useless_vec)] - -#[macro_use] -extern crate option_helpers; use std::collections::{BTreeMap, HashMap, HashSet, VecDeque}; use std::ops::Mul; use std::rc::{self, Rc}; use std::sync::{self, Arc}; -use option_helpers::{IteratorFalsePositives, IteratorMethodFalsePositives}; - struct Lt<'a> { foo: &'a u32, } @@ -97,43 +89,4 @@ impl Mul for T { } } -/// Checks implementation of `FILTER_NEXT` lint. -#[rustfmt::skip] -fn filter_next() { - let v = vec![3, 2, 1, 0, -1, -2, -3]; - - // Multi-line case. - let _ = v.iter().filter(|&x| { - //~^ filter_next - *x < 0 - } - ).next(); - - // Check that we don't lint if the caller is not an `Iterator`. - let foo = IteratorFalsePositives { foo: 0 }; - let _ = foo.filter().next(); - - let foo = IteratorMethodFalsePositives {}; - let _ = foo.filter(42).next(); -} - -#[rustfmt::skip] -fn filter_next_back() { - let v = vec![3, 2, 1, 0, -1, -2, -3]; - - // Multi-line case. - let _ = v.iter().filter(|&x| { - //~^ filter_next - *x < 0 - } - ).next_back(); - - // Check that we don't lint if the caller is not an `Iterator`. - let foo = IteratorFalsePositives { foo: 0 }; - let _ = foo.filter().next_back(); - - let foo = IteratorMethodFalsePositives {}; - let _ = foo.filter(42).next_back(); -} - fn main() {} diff --git a/tests/ui/methods.stderr b/tests/ui/methods.stderr index a637818cee48c..1136b33ea9104 100644 --- a/tests/ui/methods.stderr +++ b/tests/ui/methods.stderr @@ -1,5 +1,5 @@ error: methods called `new` usually return `Self` - --> tests/ui/methods.rs:84:5 + --> tests/ui/methods.rs:76:5 | LL | / fn new() -> i32 { LL | | @@ -10,30 +10,5 @@ LL | | } = note: `-D clippy::new-ret-no-self` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::new_ret_no_self)]` -error: called `filter(..).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(..)` instead - --> tests/ui/methods.rs:106:13 - | -LL | let _ = v.iter().filter(|&x| { - | _____________^ -LL | | -LL | | *x < 0 -LL | | } -LL | | ).next(); - | |___________________________^ - | - = note: `-D clippy::filter-next` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::filter_next)]` - -error: called `filter(..).next_back()` on an `DoubleEndedIterator`. This is more succinctly expressed by calling `.rfind(..)` instead - --> tests/ui/methods.rs:125:13 - | -LL | let _ = v.iter().filter(|&x| { - | _____________^ -LL | | -LL | | *x < 0 -LL | | } -LL | | ).next_back(); - | |________________________________^ - -error: aborting due to 3 previous errors +error: aborting due to 1 previous error diff --git a/tests/ui/methods_fixable.fixed b/tests/ui/methods_fixable.fixed deleted file mode 100644 index 17a751eb79457..0000000000000 --- a/tests/ui/methods_fixable.fixed +++ /dev/null @@ -1,25 +0,0 @@ -#![warn(clippy::filter_next)] -#![expect(clippy::useless_vec)] - -/// Checks implementation of `FILTER_NEXT` lint. -fn main() { - let v = vec![3, 2, 1, 0, -1, -2, -3]; - - // Single-line case. - let _ = v.iter().find(|&x| *x < 0); - //~^ filter_next - - let _ = v.iter().rfind(|&x| *x < 0); - //~^ filter_next -} - -#[clippy::msrv = "1.27"] -fn msrv_1_27() { - let _ = vec![1].into_iter().rfind(|&x| x < 0); - //~^ filter_next -} - -#[clippy::msrv = "1.26"] -fn msrv_1_26() { - let _ = vec![1].into_iter().filter(|&x| x < 0).next_back(); -} diff --git a/tests/ui/methods_fixable.rs b/tests/ui/methods_fixable.rs deleted file mode 100644 index b2520acc36385..0000000000000 --- a/tests/ui/methods_fixable.rs +++ /dev/null @@ -1,25 +0,0 @@ -#![warn(clippy::filter_next)] -#![expect(clippy::useless_vec)] - -/// Checks implementation of `FILTER_NEXT` lint. -fn main() { - let v = vec![3, 2, 1, 0, -1, -2, -3]; - - // Single-line case. - let _ = v.iter().filter(|&x| *x < 0).next(); - //~^ filter_next - - let _ = v.iter().filter(|&x| *x < 0).next_back(); - //~^ filter_next -} - -#[clippy::msrv = "1.27"] -fn msrv_1_27() { - let _ = vec![1].into_iter().filter(|&x| x < 0).next_back(); - //~^ filter_next -} - -#[clippy::msrv = "1.26"] -fn msrv_1_26() { - let _ = vec![1].into_iter().filter(|&x| x < 0).next_back(); -} diff --git a/tests/ui/methods_unfixable.rs b/tests/ui/methods_unfixable.rs deleted file mode 100644 index 46a5d95eb1b72..0000000000000 --- a/tests/ui/methods_unfixable.rs +++ /dev/null @@ -1,9 +0,0 @@ -#![warn(clippy::filter_next)] -//@no-rustfix -fn main() {} - -pub fn issue10029() { - let iter = (0..10); - let _ = iter.filter(|_| true).next(); - //~^ filter_next -} diff --git a/tests/ui/methods_unfixable.stderr b/tests/ui/methods_unfixable.stderr deleted file mode 100644 index 137112ae41795..0000000000000 --- a/tests/ui/methods_unfixable.stderr +++ /dev/null @@ -1,16 +0,0 @@ -error: called `filter(..).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(..)` instead - --> tests/ui/methods_unfixable.rs:7:13 - | -LL | let _ = iter.filter(|_| true).next(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `iter.find(|_| true)` - | -help: you will also need to make `iter` mutable, because `find` takes `&mut self` - --> tests/ui/methods_unfixable.rs:6:9 - | -LL | let iter = (0..10); - | ^^^^ - = note: `-D clippy::filter-next` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::filter_next)]` - -error: aborting due to 1 previous error - From f0974c97494e4297e43c527518332b79cf097f51 Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Sun, 14 Jun 2026 00:32:21 +0200 Subject: [PATCH 33/77] misc improvements --- clippy_lints/src/methods/filter_next.rs | 27 +++++++++++-------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/clippy_lints/src/methods/filter_next.rs b/clippy_lints/src/methods/filter_next.rs index 9c6b16b88bfd1..435c825c8a628 100644 --- a/clippy_lints/src/methods/filter_next.rs +++ b/clippy_lints/src/methods/filter_next.rs @@ -4,12 +4,12 @@ use clippy_utils::ty::implements_trait; use clippy_utils::{path_to_local_with_projections, sym}; use rustc_ast::{BindingMode, Mutability}; use rustc_errors::Applicability; -use rustc_hir as hir; +use rustc_hir::{Expr, Node, PatKind}; use rustc_lint::LateContext; use super::FILTER_NEXT; -#[derive(Copy, Clone)] +#[derive(Clone, Copy)] pub(super) enum Direction { Forward, Backward, @@ -17,15 +17,13 @@ pub(super) enum Direction { /// lint use of `filter().next()` for `Iterator` and `filter().next_back()` for /// `DoubleEndedIterator` -pub(super) fn check<'tcx>( - cx: &LateContext<'tcx>, - expr: &'tcx hir::Expr<'_>, - recv: &'tcx hir::Expr<'_>, - filter_arg: &'tcx hir::Expr<'_>, +pub(super) fn check( + cx: &LateContext<'_>, + expr: &Expr<'_>, + recv: &Expr<'_>, + filter_arg: &Expr<'_>, direction: Direction, ) { - // lint if caller of `.filter().next()` is an Iterator or `.filter().next_back()` is a - // DoubleEndedIterator let (required_trait, next_method, find_method) = match direction { Direction::Forward => (sym::Iterator, "next", "find"), Direction::Backward => (sym::DoubleEndedIterator, "next_back", "rfind"), @@ -38,18 +36,17 @@ pub(super) fn check<'tcx>( return; } let msg = format!( - "called `filter(..).{next_method}()` on an `{}`. This is more succinctly expressed by calling \ - `.{find_method}(..)` instead", - required_trait.as_str() + "called `filter(..).{next_method}()` on an `{required_trait}`. \ + This is more succinctly expressed by calling `.{find_method}(..)` instead", ); + // add note if not multi-line let filter_snippet = snippet(cx, filter_arg.span, ".."); if filter_snippet.lines().count() <= 1 { let iter_snippet = snippet(cx, recv.span, ".."); - // add note if not multi-line span_lint_and_then(cx, FILTER_NEXT, expr.span, msg, |diag| { let (applicability, pat) = if let Some(id) = path_to_local_with_projections(recv) - && let hir::Node::Pat(pat) = cx.tcx.hir_node(id) - && let hir::PatKind::Binding(BindingMode(_, Mutability::Not), _, ident, _) = pat.kind + && let Node::Pat(pat) = cx.tcx.hir_node(id) + && let PatKind::Binding(BindingMode(_, Mutability::Not), _, ident, _) = pat.kind { (Applicability::Unspecified, Some((pat.span, ident))) } else { From f6bc2c8a4308aac4e3370963845d408c332097be Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Sun, 14 Jun 2026 00:01:34 +0200 Subject: [PATCH 34/77] misc: wrap everything in `span_lint_and_then` ..and inline `msg`, to make next commit's diff a bit nicer --- clippy_lints/src/methods/filter_next.rs | 69 +++++++++++++------------ 1 file changed, 37 insertions(+), 32 deletions(-) diff --git a/clippy_lints/src/methods/filter_next.rs b/clippy_lints/src/methods/filter_next.rs index 435c825c8a628..af26058e58e5f 100644 --- a/clippy_lints/src/methods/filter_next.rs +++ b/clippy_lints/src/methods/filter_next.rs @@ -1,4 +1,4 @@ -use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet; use clippy_utils::ty::implements_trait; use clippy_utils::{path_to_local_with_projections, sym}; @@ -35,39 +35,44 @@ pub(super) fn check( { return; } - let msg = format!( - "called `filter(..).{next_method}()` on an `{required_trait}`. \ + span_lint_and_then( + cx, + FILTER_NEXT, + expr.span, + format!( + "called `filter(..).{next_method}()` on an `{required_trait}`. \ This is more succinctly expressed by calling `.{find_method}(..)` instead", - ); - // add note if not multi-line - let filter_snippet = snippet(cx, filter_arg.span, ".."); - if filter_snippet.lines().count() <= 1 { - let iter_snippet = snippet(cx, recv.span, ".."); - span_lint_and_then(cx, FILTER_NEXT, expr.span, msg, |diag| { - let (applicability, pat) = if let Some(id) = path_to_local_with_projections(recv) - && let Node::Pat(pat) = cx.tcx.hir_node(id) - && let PatKind::Binding(BindingMode(_, Mutability::Not), _, ident, _) = pat.kind - { - (Applicability::Unspecified, Some((pat.span, ident))) - } else { - (Applicability::MachineApplicable, None) - }; - - diag.span_suggestion( - expr.span, - "try", - format!("{iter_snippet}.{find_method}({filter_snippet})"), - applicability, - ); + ), + |diag| { + // add note if not multi-line + let filter_snippet = snippet(cx, filter_arg.span, ".."); + if filter_snippet.lines().count() <= 1 { + let iter_snippet = snippet(cx, recv.span, ".."); + let (applicability, pat) = if let Some(id) = path_to_local_with_projections(recv) + && let Node::Pat(pat) = cx.tcx.hir_node(id) + && let PatKind::Binding(BindingMode(_, Mutability::Not), _, ident, _) = pat.kind + { + (Applicability::Unspecified, Some((pat.span, ident))) + } else { + (Applicability::MachineApplicable, None) + }; - if let Some((pat_span, ident)) = pat { - diag.span_help( - pat_span, - format!("you will also need to make `{ident}` mutable, because `{find_method}` takes `&mut self`"), + diag.span_suggestion( + expr.span, + "try", + format!("{iter_snippet}.{find_method}({filter_snippet})"), + applicability, ); + + if let Some((pat_span, ident)) = pat { + diag.span_help( + pat_span, + format!( + "you will also need to make `{ident}` mutable, because `{find_method}` takes `&mut self`" + ), + ); + } } - }); - } else { - span_lint(cx, FILTER_NEXT, expr.span, msg); - } + }, + ); } From 67878aab71e97222d19bf0f07138a92e5d40093c Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Tue, 9 Sep 2025 18:58:04 +0200 Subject: [PATCH 35/77] refactor(`unit_return_expecting_ord`): use one big `span_lint_and_then` --- clippy_lints/src/unit_return_expecting_ord.rs | 41 +++++++------------ 1 file changed, 15 insertions(+), 26 deletions(-) diff --git a/clippy_lints/src/unit_return_expecting_ord.rs b/clippy_lints/src/unit_return_expecting_ord.rs index 735225a9e2cee..13baa378910d9 100644 --- a/clippy_lints/src/unit_return_expecting_ord.rs +++ b/clippy_lints/src/unit_return_expecting_ord.rs @@ -1,4 +1,4 @@ -use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; +use clippy_utils::diagnostics::span_lint_and_then; use rustc_hir::def_id::DefId; use rustc_hir::{Closure, Expr, ExprKind, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -180,32 +180,21 @@ impl<'tcx> LateLintPass<'tcx> for UnitReturnExpectingOrd { let args = std::iter::once(receiver).chain(args.iter()).collect::>(); let arg_indices = get_args_to_check(cx, expr, args.len(), fn_mut_trait, ord_trait, partial_ord_trait); for (i, trait_name) in arg_indices { - match check_arg(cx, args[i]) { - Some((span, None)) => { - span_lint( - cx, - UNIT_RETURN_EXPECTING_ORD, - span, - format!( - "this closure returns \ + if let Some((span, last_semi)) = check_arg(cx, args[i]) { + span_lint_and_then( + cx, + UNIT_RETURN_EXPECTING_ORD, + span, + format!( + "this closure returns \ the unit type which also implements {trait_name}" - ), - ); - }, - Some((span, Some(last_semi))) => { - span_lint_and_help( - cx, - UNIT_RETURN_EXPECTING_ORD, - span, - format!( - "this closure returns \ - the unit type which also implements {trait_name}" - ), - Some(last_semi), - "probably caused by this trailing semicolon", - ); - }, - None => {}, + ), + |diag| { + if let Some(last_semi) = last_semi { + diag.span_help(last_semi, "probably caused by this trailing semicolon"); + } + }, + ); } } } From 72dc832a807682ca668039cd8a10ef29048af181 Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Sun, 14 Jun 2026 00:23:35 +0200 Subject: [PATCH 36/77] extract suggestion out of the main message 1. In the singe-line case, we switch to verbose suggestions, otherwise the suggestion line gets too long due to the longer message. 2. In the multi-line case, we use span-less help, otherwise the whole multiline span gets highlighted the second time. 3. Also make the suggestion message more concise. --- clippy_lints/src/methods/filter_next.rs | 13 ++++++----- tests/ui/filter_next.stderr | 29 ++++++++++++++++++++----- tests/ui/filter_next_unfixable.stderr | 25 ++++++++++++++++----- 3 files changed, 49 insertions(+), 18 deletions(-) diff --git a/clippy_lints/src/methods/filter_next.rs b/clippy_lints/src/methods/filter_next.rs index af26058e58e5f..430f97e4a7b0f 100644 --- a/clippy_lints/src/methods/filter_next.rs +++ b/clippy_lints/src/methods/filter_next.rs @@ -39,11 +39,10 @@ pub(super) fn check( cx, FILTER_NEXT, expr.span, - format!( - "called `filter(..).{next_method}()` on an `{required_trait}`. \ - This is more succinctly expressed by calling `.{find_method}(..)` instead", - ), + format!("called `filter(..).{next_method}()` on an `{required_trait}`"), |diag| { + let sugg_msg = format!("use `.{find_method}(..)` instead"); + // add note if not multi-line let filter_snippet = snippet(cx, filter_arg.span, ".."); if filter_snippet.lines().count() <= 1 { @@ -57,9 +56,9 @@ pub(super) fn check( (Applicability::MachineApplicable, None) }; - diag.span_suggestion( + diag.span_suggestion_verbose( expr.span, - "try", + sugg_msg, format!("{iter_snippet}.{find_method}({filter_snippet})"), applicability, ); @@ -72,6 +71,8 @@ pub(super) fn check( ), ); } + } else { + diag.help(sugg_msg); } }, ); diff --git a/tests/ui/filter_next.stderr b/tests/ui/filter_next.stderr index 3c5ef757b07fd..3442edd43decb 100644 --- a/tests/ui/filter_next.stderr +++ b/tests/ui/filter_next.stderr @@ -1,23 +1,40 @@ -error: called `filter(..).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(..)` instead +error: called `filter(..).next()` on an `Iterator` --> tests/ui/filter_next.rs:16:13 | LL | let _ = v.iter().filter(|&x| *x < 0).next(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `v.iter().find(|&x| *x < 0)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::filter-next` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::filter_next)]` +help: use `.find(..)` instead + | +LL - let _ = v.iter().filter(|&x| *x < 0).next(); +LL + let _ = v.iter().find(|&x| *x < 0); + | -error: called `filter(..).next_back()` on an `DoubleEndedIterator`. This is more succinctly expressed by calling `.rfind(..)` instead +error: called `filter(..).next_back()` on an `DoubleEndedIterator` --> tests/ui/filter_next.rs:19:13 | LL | let _ = v.iter().filter(|&x| *x < 0).next_back(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `v.iter().rfind(|&x| *x < 0)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `.rfind(..)` instead + | +LL - let _ = v.iter().filter(|&x| *x < 0).next_back(); +LL + let _ = v.iter().rfind(|&x| *x < 0); + | -error: called `filter(..).next_back()` on an `DoubleEndedIterator`. This is more succinctly expressed by calling `.rfind(..)` instead +error: called `filter(..).next_back()` on an `DoubleEndedIterator` --> tests/ui/filter_next.rs:43:13 | LL | let _ = vec![1].into_iter().filter(|&x| x < 0).next_back(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec![1].into_iter().rfind(|&x| x < 0)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `.rfind(..)` instead + | +LL - let _ = vec![1].into_iter().filter(|&x| x < 0).next_back(); +LL + let _ = vec![1].into_iter().rfind(|&x| x < 0); + | error: aborting due to 3 previous errors diff --git a/tests/ui/filter_next_unfixable.stderr b/tests/ui/filter_next_unfixable.stderr index 1a31f1f17ca1d..ca607714d4ff1 100644 --- a/tests/ui/filter_next_unfixable.stderr +++ b/tests/ui/filter_next_unfixable.stderr @@ -1,4 +1,4 @@ -error: called `filter(..).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(..)` instead +error: called `filter(..).next()` on an `Iterator` --> tests/ui/filter_next_unfixable.rs:9:13 | LL | let _ = v.iter().filter(|&x| { @@ -9,10 +9,11 @@ LL | | } LL | | ).next(); | |___________________________^ | + = help: use `.find(..)` instead = note: `-D clippy::filter-next` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::filter_next)]` -error: called `filter(..).next_back()` on an `DoubleEndedIterator`. This is more succinctly expressed by calling `.rfind(..)` instead +error: called `filter(..).next_back()` on an `DoubleEndedIterator` --> tests/ui/filter_next_unfixable.rs:15:13 | LL | let _ = v.iter().filter(|&x| { @@ -22,30 +23,42 @@ LL | | *x < 0 LL | | } LL | | ).next_back(); | |________________________________^ + | + = help: use `.rfind(..)` instead -error: called `filter(..).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(..)` instead +error: called `filter(..).next()` on an `Iterator` --> tests/ui/filter_next_unfixable.rs:27:17 | LL | let _ = iter.filter(|_| true).next(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `iter.find(|_| true)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: you will also need to make `iter` mutable, because `find` takes `&mut self` --> tests/ui/filter_next_unfixable.rs:26:13 | LL | let iter = (0..10); | ^^^^ +help: use `.find(..)` instead + | +LL - let _ = iter.filter(|_| true).next(); +LL + let _ = iter.find(|_| true); + | -error: called `filter(..).next_back()` on an `DoubleEndedIterator`. This is more succinctly expressed by calling `.rfind(..)` instead +error: called `filter(..).next_back()` on an `DoubleEndedIterator` --> tests/ui/filter_next_unfixable.rs:32:17 | LL | let _ = iter.filter(|_| true).next_back(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `iter.rfind(|_| true)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: you will also need to make `iter` mutable, because `rfind` takes `&mut self` --> tests/ui/filter_next_unfixable.rs:31:13 | LL | let iter = (0..10); | ^^^^ +help: use `.rfind(..)` instead + | +LL - let _ = iter.filter(|_| true).next_back(); +LL + let _ = iter.rfind(|_| true); + | error: aborting due to 4 previous errors From 537443bf6a80f0a248ae770cd1feef0c7a34fe2b Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Sun, 14 Jun 2026 00:53:02 +0200 Subject: [PATCH 37/77] fix: respect reduced applicability --- clippy_lints/src/methods/filter_next.rs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/clippy_lints/src/methods/filter_next.rs b/clippy_lints/src/methods/filter_next.rs index 430f97e4a7b0f..67674d723860e 100644 --- a/clippy_lints/src/methods/filter_next.rs +++ b/clippy_lints/src/methods/filter_next.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::snippet; +use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::implements_trait; use clippy_utils::{path_to_local_with_projections, sym}; use rustc_ast::{BindingMode, Mutability}; @@ -43,24 +43,26 @@ pub(super) fn check( |diag| { let sugg_msg = format!("use `.{find_method}(..)` instead"); + let mut app = Applicability::MachineApplicable; // add note if not multi-line - let filter_snippet = snippet(cx, filter_arg.span, ".."); + let filter_snippet = snippet_with_applicability(cx, filter_arg.span, "..", &mut app); if filter_snippet.lines().count() <= 1 { - let iter_snippet = snippet(cx, recv.span, ".."); - let (applicability, pat) = if let Some(id) = path_to_local_with_projections(recv) + let iter_snippet = snippet_with_applicability(cx, recv.span, "..", &mut app); + let pat = if let Some(id) = path_to_local_with_projections(recv) && let Node::Pat(pat) = cx.tcx.hir_node(id) && let PatKind::Binding(BindingMode(_, Mutability::Not), _, ident, _) = pat.kind { - (Applicability::Unspecified, Some((pat.span, ident))) + app = Applicability::Unspecified; + Some((pat.span, ident)) } else { - (Applicability::MachineApplicable, None) + None }; diag.span_suggestion_verbose( expr.span, sugg_msg, format!("{iter_snippet}.{find_method}({filter_snippet})"), - applicability, + app, ); if let Some((pat_span, ident)) = pat { From bef6f41446798c9053828bafc093fca145924aa6 Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Sun, 14 Jun 2026 14:16:05 +0200 Subject: [PATCH 38/77] also suggest in the multi-line case This used to be a workaround for a rustc diagnostics issue which has since been resolved --- clippy_lints/src/methods/filter_next.rs | 52 +++++++++++-------------- tests/ui/filter_next.fixed | 13 +++++++ tests/ui/filter_next.rs | 15 +++++++ tests/ui/filter_next.stderr | 42 +++++++++++++++++++- tests/ui/filter_next_unfixable.rs | 18 +-------- tests/ui/filter_next_unfixable.stderr | 40 ++++--------------- 6 files changed, 98 insertions(+), 82 deletions(-) diff --git a/clippy_lints/src/methods/filter_next.rs b/clippy_lints/src/methods/filter_next.rs index 67674d723860e..3584833bc61cd 100644 --- a/clippy_lints/src/methods/filter_next.rs +++ b/clippy_lints/src/methods/filter_next.rs @@ -41,40 +41,32 @@ pub(super) fn check( expr.span, format!("called `filter(..).{next_method}()` on an `{required_trait}`"), |diag| { - let sugg_msg = format!("use `.{find_method}(..)` instead"); - let mut app = Applicability::MachineApplicable; - // add note if not multi-line let filter_snippet = snippet_with_applicability(cx, filter_arg.span, "..", &mut app); - if filter_snippet.lines().count() <= 1 { - let iter_snippet = snippet_with_applicability(cx, recv.span, "..", &mut app); - let pat = if let Some(id) = path_to_local_with_projections(recv) - && let Node::Pat(pat) = cx.tcx.hir_node(id) - && let PatKind::Binding(BindingMode(_, Mutability::Not), _, ident, _) = pat.kind - { - app = Applicability::Unspecified; - Some((pat.span, ident)) - } else { - None - }; - - diag.span_suggestion_verbose( - expr.span, - sugg_msg, - format!("{iter_snippet}.{find_method}({filter_snippet})"), - app, - ); + let iter_snippet = snippet_with_applicability(cx, recv.span, "..", &mut app); - if let Some((pat_span, ident)) = pat { - diag.span_help( - pat_span, - format!( - "you will also need to make `{ident}` mutable, because `{find_method}` takes `&mut self`" - ), - ); - } + let pat = if let Some(id) = path_to_local_with_projections(recv) + && let Node::Pat(pat) = cx.tcx.hir_node(id) + && let PatKind::Binding(BindingMode(_, Mutability::Not), _, ident, _) = pat.kind + { + app = Applicability::Unspecified; + Some((pat.span, ident)) } else { - diag.help(sugg_msg); + None + }; + + diag.span_suggestion_verbose( + expr.span, + format!("use `.{find_method}(..)` instead"), + format!("{iter_snippet}.{find_method}({filter_snippet})"), + app, + ); + + if let Some((pat_span, ident)) = pat { + diag.span_help( + pat_span, + format!("you will also need to make `{ident}` mutable, because `{find_method}` takes `&mut self`"), + ); } }, ); diff --git a/tests/ui/filter_next.fixed b/tests/ui/filter_next.fixed index e982c9233d28e..5502fa1fb2733 100644 --- a/tests/ui/filter_next.fixed +++ b/tests/ui/filter_next.fixed @@ -19,6 +19,19 @@ fn filter_next() { let _ = v.iter().rfind(|&x| *x < 0); //~^ filter_next + // Multi-line case. + #[rustfmt::skip] + let _ = v.iter().find(|&x| { + //~^ filter_next + *x < 0 + }); + + #[rustfmt::skip] + let _ = v.iter().rfind(|&x| { + //~^ filter_next + *x < 0 + }); + // Check that we don't lint if the caller is not an `Iterator`. let foo = IteratorFalsePositives { foo: 0 }; let _ = foo.filter().next(); diff --git a/tests/ui/filter_next.rs b/tests/ui/filter_next.rs index c6575de8f95c8..c8e9f060cd609 100644 --- a/tests/ui/filter_next.rs +++ b/tests/ui/filter_next.rs @@ -19,6 +19,21 @@ fn filter_next() { let _ = v.iter().filter(|&x| *x < 0).next_back(); //~^ filter_next + // Multi-line case. + #[rustfmt::skip] + let _ = v.iter().filter(|&x| { + //~^ filter_next + *x < 0 + } + ).next(); + + #[rustfmt::skip] + let _ = v.iter().filter(|&x| { + //~^ filter_next + *x < 0 + } + ).next_back(); + // Check that we don't lint if the caller is not an `Iterator`. let foo = IteratorFalsePositives { foo: 0 }; let _ = foo.filter().next(); diff --git a/tests/ui/filter_next.stderr b/tests/ui/filter_next.stderr index 3442edd43decb..19c2428c3d17d 100644 --- a/tests/ui/filter_next.stderr +++ b/tests/ui/filter_next.stderr @@ -24,8 +24,46 @@ LL - let _ = v.iter().filter(|&x| *x < 0).next_back(); LL + let _ = v.iter().rfind(|&x| *x < 0); | +error: called `filter(..).next()` on an `Iterator` + --> tests/ui/filter_next.rs:24:13 + | +LL | let _ = v.iter().filter(|&x| { + | _____________^ +LL | | +LL | | *x < 0 +LL | | } +LL | | ).next(); + | |___________________________^ + | +help: use `.find(..)` instead + | +LL ~ let _ = v.iter().find(|&x| { +LL + +LL + *x < 0 +LL ~ }); + | + +error: called `filter(..).next_back()` on an `DoubleEndedIterator` + --> tests/ui/filter_next.rs:31:13 + | +LL | let _ = v.iter().filter(|&x| { + | _____________^ +LL | | +LL | | *x < 0 +LL | | } +LL | | ).next_back(); + | |________________________________^ + | +help: use `.rfind(..)` instead + | +LL ~ let _ = v.iter().rfind(|&x| { +LL + +LL + *x < 0 +LL ~ }); + | + error: called `filter(..).next_back()` on an `DoubleEndedIterator` - --> tests/ui/filter_next.rs:43:13 + --> tests/ui/filter_next.rs:58:13 | LL | let _ = vec![1].into_iter().filter(|&x| x < 0).next_back(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -36,5 +74,5 @@ LL - let _ = vec![1].into_iter().filter(|&x| x < 0).next_back(); LL + let _ = vec![1].into_iter().rfind(|&x| x < 0); | -error: aborting due to 3 previous errors +error: aborting due to 5 previous errors diff --git a/tests/ui/filter_next_unfixable.rs b/tests/ui/filter_next_unfixable.rs index ae70931ddf3b5..07a0db1353500 100644 --- a/tests/ui/filter_next_unfixable.rs +++ b/tests/ui/filter_next_unfixable.rs @@ -1,23 +1,7 @@ //@no-rustfix #![warn(clippy::filter_next)] -#[rustfmt::skip] -fn main() { - let v = [3, 2, 1, 0, -1, -2, -3]; - - // Multi-line case -- only a note is emitted - let _ = v.iter().filter(|&x| { - //~^ filter_next - *x < 0 - } - ).next(); - - let _ = v.iter().filter(|&x| { - //~^ filter_next - *x < 0 - } - ).next_back(); -} +fn main() {} // The fixed version doesn't compile, as `iter` isn't `mut`. // We do emit a note suggesting adding it, but not an autofix diff --git a/tests/ui/filter_next_unfixable.stderr b/tests/ui/filter_next_unfixable.stderr index ca607714d4ff1..2c35badec4853 100644 --- a/tests/ui/filter_next_unfixable.stderr +++ b/tests/ui/filter_next_unfixable.stderr @@ -1,42 +1,16 @@ error: called `filter(..).next()` on an `Iterator` - --> tests/ui/filter_next_unfixable.rs:9:13 - | -LL | let _ = v.iter().filter(|&x| { - | _____________^ -LL | | -LL | | *x < 0 -LL | | } -LL | | ).next(); - | |___________________________^ - | - = help: use `.find(..)` instead - = note: `-D clippy::filter-next` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::filter_next)]` - -error: called `filter(..).next_back()` on an `DoubleEndedIterator` - --> tests/ui/filter_next_unfixable.rs:15:13 - | -LL | let _ = v.iter().filter(|&x| { - | _____________^ -LL | | -LL | | *x < 0 -LL | | } -LL | | ).next_back(); - | |________________________________^ - | - = help: use `.rfind(..)` instead - -error: called `filter(..).next()` on an `Iterator` - --> tests/ui/filter_next_unfixable.rs:27:17 + --> tests/ui/filter_next_unfixable.rs:11:17 | LL | let _ = iter.filter(|_| true).next(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: you will also need to make `iter` mutable, because `find` takes `&mut self` - --> tests/ui/filter_next_unfixable.rs:26:13 + --> tests/ui/filter_next_unfixable.rs:10:13 | LL | let iter = (0..10); | ^^^^ + = note: `-D clippy::filter-next` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::filter_next)]` help: use `.find(..)` instead | LL - let _ = iter.filter(|_| true).next(); @@ -44,13 +18,13 @@ LL + let _ = iter.find(|_| true); | error: called `filter(..).next_back()` on an `DoubleEndedIterator` - --> tests/ui/filter_next_unfixable.rs:32:17 + --> tests/ui/filter_next_unfixable.rs:16:17 | LL | let _ = iter.filter(|_| true).next_back(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: you will also need to make `iter` mutable, because `rfind` takes `&mut self` - --> tests/ui/filter_next_unfixable.rs:31:13 + --> tests/ui/filter_next_unfixable.rs:15:13 | LL | let iter = (0..10); | ^^^^ @@ -60,5 +34,5 @@ LL - let _ = iter.filter(|_| true).next_back(); LL + let _ = iter.rfind(|_| true); | -error: aborting due to 4 previous errors +error: aborting due to 2 previous errors From 4200d7fc3fe95d11b01e8dabc343ebbed5e7a579 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Sun, 14 Jun 2026 14:57:07 +0200 Subject: [PATCH 39/77] Add funding links --- .github/FUNDING.yml | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .github/FUNDING.yml diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000000000..16ac7b6eb9bc9 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,2 @@ +github: rustfoundation +custom: [ "rust-lang.org/funding" ] From 5a17348bad97e1ac11ab9a9df0601fffc9962040 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sun, 14 Jun 2026 10:10:31 -0400 Subject: [PATCH 40/77] Merge comment and cfg checking in `matches` lint pass. --- clippy_lints/src/matches/mod.rs | 154 +++++++++++++++----------------- 1 file changed, 72 insertions(+), 82 deletions(-) diff --git a/clippy_lints/src/matches/mod.rs b/clippy_lints/src/matches/mod.rs index ae0f3ffa0edc9..02b2d11d8aa61 100644 --- a/clippy_lints/src/matches/mod.rs +++ b/clippy_lints/src/matches/mod.rs @@ -26,14 +26,13 @@ mod wild_in_or_pats; use clippy_config::Conf; use clippy_utils::msrvs::{self, Msrv}; -use clippy_utils::source::walk_span_to_context; -use clippy_utils::{ - higher, is_direct_expn_of, is_in_const_context, is_span_match, span_contains_cfg, span_extract_comments, sym, -}; +use clippy_utils::source::SpanExt; +use clippy_utils::{higher, is_direct_expn_of, is_in_const_context, is_span_match, sym, tokenize_with_text}; use rustc_hir::{Arm, Expr, ExprKind, LetStmt, MatchSource, Pat, PatKind}; +use rustc_lexer::{TokenKind, is_whitespace}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::impl_lint_pass; -use rustc_span::{SpanData, SyntaxContext}; +use rustc_span::Span; declare_clippy_lint! { /// ### What it does @@ -1084,7 +1083,29 @@ impl<'tcx> LateLintPass<'tcx> for Matches { try_err::check(cx, expr, ex); } - if !from_expansion && !contains_cfg_arm(cx, expr, ex, arms) { + if !from_expansion + && let mut has_cfg = false + && let mut has_comments = false + && walk_intra_arm_text(cx, expr.span, ex.span, arms, |s| { + let mut iter = tokenize_with_text(s).filter(|(t, ..)| match t { + TokenKind::Whitespace => false, + TokenKind::LineComment { .. } | TokenKind::BlockComment { .. } => { + has_comments = true; + false + }, + _ => true, + }); + while let Some((t, ..)) = iter.next() { + if matches!(t, TokenKind::Pound) + && matches!(iter.next(), Some((TokenKind::OpenBracket, ..))) + && matches!(iter.next(), Some((TokenKind::Ident, "cfg", _))) + { + has_cfg = true; + } + } + }) + && !has_cfg + { if source == MatchSource::Normal { if !(self.msrv.meets(cx, msrvs::MATCHES_MACRO) && match_like_matches::check_match(cx, expr, ex, arms)) @@ -1093,25 +1114,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches { } redundant_pattern_match::check_match(cx, expr, ex, arms); - let mut match_comments = span_extract_comments(cx, expr.span); - // We remove comments from inside arms block. - if !match_comments.is_empty() { - for arm in arms { - for comment in span_extract_comments(cx, arm.body.span) { - if let Some(index) = match_comments - .iter() - .enumerate() - .find(|(_, cm)| **cm == comment) - .map(|(index, _)| index) - { - match_comments.remove(index); - } - } - } - } - // If there are still comments, it means they are outside of the arms. Tell the lint - // code about it. - single_match::check(cx, ex, arms, expr, !match_comments.is_empty()); + single_match::check(cx, ex, arms, expr, has_comments); match_bool::check(cx, ex, arms, expr); overlapping_arms::check(cx, ex, arms); match_wild_enum::check(cx, ex, arms); @@ -1216,64 +1219,51 @@ impl<'tcx> LateLintPass<'tcx> for Matches { } } -/// Checks if there are any arms with a `#[cfg(..)]` attribute. -fn contains_cfg_arm(cx: &LateContext<'_>, e: &Expr<'_>, scrutinee: &Expr<'_>, arms: &[Arm<'_>]) -> bool { - let Some(scrutinee_span) = walk_span_to_context(scrutinee.span, SyntaxContext::root()) else { - // Shouldn't happen, but treat this as though a `cfg` attribute were found - return true; - }; - - let start = scrutinee_span.hi(); - let mut arm_spans = arms.iter().map(|arm| { - let data = arm.span.data(); - (data.ctxt == SyntaxContext::root()).then_some((data.lo, data.hi)) - }); - let end = e.span.hi(); - - // Walk through all the non-code space before each match arm. The space trailing the final arm is - // handled after the `try_fold` e.g. - // - // match foo { - // _________^- everything between the scrutinee and arm1 - //| arm1 => (), - //|---^___________^ everything before arm2 - //| #[cfg(feature = "enabled")] - //| arm2 => some_code(), - //|---^____________________^ everything before arm3 - //| // some comment about arm3 - //| arm3 => some_code(), - //|---^____________________^ everything after arm3 - //| #[cfg(feature = "disabled")] - //| arm4 = some_code(), - //|}; - //|^ - let found = arm_spans.try_fold(start, |start, range| { - let Some((end, next_start)) = range else { - // Shouldn't happen as macros can't expand to match arms, but treat this as though a `cfg` attribute - // were found. - return Err(()); - }; - let span = SpanData { - lo: start, - hi: end, - ctxt: SyntaxContext::root(), - parent: None, - } - .span(); - (!span_contains_cfg(cx, span)).then_some(next_start).ok_or(()) - }); - match found { - Ok(start) => { - let span = SpanData { - lo: start, - hi: end, - ctxt: SyntaxContext::root(), - parent: None, +/// Calls the given function for each segment of the source text within the +/// match block which is not part of any arm. For the purposes of this function +/// attributes on an arm are not considered part of the arm. +/// +/// This will return whether all the relevant source text could be retrieved. If +/// all the source text cannot be retrieved it should be assumed that the match +/// originates from a macro. +#[must_use] +fn walk_intra_arm_text( + cx: &LateContext<'_>, + match_sp: Span, + scrutinee_sp: Span, + arms: &[Arm<'_>], + mut f: impl FnMut(&str), +) -> bool { + if let Some(src) = match_sp.get_source_range(cx) + && let scrutinee_sp = scrutinee_sp.source_callsite().data() + && let block_start = (scrutinee_sp.hi.0 - src.sf.start_pos.0) as usize + && let Some(src_text) = src.sf.src.as_ref().map(|x| &***x) + && let Some(block_text) = src_text.get(block_start..src.range.end) + && let Some(stripped_text) = block_text.trim_start_matches(is_whitespace).strip_prefix('{') + && let arms_start = block_start + (block_text.len() - stripped_text.len()) + && let Some(arms_end) = stripped_text + .trim_end_matches(|c| is_whitespace(c) || c == ')') + .strip_suffix('}') + .map(|s| src.range.end - (stripped_text.len() - s.len())) + && let Some(range) = arms.iter().try_fold(arms_start..arms_end, |range, arm| { + let arm_sp: rustc_span::SpanData = arm.span.source_callsite().data(); + let arm_range = (arm_sp.lo.0 - src.sf.start_pos.0) as usize..(arm_sp.hi.0 - src.sf.start_pos.0) as usize; + if range.start <= arm_range.start + && arm_range.end <= range.end + && let Some(src) = src_text.get(range.start..arm_range.start) + { + f(src); + Some(arm_range.end..range.end) + } else { + None } - .span(); - span_contains_cfg(cx, span) - }, - Err(()) => true, + }) + && let Some(src) = src_text.get(range) + { + f(src); + true + } else { + false } } From 15025dcd2f0e47ec150dde47854a798714122550 Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Sun, 14 Jun 2026 22:58:44 +0200 Subject: [PATCH 41/77] Fix ICE when the `clippy::author` attribute is applied to an item --- clippy_lints/src/utils/author.rs | 34 +++++++++++++++++++++++------- tests/ui/author/issue_17240.rs | 8 +++++++ tests/ui/author/issue_17240.stdout | 20 ++++++++++++++++++ 3 files changed, 54 insertions(+), 8 deletions(-) create mode 100644 tests/ui/author/issue_17240.rs create mode 100644 tests/ui/author/issue_17240.stdout diff --git a/clippy_lints/src/utils/author.rs b/clippy_lints/src/utils/author.rs index c60d84785a229..2bcf369fb3334 100644 --- a/clippy_lints/src/utils/author.rs +++ b/clippy_lints/src/utils/author.rs @@ -6,11 +6,11 @@ use rustc_ast::ast::{LitFloatType, LitKind}; use rustc_data_structures::fx::FxHashMap; use rustc_hir::def_id::DefId; use rustc_hir::{ - self as hir, BindingMode, CaptureBy, Closure, ClosureKind, ConstArg, ConstArgKind, CoroutineKind, ExprKind, + self as hir, BindingMode, Body, CaptureBy, Closure, ClosureKind, ConstArg, ConstArgKind, CoroutineKind, ExprKind, FnRetTy, HirId, Lit, PatExprKind, PatKind, QPath, StmtKind, StructTailExpr, }; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty::{FloatTy, IntTy, UintTy}; +use rustc_middle::ty::{FloatTy, IntTy, TypeckResults, UintTy}; use rustc_session::declare_lint_pass; use rustc_span::symbol::{Ident, Symbol}; use std::cell::Cell; @@ -137,15 +137,31 @@ impl<'tcx> LateLintPass<'tcx> for Author { fn check_item(cx: &LateContext<'_>, hir_id: HirId) { if let Some(body) = cx.tcx.hir_maybe_body_owned_by(hir_id.expect_owner().def_id) { - check_node(cx, hir_id, |v| { - v.expr(&v.bind("expr", body.value)); - }); + check_node_with_body( + cx, + hir_id, + |v| { + v.expr(&v.bind("expr", body.value)); + }, + Some(body), + ); } } fn check_node(cx: &LateContext<'_>, hir_id: HirId, f: impl Fn(&PrintVisitor<'_, '_>)) { + check_node_with_body(cx, hir_id, f, None); +} + +/// Check the node at `hir_id`, in the context of `body` or the default from `cx` if none is given. +fn check_node_with_body( + cx: &LateContext<'_>, + hir_id: HirId, + f: impl Fn(&PrintVisitor<'_, '_>), + body: Option<&Body<'_>>, +) { if has_attr(cx, hir_id) { - f(&PrintVisitor::new(cx)); + let typeck_results = body.map_or_else(|| cx.typeck_results(), |body| cx.tcx.typeck_body(body.id())); + f(&PrintVisitor::new(cx, typeck_results)); println!("{{"); println!(" // report your lint here"); println!("}}"); @@ -199,6 +215,7 @@ impl Display for OptionPat { struct PrintVisitor<'a, 'tcx> { cx: &'a LateContext<'tcx>, + typeck_results: &'tcx TypeckResults<'tcx>, /// Fields are the current index that needs to be appended to pattern /// binding names ids: Cell>, @@ -207,9 +224,10 @@ struct PrintVisitor<'a, 'tcx> { } impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { - fn new(cx: &'a LateContext<'tcx>) -> Self { + fn new(cx: &'a LateContext<'tcx>, typeck_results: &'tcx TypeckResults<'tcx>) -> Self { Self { cx, + typeck_results, ids: Cell::default(), first: Cell::new(true), } @@ -291,7 +309,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { } fn maybe_path<'p>(&self, path: &Binding>) { - if let Some(id) = path.value.res(self.cx).opt_def_id() + if let Some(id) = path.value.res(self.typeck_results).opt_def_id() && !id.is_local() { if let Some(lang) = self.cx.tcx.lang_items().from_def_id(id) { diff --git a/tests/ui/author/issue_17240.rs b/tests/ui/author/issue_17240.rs new file mode 100644 index 0000000000000..591a19907720a --- /dev/null +++ b/tests/ui/author/issue_17240.rs @@ -0,0 +1,8 @@ +//@ check-pass +// Ensure that a proper body is used when printing paths (`x`) +// if the attribute is placed on an item. +#[clippy::author] +fn main() { + let x = 42i32; + _ = -x; +} diff --git a/tests/ui/author/issue_17240.stdout b/tests/ui/author/issue_17240.stdout new file mode 100644 index 0000000000000..81c927180ce1c --- /dev/null +++ b/tests/ui/author/issue_17240.stdout @@ -0,0 +1,20 @@ +if let ExprKind::Block(block, None) = expr.kind + && block.stmts.len() == 2 + && let StmtKind::Let(local) = block.stmts[0].kind + && let Some(init) = local.init + && let ExprKind::Lit(ref lit) = init.kind + && let LitKind::Int(42, LitIntType::Signed(IntTy::I32)) = lit.node + && let PatKind::Binding(BindingMode::NONE, _, name, None) = local.pat.kind + && name.as_str() == "x" + && let StmtKind::Semi(e) = block.stmts[1].kind + && let ExprKind::Block(block1, None) = e.kind + && block1.stmts.len() == 1 + && let StmtKind::Let(local1) = block1.stmts[0].kind + && let Some(init1) = local1.init + && let ExprKind::Unary(UnOp::Neg, inner) = init1.kind + && let PatKind::Wild = local1.pat.kind + && block1.expr.is_none() + && block.expr.is_none() +{ + // report your lint here +} From d9517a64c9b57531e0dd0cee34a0987c01024b42 Mon Sep 17 00:00:00 2001 From: Zac Harrold Date: Tue, 5 May 2026 16:00:56 +1000 Subject: [PATCH 42/77] fix: [std_instead_of_core] false positive for core::io Using suggestion proposed in: https://github.com/rust-lang/rust-clippy/pull/16964#issuecomment-4699031740 --- clippy_lints/src/std_instead_of_core.rs | 29 ++++++++++--------- tests/ui/std_instead_of_core.fixed | 20 +++++++++++++ tests/ui/std_instead_of_core.rs | 20 +++++++++++++ tests/ui/std_instead_of_core.stderr | 14 ++++++++- tests/ui/std_instead_of_core_unfixable.rs | 11 +++++++ tests/ui/std_instead_of_core_unfixable.stderr | 18 +++++++++++- 6 files changed, 96 insertions(+), 16 deletions(-) diff --git a/clippy_lints/src/std_instead_of_core.rs b/clippy_lints/src/std_instead_of_core.rs index d519afba61b53..0f7cbd503bcd8 100644 --- a/clippy_lints/src/std_instead_of_core.rs +++ b/clippy_lints/src/std_instead_of_core.rs @@ -238,20 +238,21 @@ fn get_first_segment<'tcx>(path: &Path<'tcx>) -> Option<&'tcx PathSegment<'tcx>> /// Does not catch individually moved items fn is_stable(cx: &LateContext<'_>, mut def_id: DefId, msrv: Msrv) -> bool { loop { - if let Some(stability) = cx.tcx.lookup_stability(def_id) - && let StabilityLevel::Stable { - since, - allowed_through_unstable_modules: None, - } = stability.level - { - let stable = match since { - StableSince::Version(v) => msrv.meets(cx, v), - StableSince::Current => msrv.current(cx).is_none(), - StableSince::Err(_) => false, - }; - - if !stable { - return false; + if let Some(stability) = cx.tcx.lookup_stability(def_id) { + match stability.level { + // Workaround for items from `core::intrinsics` with a stable export in a different module. + // Not that we ignore the `since` field as we are already accessing the item in question. + StabilityLevel::Stable { + allowed_through_unstable_modules: Some(_), + .. + } => return true, + StabilityLevel::Stable { since, .. } => match since { + StableSince::Version(v) if !msrv.meets(cx, v) => return false, + StableSince::Current if msrv.current(cx).is_none() => return false, + StableSince::Err(_) => return false, + StableSince::Version(_) | StableSince::Current => {}, + }, + StabilityLevel::Unstable { .. } => return false, } } diff --git a/tests/ui/std_instead_of_core.fixed b/tests/ui/std_instead_of_core.fixed index c27cec558242d..3020ed5c6f39d 100644 --- a/tests/ui/std_instead_of_core.fixed +++ b/tests/ui/std_instead_of_core.fixed @@ -96,3 +96,23 @@ fn issue15579() { let layout = alloc::Layout::new::(); } + +#[warn(clippy::std_instead_of_core)] +fn issue13158_core_io() { + // items moved from std::io into core::io are stable in an unstable module. + use std::io::ErrorKind; +} + +#[clippy::msrv = "1.40"] +fn issue13158_msrv_1_40(_: &dyn std::panic::UnwindSafe) {} + +#[clippy::msrv = "1.41"] +fn issue13158_msrv_1_41(_: &dyn core::panic::UnwindSafe) {} +//~^ std_instead_of_core + +#[clippy::msrv = "1.80"] +fn issue13158_msrv_1_80(_: &dyn std::error::Error) {} + +#[clippy::msrv = "1.81"] +fn issue13158_msrv_1_81(_: &dyn core::error::Error) {} +//~^ std_instead_of_core diff --git a/tests/ui/std_instead_of_core.rs b/tests/ui/std_instead_of_core.rs index 7d53f7fc3072b..49b4218aa8983 100644 --- a/tests/ui/std_instead_of_core.rs +++ b/tests/ui/std_instead_of_core.rs @@ -96,3 +96,23 @@ fn issue15579() { let layout = alloc::Layout::new::(); } + +#[warn(clippy::std_instead_of_core)] +fn issue13158_core_io() { + // items moved from std::io into core::io are stable in an unstable module. + use std::io::ErrorKind; +} + +#[clippy::msrv = "1.40"] +fn issue13158_msrv_1_40(_: &dyn std::panic::UnwindSafe) {} + +#[clippy::msrv = "1.41"] +fn issue13158_msrv_1_41(_: &dyn std::panic::UnwindSafe) {} +//~^ std_instead_of_core + +#[clippy::msrv = "1.80"] +fn issue13158_msrv_1_80(_: &dyn std::error::Error) {} + +#[clippy::msrv = "1.81"] +fn issue13158_msrv_1_81(_: &dyn std::error::Error) {} +//~^ std_instead_of_core diff --git a/tests/ui/std_instead_of_core.stderr b/tests/ui/std_instead_of_core.stderr index a5f8fbbe37cb8..0363852cf8d49 100644 --- a/tests/ui/std_instead_of_core.stderr +++ b/tests/ui/std_instead_of_core.stderr @@ -97,5 +97,17 @@ error: used import from `std` instead of `core` LL | fn msrv_1_77(_: std::net::IpAddr) {} | ^^^ help: consider importing the item from `core`: `core` -error: aborting due to 15 previous errors +error: used import from `std` instead of `core` + --> tests/ui/std_instead_of_core.rs:110:33 + | +LL | fn issue13158_msrv_1_41(_: &dyn std::panic::UnwindSafe) {} + | ^^^ help: consider importing the item from `core`: `core` + +error: used import from `std` instead of `core` + --> tests/ui/std_instead_of_core.rs:117:33 + | +LL | fn issue13158_msrv_1_81(_: &dyn std::error::Error) {} + | ^^^ help: consider importing the item from `core`: `core` + +error: aborting due to 17 previous errors diff --git a/tests/ui/std_instead_of_core_unfixable.rs b/tests/ui/std_instead_of_core_unfixable.rs index 5e71159ac6c5d..66d834b5e4279 100644 --- a/tests/ui/std_instead_of_core_unfixable.rs +++ b/tests/ui/std_instead_of_core_unfixable.rs @@ -14,3 +14,14 @@ fn issue15143() { //~^ std_instead_of_core //~| std_instead_of_alloc } + +#[rustfmt::skip] +fn pr16964() { + use std::{ + borrow::Cow, + //~^ std_instead_of_alloc + collections::BTreeSet, + //~^ std_instead_of_alloc + ffi::OsString, + }; +} diff --git a/tests/ui/std_instead_of_core_unfixable.stderr b/tests/ui/std_instead_of_core_unfixable.stderr index 147b46022126b..6fa8f47a4d6f4 100644 --- a/tests/ui/std_instead_of_core_unfixable.stderr +++ b/tests/ui/std_instead_of_core_unfixable.stderr @@ -26,5 +26,21 @@ LL | use std::{error::Error, vec::Vec, fs::File}; = note: `-D clippy::std-instead-of-alloc` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::std_instead_of_alloc)]` -error: aborting due to 3 previous errors +error: used import from `std` instead of `alloc` + --> tests/ui/std_instead_of_core_unfixable.rs:21:17 + | +LL | borrow::Cow, + | ^^^ + | + = help: consider importing the item from `alloc` + +error: used import from `std` instead of `alloc` + --> tests/ui/std_instead_of_core_unfixable.rs:23:22 + | +LL | collections::BTreeSet, + | ^^^^^^^^ + | + = help: consider importing the item from `alloc` + +error: aborting due to 5 previous errors From 6667ea1ebb038edb7bcc14c53ed4a1e193a971c1 Mon Sep 17 00:00:00 2001 From: mistaste Date: Mon, 15 Jun 2026 04:19:48 +0300 Subject: [PATCH 43/77] Don't trigger `unnecessary_box_returns` when the size depends on generics The lint fired on return types such as `Box<[T; N]>`, suggesting to return the array unboxed. The size of such a type depends on generic parameters and cannot be computed here: `approx_ty_size` falls back to `0` for an array with a const- generic length or a generic element type, so the size check always passed. Use the type's layout directly and only lint when it can actually be computed. This keeps the existing behaviour for concrete types (and for generic types with a known layout such as `Box>`) while no longer suggesting to unbox a value whose size is unknown and potentially large. --- clippy_lints/src/unnecessary_box_returns.rs | 11 ++++++++--- tests/ui/unnecessary_box_returns.rs | 10 ++++++++++ 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/unnecessary_box_returns.rs b/clippy_lints/src/unnecessary_box_returns.rs index 8d4f1a153def8..4112e1b6ca63f 100644 --- a/clippy_lints/src/unnecessary_box_returns.rs +++ b/clippy_lints/src/unnecessary_box_returns.rs @@ -1,10 +1,10 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::ty::approx_ty_size; use rustc_errors::Applicability; use rustc_hir::def_id::LocalDefId; use rustc_hir::{FnDecl, FnRetTy, ImplItemKind, Item, ItemKind, Node, TraitItem, TraitItemKind}; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::layout::LayoutOf; use rustc_session::impl_lint_pass; use rustc_span::Symbol; @@ -81,8 +81,13 @@ impl UnnecessaryBoxReturns { // It's sometimes useful to return Box if T is unsized, so don't lint those. // Also, don't lint if we know that T is very large, in which case returning - // a Box may be beneficial. - if boxed_ty.is_sized(cx.tcx, cx.typing_env()) && approx_ty_size(cx, boxed_ty) <= self.maximum_size { + // a Box may be beneficial. When the size depends on generic parameters + // (e.g. `[T; N]`) it cannot be determined here, so don't lint that either, as + // the `Box` may be a deliberate choice to avoid copying a large value. + if boxed_ty.is_sized(cx.tcx, cx.typing_env()) + && let Ok(layout) = cx.layout_of(boxed_ty) + && layout.size.bytes() <= self.maximum_size + { span_lint_and_then( cx, UNNECESSARY_BOX_RETURNS, diff --git a/tests/ui/unnecessary_box_returns.rs b/tests/ui/unnecessary_box_returns.rs index a7ab7e90be06b..b0a892e2e2157 100644 --- a/tests/ui/unnecessary_box_returns.rs +++ b/tests/ui/unnecessary_box_returns.rs @@ -71,6 +71,16 @@ impl HasHuge { } } +// don't lint (issue #17202): the size of `[T; N]` depends on a const generic parameter +fn const_generic_array(value: Box<[T; N]>) -> Box<[T; N]> { + value +} + +// don't lint (issue #17202): the size of `[T; 10]` depends on the generic element type +fn generic_element_array(value: Box<[T; 10]>) -> Box<[T; 10]> { + value +} + fn main() { // don't lint: this is a closure let a = || -> Box { Box::new(5) }; From 3054d6fbad391ba906de3537d1fd7855740e5e4c Mon Sep 17 00:00:00 2001 From: mistaste Date: Mon, 15 Jun 2026 14:14:14 +0300 Subject: [PATCH 44/77] Add test for Box> with known layout --- tests/ui/unnecessary_box_returns.rs | 7 +++++++ tests/ui/unnecessary_box_returns.stderr | 10 +++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/tests/ui/unnecessary_box_returns.rs b/tests/ui/unnecessary_box_returns.rs index b0a892e2e2157..e550996256f44 100644 --- a/tests/ui/unnecessary_box_returns.rs +++ b/tests/ui/unnecessary_box_returns.rs @@ -81,6 +81,13 @@ fn generic_element_array(value: Box<[T; 10]>) -> Box<[T; 10]> { value } +// lint: the size of `Vec` is known regardless of the generic element type +#[expect(clippy::box_collection)] +fn generic_vec(value: Box>) -> Box> { + //~^ unnecessary_box_returns + value +} + fn main() { // don't lint: this is a closure let a = || -> Box { Box::new(5) }; diff --git a/tests/ui/unnecessary_box_returns.stderr b/tests/ui/unnecessary_box_returns.stderr index ab1d90f13b922..8eb39fca5680b 100644 --- a/tests/ui/unnecessary_box_returns.stderr +++ b/tests/ui/unnecessary_box_returns.stderr @@ -32,5 +32,13 @@ LL | fn _bxed_foo() -> Box { | = help: changing this also requires a change to the return expressions in this function -error: aborting due to 4 previous errors +error: boxed return of the sized type `std::vec::Vec` + --> tests/ui/unnecessary_box_returns.rs:86:42 + | +LL | fn generic_vec(value: Box>) -> Box> { + | ^^^^^^^^^^^ help: try: `std::vec::Vec` + | + = help: changing this also requires a change to the return expressions in this function + +error: aborting due to 5 previous errors From cabc5a616a967e4b42f0a4ed25a1cfea058a548a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandra=20Gonz=C3=A1lez?= Date: Mon, 15 Jun 2026 13:47:24 +0200 Subject: [PATCH 45/77] Revert "feat: Add profile-specific configuration for disallowed methods and types" --- CHANGELOG.md | 1 - book/src/lint_configuration.md | 22 -- clippy_config/src/conf.rs | 211 +----------------- clippy_config/src/types.rs | 9 - clippy_lints/src/disallowed_methods.rs | 125 +---------- clippy_lints/src/disallowed_types.rs | 167 +++----------- clippy_utils/src/attrs.rs | 2 - clippy_utils/src/disallowed_profiles.rs | 180 --------------- clippy_utils/src/lib.rs | 1 - clippy_utils/src/sym.rs | 2 - .../disallowed_profiles_methods/clippy.toml | 13 -- .../disallowed_profiles_methods/main.rs | 78 ------- .../disallowed_profiles_methods/main.stderr | 72 ------ .../disallowed_profiles_types/clippy.toml | 13 -- .../ui-toml/disallowed_profiles_types/main.rs | 61 ----- .../disallowed_profiles_types/main.stderr | 78 ------- .../toml_unknown_key/conf_unknown_key.stderr | 3 - 17 files changed, 39 insertions(+), 999 deletions(-) delete mode 100644 clippy_utils/src/disallowed_profiles.rs delete mode 100644 tests/ui-toml/disallowed_profiles_methods/clippy.toml delete mode 100644 tests/ui-toml/disallowed_profiles_methods/main.rs delete mode 100644 tests/ui-toml/disallowed_profiles_methods/main.stderr delete mode 100644 tests/ui-toml/disallowed_profiles_types/clippy.toml delete mode 100644 tests/ui-toml/disallowed_profiles_types/main.rs delete mode 100644 tests/ui-toml/disallowed_profiles_types/main.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index d06a72d9c4155..8fb6356ff8e87 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7609,7 +7609,6 @@ Released 2018-09-13 [`module-items-ordered-within-groupings`]: https://doc.rust-lang.org/clippy/lint_configuration.html#module-items-ordered-within-groupings [`msrv`]: https://doc.rust-lang.org/clippy/lint_configuration.html#msrv [`pass-by-value-size-limit`]: https://doc.rust-lang.org/clippy/lint_configuration.html#pass-by-value-size-limit -[`profiles`]: https://doc.rust-lang.org/clippy/lint_configuration.html#profiles [`pub-underscore-fields-behavior`]: https://doc.rust-lang.org/clippy/lint_configuration.html#pub-underscore-fields-behavior [`recursive-self-in-type-definitions`]: https://doc.rust-lang.org/clippy/lint_configuration.html#recursive-self-in-type-definitions [`semicolon-inside-block-ignore-singleline`]: https://doc.rust-lang.org/clippy/lint_configuration.html#semicolon-inside-block-ignore-singleline diff --git a/book/src/lint_configuration.md b/book/src/lint_configuration.md index e123d7ba5704d..dd10ef0538c25 100644 --- a/book/src/lint_configuration.md +++ b/book/src/lint_configuration.md @@ -986,28 +986,6 @@ The minimum size (in bytes) to consider a type for passing by reference instead * [`large_types_passed_by_value`](https://rust-lang.github.io/rust-clippy/master/index.html#large_types_passed_by_value) -## `profiles` -Named profiles of disallowed items (unrelated to Cargo build profiles). - -#### Example - -```toml -[profiles.persistent] -disallowed-methods = [{ path = "std::env::temp_dir" }] -disallowed-types = [{ path = "std::time::Instant", reason = "use our custom time API" }] - -[profiles.single_threaded] -disallowed-methods = [{ path = "std::thread::spawn" }] -``` - -**Default Value:** `{}` - ---- -**Affected lints:** -* [`disallowed_methods`](https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_methods) -* [`disallowed_types`](https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_types) - - ## `pub-underscore-fields-behavior` Lint "public" fields in a struct that are prefixed with an underscore based on their exported visibility, or whether they are marked as "pub". diff --git a/clippy_config/src/conf.rs b/clippy_config/src/conf.rs index 47bc7b572c9d0..5a06cb477c304 100644 --- a/clippy_config/src/conf.rs +++ b/clippy_config/src/conf.rs @@ -1,13 +1,12 @@ use crate::ClippyConfiguration; use crate::types::{ - DisallowedPath, DisallowedPathWithoutReplacement, DisallowedProfile, InherentImplLintScope, MacroMatcher, - MatchLintBehaviour, PubUnderscoreFieldsBehaviour, Rename, SourceItemOrdering, SourceItemOrderingCategory, + DisallowedPath, DisallowedPathWithoutReplacement, InherentImplLintScope, MacroMatcher, MatchLintBehaviour, + PubUnderscoreFieldsBehaviour, Rename, SourceItemOrdering, SourceItemOrderingCategory, SourceItemOrderingModuleItemGroupings, SourceItemOrderingModuleItemKind, SourceItemOrderingTraitAssocItemKind, SourceItemOrderingTraitAssocItemKinds, SourceItemOrderingWithinModuleItemGroupings, }; use clippy_utils::msrvs::Msrv; use itertools::Itertools; -use rustc_data_structures::fx::FxHashMap; use rustc_errors::Applicability; use rustc_session::Session; use rustc_span::edit_distance::edit_distance; @@ -223,74 +222,12 @@ macro_rules! deserialize { }}; } -macro_rules! parse_conf_value { - ( - $map:expr, - $ty:ty, - $errors:expr, - $file:expr, - $field_span:expr, - profiles @[$($profiles:expr)?], - disallowed @[$($disallowed:expr)?] - ) => { - parse_conf_value_impl!( - $map, - $ty, - $errors, - $file, - $field_span, - ($($profiles)?), - ($($disallowed)?) - ) - }; -} - -macro_rules! parse_conf_value_impl { - ($map:expr, $ty:ty, $errors:expr, $file:expr, $field_span:expr, (), ()) => {{ - let _ = &$field_span; - deserialize!($map, $ty, $errors, $file) - }}; - ($map:expr, $ty:ty, $errors:expr, $file:expr, $field_span:expr, ($profiles:expr), ()) => {{ - let raw_value = $map.next_value::()?; - let value_span = $field_span.clone(); - let toml::Value::Table(table) = raw_value else { - $errors.push(ConfError::spanned( - $file, - "expected table with named profiles", - None, - value_span.clone(), - )); - continue; - }; - - let map = parse_profiles(table, $file, value_span.clone(), &mut $errors); - - (map, value_span) - }}; - ($map:expr, $ty:ty, $errors:expr, $file:expr, $field_span:expr, (), ($disallowed:expr)) => {{ - let _ = &$field_span; - deserialize!($map, $ty, $errors, $file, $disallowed) - }}; - ( - $map:expr, - $ty:ty, - $errors:expr, - $file:expr, - $field_span:expr, - ($profiles:expr), - ($disallowed:expr) - ) => { - compile_error!("field cannot specify both profiles and disallowed-paths attributes") - }; -} - macro_rules! define_Conf { ($( $(#[doc = $doc:literal])+ $(#[conf_deprecated($dep:literal, $new_conf:ident)])? $(#[default_text = $default_text:expr])? $(#[disallowed_paths_allow_replacements = $replacements_allowed:expr])? - $(#[profiles = $profiles:expr])? $(#[lints($($for_lints:ident),* $(,)?)])? $name:ident: $ty:ty = $default:expr, )*) => { @@ -345,20 +282,10 @@ macro_rules! define_Conf { match field { $(Field::$name => { - let field_span = name.span(); // Is this a deprecated field, i.e., is `$dep` set? If so, push a warning. $(warnings.push(ConfError::spanned(self.0, format!("deprecated field `{}`. {}", name.get_ref(), $dep), None, name.span()));)? - let (value, value_span) = parse_conf_value!( - map, - $ty, - errors, - self.0, - field_span, - // Disallowed-profile table parsing is special-cased to preserve spans for - // diagnostics in disallowed-path entries. - profiles @[$($profiles)?], - disallowed @[$($replacements_allowed)?] - ); + let (value, value_span) = + deserialize!(map, $ty, errors, self.0 $(, $replacements_allowed)?); // Was this field set previously? if $name.is_some() { errors.push(ConfError::spanned(self.0, format!("duplicate field `{}`", name.get_ref()), None, name.span())); @@ -415,121 +342,6 @@ fn span_from_toml_range(file: &SourceFile, span: Range) -> Span { ) } -fn parse_profiles( - table: toml::value::Table, - file: &SourceFile, - value_span: Range, - errors: &mut Vec, -) -> FxHashMap { - let mut profiles = FxHashMap::default(); - let config_span = span_from_toml_range(file, value_span.clone()); - - for (profile_name, profile_value) in table { - let toml::Value::Table(mut profile_table) = profile_value else { - errors.push(ConfError::spanned( - file, - format!("invalid profile `{profile_name}`: expected table"), - None, - value_span.clone(), - )); - continue; - }; - - let disallowed_methods = match profile_table - .remove("disallowed-methods") - .or_else(|| profile_table.remove("disallowed_methods")) - { - Some(value) => parse_profile_list( - file, - &profile_name, - "disallowed-methods", - value, - value_span.clone(), - config_span, - errors, - ), - None => Vec::new(), - }; - - let disallowed_types = match profile_table - .remove("disallowed-types") - .or_else(|| profile_table.remove("disallowed_types")) - { - Some(value) => parse_profile_list( - file, - &profile_name, - "disallowed-types", - value, - value_span.clone(), - config_span, - errors, - ), - None => Vec::new(), - }; - - if !profile_table.is_empty() { - let keys = profile_table.keys().map(String::as_str).collect::>().join(", "); - errors.push(ConfError::spanned( - file, - format!("profile `{profile_name}` has unknown keys: {keys}"), - None, - value_span.clone(), - )); - } - - profiles.insert( - profile_name, - DisallowedProfile { - disallowed_methods, - disallowed_types, - }, - ); - } - - profiles -} - -fn parse_profile_list( - file: &SourceFile, - profile_name: &str, - key_name: &str, - value: toml::Value, - value_span: Range, - config_span: Span, - errors: &mut Vec, -) -> Vec { - let toml::Value::Array(entries) = value else { - errors.push(ConfError::spanned( - file, - format!("profile `{profile_name}`: `{key_name}` must be an array"), - None, - value_span, - )); - return Vec::new(); - }; - - let mut disallowed = Vec::with_capacity(entries.len()); - for entry in entries { - match DisallowedPath::deserialize(entry.clone()) { - Ok(mut path) => { - path.set_span(config_span); - disallowed.push(path); - }, - Err(err) => errors.push(ConfError::spanned( - file, - format!( - "profile `{profile_name}`: {}", - err.to_string().replace('\n', " ").trim() - ), - None, - value_span.clone(), - )), - } - } - - disallowed -} - define_Conf! { /// Which crates to allow absolute paths from #[lints(absolute_paths)] @@ -1029,21 +841,6 @@ define_Conf! { /// The minimum size (in bytes) to consider a type for passing by reference instead of by value. #[lints(large_types_passed_by_value)] pass_by_value_size_limit: u64 = 256, - /// Named profiles of disallowed items (unrelated to Cargo build profiles). - /// - /// #### Example - /// - /// ```toml - /// [profiles.persistent] - /// disallowed-methods = [{ path = "std::env::temp_dir" }] - /// disallowed-types = [{ path = "std::time::Instant", reason = "use our custom time API" }] - /// - /// [profiles.single_threaded] - /// disallowed-methods = [{ path = "std::thread::spawn" }] - /// ``` - #[profiles = true] - #[lints(disallowed_methods, disallowed_types)] - profiles: FxHashMap = FxHashMap::default(), /// Lint "public" fields in a struct that are prefixed with an underscore based on their /// exported visibility, or whether they are marked as "pub". #[lints(pub_underscore_fields)] diff --git a/clippy_config/src/types.rs b/clippy_config/src/types.rs index 5eaa44ddd51d7..8d9326a904b1e 100644 --- a/clippy_config/src/types.rs +++ b/clippy_config/src/types.rs @@ -57,15 +57,6 @@ impl<'de, const REPLACEMENT_ALLOWED: bool> Deserialize<'de> for DisallowedPath, - #[serde(default, alias = "disallowed_types")] - pub disallowed_types: Vec, -} - // `DisallowedPathEnum` is an implementation detail to enable the `Deserialize` implementation just // above. `DisallowedPathEnum` is not meant to be used outside of this file. #[derive(Debug, Deserialize, Serialize)] diff --git a/clippy_lints/src/disallowed_methods.rs b/clippy_lints/src/disallowed_methods.rs index 58cc318d57ccd..e2fd71b7d990f 100644 --- a/clippy_lints/src/disallowed_methods.rs +++ b/clippy_lints/src/disallowed_methods.rs @@ -1,18 +1,13 @@ use clippy_config::Conf; use clippy_config::types::{DisallowedPath, create_disallowed_map}; -use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; -use clippy_utils::disallowed_profiles::{ProfileEntry, ProfileResolver}; +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::paths::PathNS; -use clippy_utils::sym; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_data_structures::smallvec::SmallVec; use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def_id::DefIdMap; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::TyCtxt; use rustc_session::impl_lint_pass; -use rustc_span::{Span, Symbol}; declare_clippy_lint! { /// ### What it does @@ -60,19 +55,6 @@ declare_clippy_lint! { /// let mut xs = Vec::new(); // Vec::new is _not_ disallowed in the config. /// xs.push(123); // Vec::push is _not_ disallowed in the config. /// ``` - /// - /// Disallowed profiles allow scoping different disallow lists: - /// ```toml - /// [profiles.forward_pass] - /// disallowed-methods = [{ path = "crate::devices::Buffer::copy_to_host", reason = "Forward code must not touch host buffers" }] - /// ``` - /// - /// ```rust,ignore - /// #[clippy::disallowed_profile("forward_pass")] - /// fn evaluate() { - /// // Method calls in this function use the `forward_pass` profile. - /// } - /// ``` #[clippy::version = "1.49.0"] pub DISALLOWED_METHODS, style, @@ -82,22 +64,12 @@ declare_clippy_lint! { impl_lint_pass!(DisallowedMethods => [DISALLOWED_METHODS]); pub struct DisallowedMethods { - default: DefIdMap<(&'static str, &'static DisallowedPath)>, - /// Lookup per profile that declares a non-empty `disallowed_methods` list. Profiles - /// declared in `[profiles.*]` but without `disallowed_methods` entries are absent here. - profiles: FxHashMap>, - /// Every profile name declared in `[profiles.*]`, regardless of whether it contributes - /// to this lint. Used to suppress the "unknown profile" warning for profiles that exist - /// in config but only define entries for other lints (e.g. `disallowed_types`). - known_profiles: FxHashSet, - profile_cache: ProfileResolver, - warned_unknown_profiles: FxHashSet, + disallowed: DefIdMap<(&'static str, &'static DisallowedPath)>, } impl DisallowedMethods { - #[allow(rustc::potential_query_instability)] // Profiles are sorted for deterministic iteration. pub fn new(tcx: TyCtxt<'_>, conf: &'static Conf) -> Self { - let (default, _) = create_disallowed_map( + let (disallowed, _) = create_disallowed_map( tcx, &conf.disallowed_methods, PathNS::Value, @@ -110,62 +82,7 @@ impl DisallowedMethods { "function", false, ); - - let mut profiles = FxHashMap::default(); - let mut known_profiles = FxHashSet::default(); - let mut profile_entries: Vec<_> = conf.profiles.iter().collect(); - profile_entries.sort_by_key(|(a, _)| *a); - for (name, profile) in profile_entries { - let symbol = Symbol::intern(name.as_str()); - known_profiles.insert(symbol); - - let paths = profile.disallowed_methods.as_slice(); - if paths.is_empty() { - continue; - } - - let (map, _) = create_disallowed_map( - tcx, - paths, - PathNS::Value, - |def_kind| { - matches!( - def_kind, - DefKind::Fn | DefKind::Ctor(_, CtorKind::Fn) | DefKind::AssocFn - ) - }, - "function", - false, - ); - profiles.insert(symbol, map); - } - - Self { - default, - profiles, - known_profiles, - profile_cache: ProfileResolver::default(), - warned_unknown_profiles: FxHashSet::default(), - } - } - - fn warn_unknown_profile(&mut self, cx: &LateContext<'_>, entry: &ProfileEntry) { - if self.warned_unknown_profiles.insert(entry.span) { - let attr_name = if entry.attr_name == sym::disallowed_profiles { - "clippy::disallowed_profiles" - } else { - "clippy::disallowed_profile" - }; - span_lint( - cx, - DISALLOWED_METHODS, - entry.span, - format!( - "`{attr_name}` references unknown profile `{}` for `clippy::disallowed_methods`", - entry.name - ), - ); - } + Self { disallowed } } } @@ -181,43 +98,13 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedMethods { }, _ => return, }; - let mut active_profiles = SmallVec::<[Symbol; 2]>::new(); - // Copy entries out of the cache before iterating: `warn_unknown_profile` takes - // `&mut self`, which conflicts with the borrow held by `active_profiles(...)`. - let entries: SmallVec<[ProfileEntry; 2]> = self - .profile_cache - .active_profiles(cx, expr.hir_id) - .map(|selection| selection.iter().copied().collect()) - .unwrap_or_default(); - for entry in &entries { - if self.profiles.contains_key(&entry.name) { - active_profiles.push(entry.name); - } else if !self.known_profiles.contains(&entry.name) { - self.warn_unknown_profile(cx, entry); - } - } - - if let Some((profile, &(path, disallowed_path))) = active_profiles.iter().find_map(|symbol| { - self.profiles - .get(symbol) - .and_then(|map| map.get(&id).map(|info| (*symbol, info))) - }) { - let diag_amendment = disallowed_path.diag_amendment(span); - span_lint_and_then( - cx, - DISALLOWED_METHODS, - span, - format!("use of a disallowed method `{path}` (profile: {profile})"), - |diag| diag_amendment(diag), - ); - } else if let Some(&(path, disallowed_path)) = self.default.get(&id) { - let diag_amendment = disallowed_path.diag_amendment(span); + if let Some(&(path, disallowed_path)) = self.disallowed.get(&id) { span_lint_and_then( cx, DISALLOWED_METHODS, span, format!("use of a disallowed method `{path}`"), - |diag| diag_amendment(diag), + disallowed_path.diag_amendment(span), ); } } diff --git a/clippy_lints/src/disallowed_types.rs b/clippy_lints/src/disallowed_types.rs index 37dd605617a7a..2c520d053f439 100644 --- a/clippy_lints/src/disallowed_types.rs +++ b/clippy_lints/src/disallowed_types.rs @@ -1,18 +1,15 @@ use clippy_config::Conf; use clippy_config::types::{DisallowedPath, create_disallowed_map}; -use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; -use clippy_utils::disallowed_profiles::{ProfileEntry, ProfileResolver}; +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::paths::PathNS; -use clippy_utils::sym; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_data_structures::smallvec::SmallVec; +use rustc_data_structures::fx::FxHashMap; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefIdMap; use rustc_hir::{AmbigArg, Item, ItemKind, PolyTraitRef, PrimTy, Ty, TyKind, UseKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::TyCtxt; use rustc_session::impl_lint_pass; -use rustc_span::{Span, Symbol}; +use rustc_span::Span; declare_clippy_lint! { /// ### What it does @@ -54,17 +51,6 @@ declare_clippy_lint! { /// // A similar type that is allowed by the config /// use std::collections::HashMap; /// ``` - /// - /// Disallowed profiles can scope lists to specific modules: - /// ```toml - /// [profiles.forward_pass] - /// disallowed-types = [{ path = "crate::buffers::HostBuffer", reason = "Prefer device buffers in forward computations" }] - /// ``` - /// - /// ```rust,ignore - /// #[clippy::disallowed_profile("forward_pass")] - /// fn forward_step(buffer: crate::buffers::DeviceBuffer) { /* ... */ } - /// ``` #[clippy::version = "1.55.0"] pub DISALLOWED_TYPES, style, @@ -73,127 +59,37 @@ declare_clippy_lint! { impl_lint_pass!(DisallowedTypes => [DISALLOWED_TYPES]); -struct TypeLookup { +pub struct DisallowedTypes { def_ids: DefIdMap<(&'static str, &'static DisallowedPath)>, prim_tys: FxHashMap, } -impl TypeLookup { - fn from_config(tcx: TyCtxt<'_>, paths: &'static [DisallowedPath]) -> Self { - let (def_ids, prim_tys) = create_disallowed_map(tcx, paths, PathNS::Type, def_kind_predicate, "type", true); - Self { def_ids, prim_tys } - } - - fn find(&self, res: &Res) -> Option<(&'static str, &'static DisallowedPath)> { - match res { - Res::Def(_, did) => self.def_ids.get(did).copied(), - Res::PrimTy(prim) => self.prim_tys.get(prim).copied(), - _ => None, - } - } -} - -pub struct DisallowedTypes { - default: TypeLookup, - /// Lookup per profile that declares a non-empty `disallowed_types` list. Profiles - /// declared in `[profiles.*]` but without `disallowed_types` entries are absent here. - profiles: FxHashMap, - /// Every profile name declared in `[profiles.*]`, regardless of whether it contributes - /// to this lint. Used to suppress the "unknown profile" warning for profiles that exist - /// in config but only define entries for other lints (e.g. `disallowed_methods`). - known_profiles: FxHashSet, - profile_cache: ProfileResolver, - warned_unknown_profiles: FxHashSet, -} - impl DisallowedTypes { - #[allow(rustc::potential_query_instability)] // Profiles are sorted for deterministic iteration. pub fn new(tcx: TyCtxt<'_>, conf: &'static Conf) -> Self { - let default = TypeLookup::from_config(tcx, &conf.disallowed_types); - - let mut profiles = FxHashMap::default(); - let mut known_profiles = FxHashSet::default(); - let mut profile_entries: Vec<_> = conf.profiles.iter().collect(); - profile_entries.sort_by_key(|(a, _)| *a); - for (name, profile) in profile_entries { - let symbol = Symbol::intern(name.as_str()); - known_profiles.insert(symbol); - - let paths = profile.disallowed_types.as_slice(); - if paths.is_empty() { - continue; - } - profiles.insert(symbol, TypeLookup::from_config(tcx, paths)); - } - - Self { - default, - profiles, - known_profiles, - profile_cache: ProfileResolver::default(), - warned_unknown_profiles: FxHashSet::default(), - } - } - - fn warn_unknown_profile(&mut self, cx: &LateContext<'_>, entry: &ProfileEntry) { - if self.warned_unknown_profiles.insert(entry.span) { - let attr_name = if entry.attr_name == sym::disallowed_profiles { - "clippy::disallowed_profiles" - } else { - "clippy::disallowed_profile" - }; - span_lint( - cx, - DISALLOWED_TYPES, - entry.span, - format!( - "`{attr_name}` references unknown profile `{}` for `clippy::disallowed_types`", - entry.name - ), - ); - } + let (def_ids, prim_tys) = create_disallowed_map( + tcx, + &conf.disallowed_types, + PathNS::Type, + def_kind_predicate, + "type", + true, + ); + Self { def_ids, prim_tys } } - fn check_res_emit(&mut self, cx: &LateContext<'_>, hir_id: rustc_hir::HirId, res: &Res, span: Span) { - let mut active_profiles = SmallVec::<[Symbol; 2]>::new(); - // Copy entries out of the cache before iterating: `warn_unknown_profile` takes - // `&mut self`, which conflicts with the borrow held by `active_profiles(...)`. - let entries: SmallVec<[ProfileEntry; 2]> = self - .profile_cache - .active_profiles(cx, hir_id) - .map(|selection| selection.iter().copied().collect()) - .unwrap_or_default(); - for entry in &entries { - if self.profiles.contains_key(&entry.name) { - active_profiles.push(entry.name); - } else if !self.known_profiles.contains(&entry.name) { - self.warn_unknown_profile(cx, entry); - } - } - - if let Some((profile, (path, disallowed_path))) = active_profiles.iter().find_map(|symbol| { - self.profiles - .get(symbol) - .and_then(|lookup| lookup.find(res).map(|info| (*symbol, info))) - }) { - let diag_amendment = disallowed_path.diag_amendment(span); - span_lint_and_then( - cx, - DISALLOWED_TYPES, - span, - format!("use of a disallowed type `{path}` (profile: {profile})"), - |diag| diag_amendment(diag), - ); - } else if let Some((path, disallowed_path)) = self.default.find(res) { - let diag_amendment = disallowed_path.diag_amendment(span); - span_lint_and_then( - cx, - DISALLOWED_TYPES, - span, - format!("use of a disallowed type `{path}`"), - |diag| diag_amendment(diag), - ); - } + fn check_res_emit(&self, cx: &LateContext<'_>, res: &Res, span: Span) { + let (path, disallowed_path) = match res { + Res::Def(_, did) if let Some(&x) = self.def_ids.get(did) => x, + Res::PrimTy(prim) if let Some(&x) = self.prim_tys.get(prim) => x, + _ => return, + }; + span_lint_and_then( + cx, + DISALLOWED_TYPES, + span, + format!("use of a disallowed type `{path}`"), + disallowed_path.diag_amendment(span), + ); } } @@ -215,22 +111,17 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedTypes { if let ItemKind::Use(path, UseKind::Single(_)) = &item.kind && let Some(res) = path.res.type_ns { - self.check_res_emit(cx, item.hir_id(), &res, item.span); + self.check_res_emit(cx, &res, item.span); } } fn check_ty(&mut self, cx: &LateContext<'tcx>, ty: &'tcx Ty<'tcx, AmbigArg>) { if let TyKind::Path(path) = &ty.kind { - self.check_res_emit(cx, ty.hir_id, &cx.qpath_res(path, ty.hir_id), ty.span); + self.check_res_emit(cx, &cx.qpath_res(path, ty.hir_id), ty.span); } } fn check_poly_trait_ref(&mut self, cx: &LateContext<'tcx>, poly: &'tcx PolyTraitRef<'tcx>) { - self.check_res_emit( - cx, - poly.trait_ref.hir_ref_id, - &poly.trait_ref.path.res, - poly.trait_ref.path.span, - ); + self.check_res_emit(cx, &poly.trait_ref.path.res, poly.trait_ref.path.span); } } diff --git a/clippy_utils/src/attrs.rs b/clippy_utils/src/attrs.rs index 2341007cd49e8..ca3ed73b84817 100644 --- a/clippy_utils/src/attrs.rs +++ b/clippy_utils/src/attrs.rs @@ -37,8 +37,6 @@ pub fn check_clippy_attr(sess: &Session, attr: &A) { | sym::version | sym::cognitive_complexity | sym::dump - | sym::disallowed_profile - | sym::disallowed_profiles | sym::msrv | sym::has_significant_drop | sym::format_args => {}, diff --git a/clippy_utils/src/disallowed_profiles.rs b/clippy_utils/src/disallowed_profiles.rs deleted file mode 100644 index 98a498981b3b5..0000000000000 --- a/clippy_utils/src/disallowed_profiles.rs +++ /dev/null @@ -1,180 +0,0 @@ -use crate::sym; -use rustc_ast::ast::{LitKind, MetaItemInner}; -use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::smallvec::SmallVec; -use rustc_hir::{Attribute, HirId}; -use rustc_lint::LateContext; -use rustc_span::{Span, Symbol}; - -/// One profile name referenced by a `#[clippy::disallowed_profile(...)]` or -/// `#[clippy::disallowed_profiles(...)]` attribute on an item. -/// -/// A single attribute produces one `ProfileEntry` per string argument. The entry records which -/// attribute variant introduced it, the profile name, and the span of that string literal so -/// diagnostics (e.g. "unknown profile") can point at the exact argument. -#[derive(Copy, Clone)] -pub struct ProfileEntry { - pub attr_name: Symbol, - pub name: Symbol, - pub span: Span, -} - -/// The set of profiles active at some `HirId`, obtained by walking up the HIR from that id and -/// collecting the first ancestor that carries a `#[clippy::disallowed_profile(s)]` attribute. -/// -/// An empty selection is represented by `None` at the call site; a `ProfileSelection` is always -/// non-empty. -#[derive(Clone)] -pub struct ProfileSelection { - entries: SmallVec<[ProfileEntry; 2]>, -} - -impl ProfileSelection { - pub fn new(entries: SmallVec<[ProfileEntry; 2]>) -> Self { - Self { entries } - } - - pub fn is_empty(&self) -> bool { - self.entries.is_empty() - } - - pub fn iter(&self) -> impl Iterator { - self.entries.iter() - } -} - -#[derive(Default)] -pub struct ProfileResolver { - cache: FxHashMap>, -} - -impl ProfileResolver { - pub fn active_profiles(&mut self, cx: &LateContext<'_>, hir_id: HirId) -> Option<&ProfileSelection> { - // NOTE: The `contains_key`+`get` dance is intentional: using only `get` here triggers borrowck - // errors because we need to mutate `self.cache` on cache misses. - if self.cache.contains_key(&hir_id) { - return self.cache.get(&hir_id).and_then(|selection| selection.as_ref()); - } - - let (resolved, visited) = self.resolve(cx, hir_id); - - for id in visited { - self.cache.entry(id).or_insert_with(|| resolved.clone()); - } - self.cache.insert(hir_id, resolved); - - self.cache.get(&hir_id).and_then(|selection| selection.as_ref()) - } - - fn resolve(&self, cx: &LateContext<'_>, start: HirId) -> (Option, SmallVec<[HirId; 8]>) { - let mut visited = SmallVec::<[HirId; 8]>::new(); - let mut current = Some(start); - - while let Some(id) = current { - if let Some(cached) = self.cache.get(&id) { - return (cached.clone(), visited); - } - - visited.push(id); - - if let Some(selection) = profiles_from_attrs(cx, cx.tcx.hir_attrs(id)) { - return (Some(selection), visited); - } - - if id == rustc_hir::CRATE_HIR_ID { - current = None; - } else { - current = Some(cx.tcx.parent_hir_id(id)); - } - } - - (None, visited) - } -} - -fn profiles_from_attrs(cx: &LateContext<'_>, attrs: &[Attribute]) -> Option { - let mut entries = SmallVec::<[ProfileEntry; 2]>::new(); - - for attr in attrs { - let path = attr.path(); - if path.len() != 2 || path[0] != sym::clippy { - continue; - } - - let name = path[1]; - if name != sym::disallowed_profile && name != sym::disallowed_profiles { - continue; - } - - let attr_label = if name == sym::disallowed_profiles { - "`clippy::disallowed_profiles`" - } else { - "`clippy::disallowed_profile`" - }; - - let Some(items) = attr.meta_item_list() else { - cx.tcx - .sess - .dcx() - .struct_span_err(attr.span(), format!("{attr_label} expects string arguments")) - .emit(); - continue; - }; - - if items.is_empty() { - cx.tcx - .sess - .dcx() - .struct_span_err(attr.span(), format!("{attr_label} expects at least one profile name")) - .emit(); - continue; - } - - if name == sym::disallowed_profile && items.len() != 1 { - cx.tcx - .sess - .dcx() - .struct_span_err(attr.span(), "use `clippy::disallowed_profiles` for multiple profiles") - .emit(); - } - - for item in items { - match literal_symbol(&item) { - Some((symbol, span)) => entries.push(ProfileEntry { - attr_name: name, - name: symbol, - span, - }), - None => emit_string_error(cx, &item), - } - } - } - - if entries.is_empty() { - None - } else { - Some(ProfileSelection::new(entries)) - } -} - -fn literal_symbol(item: &MetaItemInner) -> Option<(Symbol, Span)> { - match item { - MetaItemInner::Lit(lit) => { - let LitKind::Str(symbol, _) = lit.kind else { return None }; - Some((symbol, lit.span)) - }, - MetaItemInner::MetaItem(_) => None, - } -} - -fn emit_string_error(cx: &LateContext<'_>, item: &MetaItemInner) { - let span = match item { - MetaItemInner::Lit(lit) => lit.span, - MetaItemInner::MetaItem(meta) => meta.span, - }; - cx.tcx - .sess - .dcx() - .struct_span_err(span, "expected string literal profile name") - .emit(); -} diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index a067e55595692..83acfb49e3556 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -46,7 +46,6 @@ mod check_proc_macro; pub mod comparisons; pub mod consts; pub mod diagnostics; -pub mod disallowed_profiles; pub mod eager_or_lazy; pub mod higher; mod hir_utils; diff --git a/clippy_utils/src/sym.rs b/clippy_utils/src/sym.rs index f414c0ac47fa4..fe8c62d3a0fa4 100644 --- a/clippy_utils/src/sym.rs +++ b/clippy_utils/src/sym.rs @@ -208,8 +208,6 @@ generate! { deprecated_in_future, deref_mut_method, diagnostics, - disallowed_profile, - disallowed_profiles, disallowed_types, drain, dump, diff --git a/tests/ui-toml/disallowed_profiles_methods/clippy.toml b/tests/ui-toml/disallowed_profiles_methods/clippy.toml deleted file mode 100644 index c77f5658ae69c..0000000000000 --- a/tests/ui-toml/disallowed_profiles_methods/clippy.toml +++ /dev/null @@ -1,13 +0,0 @@ -disallowed-methods = [ - { path = "std::mem::drop" } -] - -[profiles.forward_pass] -disallowed-methods = [ - { path = "alloc::vec::Vec::push", reason = "push is forbidden in forward profile" } -] - -[profiles.export] -disallowed-methods = [ - { path = "core::option::Option::unwrap" } -] diff --git a/tests/ui-toml/disallowed_profiles_methods/main.rs b/tests/ui-toml/disallowed_profiles_methods/main.rs deleted file mode 100644 index 07bb22e05d6f7..0000000000000 --- a/tests/ui-toml/disallowed_profiles_methods/main.rs +++ /dev/null @@ -1,78 +0,0 @@ -#![warn(clippy::disallowed_methods)] -#![allow( - unused, - clippy::no_effect, - clippy::needless_borrow, - clippy::vec_init_then_push, - clippy::unnecessary_literal_unwrap -)] - -fn default_violation() { - let value = String::from("test"); - std::mem::drop(value); //~ ERROR: use of a disallowed method `std::mem::drop` -} - -#[expect(clippy::disallowed_methods)] -fn expected_violation() { - let value = String::from("test"); - std::mem::drop(value); -} - -#[clippy::disallowed_profile("forward_pass")] -fn forward_profile() { - let mut values = Vec::new(); - values.push(1); //~ ERROR: use of a disallowed method `alloc::vec::Vec::push` (profile: forward_pass) -} - -#[clippy::disallowed_profile("export")] -fn export_profile() { - let value = Some(1); - value.unwrap(); //~ ERROR: use of a disallowed method `core::option::Option::unwrap` (profile: export) -} - -#[clippy::disallowed_profile("unknown_profile")] -//~^ ERROR: unknown profile `unknown_profile` for -//~| ERROR: unknown profile `unknown_profile` for -fn unknown_profile() { - let mut values = Vec::new(); - values.push(1); - // unknown profile falls back to the default list - std::mem::drop(values); //~ ERROR: use of a disallowed method `std::mem::drop` -} - -#[clippy::disallowed_profiles("forward_pass", "export")] -fn merged_profiles() { - let mut values = Vec::new(); - values.push(1); //~ ERROR: use of a disallowed method `alloc::vec::Vec::push` (profile: forward_pass) - let value = Some(1); - value.unwrap(); //~ ERROR: use of a disallowed method `core::option::Option::unwrap` (profile: export) -} - -// `#[expect(clippy::disallowed_methods)]` silences the body warning and the unknown-profile -// warning tagged under `DISALLOWED_METHODS`, but not the one tagged under `DISALLOWED_TYPES`. -#[expect(clippy::disallowed_methods)] -#[clippy::disallowed_profile("unknown_profile_expect_before")] -//~^ ERROR: unknown profile `unknown_profile_expect_before` for `clippy::disallowed_types` -fn expect_before_unknown_profile() { - let value = String::from("test"); - std::mem::drop(value); -} - -#[clippy::disallowed_profile("unknown_profile_expect_after")] -//~^ ERROR: unknown profile `unknown_profile_expect_after` for `clippy::disallowed_types` -#[expect(clippy::disallowed_methods)] -fn expect_after_unknown_profile() { - let value = String::from("test"); - std::mem::drop(value); -} - -fn main() { - default_violation(); - expected_violation(); - forward_profile(); - export_profile(); - unknown_profile(); - merged_profiles(); - expect_before_unknown_profile(); - expect_after_unknown_profile(); -} diff --git a/tests/ui-toml/disallowed_profiles_methods/main.stderr b/tests/ui-toml/disallowed_profiles_methods/main.stderr deleted file mode 100644 index 5f64b1bf4499b..0000000000000 --- a/tests/ui-toml/disallowed_profiles_methods/main.stderr +++ /dev/null @@ -1,72 +0,0 @@ -error: use of a disallowed method `std::mem::drop` - --> tests/ui-toml/disallowed_profiles_methods/main.rs:12:5 - | -LL | std::mem::drop(value); - | ^^^^^^^^^^^^^^ - | - = note: `-D clippy::disallowed-methods` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::disallowed_methods)]` - -error: use of a disallowed method `alloc::vec::Vec::push` (profile: forward_pass) - --> tests/ui-toml/disallowed_profiles_methods/main.rs:24:12 - | -LL | values.push(1); - | ^^^^ - | - = note: push is forbidden in forward profile - -error: use of a disallowed method `core::option::Option::unwrap` (profile: export) - --> tests/ui-toml/disallowed_profiles_methods/main.rs:30:11 - | -LL | value.unwrap(); - | ^^^^^^ - -error: `clippy::disallowed_profile` references unknown profile `unknown_profile` for `clippy::disallowed_methods` - --> tests/ui-toml/disallowed_profiles_methods/main.rs:33:30 - | -LL | #[clippy::disallowed_profile("unknown_profile")] - | ^^^^^^^^^^^^^^^^^ - -error: `clippy::disallowed_profile` references unknown profile `unknown_profile` for `clippy::disallowed_types` - --> tests/ui-toml/disallowed_profiles_methods/main.rs:33:30 - | -LL | #[clippy::disallowed_profile("unknown_profile")] - | ^^^^^^^^^^^^^^^^^ - | - = note: `-D clippy::disallowed-types` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::disallowed_types)]` - -error: use of a disallowed method `std::mem::drop` - --> tests/ui-toml/disallowed_profiles_methods/main.rs:40:5 - | -LL | std::mem::drop(values); - | ^^^^^^^^^^^^^^ - -error: use of a disallowed method `alloc::vec::Vec::push` (profile: forward_pass) - --> tests/ui-toml/disallowed_profiles_methods/main.rs:46:12 - | -LL | values.push(1); - | ^^^^ - | - = note: push is forbidden in forward profile - -error: use of a disallowed method `core::option::Option::unwrap` (profile: export) - --> tests/ui-toml/disallowed_profiles_methods/main.rs:48:11 - | -LL | value.unwrap(); - | ^^^^^^ - -error: `clippy::disallowed_profile` references unknown profile `unknown_profile_expect_before` for `clippy::disallowed_types` - --> tests/ui-toml/disallowed_profiles_methods/main.rs:54:30 - | -LL | #[clippy::disallowed_profile("unknown_profile_expect_before")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: `clippy::disallowed_profile` references unknown profile `unknown_profile_expect_after` for `clippy::disallowed_types` - --> tests/ui-toml/disallowed_profiles_methods/main.rs:61:30 - | -LL | #[clippy::disallowed_profile("unknown_profile_expect_after")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 10 previous errors - diff --git a/tests/ui-toml/disallowed_profiles_types/clippy.toml b/tests/ui-toml/disallowed_profiles_types/clippy.toml deleted file mode 100644 index 3c47b2afe26fe..0000000000000 --- a/tests/ui-toml/disallowed_profiles_types/clippy.toml +++ /dev/null @@ -1,13 +0,0 @@ -disallowed-types = [ - { path = "std::rc::Rc" } -] - -[profiles.forward_pass] -disallowed-types = [ - { path = "std::cell::RefCell", reason = "Prefer shared references" } -] - -[profiles.export] -disallowed-types = [ - { path = "std::sync::Mutex" } -] diff --git a/tests/ui-toml/disallowed_profiles_types/main.rs b/tests/ui-toml/disallowed_profiles_types/main.rs deleted file mode 100644 index 0161417dd6022..0000000000000 --- a/tests/ui-toml/disallowed_profiles_types/main.rs +++ /dev/null @@ -1,61 +0,0 @@ -#![warn(clippy::disallowed_types)] -#![allow(dead_code)] - -use std::rc::Rc; //~ ERROR: use of a disallowed type `std::rc::Rc` -use std::sync::Mutex; - -struct Wrapper; - -fn default_type() { - let _value: Rc = todo!(); //~ ERROR: use of a disallowed type `std::rc::Rc` -} - -#[clippy::disallowed_profile("forward_pass")] -fn forward_profile() { - let _value: std::cell::RefCell = todo!(); //~ ERROR: use of a disallowed type `std::cell::RefCell` (profile: forward_pass) -} - -#[clippy::disallowed_profile("export")] -fn export_profile() { - let _value: Mutex = todo!(); //~ ERROR: use of a disallowed type `std::sync::Mutex` (profile: export) -} - -#[clippy::disallowed_profile("unknown_type_profile")] -//~^ ERROR: unknown profile `unknown_type_profile` for -//~| ERROR: unknown profile `unknown_type_profile` for -fn unknown_profile() { - let _other = 1u32; - let _fallback: Rc = todo!(); //~ ERROR: use of a disallowed type `std::rc::Rc` -} - -#[clippy::disallowed_profiles("forward_pass", "export")] -fn merged_profiles() { - let _value: std::cell::RefCell = todo!(); //~ ERROR: use of a disallowed type `std::cell::RefCell` (profile: forward_pass) - let _other: Mutex = todo!(); //~ ERROR: use of a disallowed type `std::sync::Mutex` (profile: export) -} - -// `#[expect(clippy::disallowed_types)]` silences the body warning and the unknown-profile -// warning tagged under `DISALLOWED_TYPES`, but not one tagged under `DISALLOWED_METHODS`. -#[expect(clippy::disallowed_types)] -#[clippy::disallowed_profile("unknown_type_profile_expect_before")] -//~^ ERROR: unknown profile `unknown_type_profile_expect_before` for `clippy::disallowed_methods` -fn expect_before_unknown_profile() { - let _value: Rc = todo!(); -} - -#[clippy::disallowed_profile("unknown_type_profile_expect_after")] -//~^ ERROR: unknown profile `unknown_type_profile_expect_after` for `clippy::disallowed_methods` -#[expect(clippy::disallowed_types)] -fn expect_after_unknown_profile() { - let _value: Rc = todo!(); -} - -fn main() { - default_type(); - forward_profile(); - export_profile(); - unknown_profile(); - merged_profiles(); - expect_before_unknown_profile(); - expect_after_unknown_profile(); -} diff --git a/tests/ui-toml/disallowed_profiles_types/main.stderr b/tests/ui-toml/disallowed_profiles_types/main.stderr deleted file mode 100644 index 68d63e218c0de..0000000000000 --- a/tests/ui-toml/disallowed_profiles_types/main.stderr +++ /dev/null @@ -1,78 +0,0 @@ -error: use of a disallowed type `std::rc::Rc` - --> tests/ui-toml/disallowed_profiles_types/main.rs:4:1 - | -LL | use std::rc::Rc; - | ^^^^^^^^^^^^^^^^ - | - = note: `-D clippy::disallowed-types` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::disallowed_types)]` - -error: use of a disallowed type `std::rc::Rc` - --> tests/ui-toml/disallowed_profiles_types/main.rs:10:17 - | -LL | let _value: Rc = todo!(); - | ^^^^^^^ - -error: use of a disallowed type `std::cell::RefCell` (profile: forward_pass) - --> tests/ui-toml/disallowed_profiles_types/main.rs:15:17 - | -LL | let _value: std::cell::RefCell = todo!(); - | ^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: Prefer shared references - -error: use of a disallowed type `std::sync::Mutex` (profile: export) - --> tests/ui-toml/disallowed_profiles_types/main.rs:20:17 - | -LL | let _value: Mutex = todo!(); - | ^^^^^^^^^^ - -error: `clippy::disallowed_profile` references unknown profile `unknown_type_profile` for `clippy::disallowed_methods` - --> tests/ui-toml/disallowed_profiles_types/main.rs:23:30 - | -LL | #[clippy::disallowed_profile("unknown_type_profile")] - | ^^^^^^^^^^^^^^^^^^^^^^ - | - = note: `-D clippy::disallowed-methods` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::disallowed_methods)]` - -error: `clippy::disallowed_profile` references unknown profile `unknown_type_profile` for `clippy::disallowed_types` - --> tests/ui-toml/disallowed_profiles_types/main.rs:23:30 - | -LL | #[clippy::disallowed_profile("unknown_type_profile")] - | ^^^^^^^^^^^^^^^^^^^^^^ - -error: use of a disallowed type `std::rc::Rc` - --> tests/ui-toml/disallowed_profiles_types/main.rs:28:20 - | -LL | let _fallback: Rc = todo!(); - | ^^^^^^^ - -error: use of a disallowed type `std::cell::RefCell` (profile: forward_pass) - --> tests/ui-toml/disallowed_profiles_types/main.rs:33:17 - | -LL | let _value: std::cell::RefCell = todo!(); - | ^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: Prefer shared references - -error: use of a disallowed type `std::sync::Mutex` (profile: export) - --> tests/ui-toml/disallowed_profiles_types/main.rs:34:17 - | -LL | let _other: Mutex = todo!(); - | ^^^^^^^^^^ - -error: `clippy::disallowed_profile` references unknown profile `unknown_type_profile_expect_before` for `clippy::disallowed_methods` - --> tests/ui-toml/disallowed_profiles_types/main.rs:40:30 - | -LL | #[clippy::disallowed_profile("unknown_type_profile_expect_before")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: `clippy::disallowed_profile` references unknown profile `unknown_type_profile_expect_after` for `clippy::disallowed_methods` - --> tests/ui-toml/disallowed_profiles_types/main.rs:46:30 - | -LL | #[clippy::disallowed_profile("unknown_type_profile_expect_after")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 11 previous errors - diff --git a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr index ba930d094fc19..6bb3db8db67f0 100644 --- a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr +++ b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr @@ -70,7 +70,6 @@ error: error reading Clippy's configuration file: unknown field `foobar`, expect module-items-ordered-within-groupings msrv pass-by-value-size-limit - profiles pub-underscore-fields-behavior recursive-self-in-type-definitions semicolon-inside-block-ignore-singleline @@ -172,7 +171,6 @@ error: error reading Clippy's configuration file: unknown field `barfoo`, expect module-items-ordered-within-groupings msrv pass-by-value-size-limit - profiles pub-underscore-fields-behavior recursive-self-in-type-definitions semicolon-inside-block-ignore-singleline @@ -274,7 +272,6 @@ error: error reading Clippy's configuration file: unknown field `allow_mixed_uni module-items-ordered-within-groupings msrv pass-by-value-size-limit - profiles pub-underscore-fields-behavior recursive-self-in-type-definitions semicolon-inside-block-ignore-singleline From 491d90b79dcaa40abcc5e33e05c9675dac585ecf Mon Sep 17 00:00:00 2001 From: Hamdan-Khan Date: Mon, 15 Jun 2026 16:49:25 +0500 Subject: [PATCH 46/77] Do not trigger `ref_patterns` lint on automatically derived code Code marked with `#[automatically_derived]` attribute is macro generated and its syntax is out of user's control. Since `ref_patterns` is a lint for clarity, it should not be triggered for auto derived code. Fixed by converting the lint into a late pass lint and checking the auto derived attribute using `in_automatically_derived` utility. --- clippy_lints/src/lib.rs | 2 +- clippy_lints/src/ref_patterns.rs | 12 +++++++----- tests/ui/ref_patterns.rs | 10 ++++++++++ 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 4a7659a9cc210..600b37c4204c0 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -534,7 +534,6 @@ rustc_lint::early_lint_methods!( PartialPubFields: partial_pub_fields::PartialPubFields = partial_pub_fields::PartialPubFields, UnderscoreTyped: let_with_type_underscore::UnderscoreTyped = let_with_type_underscore::UnderscoreTyped, ExcessiveNesting: excessive_nesting::ExcessiveNesting = excessive_nesting::ExcessiveNesting::new(conf), - RefPatterns: ref_patterns::RefPatterns = ref_patterns::RefPatterns, NeedlessElse: needless_else::NeedlessElse = needless_else::NeedlessElse, RawStrings: raw_strings::RawStrings = raw_strings::RawStrings::new(conf), Visibility: visibility::Visibility = visibility::Visibility, @@ -862,6 +861,7 @@ rustc_lint::late_lint_methods!( ByteCharSlice: byte_char_slices::ByteCharSlice = byte_char_slices::ByteCharSlice, ManualAssertEq: manual_assert_eq::ManualAssertEq = manual_assert_eq::ManualAssertEq, WithCapacityZero: with_capacity_zero::WithCapacityZero = with_capacity_zero::WithCapacityZero, + RefPatterns: ref_patterns::RefPatterns = ref_patterns::RefPatterns, // add late passes here, used by `cargo dev new_lint` ]] ); diff --git a/clippy_lints/src/ref_patterns.rs b/clippy_lints/src/ref_patterns.rs index b6a28571230a6..22d1c21aa43ba 100644 --- a/clippy_lints/src/ref_patterns.rs +++ b/clippy_lints/src/ref_patterns.rs @@ -1,6 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_then; -use rustc_ast::ast::{BindingMode, Pat, PatKind}; -use rustc_lint::{EarlyContext, EarlyLintPass}; +use clippy_utils::in_automatically_derived; +use rustc_hir::{BindingMode, Pat, PatKind}; +use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; declare_clippy_lint! { @@ -29,10 +30,11 @@ declare_clippy_lint! { declare_lint_pass!(RefPatterns => [REF_PATTERNS]); -impl EarlyLintPass for RefPatterns { - fn check_pat(&mut self, cx: &EarlyContext<'_>, pat: &Pat) { - if let PatKind::Ident(BindingMode::REF, _, _) = pat.kind +impl<'tcx> LateLintPass<'tcx> for RefPatterns { + fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'tcx>) { + if let PatKind::Binding(BindingMode::REF, _, _, _) = pat.kind && !pat.span.from_expansion() + && !in_automatically_derived(cx.tcx, pat.hir_id) { #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")] span_lint_and_then(cx, REF_PATTERNS, pat.span, "usage of ref pattern", |diag| { diff --git a/tests/ui/ref_patterns.rs b/tests/ui/ref_patterns.rs index 2905af13ccb63..3628cc3d537c0 100644 --- a/tests/ui/ref_patterns.rs +++ b/tests/ui/ref_patterns.rs @@ -19,4 +19,14 @@ fn use_in_binding() { fn use_in_parameter(ref x: i32) {} //~^ ref_patterns +struct Foo {} + +// shouldn't trigger the lint +#[automatically_derived] +impl Foo { + fn foo() { + if let Some(ref x) = Some(1) {} + } +} + fn main() {} From 41306052d1e358256d5544e603ed08798cc0c64d Mon Sep 17 00:00:00 2001 From: Urgau <3616612+Urgau@users.noreply.github.com> Date: Wed, 17 Jun 2026 21:06:17 +0200 Subject: [PATCH 47/77] Enable triagebot `merge` and `delegate` commands --- triagebot.toml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/triagebot.toml b/triagebot.toml index 667468474b3c1..13ea2b250758c 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -60,6 +60,11 @@ labels = ["S-waiting-on-concerns"] [view-all-comments-link] threshold = 20 +# Allows `merge` and `delegate` commands for merging a PR +# Documentation at: https://forge.rust-lang.org/triagebot/merge.html +[merge] +type = "merge-queue" + [notify-zulip."lint-nominated"] zulip_stream = 577190 # #clippy/fcp topic = "FCP rust-clippy#{number}: {title}" From 830e6ebf1561209c73952f2099fe68a6cb2fb535 Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Tue, 16 Jun 2026 08:48:40 +0200 Subject: [PATCH 48/77] Do not check for unused lifetimes in expanded code --- clippy_lints/src/lifetimes.rs | 4 +++- tests/ui/extra_unused_lifetimes.rs | 14 ++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/clippy_lints/src/lifetimes.rs b/clippy_lints/src/lifetimes.rs index 2b4828872b202..3e58448af5266 100644 --- a/clippy_lints/src/lifetimes.rs +++ b/clippy_lints/src/lifetimes.rs @@ -161,7 +161,9 @@ impl<'tcx> LateLintPass<'tcx> for Lifetimes { } fn check_poly_trait_ref(&mut self, cx: &LateContext<'tcx>, poly_trait_ref: &'tcx PolyTraitRef<'tcx>) { - report_extra_trait_object_lifetimes(cx, poly_trait_ref.bound_generic_params, &poly_trait_ref.trait_ref); + if !poly_trait_ref.span.from_expansion() { + report_extra_trait_object_lifetimes(cx, poly_trait_ref.bound_generic_params, &poly_trait_ref.trait_ref); + } } fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>) { diff --git a/tests/ui/extra_unused_lifetimes.rs b/tests/ui/extra_unused_lifetimes.rs index 2e062208935a2..fa2ebddfde3f2 100644 --- a/tests/ui/extra_unused_lifetimes.rs +++ b/tests/ui/extra_unused_lifetimes.rs @@ -211,4 +211,18 @@ mod proc_macro_generated { } } +mod issue17255 { + + trait AnotherSimpleTrait<'a> {} + + macro_rules! mac { + ($lt:lifetime, $t:ident, $tr:path) => { + impl<$t: for<'lt> $tr> AnotherSimpleTrait<'_> for $t {} + }; + } + + // Do not lint code expanded from macros + mac!('a, T, super::SimplerTrait); +} + fn main() {} From bfb63abdd5333de74b28b9e512dd418a8a8895c6 Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Fri, 29 Aug 2025 19:08:17 +0200 Subject: [PATCH 49/77] fix(same_type_modulo_regions): also ignore regions in references ..and add a bunch more cases --- clippy_utils/src/ty/mod.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/clippy_utils/src/ty/mod.rs b/clippy_utils/src/ty/mod.rs index 056eb818c1ac3..0b394ce74c07c 100644 --- a/clippy_utils/src/ty/mod.rs +++ b/clippy_utils/src/ty/mod.rs @@ -33,7 +33,7 @@ use std::{debug_assert_matches, iter, mem}; use crate::paths::{PathNS, lookup_path_str}; use crate::res::{MaybeDef, MaybeQPath}; -use crate::sym; +use crate::{over, sym}; mod type_certainty; pub use type_certainty::expr_type_is_certain; @@ -485,8 +485,8 @@ pub fn peel_n_ty_refs(mut ty: Ty<'_>, n: usize) -> (Ty<'_>, Option) /// and `false` for: /// - `Result` and `Result` pub fn same_type_modulo_regions<'tcx>(a: Ty<'tcx>, b: Ty<'tcx>) -> bool { - match (&a.kind(), &b.kind()) { - (&ty::Adt(did_a, args_a), &ty::Adt(did_b, args_b)) => { + match (a.kind(), b.kind()) { + (ty::Adt(did_a, args_a), ty::Adt(did_b, args_b)) => { if did_a != did_b { return false; } @@ -499,6 +499,9 @@ pub fn same_type_modulo_regions<'tcx>(a: Ty<'tcx>, b: Ty<'tcx>) -> bool { _ => true, }) }, + (ty::Ref(_, a, mut_a), ty::Ref(_, b, mut_b)) => mut_a == mut_b && same_type_modulo_regions(*a, *b), + (ty::Tuple(as_), ty::Tuple(bs)) => over(as_, bs, |a, b| same_type_modulo_regions(*a, *b)), + (ty::Array(a, na), ty::Array(b, nb)) => na == nb && same_type_modulo_regions(*a, *b), _ => a == b, } } From ec2d840564455376940d1481eb5c0e7d666885b2 Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Sun, 19 Oct 2025 16:16:47 +0200 Subject: [PATCH 50/77] fix(extra_unused_type_parameters): don't suggest an autofix --- .../src/extra_unused_type_parameters.rs | 2 +- .../extra_unused_type_parameters_unfixable.rs | 15 ++++++++++++++ ...ra_unused_type_parameters_unfixable.stderr | 20 +++++++++++++++---- 3 files changed, 32 insertions(+), 5 deletions(-) diff --git a/clippy_lints/src/extra_unused_type_parameters.rs b/clippy_lints/src/extra_unused_type_parameters.rs index 93a6dc59993a6..a6f80da5dab9c 100644 --- a/clippy_lints/src/extra_unused_type_parameters.rs +++ b/clippy_lints/src/extra_unused_type_parameters.rs @@ -102,7 +102,7 @@ impl<'cx, 'tcx> TypeWalker<'cx, 'tcx> { fn emit_sugg(&self, spans: Vec, msg: String, help: &'static str) { let suggestions: Vec<(Span, String)> = spans.iter().copied().zip(std::iter::repeat(String::new())).collect(); span_lint_and_then(self.cx, EXTRA_UNUSED_TYPE_PARAMETERS, spans, msg, |diag| { - diag.multipart_suggestion(help, suggestions, Applicability::MachineApplicable); + diag.multipart_suggestion(help, suggestions, Applicability::MaybeIncorrect); }); } diff --git a/tests/ui/extra_unused_type_parameters_unfixable.rs b/tests/ui/extra_unused_type_parameters_unfixable.rs index 87ce517a0a451..6a20967b7fc50 100644 --- a/tests/ui/extra_unused_type_parameters_unfixable.rs +++ b/tests/ui/extra_unused_type_parameters_unfixable.rs @@ -1,3 +1,5 @@ +//@no-rustfix + #![warn(clippy::extra_unused_type_parameters)] fn unused_where_clause(x: U) @@ -24,4 +26,17 @@ where unimplemented!(); } +// The fix just removes the type parameter from the definition of `unused_ty`, but it doesn't adjust +// its callsites, leading to compilation errors. +mod issue15884 { + fn unused_ty(x: u8) { + //~^ extra_unused_type_parameters + unimplemented!() + } + + fn main() { + unused_ty::(0); + } +} + fn main() {} diff --git a/tests/ui/extra_unused_type_parameters_unfixable.stderr b/tests/ui/extra_unused_type_parameters_unfixable.stderr index 0765c41609368..2c7051886bf45 100644 --- a/tests/ui/extra_unused_type_parameters_unfixable.stderr +++ b/tests/ui/extra_unused_type_parameters_unfixable.stderr @@ -1,5 +1,5 @@ error: type parameter `T` goes unused in function definition - --> tests/ui/extra_unused_type_parameters_unfixable.rs:3:24 + --> tests/ui/extra_unused_type_parameters_unfixable.rs:5:24 | LL | fn unused_where_clause(x: U) | ^ @@ -9,7 +9,7 @@ LL | fn unused_where_clause(x: U) = help: to override `-D warnings` add `#[allow(clippy::extra_unused_type_parameters)]` error: type parameters go unused in function definition: T, V - --> tests/ui/extra_unused_type_parameters_unfixable.rs:11:30 + --> tests/ui/extra_unused_type_parameters_unfixable.rs:13:30 | LL | fn unused_multi_where_clause(x: U) | ^ ^^^^^^^^^^ @@ -17,12 +17,24 @@ LL | fn unused_multi_where_clause(x: U) = help: consider removing the parameters error: type parameters go unused in function definition: T, U, V - --> tests/ui/extra_unused_type_parameters_unfixable.rs:19:28 + --> tests/ui/extra_unused_type_parameters_unfixable.rs:21:28 | LL | fn unused_all_where_clause() | ^ ^^^^^^^^^^ ^^^^^^^^^^ | = help: consider removing the parameters -error: aborting due to 3 previous errors +error: type parameter `T` goes unused in function definition + --> tests/ui/extra_unused_type_parameters_unfixable.rs:32:17 + | +LL | fn unused_ty(x: u8) { + | ^^^ + | +help: consider removing the parameter + | +LL - fn unused_ty(x: u8) { +LL + fn unused_ty(x: u8) { + | + +error: aborting due to 4 previous errors From dab03c8ce650af8319f8fe31ac6e331f06c48a41 Mon Sep 17 00:00:00 2001 From: Gri-ffin Date: Fri, 8 May 2026 12:28:02 +0100 Subject: [PATCH 51/77] fix: avoid ICE when evaluating constants containing unsized type args --- clippy_utils/src/consts.rs | 15 ++++++++++----- tests/ui/crashes/ice-16950.rs | 28 ++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 5 deletions(-) create mode 100644 tests/ui/crashes/ice-16950.rs diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs index 26aef9c1fc910..5b74abdb69ff1 100644 --- a/clippy_utils/src/consts.rs +++ b/clippy_utils/src/consts.rs @@ -885,12 +885,17 @@ impl<'tcx> ConstEvalCtxt<'tcx> { _ => return None, }; + let args = self.typeck.node_args(id); + // We must use the const's own TypingEnv here. + // If we rely on the caller, a 'where Self: Sized' bound + // could trick us into thinking an unsized type is safe, triggering ICE later. + let const_typing_env = ty::TypingEnv::post_analysis(self.tcx, did); + if args.types().any(|ty| !ty.is_sized(self.tcx, const_typing_env)) { + return None; + } + self.tcx - .const_eval_resolve( - self.typing_env, - mir::UnevaluatedConst::new(did, self.typeck.node_args(id)), - qpath.span(), - ) + .const_eval_resolve(self.typing_env, mir::UnevaluatedConst::new(did, args), qpath.span()) .ok() } diff --git a/tests/ui/crashes/ice-16950.rs b/tests/ui/crashes/ice-16950.rs new file mode 100644 index 0000000000000..7e3d979edea3e --- /dev/null +++ b/tests/ui/crashes/ice-16950.rs @@ -0,0 +1,28 @@ +//@check-pass +#![feature(trivial_bounds)] +#![allow(dead_code)] + +struct Helper(T); + +trait Unsized { + const SIZE: usize = usize::MAX; +} + +impl Unsized for T {} + +impl Helper { + const SIZE: usize = size_of::(); +} + +struct TrickClippy(str); + +impl TrickClippy { + fn trick_clippy() -> bool + where + Self: Sized, + { + Helper::::SIZE == str::SIZE + } +} + +fn main() {} From 4afa801d5e4317de07e35114610102b27cffa69c Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Fri, 29 Aug 2025 19:08:17 +0200 Subject: [PATCH 52/77] feat(unnecessary_unwrap_unchecked): new lint Co-authored-by: Catherine Flores --- CHANGELOG.md | 1 + clippy_lints/src/declared_lints.rs | 1 + clippy_lints/src/methods/mod.rs | 36 ++- .../methods/unnecessary_unwrap_unchecked.rs | 276 ++++++++++++++++++ clippy_utils/src/ty/mod.rs | 8 + .../unnecessary_unwrap_unchecked_helper.rs | 17 ++ tests/ui/unnecessary_unwrap_unchecked.fixed | 104 +++++++ tests/ui/unnecessary_unwrap_unchecked.rs | 104 +++++++ tests/ui/unnecessary_unwrap_unchecked.stderr | 88 ++++++ 9 files changed, 634 insertions(+), 1 deletion(-) create mode 100644 clippy_lints/src/methods/unnecessary_unwrap_unchecked.rs create mode 100644 tests/ui/auxiliary/unnecessary_unwrap_unchecked_helper.rs create mode 100644 tests/ui/unnecessary_unwrap_unchecked.fixed create mode 100644 tests/ui/unnecessary_unwrap_unchecked.rs create mode 100644 tests/ui/unnecessary_unwrap_unchecked.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index 2aac684cd09bf..ee6b3c66e6ecb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7459,6 +7459,7 @@ Released 2018-09-13 [`unnecessary_to_owned`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_to_owned [`unnecessary_trailing_comma`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_trailing_comma [`unnecessary_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_unwrap +[`unnecessary_unwrap_unchecked`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_unwrap_unchecked [`unnecessary_wraps`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_wraps [`unneeded_field_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#unneeded_field_pattern [`unneeded_struct_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#unneeded_struct_pattern diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 79429766c639f..51a848d022d80 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -509,6 +509,7 @@ pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[ crate::methods::UNNECESSARY_RESULT_MAP_OR_ELSE_INFO, crate::methods::UNNECESSARY_SORT_BY_INFO, crate::methods::UNNECESSARY_TO_OWNED_INFO, + crate::methods::UNNECESSARY_UNWRAP_UNCHECKED_INFO, crate::methods::UNWRAP_OR_DEFAULT_INFO, crate::methods::UNWRAP_USED_INFO, crate::methods::USELESS_ASREF_INFO, diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 77baf2ce7a4d1..38a3b1705ad17 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -143,6 +143,7 @@ mod unnecessary_map_or_else; mod unnecessary_min_or_max; mod unnecessary_sort_by; mod unnecessary_to_owned; +mod unnecessary_unwrap_unchecked; mod unwrap_expect_used; mod useless_asref; mod useless_nonzero_new_unchecked; @@ -4602,6 +4603,34 @@ declare_clippy_lint! { "unnecessary calls to `to_owned`-like functions" } +declare_clippy_lint! { + /// ### What it does + /// Checks for calls to `unwrap_unchecked` when an `_unchecked` variant of the function exists. + /// + /// ### Why is this bad? + /// Calling the non-unchecked variant may result in checking that is then discarded + /// if `unwrap_unchecked` is called directly afterwards, whereas the unchecked + /// variant most likely avoids performing the check completely. + /// + /// ### Known problems + /// + /// The unchecked variant is only suggested if it's defined in the same `impl` block + /// as the non-unchecked one + /// + /// ### Example + /// ```rust + /// let s = unsafe { std::str::from_utf8(&[]).unwrap_unchecked() }; + /// ``` + /// Use instead: + /// ```rust + /// let s = unsafe { std::str::from_utf8_unchecked(&[]) }; + /// ``` + #[clippy::version = "1.98.0"] + pub UNNECESSARY_UNWRAP_UNCHECKED, + complexity, + "calling `unwrap_unchecked` on a function which has an `_unchecked` variant" +} + declare_clippy_lint! { /// ### What it does /// Checks for usages of the following functions with an argument that constructs a default value @@ -5042,6 +5071,7 @@ impl_lint_pass!(Methods => [ UNNECESSARY_RESULT_MAP_OR_ELSE, UNNECESSARY_SORT_BY, UNNECESSARY_TO_OWNED, + UNNECESSARY_UNWRAP_UNCHECKED, UNWRAP_OR_DEFAULT, UNWRAP_USED, USELESS_ASREF, @@ -5401,7 +5431,11 @@ impl Methods { } unnecessary_literal_unwrap::check(cx, expr, recv, name, args); }, - (sym::expect_err, [_]) | (sym::unwrap_err | sym::unwrap_unchecked | sym::unwrap_err_unchecked, []) => { + (sym::unwrap_unchecked, []) => { + unnecessary_unwrap_unchecked::check(cx, expr, recv, call_span); + unnecessary_literal_unwrap::check(cx, expr, recv, name, args); + }, + (sym::expect_err, [_]) | (sym::unwrap_err | sym::unwrap_err_unchecked, []) => { unnecessary_literal_unwrap::check(cx, expr, recv, name, args); }, (sym::extend, [arg]) => { diff --git a/clippy_lints/src/methods/unnecessary_unwrap_unchecked.rs b/clippy_lints/src/methods/unnecessary_unwrap_unchecked.rs new file mode 100644 index 0000000000000..3f7f146446361 --- /dev/null +++ b/clippy_lints/src/methods/unnecessary_unwrap_unchecked.rs @@ -0,0 +1,276 @@ +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::res::MaybeQPath; +use clippy_utils::ty::{option_or_result_arg_ty, same_type_modulo_regions}; +use clippy_utils::{is_from_proc_macro, last_path_segment, over}; +use rustc_errors::Applicability; +use rustc_hir::def::{DefKind, Namespace, Res}; +use rustc_hir::def_id::DefId; +use rustc_hir::{Body, Expr, ExprKind, PatKind, Safety}; +use rustc_lint::LateContext; +use rustc_middle::ty::{self, Ty}; +use rustc_span::Span; +use rustc_span::symbol::Ident; + +use super::UNNECESSARY_UNWRAP_UNCHECKED; + +#[derive(Clone, Copy, Debug)] +enum Variant { + /// Free `fn` in a module + Fn, + /// Associated item from an `impl` + Assoc(AssocKind), +} + +impl Variant { + fn msg(self) -> &'static str { + // Don't use `format!` instead -- it won't be optimized out. + match self { + Variant::Fn => "usage of `unwrap_unchecked` when an `_unchecked` variant of the function exists", + Variant::Assoc(AssocKind::Fn) => { + "usage of `unwrap_unchecked` when an `_unchecked` variant of the associated function exists" + }, + Variant::Assoc(AssocKind::Method) => { + "usage of `unwrap_unchecked` when an `_unchecked` variant of the method exists" + }, + } + } +} + +/// This only exists so the help message shows `associated function` or `method`, depending on +/// whether it has a `self` parameter. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +enum AssocKind { + /// No `self`: `fn new() -> Self` + Fn, + /// Has `self`: `fn ty<'tcx>(&self) -> Ty<'tcx>` + Method, +} + +impl AssocKind { + fn new(fn_has_self_parameter: bool) -> Self { + if fn_has_self_parameter { Self::Method } else { Self::Fn } + } +} + +fn unchecked_ident(checked_ident: Ident) -> Option { + let checked_ident = checked_ident.to_string(); + // Only add `_unchecked` if it doesn't already end with `_` + (!checked_ident.ends_with('_')).then(|| Ident::from_str(&(checked_ident + "_unchecked"))) +} + +/// Find a function called the same as `checked`, but with added `_unchecked`. +/// +/// This doesn't check if the methods are actually "similar" -- for that, see +/// [`same_functions_modulo_safety`] +fn find_unchecked_sibling_fn( + cx: &LateContext<'_>, + checked_def_id: DefId, + checked_ident: Ident, +) -> Option<(DefId, Ident)> { + // Don't use `parent_module`. We only want to lint if its first parent is a `Mod`, + // i.e. if this is a free-standing function + let parent = cx.tcx.parent(checked_def_id); + if cx.tcx.def_kind(parent) == DefKind::Mod + && let children = parent.as_local().map_or_else( + || cx.tcx.module_children(parent), + // We must use a !query for local modules to prevent an ICE. + |parent| cx.tcx.module_children_local(parent), + ) + // Make sure that there are other functions in this module + // (otherwise there couldn't be an unchecked version) + && children.len() > 1 + && let Some(unchecked_ident) = unchecked_ident(checked_ident) + && let Some(unchecked_def_id) = children.iter().find_map(|child| { + if child.ident == unchecked_ident + && let Res::Def(DefKind::Fn, def_id) = child.res + { + Some(def_id) + } else { + None + } + }) + { + Some((unchecked_def_id, unchecked_ident)) + } else { + None + } +} + +/// Find a method called the same as `checked`, but with added `_unchecked`. +/// +/// This doesn't check if the methods are actually "similar" -- for that, see +/// [`same_functions_modulo_safety`] +fn find_unchecked_sibling_method<'tcx>( + cx: &LateContext<'tcx>, + checked_def_id: DefId, + checked_ident: Ident, +) -> Option<(&'tcx ty::AssocItem, Ident)> { + // Don't use `parent_impl`. We only want to lint if its first parent is an `Impl` + let parent = cx.tcx.parent(checked_def_id); + if matches!(cx.tcx.def_kind(parent), DefKind::Impl { .. }) + && let Some(unchecked_ident) = unchecked_ident(checked_ident) + // Only look in the same impl (to avoid dealing with generics etc.) + && let Some(unchecked) = cx.tcx.associated_items(parent).find_by_ident_and_namespace( + cx.tcx, + unchecked_ident, + Namespace::ValueNS, + parent, + ) + { + Some((unchecked, unchecked_ident)) + } else { + None + } +} + +/// Checks that `checked_def_id` and `unchecked_def_id` refer to functions with: +/// - same visibility +/// - identical signatures, apart from unsafety +/// - "matching" return types: the checked version returns `Option`/`Result`, while the +/// unchecked one returns `T` +fn same_functions_modulo_safety<'tcx>( + cx: &LateContext<'tcx>, + checked_def_id: DefId, + unchecked_def_id: DefId, + unwrapped_ret_ty: Ty<'tcx>, +) -> bool { + let hir_body = |def_id: DefId| -> Option<&'tcx Body<'tcx>> { cx.tcx.hir_maybe_body_owned_by(def_id.as_local()?) }; + let fn_sig = |def_id| cx.tcx.fn_sig(def_id).skip_binder().skip_binder(); + + if match (hir_body(checked_def_id), hir_body(unchecked_def_id)) { + // For local functions, we can get the parameter names. In that case, we want to make sure + // that the latter are equal between the checked and unchecked versions. + (Some(checked_body), Some(unchecked_body)) => { + over(checked_body.params, unchecked_body.params, |p1, p2| { + // We only allow simple params (plain bindings) for now, to stay on the safer side. + if let PatKind::Binding(bm1, _, ident1, None) = p1.pat.kind + && let PatKind::Binding(bm2, _, ident2, None) = p2.pat.kind + { + bm1 == bm2 && ident1 == ident2 + } else { + false + } + }) + }, + // For non-local functions, parameter names are not accessible. Oh well, we'll let it slip + (None, None) => true, + // If only one of the versions is non-local, then something weird happened. Bail just in case + _ => false, + } { + // Check that the functions have identical signatures, apart from safety, and return type (see + // below) + let checked_fn_sig = fn_sig(checked_def_id); + let unchecked_fn_sig = fn_sig(unchecked_def_id); + + (checked_fn_sig.safety() == Safety::Safe && unchecked_fn_sig.safety() == Safety::Unsafe) + && checked_fn_sig.c_variadic() == unchecked_fn_sig.c_variadic() + && checked_fn_sig.abi() == unchecked_fn_sig.abi() + // NOTE: the reason we use `same_type_modulo_regions` all over the place here is that + // the regions of different functions will be distinct, even if they are called the same + && over(checked_fn_sig.inputs(), unchecked_fn_sig.inputs(), |ty1, ty2| { + same_type_modulo_regions(*ty1, *ty2) + }) + // The checked version should return `Option` or `Result`, + // and the unchecked version should return just `T` + && same_type_modulo_regions(unchecked_fn_sig.output(), unwrapped_ret_ty) + && option_or_result_arg_ty(cx, checked_fn_sig.output()) + .is_some_and(|wrapped_ty| same_type_modulo_regions(wrapped_ty, unwrapped_ret_ty)) + // Check that the visibilities are the same (for the purposes of replacing, it would be enough to have + // the former _at least as_ visible as the latter, but we don't bother) + && cx.tcx.visibility(unchecked_def_id) == cx.tcx.visibility(checked_def_id) + } else { + false + } +} + +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, recv: &Expr<'_>, call_span: Span) { + if expr.span.from_expansion() { + return; + } + let expected_ret_ty = cx.typeck_results().expr_ty(expr); + let (variant, checked_span, unchecked_sugg, unchecked_full_path) = match recv.kind { + // Construct `Variant::Fn(_)`, if applicable. This is necessary for us to handle + // functions like `std::str::from_utf8_unchecked`. + ExprKind::Call(path, _) + if let ExprKind::Path(qpath) = path.kind + && let checked_ident = last_path_segment(&qpath).ident + && let checked_def_id = path.res(cx).def_id() + && let Some((unchecked_def_id, unchecked_ident)) = + find_unchecked_sibling_fn(cx, checked_def_id, checked_ident) + && same_functions_modulo_safety(cx, checked_def_id, unchecked_def_id, expected_ret_ty) => + { + let unchecked_full_path = cx.tcx.def_path_str(unchecked_def_id); + ( + Variant::Fn, + checked_ident.span, + if checked_ident.span == path.span { + // replacing `bar(x)` with `bar_unchecked(x)` + // `bar_unchecked` might not be in scope, so suggest the full path + unchecked_full_path.clone() + } else { + // replacing `foo::bar(x)` with `foo::bar_unchecked(x)` + // since the path is qualified, we can just replace the final segment + unchecked_ident.to_string() + }, + unchecked_full_path, + ) + }, + // We unfortunately must handle `A::a(&a)` and `a.a()` separately, this handles the + // former + ExprKind::Call(path, _) + if let ExprKind::Path(qpath) = path.kind + && let checked_ident = last_path_segment(&qpath).ident + && let checked_def_id = path.res(cx).def_id() + && let Some((unchecked, unchecked_ident)) = + find_unchecked_sibling_method(cx, checked_def_id, checked_ident) + && let ty::AssocKind::Fn { has_self, .. } = unchecked.kind + && same_functions_modulo_safety(cx, checked_def_id, unchecked.def_id, expected_ret_ty) => + { + let unchecked_full_path = cx.tcx.def_path_str(unchecked.def_id); + ( + Variant::Assoc(AssocKind::new(has_self)), + // since this is basically a method call, we only need to replace the method ident + checked_ident.span, + unchecked_ident.to_string(), + unchecked_full_path, + ) + }, + // ... And now the latter ^^ + ExprKind::MethodCall(segment, _, _, _) + if let checked_ident = segment.ident + && let Some(checked_def_id) = cx.typeck_results().type_dependent_def_id(recv.hir_id) + && let Some((unchecked, unchecked_ident)) = + find_unchecked_sibling_method(cx, checked_def_id, checked_ident) + && same_functions_modulo_safety(cx, checked_def_id, unchecked.def_id, expected_ret_ty) => + { + let unchecked_full_path = cx.tcx.def_path_str(unchecked.def_id); + ( + Variant::Assoc(AssocKind::Method), + // since this is a method call, we only need to replace the method ident + checked_ident.span, + unchecked_ident.to_string(), + unchecked_full_path, + ) + }, + _ => return, + }; + + if !is_from_proc_macro(cx, expr) { + span_lint_and_then(cx, UNNECESSARY_UNWRAP_UNCHECKED, expr.span, variant.msg(), |diag| { + let sugg = vec![ + // replace the function with the unchecked version + (checked_span, unchecked_sugg), + // remove the call to `.unwrap_unchecked()` + (call_span.with_lo(recv.span.hi()), String::new()), + ]; + diag.multipart_suggestion( + format!("use `{unchecked_full_path}` instead, and remove the call to `.unwrap_unchecked()`"), + sugg, + // TODO: make this `MachineApplicable` when the function comes from std/alloc/core + // The reasoning is that, if the function comes from std/alloc/core, its checked and unchecked are + // pretty likely to have their semantics match. + Applicability::MaybeIncorrect, + ); + }); + } +} diff --git a/clippy_utils/src/ty/mod.rs b/clippy_utils/src/ty/mod.rs index 0b394ce74c07c..e9ba7cfc4628a 100644 --- a/clippy_utils/src/ty/mod.rs +++ b/clippy_utils/src/ty/mod.rs @@ -1344,6 +1344,14 @@ pub fn option_arg_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option` or a `Result` and return its argument type (`T`) if it is. +pub fn option_or_result_arg_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option> { + match ty.kind() { + ty::Adt(adt, args) if matches!(adt.opt_diag_name(cx), Some(sym::Option | sym::Result)) => Some(args.type_at(0)), + _ => None, + } +} + /// Check if a Ty<'_> of `Iterator` contains any mutable access to non-owning types by checking if /// it contains fields of mutable references or pointers, or references/pointers to non-`Freeze` /// types, or `PhantomData` types containing any of the previous. This can be used to check whether diff --git a/tests/ui/auxiliary/unnecessary_unwrap_unchecked_helper.rs b/tests/ui/auxiliary/unnecessary_unwrap_unchecked_helper.rs new file mode 100644 index 0000000000000..4cc9ac80692d2 --- /dev/null +++ b/tests/ui/auxiliary/unnecessary_unwrap_unchecked_helper.rs @@ -0,0 +1,17 @@ +#![allow(unused, clippy::missing_safety_doc)] + +pub fn lol() -> Option { + Some(0) +} + +pub unsafe fn lol_unchecked() -> u32 { + 0 +} + +pub fn kek() -> Option { + Some(0) +} + +unsafe fn kek_unchecked() -> u32 { + 0 +} diff --git a/tests/ui/unnecessary_unwrap_unchecked.fixed b/tests/ui/unnecessary_unwrap_unchecked.fixed new file mode 100644 index 0000000000000..274bb7a00bfb0 --- /dev/null +++ b/tests/ui/unnecessary_unwrap_unchecked.fixed @@ -0,0 +1,104 @@ +//@aux-build:unnecessary_unwrap_unchecked_helper.rs +//@aux-build:proc_macros.rs +#![warn(clippy::unnecessary_unwrap_unchecked)] + +use proc_macros::{external, with_span}; + +#[rustfmt::skip] +use unnecessary_unwrap_unchecked_helper::{lol, kek}; + +mod b { + pub fn test_fn() -> Option { + Some(0) + } + + pub unsafe fn test_fn_unchecked() -> u32 { + 0 + } +} + +fn test_fn() -> Option { + Some(0) +} + +unsafe fn test_fn_unchecked() -> u32 { + 0 +} + +struct A; + +impl A { + fn a(&self) -> Option { + Some(0) + } + + unsafe fn a_unchecked(&self) -> u32 { + 0 + } + + fn an_assoc_fn() -> Option { + Some(0) + } + + unsafe fn an_assoc_fn_unchecked() -> u32 { + 0 + } +} + +struct B; + +impl B { + fn b(&self) -> Option { + Some(0) + } +} + +impl B { + unsafe fn b_unchecked(&self) -> u32 { + 0 + } +} + +fn main() { + let string_slice = unsafe { std::str::from_utf8_unchecked(&[]) }; + //~^ unnecessary_unwrap_unchecked + let a = unsafe { A::a_unchecked(&A) }; + //~^ unnecessary_unwrap_unchecked + let a = unsafe { + let a = A; + a.a_unchecked() + }; + //~^^ unnecessary_unwrap_unchecked + let an_assoc_fn = unsafe { A::an_assoc_fn_unchecked() }; + //~^ unnecessary_unwrap_unchecked + let extern_fn = unsafe { unnecessary_unwrap_unchecked_helper::lol_unchecked() }; + //~^ unnecessary_unwrap_unchecked + let extern_fn_qualified = unsafe { unnecessary_unwrap_unchecked_helper::lol_unchecked() }; + //~^ unnecessary_unwrap_unchecked + let local_fn = unsafe { b::test_fn_unchecked() }; + //~^ unnecessary_unwrap_unchecked + + // Don't lint: unlike `kek`, `kek_unchecked` isn't accessible from here + let extern_pub_fn = unsafe { kek().unwrap_unchecked() }; + + // Don't lint: `B::b` and `B::b_unchecked` come from distinct impl blocks + // (even though that wouldn't actually make the suggestion invalid in this case) + let b = unsafe { + let b = B; + b.b().unwrap_unchecked() + }; + + macro_rules! local { + () => {{ + unsafe { ::std::str::from_utf8(&[]).unwrap_unchecked() }; + }}; + } + local!(); + external! { + unsafe { std::str::from_utf8(&[]).unwrap_unchecked() }; + } + with_span! { + span + unsafe { std::str::from_utf8(&[]).unwrap_unchecked() }; + } +} diff --git a/tests/ui/unnecessary_unwrap_unchecked.rs b/tests/ui/unnecessary_unwrap_unchecked.rs new file mode 100644 index 0000000000000..006a541365a58 --- /dev/null +++ b/tests/ui/unnecessary_unwrap_unchecked.rs @@ -0,0 +1,104 @@ +//@aux-build:unnecessary_unwrap_unchecked_helper.rs +//@aux-build:proc_macros.rs +#![warn(clippy::unnecessary_unwrap_unchecked)] + +use proc_macros::{external, with_span}; + +#[rustfmt::skip] +use unnecessary_unwrap_unchecked_helper::{lol, kek}; + +mod b { + pub fn test_fn() -> Option { + Some(0) + } + + pub unsafe fn test_fn_unchecked() -> u32 { + 0 + } +} + +fn test_fn() -> Option { + Some(0) +} + +unsafe fn test_fn_unchecked() -> u32 { + 0 +} + +struct A; + +impl A { + fn a(&self) -> Option { + Some(0) + } + + unsafe fn a_unchecked(&self) -> u32 { + 0 + } + + fn an_assoc_fn() -> Option { + Some(0) + } + + unsafe fn an_assoc_fn_unchecked() -> u32 { + 0 + } +} + +struct B; + +impl B { + fn b(&self) -> Option { + Some(0) + } +} + +impl B { + unsafe fn b_unchecked(&self) -> u32 { + 0 + } +} + +fn main() { + let string_slice = unsafe { std::str::from_utf8(&[]).unwrap_unchecked() }; + //~^ unnecessary_unwrap_unchecked + let a = unsafe { A::a(&A).unwrap_unchecked() }; + //~^ unnecessary_unwrap_unchecked + let a = unsafe { + let a = A; + a.a().unwrap_unchecked() + }; + //~^^ unnecessary_unwrap_unchecked + let an_assoc_fn = unsafe { A::an_assoc_fn().unwrap_unchecked() }; + //~^ unnecessary_unwrap_unchecked + let extern_fn = unsafe { lol().unwrap_unchecked() }; + //~^ unnecessary_unwrap_unchecked + let extern_fn_qualified = unsafe { unnecessary_unwrap_unchecked_helper::lol().unwrap_unchecked() }; + //~^ unnecessary_unwrap_unchecked + let local_fn = unsafe { b::test_fn().unwrap_unchecked() }; + //~^ unnecessary_unwrap_unchecked + + // Don't lint: unlike `kek`, `kek_unchecked` isn't accessible from here + let extern_pub_fn = unsafe { kek().unwrap_unchecked() }; + + // Don't lint: `B::b` and `B::b_unchecked` come from distinct impl blocks + // (even though that wouldn't actually make the suggestion invalid in this case) + let b = unsafe { + let b = B; + b.b().unwrap_unchecked() + }; + + macro_rules! local { + () => {{ + unsafe { ::std::str::from_utf8(&[]).unwrap_unchecked() }; + }}; + } + local!(); + external! { + unsafe { std::str::from_utf8(&[]).unwrap_unchecked() }; + } + with_span! { + span + unsafe { std::str::from_utf8(&[]).unwrap_unchecked() }; + } +} diff --git a/tests/ui/unnecessary_unwrap_unchecked.stderr b/tests/ui/unnecessary_unwrap_unchecked.stderr new file mode 100644 index 0000000000000..359e50a33c9b7 --- /dev/null +++ b/tests/ui/unnecessary_unwrap_unchecked.stderr @@ -0,0 +1,88 @@ +error: usage of `unwrap_unchecked` when an `_unchecked` variant of the function exists + --> tests/ui/unnecessary_unwrap_unchecked.rs:63:33 + | +LL | let string_slice = unsafe { std::str::from_utf8(&[]).unwrap_unchecked() }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::unnecessary-unwrap-unchecked` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unnecessary_unwrap_unchecked)]` +help: use `std::str::from_utf8_unchecked` instead, and remove the call to `.unwrap_unchecked()` + | +LL - let string_slice = unsafe { std::str::from_utf8(&[]).unwrap_unchecked() }; +LL + let string_slice = unsafe { std::str::from_utf8_unchecked(&[]) }; + | + +error: usage of `unwrap_unchecked` when an `_unchecked` variant of the method exists + --> tests/ui/unnecessary_unwrap_unchecked.rs:65:22 + | +LL | let a = unsafe { A::a(&A).unwrap_unchecked() }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `A::a_unchecked` instead, and remove the call to `.unwrap_unchecked()` + | +LL - let a = unsafe { A::a(&A).unwrap_unchecked() }; +LL + let a = unsafe { A::a_unchecked(&A) }; + | + +error: usage of `unwrap_unchecked` when an `_unchecked` variant of the method exists + --> tests/ui/unnecessary_unwrap_unchecked.rs:69:9 + | +LL | a.a().unwrap_unchecked() + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `A::a_unchecked` instead, and remove the call to `.unwrap_unchecked()` + | +LL - a.a().unwrap_unchecked() +LL + a.a_unchecked() + | + +error: usage of `unwrap_unchecked` when an `_unchecked` variant of the associated function exists + --> tests/ui/unnecessary_unwrap_unchecked.rs:72:32 + | +LL | let an_assoc_fn = unsafe { A::an_assoc_fn().unwrap_unchecked() }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `A::an_assoc_fn_unchecked` instead, and remove the call to `.unwrap_unchecked()` + | +LL - let an_assoc_fn = unsafe { A::an_assoc_fn().unwrap_unchecked() }; +LL + let an_assoc_fn = unsafe { A::an_assoc_fn_unchecked() }; + | + +error: usage of `unwrap_unchecked` when an `_unchecked` variant of the function exists + --> tests/ui/unnecessary_unwrap_unchecked.rs:74:30 + | +LL | let extern_fn = unsafe { lol().unwrap_unchecked() }; + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `unnecessary_unwrap_unchecked_helper::lol_unchecked` instead, and remove the call to `.unwrap_unchecked()` + | +LL - let extern_fn = unsafe { lol().unwrap_unchecked() }; +LL + let extern_fn = unsafe { unnecessary_unwrap_unchecked_helper::lol_unchecked() }; + | + +error: usage of `unwrap_unchecked` when an `_unchecked` variant of the function exists + --> tests/ui/unnecessary_unwrap_unchecked.rs:76:40 + | +LL | let extern_fn_qualified = unsafe { unnecessary_unwrap_unchecked_helper::lol().unwrap_unchecked() }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `unnecessary_unwrap_unchecked_helper::lol_unchecked` instead, and remove the call to `.unwrap_unchecked()` + | +LL - let extern_fn_qualified = unsafe { unnecessary_unwrap_unchecked_helper::lol().unwrap_unchecked() }; +LL + let extern_fn_qualified = unsafe { unnecessary_unwrap_unchecked_helper::lol_unchecked() }; + | + +error: usage of `unwrap_unchecked` when an `_unchecked` variant of the function exists + --> tests/ui/unnecessary_unwrap_unchecked.rs:78:29 + | +LL | let local_fn = unsafe { b::test_fn().unwrap_unchecked() }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `b::test_fn_unchecked` instead, and remove the call to `.unwrap_unchecked()` + | +LL - let local_fn = unsafe { b::test_fn().unwrap_unchecked() }; +LL + let local_fn = unsafe { b::test_fn_unchecked() }; + | + +error: aborting due to 7 previous errors + From 57f180d1bc9d3ed7bba9ef499e55363c2c0c113d Mon Sep 17 00:00:00 2001 From: Gri-ffin Date: Wed, 10 Jun 2026 20:32:26 +0100 Subject: [PATCH 53/77] prevent OOM/hang when checking validity of large types by changing to layout based check --- clippy_utils/src/ty/mod.rs | 106 +++++++++++++++++++++++++++----- tests/ui/uninit_vec.rs | 122 +++++++++++++++++++++++++++++++++++++ tests/ui/uninit_vec.stderr | 79 +++++++++++++++++++++++- 3 files changed, 290 insertions(+), 17 deletions(-) diff --git a/clippy_utils/src/ty/mod.rs b/clippy_utils/src/ty/mod.rs index 056eb818c1ac3..dc8edb22c9f88 100644 --- a/clippy_utils/src/ty/mod.rs +++ b/clippy_utils/src/ty/mod.rs @@ -3,7 +3,7 @@ #![allow(clippy::module_name_repetitions)] use core::ops::ControlFlow; -use rustc_abi::VariantIdx; +use rustc_abi::{BackendRepr, FieldsShape, VariantIdx, Variants}; use rustc_ast::ast::Mutability; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir as hir; @@ -17,7 +17,7 @@ use rustc_middle::mir::ConstValue; use rustc_middle::mir::interpret::Scalar; use rustc_middle::traits::EvaluationResult; use rustc_middle::ty::adjustment::{Adjust, Adjustment, DerefAdjustKind}; -use rustc_middle::ty::layout::ValidityRequirement; +use rustc_middle::ty::layout::{LayoutError, LayoutOf, TyAndLayout}; use rustc_middle::ty::{ self, AdtDef, AliasTy, AssocItem, AssocTag, Binder, BoundRegion, BoundVarIndexKind, FnSig, GenericArg, GenericArgKind, GenericArgsRef, IntTy, Region, RegionKind, TraitRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, @@ -505,29 +505,103 @@ pub fn same_type_modulo_regions<'tcx>(a: Ty<'tcx>, b: Ty<'tcx>) -> bool { /// Checks if a given type looks safe to be uninitialized. pub fn is_uninit_value_valid_for_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { - let typing_env = cx.typing_env().with_post_analysis_normalized(cx.tcx); - cx.tcx - .check_validity_requirement((ValidityRequirement::Uninit, typing_env.as_query_input(ty))) - .unwrap_or_else(|_| is_uninit_value_valid_for_ty_fallback(cx, ty)) + match cx.layout_of(ty) { + Ok(layout) => is_uninit_value_valid_for_layout(cx, layout), + // The type layout is either not concrete enough yet or too large, fall back to structural check instead + Err(LayoutError::TooGeneric(_) | LayoutError::SizeOverflow(_)) => is_uninit_value_valid_for_ty_fallback(cx, ty), + Err(_) => false, + } +} + +fn is_uninit_value_valid_for_layout<'tcx>(cx: &LateContext<'tcx>, layout: TyAndLayout<'tcx>) -> bool { + // ZSTs contribute no bytes to the vector buffer + if layout.layout.is_zst() { + return true; + } + + match layout.layout.backend_repr { + BackendRepr::Scalar(s) => s.is_uninit_valid(), + BackendRepr::ScalarPair(a, b) => a.is_uninit_valid() && b.is_uninit_valid(), + BackendRepr::SimdVector { element, count } => count == 0 || element.is_uninit_valid(), + BackendRepr::SimdScalableVector { element, .. } => element.is_uninit_valid(), + // Here validity is determined by the structural fields instead. + BackendRepr::Memory { .. } => match &layout.layout.variants { + Variants::Single { .. } => match &layout.layout.fields { + FieldsShape::Primitive => { + debug_assert!(false, "Both Scalar primitives and ! should be handled above."); + false + }, + // Arrays are valid if empty, or if their elements are valid. + FieldsShape::Array { count, .. } => { + if *count == 0 { + true + } else { + is_uninit_value_valid_for_layout(cx, layout.field(cx, 0)) + } + }, + // Structs like types are valid only if all fields are valid. + FieldsShape::Arbitrary { offsets, .. } => { + (0..offsets.len()).all(|i| is_uninit_value_valid_for_layout(cx, layout.field(cx, i))) + }, + // Unions are valid if at least one field is valid. + FieldsShape::Union(count) => { + (0..count.get()).any(|i| is_uninit_value_valid_for_layout(cx, layout.field(cx, i))) + }, + }, + // Types with no valid variants must be uninhabited + Variants::Empty => true, + // Enum like with multiple inhabited variants have a discriminant, they cannot be uninitialized. + Variants::Multiple { .. } => false, + }, + } } -/// A fallback for polymorphic types, which are not supported by `check_validity_requirement`. +/// Fallback for polymorphic types where `layout_of` fails fn is_uninit_value_valid_for_ty_fallback<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { + let typing_env = cx.typing_env().with_post_analysis_normalized(cx.tcx); + match *ty.kind() { // The array length may be polymorphic, let's try the inner type. - ty::Array(component, _) => is_uninit_value_valid_for_ty(cx, component), + ty::Array(component, len) => { + // Zero-length arrays are always valid + if len.try_to_target_usize(cx.tcx) == Some(0) { + return true; + } + is_uninit_value_valid_for_ty(cx, component) + }, // Peek through tuples and try their fallbacks. ty::Tuple(types) => types.iter().all(|ty| is_uninit_value_valid_for_ty(cx, ty)), - // Unions are always fine right now. - // This includes MaybeUninit, the main way people use uninitialized memory. - ty::Adt(adt, _) if adt.is_union() => true, + // For Unions, check if any field is uninit + ty::Adt(adt, args) if adt.is_union() => adt.all_fields().any(|field| { + let unnormalized_field_ty = field.ty(cx.tcx, args); + let Ok(field_ty) = cx.tcx.try_normalize_erasing_regions(typing_env, unnormalized_field_ty) else { + debug_assert!( + false, + "failed to normalize field type `{unnormalized_field_ty:?}`, ParamEnv is likely set incorrectly." + ); + return false; + }; + is_uninit_value_valid_for_ty(cx, field_ty) + }), // Types (e.g. `UnsafeCell>`) that recursively contain only types that can be uninit // can themselves be uninit too. - // This purposefully ignores enums as they may have a discriminant that can't be uninit. - ty::Adt(adt, args) if adt.is_struct() => adt - .all_fields() - .all(|field| is_uninit_value_valid_for_ty(cx, field.ty(cx.tcx, args).skip_norm_wip())), - // For the rest, conservatively assume that they cannot be uninit. + // This also applies for single variant enums, whose validity is determined by their fields. + ty::Adt(adt, args) if adt.is_struct() || adt.variants().len() == 1 => adt.all_fields().all(|field| { + let unnormalized_field_ty = field.ty(cx.tcx, args); + let Ok(field_ty) = cx.tcx.try_normalize_erasing_regions(typing_env, unnormalized_field_ty) else { + debug_assert!( + false, + "failed to normalize field type `{unnormalized_field_ty:?}`, ParamEnv is likely set incorrectly." + ); + return false; + }; + + is_uninit_value_valid_for_ty(cx, field_ty) + }), + // Without a usable whole type layout, + // conservatively reject remaining enum cases + ty::Adt(adt, _) if adt.is_enum() => false, + // Conservatively reject remaining types _ => false, } } diff --git a/tests/ui/uninit_vec.rs b/tests/ui/uninit_vec.rs index a0bac28e87292..ae5c685d89abd 100644 --- a/tests/ui/uninit_vec.rs +++ b/tests/ui/uninit_vec.rs @@ -205,3 +205,125 @@ fn main() { } } } + +mod issue_11715 { + use std::mem::MaybeUninit; + #[cfg(target_pointer_width = "64")] + const HUGE: usize = 4_294_967_296; + #[cfg(target_pointer_width = "32")] + const HUGE: usize = 268_435_455; + + fn large_maybeuninit_vec_ice() { + let mut v: Vec<[MaybeUninit; HUGE]> = Vec::with_capacity(1); + unsafe { v.set_len(1) }; + } + + fn large_u8_vec_ice() { + let mut v: Vec<[u8; HUGE]> = Vec::with_capacity(1); + //~^ uninit_vec + unsafe { v.set_len(1) }; + } + + fn large_nested_maybeuninit_vec_ice() { + let mut v: Vec<[[MaybeUninit; HUGE]; 2]> = Vec::with_capacity(1); + unsafe { v.set_len(1) }; + } + + struct HeavyWrapperSafe([MaybeUninit; HUGE]); + fn large_struct_maybeuninit_vec_ice() { + let mut v: Vec = Vec::with_capacity(1); + unsafe { v.set_len(1) }; + } + + struct HeavyWrapperUnsafe([u8; HUGE]); + fn large_struct_u8_vec_ice() { + let mut v: Vec = Vec::with_capacity(1); + //~^ uninit_vec + unsafe { v.set_len(1) }; + } + + #[allow(clippy::large_enum_variant)] + enum HeavyEnum { + A([MaybeUninit; HUGE]), + B, + } + fn large_enum_vec_ice() { + let mut v: Vec = Vec::with_capacity(1); + //~^ uninit_vec + unsafe { v.set_len(1) }; + } + + enum Uninhabited {} + fn uninhabited_enum() { + let mut v: Vec = Vec::with_capacity(1); + unsafe { v.set_len(1) }; + } + + enum SingleVariant { + OnlyOne, + } + fn single_variant_enum() { + let mut v: Vec = Vec::with_capacity(1); + unsafe { v.set_len(1) }; + } + + enum OneVariantU8 { + ThisOne([u8; HUGE]), + } + fn one_variant_u8() { + let mut v: Vec = Vec::with_capacity(1); + //~^ uninit_vec + unsafe { v.set_len(1) }; + } + + enum OneVariantMaybeUninit { + ThisOne([MaybeUninit; HUGE]), + } + fn one_variant_maybe_uninit() { + let mut v: Vec = Vec::with_capacity(1); + unsafe { v.set_len(1) }; + } + + fn generic_vec_lints() { + let mut v: Vec = Vec::with_capacity(1); + //~^ uninit_vec + unsafe { v.set_len(1) }; + } + + fn generic_vec_maybeuninit() { + let mut v: Vec> = Vec::with_capacity(1); + unsafe { v.set_len(1) }; + } + + trait Assoc { + type Item; + } + fn projection_vec_lints() { + let mut v: Vec<::Item> = Vec::with_capacity(1); + //~^ uninit_vec + unsafe { v.set_len(1) }; + } + + struct Concrete; + impl Assoc for Concrete { + type Item = MaybeUninit; + } + fn normalized_projection_vec_ok() { + let mut v: Vec<::Item> = Vec::with_capacity(1); + unsafe { v.set_len(1) }; + } + + enum E { + Foo(MaybeUninit), + Bar(U), + } + fn enum_uninhabited_zst() { + let mut v: Vec> = Vec::with_capacity(1); + unsafe { v.set_len(1) }; + } + fn enum_uninhabited_non_zst() { + let mut v: Vec> = Vec::with_capacity(1); + //~^ uninit_vec + unsafe { v.set_len(1) }; + } +} diff --git a/tests/ui/uninit_vec.stderr b/tests/ui/uninit_vec.stderr index 1b821ef004e6f..56a182614b64b 100644 --- a/tests/ui/uninit_vec.stderr +++ b/tests/ui/uninit_vec.stderr @@ -159,5 +159,82 @@ LL | vec.set_len(1); | = help: initialize the buffer or wrap the content in `MaybeUninit` -error: aborting due to 15 previous errors +error: calling `set_len()` immediately after reserving a buffer creates uninitialized values + --> tests/ui/uninit_vec.rs:222:9 + | +LL | let mut v: Vec<[u8; HUGE]> = Vec::with_capacity(1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | unsafe { v.set_len(1) }; + | ^^^^^^^^^^^^ + | + = help: initialize the buffer or wrap the content in `MaybeUninit` + +error: calling `set_len()` immediately after reserving a buffer creates uninitialized values + --> tests/ui/uninit_vec.rs:240:9 + | +LL | let mut v: Vec = Vec::with_capacity(1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | unsafe { v.set_len(1) }; + | ^^^^^^^^^^^^ + | + = help: initialize the buffer or wrap the content in `MaybeUninit` + +error: calling `set_len()` immediately after reserving a buffer creates uninitialized values + --> tests/ui/uninit_vec.rs:251:9 + | +LL | let mut v: Vec = Vec::with_capacity(1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | unsafe { v.set_len(1) }; + | ^^^^^^^^^^^^ + | + = help: initialize the buffer or wrap the content in `MaybeUninit` + +error: calling `set_len()` immediately after reserving a buffer creates uninitialized values + --> tests/ui/uninit_vec.rs:274:9 + | +LL | let mut v: Vec = Vec::with_capacity(1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | unsafe { v.set_len(1) }; + | ^^^^^^^^^^^^ + | + = help: initialize the buffer or wrap the content in `MaybeUninit` + +error: calling `set_len()` immediately after reserving a buffer creates uninitialized values + --> tests/ui/uninit_vec.rs:288:9 + | +LL | let mut v: Vec = Vec::with_capacity(1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | unsafe { v.set_len(1) }; + | ^^^^^^^^^^^^ + | + = help: initialize the buffer or wrap the content in `MaybeUninit` + +error: calling `set_len()` immediately after reserving a buffer creates uninitialized values + --> tests/ui/uninit_vec.rs:302:9 + | +LL | let mut v: Vec<::Item> = Vec::with_capacity(1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | unsafe { v.set_len(1) }; + | ^^^^^^^^^^^^ + | + = help: initialize the buffer or wrap the content in `MaybeUninit` + +error: calling `set_len()` immediately after reserving a buffer creates uninitialized values + --> tests/ui/uninit_vec.rs:325:9 + | +LL | let mut v: Vec> = Vec::with_capacity(1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | unsafe { v.set_len(1) }; + | ^^^^^^^^^^^^ + | + = help: initialize the buffer or wrap the content in `MaybeUninit` + +error: aborting due to 22 previous errors From 782225d25e06f2423e65aec3710d975b90090102 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sun, 14 Jun 2026 14:23:30 -0400 Subject: [PATCH 54/77] Find a shared context for the format string and the `format!` call in `format_args_collector`. --- .../src/utils/format_args_collector.rs | 151 ++++++++++++------ tests/ui/unnecessary_trailing_comma.fixed | 2 +- tests/ui/unnecessary_trailing_comma.rs | 2 +- tests/ui/unnecessary_trailing_comma.stderr | 8 +- 4 files changed, 108 insertions(+), 55 deletions(-) diff --git a/clippy_lints/src/utils/format_args_collector.rs b/clippy_lints/src/utils/format_args_collector.rs index ee1729750f2e5..6401b48f70b05 100644 --- a/clippy_lints/src/utils/format_args_collector.rs +++ b/clippy_lints/src/utils/format_args_collector.rs @@ -1,18 +1,18 @@ use clippy_utils::macros::FormatArgsStorage; -use clippy_utils::source::SpanExt; -use itertools::Itertools; +use clippy_utils::source::{SpanExt, walk_span_to_context}; use rustc_ast::{Crate, Expr, ExprKind, FormatArgs}; use rustc_data_structures::fx::FxHashMap; use rustc_lexer::{FrontmatterAllowed, TokenKind, tokenize}; -use rustc_lint::{EarlyContext, EarlyLintPass}; +use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_session::impl_lint_pass; -use rustc_span::{Span, hygiene}; -use std::iter::once; +use rustc_span::source_map::SourceMap; +use rustc_span::{Span, SpanData}; use std::mem; /// Populates [`FormatArgsStorage`] with AST [`FormatArgs`] nodes pub struct FormatArgsCollector { format_args: FxHashMap, + parent_spans: Vec, storage: FormatArgsStorage, } @@ -20,6 +20,7 @@ impl FormatArgsCollector { pub fn new(storage: FormatArgsStorage) -> Self { Self { format_args: FxHashMap::default(), + parent_spans: Vec::new(), storage, } } @@ -30,7 +31,7 @@ impl_lint_pass!(FormatArgsCollector => []); impl EarlyLintPass for FormatArgsCollector { fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { if let ExprKind::FormatArgs(args) = &expr.kind { - if has_span_from_proc_macro(cx, args) { + if self.has_span_from_external_macro(cx.sess().source_map(), expr.span, args) { return; } @@ -43,53 +44,99 @@ impl EarlyLintPass for FormatArgsCollector { } } -/// Detects if the format string or an argument has its span set by a proc macro to something inside -/// a macro callsite, e.g. -/// -/// ```ignore -/// println!(some_proc_macro!("input {}"), a); -/// ``` -/// -/// Where `some_proc_macro` expands to -/// -/// ```ignore -/// println!("output {}", a); -/// ``` -/// -/// But with the span of `"output {}"` set to the macro input -/// -/// ```ignore -/// println!(some_proc_macro!("input {}"), a); -/// // ^^^^^^^^^^ -/// ``` -fn has_span_from_proc_macro(cx: &EarlyContext<'_>, args: &FormatArgs) -> bool { - let ctxt = args.span.ctxt(); +impl FormatArgsCollector { + /// Detects if the format string or an argument has its span set by a proc macro to something + /// inside a macro callsite, e.g. + /// + /// ```ignore + /// println!(some_proc_macro!("input {}"), a); + /// ``` + /// + /// Where `some_proc_macro` expands to + /// + /// ```ignore + /// println!("output {}", a); + /// ``` + /// + /// But with the span of `"output {}"` set to the macro input + /// + /// ```ignore + /// println!(some_proc_macro!("input {}"), a); + /// // ^^^^^^^^^^ + /// ``` + fn has_span_from_external_macro(&mut self, sm: &SourceMap, fmt_sp: Span, args: &FormatArgs) -> bool { + let mut fmt_sp = fmt_sp.data(); + + // Find the first macro call that contains the format string. + let arg_sp = if let Some(arg_sp) = walk_span_to_context(args.span, fmt_sp.ctxt) { + arg_sp.data() + } else { + // Try to find a common parent for the format call and the format string. + self.parent_spans.clear(); + // `fmt_sp.ctxt` isn't a parent of the format string so don't add it to the + // search. The first iteration will always run since it can't be the root. + while !fmt_sp.ctxt.is_root() { + fmt_sp = fmt_sp.ctxt.outer_expn_data().call_site.data(); + self.parent_spans.push(fmt_sp); + } + let mut arg_sp = args.span.data(); + // Note: A parent span will always eventually be found since the root context + // is an ancestor of all contexts. + loop { + match self.parent_spans.iter().find(|s| s.ctxt == arg_sp.ctxt) { + Some(call_sp) if call_sp.lo <= arg_sp.lo && arg_sp.hi <= call_sp.hi => { + fmt_sp = *call_sp; + break arg_sp; + }, + // If the string isn't within the call span we some macro stuff we can't + // easily interpret. + Some(_) => return true, + None => arg_sp = arg_sp.ctxt.outer_expn_data().call_site.data(), + } + } + }; + if fmt_sp.ctxt.in_external_macro(sm) { + return true; + } + let Some(src) = arg_sp.get_source_range(sm) else { + return true; + }; + let Some(src_text) = src.sf.src.as_ref().map(|x| &***x) else { + return true; + }; - // `format!("{} {} {c}", "one", "two", c = "three")` - // ^^^^^ ^^^^^ ^^^^^^^ - let argument_span = args - .arguments - .explicit_args() - .iter() - .map(|argument| hygiene::walk_chain(argument.expr.span, ctxt)); + // Check the spans between the format string and the arguments and between each argument. + args.arguments + .explicit_args() + .iter() + .try_fold(src.range.end, |start, arg| { + let expr_sp = walk_span_to_context(arg.expr.span, fmt_sp.ctxt)?.data(); + let expr_start = (expr_sp.lo.0 - src.sf.start_pos.0) as usize; + let expr_end = (expr_sp.hi.0 - src.sf.start_pos.0) as usize; + let mut tks = tokenize(src_text.get(start..expr_start)?, FrontmatterAllowed::No) + .map(|x| x.kind) + .filter(|x| { + !matches!( + x, + TokenKind::LineComment { doc_style: None } + | TokenKind::BlockComment { + doc_style: None, + terminated: true + } + | TokenKind::Whitespace + ) + }); - // `format!("{} {} {c}", "one", "two", c = "three")` - // ^^ ^^ ^^^^^^ - !once(args.span) - .chain(argument_span) - .tuple_windows() - .map(|(start, end)| start.between(end)) - .all(|sp| { - sp.check_text(cx, |src| { - // text should be either `, name` or `, name =` - let mut iter = tokenize(src, FrontmatterAllowed::No).filter(|t| { - !matches!( - t.kind, - TokenKind::LineComment { .. } | TokenKind::BlockComment { .. } | TokenKind::Whitespace - ) - }); - iter.next().is_some_and(|t| matches!(t.kind, TokenKind::Comma)) - && iter.all(|t| matches!(t.kind, TokenKind::Ident | TokenKind::Eq)) + // `,` or `, ident =` + let matches = matches!(tks.next(), Some(TokenKind::Comma)) + && match tks.next() { + Some(TokenKind::Ident) => matches!(tks.next(), Some(TokenKind::Eq)), + Some(_) => false, + None => true, + } + && tks.next().is_none(); + matches.then_some(expr_end) }) - }) + .is_none() + } } diff --git a/tests/ui/unnecessary_trailing_comma.fixed b/tests/ui/unnecessary_trailing_comma.fixed index 499d9ee1ca235..f418fe954d400 100644 --- a/tests/ui/unnecessary_trailing_comma.fixed +++ b/tests/ui/unnecessary_trailing_comma.fixed @@ -26,9 +26,9 @@ fn simple() { println!{"Foo{{,}}"}; //~ unnecessary_trailing_comma println!{"Foo(,"}; //~ unnecessary_trailing_comma println!{"Foo[,"}; //~ unnecessary_trailing_comma + println!(concat!("Foo", "=", "{}"), 1); //~ unnecessary_trailing_comma // This should eventually work, but requires more work - println!(concat!("Foo", "=", "{}"), 1,); println!("No params", /*"a,){ */); println!("No params" /* "a,){*/, /*"a,){ */); diff --git a/tests/ui/unnecessary_trailing_comma.rs b/tests/ui/unnecessary_trailing_comma.rs index 15dea27b887b6..26770ffaeee18 100644 --- a/tests/ui/unnecessary_trailing_comma.rs +++ b/tests/ui/unnecessary_trailing_comma.rs @@ -26,9 +26,9 @@ fn simple() { println!{"Foo{{,}}", }; //~ unnecessary_trailing_comma println!{"Foo(,", }; //~ unnecessary_trailing_comma println!{"Foo[,", }; //~ unnecessary_trailing_comma + println!(concat!("Foo", "=", "{}"), 1,); //~ unnecessary_trailing_comma // This should eventually work, but requires more work - println!(concat!("Foo", "=", "{}"), 1,); println!("No params", /*"a,){ */); println!("No params" /* "a,){*/, /*"a,){ */); diff --git a/tests/ui/unnecessary_trailing_comma.stderr b/tests/ui/unnecessary_trailing_comma.stderr index 06fd5b1861a55..8ff7195a147b0 100644 --- a/tests/ui/unnecessary_trailing_comma.stderr +++ b/tests/ui/unnecessary_trailing_comma.stderr @@ -115,5 +115,11 @@ error: unnecessary trailing comma LL | println!{"Foo[,", }; | ^^ help: remove the trailing comma -error: aborting due to 19 previous errors +error: unnecessary trailing comma + --> tests/ui/unnecessary_trailing_comma.rs:29:42 + | +LL | println!(concat!("Foo", "=", "{}"), 1,); + | ^ help: remove the trailing comma + +error: aborting due to 20 previous errors From ad11a216f7b66abf7e0017108e0a13936ba2af6b Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Fri, 12 Jun 2026 10:29:40 -0400 Subject: [PATCH 55/77] Take more precise arguments in `is_const_evaluatable`. --- clippy_lints/src/assertions_on_constants.rs | 4 +- clippy_lints/src/cloned_ref_to_slice_refs.rs | 2 +- clippy_lints/src/manual_clamp.rs | 8 +++- .../src/methods/chunks_exact_to_as_chunks.rs | 2 +- clippy_lints/src/methods/str_split.rs | 5 ++- clippy_utils/src/eager_or_lazy.rs | 4 +- clippy_utils/src/msrvs.rs | 40 ++++++++++++++----- clippy_utils/src/qualify_min_const_fn.rs | 22 +++++----- clippy_utils/src/visitors.rs | 40 +++++++++---------- 9 files changed, 79 insertions(+), 48 deletions(-) diff --git a/clippy_lints/src/assertions_on_constants.rs b/clippy_lints/src/assertions_on_constants.rs index 6e57d0608bed8..118c3c23d727d 100644 --- a/clippy_lints/src/assertions_on_constants.rs +++ b/clippy_lints/src/assertions_on_constants.rs @@ -52,7 +52,9 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnConstants { _ => return, } && let Some((condition, _)) = find_assert_args(cx, e, macro_call.expn) - && is_const_evaluatable(cx, condition) + // Check if the whole expression can be moved into a const context. + // Note that const eval can evaluate things which cannot be moved (e.g. `false && x`). + && is_const_evaluatable(cx.tcx, cx.typeck_results(), condition) && let Some((Constant::Bool(assert_val), const_src)) = ConstEvalCtxt::new(cx).eval_with_source(condition, macro_call.span.ctxt()) && let in_const_context = is_inside_always_const_context(cx.tcx, e.hir_id) diff --git a/clippy_lints/src/cloned_ref_to_slice_refs.rs b/clippy_lints/src/cloned_ref_to_slice_refs.rs index 980584e9a1eec..24955ac3c6258 100644 --- a/clippy_lints/src/cloned_ref_to_slice_refs.rs +++ b/clippy_lints/src/cloned_ref_to_slice_refs.rs @@ -85,7 +85,7 @@ impl<'tcx> LateLintPass<'tcx> for ClonedRefToSliceRefs<'_> { && let Some(adjustment) = is_needless_clone_or_equivalent(cx, recv, path.ident.name, item.hir_id) // check for immutability or purity - && (!is_mutable(cx, recv) || is_const_evaluatable(cx, recv)) + && (!is_mutable(cx, recv) || is_const_evaluatable(cx.tcx, cx.typeck_results(), recv)) // get appropriate crate for `slice::from_ref` && let Some(builtin_crate) = clippy_utils::std_or_core(cx) diff --git a/clippy_lints/src/manual_clamp.rs b/clippy_lints/src/manual_clamp.rs index 6848af7748f3f..8cb60212f19da 100644 --- a/clippy_lints/src/manual_clamp.rs +++ b/clippy_lints/src/manual_clamp.rs @@ -367,12 +367,16 @@ fn is_call_max_min_pattern<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) && let Some(inner_seg) = segment(cx, inner_fn) && let Some(outer_seg) = segment(cx, outer_fn) { - let (input, inner_arg) = match (is_const_evaluatable(cx, first), is_const_evaluatable(cx, second)) { + let typeck = cx.typeck_results(); + let (input, inner_arg) = match ( + is_const_evaluatable(cx.tcx, typeck, first), + is_const_evaluatable(cx.tcx, typeck, second), + ) { (true, false) => (second, first), (false, true) => (first, second), _ => return None, }; - let is_float = cx.typeck_results().expr_ty_adjusted(input).is_floating_point(); + let is_float = typeck.expr_ty_adjusted(input).is_floating_point(); let (min, max) = match (inner_seg, outer_seg) { (FunctionType::CmpMin, FunctionType::CmpMax) => (outer_arg, inner_arg), (FunctionType::CmpMax, FunctionType::CmpMin) => (inner_arg, outer_arg), diff --git a/clippy_lints/src/methods/chunks_exact_to_as_chunks.rs b/clippy_lints/src/methods/chunks_exact_to_as_chunks.rs index 235df80e46985..e151cf43a5044 100644 --- a/clippy_lints/src/methods/chunks_exact_to_as_chunks.rs +++ b/clippy_lints/src/methods/chunks_exact_to_as_chunks.rs @@ -25,7 +25,7 @@ pub(super) fn check<'tcx>( return; } - if is_const_evaluatable(cx, arg) { + if is_const_evaluatable(cx.tcx, cx.typeck_results(), arg) { if !msrv.meets(cx, msrvs::AS_CHUNKS) { return; } diff --git a/clippy_lints/src/methods/str_split.rs b/clippy_lints/src/methods/str_split.rs index 8641f7c0abec3..fbb3dd41c7a4e 100644 --- a/clippy_lints/src/methods/str_split.rs +++ b/clippy_lints/src/methods/str_split.rs @@ -22,8 +22,9 @@ pub(super) fn check<'a>( // basic ones: a `'\n'`, `"\n"`, and `"\r\n"`. if let ExprKind::MethodCall(trim_method_name, trim_recv, [], trim_span) = split_recv.kind && trim_method_name.ident.name == sym::trim - && cx.typeck_results().expr_ty_adjusted(trim_recv).peel_refs().is_str() - && !is_const_evaluatable(cx, trim_recv) + && let typeck = cx.typeck_results() + && typeck.expr_ty_adjusted(trim_recv).peel_refs().is_str() + && !is_const_evaluatable(cx.tcx, typeck, trim_recv) && let ExprKind::Lit(split_lit) = split_arg.kind && matches!( split_lit.node, diff --git a/clippy_utils/src/eager_or_lazy.rs b/clippy_utils/src/eager_or_lazy.rs index cd609980b149b..68f1d0c2bb9fd 100644 --- a/clippy_utils/src/eager_or_lazy.rs +++ b/clippy_utils/src/eager_or_lazy.rs @@ -161,7 +161,7 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS }, Res::Def(_, id) if self.cx.tcx.is_promotable_const_fn(id) => (), // No need to walk the arguments here, `is_const_evaluatable` already did - Res::Def(..) if is_const_evaluatable(self.cx, e) => { + Res::Def(..) if is_const_evaluatable(self.cx.tcx, self.cx.typeck_results(), e) => { self.eagerness |= NoChange; return; }, @@ -177,7 +177,7 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS _ => self.eagerness = Lazy, }, // No need to walk the arguments here, `is_const_evaluatable` already did - ExprKind::MethodCall(..) if is_const_evaluatable(self.cx, e) => { + ExprKind::MethodCall(..) if is_const_evaluatable(self.cx.tcx, self.cx.typeck_results(), e) => { self.eagerness |= NoChange; return; }, diff --git a/clippy_utils/src/msrvs.rs b/clippy_utils/src/msrvs.rs index 6cdba7a03e637..daf9de05a2948 100644 --- a/clippy_utils/src/msrvs.rs +++ b/clippy_utils/src/msrvs.rs @@ -3,8 +3,9 @@ use rustc_ast::Attribute; use rustc_ast::attr::AttributeExt; use rustc_attr_parsing::parse_version; use rustc_data_structures::smallvec::SmallVec; -use rustc_hir::RustcVersion; +use rustc_hir::{HirId, RustcVersion}; use rustc_lint::LateContext; +use rustc_middle::ty::TyCtxt; use rustc_session::Session; use rustc_span::Symbol; use serde::Deserialize; @@ -118,16 +119,29 @@ impl Msrv { /// nodes for that attribute, prefer to run this check after cheaper pattern matching operations pub fn current(self, cx: &LateContext<'_>) -> Option { if SEEN_MSRV_ATTR.load(Ordering::Relaxed) { - let start = cx.last_node_with_lint_attrs; - if let Some(msrv_attr) = once(start) - .chain(cx.tcx.hir_parent_id_iter(start)) - .find_map(|id| parse_attrs(cx.tcx.sess, cx.tcx.hir_attrs(id))) - { - return Some(msrv_attr); - } + self.from_attrs(cx.tcx, cx.last_node_with_lint_attrs) + } else { + self.0 } + } - self.0 + /// Returns the MSRV at the specified node + /// + /// If the crate being linted uses an `#[clippy::msrv]` attribute this will search the parent + /// nodes for that attribute, prefer to run this check after cheaper pattern matching operations + pub fn at(self, tcx: TyCtxt<'_>, node: HirId) -> Option { + if SEEN_MSRV_ATTR.load(Ordering::Relaxed) { + self.from_attrs(tcx, node) + } else { + self.0 + } + } + + fn from_attrs(self, tcx: TyCtxt<'_>, node: HirId) -> Option { + once(node) + .chain(tcx.hir_parent_id_iter(node)) + .find_map(|id| parse_attrs(tcx.sess, tcx.hir_attrs(id))) + .or(self.0) } /// Checks if a required version from [this module](self) is met at the current node @@ -138,6 +152,14 @@ impl Msrv { self.current(cx).is_none_or(|msrv| msrv >= required) } + /// Checks if a required version from [this module](self) is met at the specified node + /// + /// If the crate being linted uses an `#[clippy::msrv]` attribute this will search the parent + /// nodes for that attribute, prefer to run this check after cheaper pattern matching operations + pub fn meets_at(self, tcx: TyCtxt<'_>, node: HirId, required: RustcVersion) -> bool { + self.at(tcx, node).is_none_or(|msrv| msrv >= required) + } + pub fn read_cargo(&mut self, sess: &Session) { let cargo_msrv = std::env::var("CARGO_PKG_RUST_VERSION") .ok() diff --git a/clippy_utils/src/qualify_min_const_fn.rs b/clippy_utils/src/qualify_min_const_fn.rs index ddb3c2d6cb4a5..d0316a77c8ff4 100644 --- a/clippy_utils/src/qualify_min_const_fn.rs +++ b/clippy_utils/src/qualify_min_const_fn.rs @@ -6,9 +6,8 @@ use crate::msrvs::{self, Msrv}; use hir::LangItem; use rustc_const_eval::check_consts::ConstCx; -use rustc_hir as hir; use rustc_hir::def_id::DefId; -use rustc_hir::{RustcVersion, StableSince}; +use rustc_hir::{self as hir, HirId, RustcVersion, StableSince}; use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::traits::Obligation; use rustc_lint::LateContext; @@ -420,14 +419,17 @@ fn check_terminator<'tcx>( /// Checks if the given `def_id` is a stable const fn, in respect to the given MSRV. pub fn is_stable_const_fn(cx: &LateContext<'_>, def_id: DefId, msrv: Msrv) -> bool { - cx.tcx.is_const_fn(def_id) - && cx - .tcx + is_stable_const_fn_at(cx.tcx, cx.last_node_with_lint_attrs, def_id, msrv) +} + +/// Checks if the given `def_id` is a stable const fn, in respect to the given MSRV. +pub fn is_stable_const_fn_at(tcx: TyCtxt<'_>, node: HirId, def_id: DefId, msrv: Msrv) -> bool { + tcx.is_const_fn(def_id) + && tcx .lookup_const_stability(def_id) .or_else(|| { - cx.tcx - .trait_of_assoc(def_id) - .and_then(|trait_def_id| cx.tcx.lookup_const_stability(trait_def_id)) + tcx.trait_of_assoc(def_id) + .and_then(|trait_def_id| tcx.lookup_const_stability(trait_def_id)) }) .is_none_or(|const_stab| { if let rustc_hir::StabilityLevel::Stable { since, .. } = const_stab.level { @@ -441,10 +443,10 @@ pub fn is_stable_const_fn(cx: &LateContext<'_>, def_id: DefId, msrv: Msrv) -> bo StableSince::Err(_) => return false, }; - msrv.meets(cx, const_stab_rust_version) + msrv.meets_at(tcx, node, const_stab_rust_version) } else { // Unstable const fn, check if the feature is enabled. - cx.tcx.features().enabled(const_stab.feature) && msrv.current(cx).is_none() + tcx.features().enabled(const_stab.feature) && msrv.at(tcx, node).is_none() } }) } diff --git a/clippy_utils/src/visitors.rs b/clippy_utils/src/visitors.rs index 28449a75a8fc5..749c8c02a84b5 100644 --- a/clippy_utils/src/visitors.rs +++ b/clippy_utils/src/visitors.rs @@ -1,6 +1,6 @@ use crate::get_enclosing_block; use crate::msrvs::Msrv; -use crate::qualify_min_const_fn::is_stable_const_fn; +use crate::qualify_min_const_fn::is_stable_const_fn_at; use crate::res::MaybeResPath; use crate::ty::needs_ordered_drop; use core::ops::ControlFlow; @@ -8,8 +8,8 @@ use rustc_ast::visit::{VisitorResult, try_visit}; use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::intravisit::{self, Visitor, walk_block, walk_expr}; use rustc_hir::{ - self as hir, AmbigArg, AnonConst, Arm, Block, BlockCheckMode, Body, BodyId, Expr, ExprKind, HirId, ItemId, - ItemKind, LetExpr, Pat, QPath, Stmt, StructTailExpr, UnOp, UnsafeSource, + self as hir, AmbigArg, AnonConst, Arm, Block, BlockCheckMode, Body, BodyId, CRATE_HIR_ID, Expr, ExprKind, HirId, + ItemId, ItemKind, LetExpr, Pat, QPath, Stmt, StructTailExpr, UnOp, UnsafeSource, }; use rustc_lint::LateContext; use rustc_middle::hir::nested_filter; @@ -322,13 +322,14 @@ pub fn is_local_used<'tcx>(cx: &LateContext<'tcx>, visitable: impl Visitable<'tc .is_some() } -/// Checks if the given expression is a constant. -pub fn is_const_evaluatable<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> bool { - struct V<'a, 'tcx> { - cx: &'a LateContext<'tcx>, +/// Checks if the given expression can be evaluated as a constant at the specified node +pub fn is_const_evaluatable<'tcx>(tcx: TyCtxt<'tcx>, typeck: &'tcx TypeckResults<'tcx>, e: &'tcx Expr<'_>) -> bool { + struct V<'tcx> { + tcx: TyCtxt<'tcx>, + typeck: &'tcx TypeckResults<'tcx>, } - impl<'tcx> Visitor<'tcx> for V<'_, 'tcx> { + impl<'tcx> Visitor<'tcx> for V<'tcx> { type Result = ControlFlow<()>; type NestedFilter = intravisit::nested_filter::None; @@ -343,29 +344,28 @@ pub fn is_const_evaluatable<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> }, _, ) if self - .cx + .typeck .qpath_res(p, hir_id) .opt_def_id() - .is_some_and(|id| is_stable_const_fn(self.cx, id, Msrv::default())) => {}, + .is_some_and(|id| is_stable_const_fn_at(self.tcx, CRATE_HIR_ID, id, Msrv::default())) => {}, ExprKind::MethodCall(..) if self - .cx - .typeck_results() + .typeck .type_dependent_def_id(e.hir_id) - .is_some_and(|id| is_stable_const_fn(self.cx, id, Msrv::default())) => {}, + .is_some_and(|id| is_stable_const_fn_at(self.tcx, CRATE_HIR_ID, id, Msrv::default())) => {}, ExprKind::Binary(_, lhs, rhs) - if self.cx.typeck_results().expr_ty(lhs).peel_refs().is_primitive_ty() - && self.cx.typeck_results().expr_ty(rhs).peel_refs().is_primitive_ty() => {}, - ExprKind::Unary(UnOp::Deref, e) if self.cx.typeck_results().expr_ty(e).is_raw_ptr() => (), - ExprKind::Unary(_, e) if self.cx.typeck_results().expr_ty(e).peel_refs().is_primitive_ty() => (), + if self.typeck.expr_ty(lhs).peel_refs().is_primitive_ty() + && self.typeck.expr_ty(rhs).peel_refs().is_primitive_ty() => {}, + ExprKind::Unary(UnOp::Deref, e) if self.typeck.expr_ty(e).is_raw_ptr() => (), + ExprKind::Unary(_, e) if self.typeck.expr_ty(e).peel_refs().is_primitive_ty() => (), ExprKind::Index(base, _, _) if matches!( - self.cx.typeck_results().expr_ty(base).peel_refs().kind(), + self.typeck.expr_ty(base).peel_refs().kind(), ty::Slice(_) | ty::Array(..) ) => {}, ExprKind::Path(ref p) if matches!( - self.cx.qpath_res(p, e.hir_id), + self.typeck.qpath_res(p, e.hir_id), Res::Def( DefKind::Const { .. } | DefKind::AssocConst { .. } @@ -403,7 +403,7 @@ pub fn is_const_evaluatable<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> } } - let mut v = V { cx }; + let mut v = V { tcx, typeck }; v.visit_expr(e).is_continue() } From 29f1ca9e191c347caea9babdeb6b7a07be846ebe Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Fri, 12 Jun 2026 10:16:30 -0400 Subject: [PATCH 56/77] Take `TyCtxt` in `for_each_expr` --- clippy_lints/src/casts/needless_type_cast.rs | 2 +- clippy_lints/src/collection_is_never_read.rs | 2 +- clippy_lints/src/doc/missing_headers.rs | 2 +- clippy_lints/src/entry.rs | 2 +- clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs | 2 +- clippy_lints/src/loops/char_indices_as_byte_indices.rs | 4 ++-- clippy_lints/src/methods/expect_fun_call.rs | 2 +- clippy_lints/src/methods/manual_inspect.rs | 2 +- clippy_lints/src/methods/or_fun_call.rs | 4 ++-- clippy_lints/src/methods/str_splitn.rs | 2 +- clippy_lints/src/missing_fields_in_debug.rs | 4 ++-- clippy_lints/src/needless_late_init.rs | 2 +- clippy_lints/src/needless_pass_by_ref_mut.rs | 2 +- clippy_lints/src/non_std_lazy_statics.rs | 2 +- clippy_lints/src/panic_in_result_fn.rs | 2 +- clippy_lints/src/redundant_test_prefix.rs | 2 +- clippy_lints/src/returns/let_and_return.rs | 2 +- clippy_lints/src/set_contains_or_insert.rs | 2 +- clippy_lints/src/shadow.rs | 2 +- clippy_lints/src/string_patterns.rs | 2 +- clippy_lints/src/undocumented_unsafe_blocks.rs | 2 +- .../src/repeated_is_diagnostic_item.rs | 4 ++-- clippy_utils/src/msrvs.rs | 6 +++--- clippy_utils/src/usage.rs | 4 ++-- clippy_utils/src/visitors.rs | 10 +++++----- 25 files changed, 36 insertions(+), 36 deletions(-) diff --git a/clippy_lints/src/casts/needless_type_cast.rs b/clippy_lints/src/casts/needless_type_cast.rs index 844d4c7acbe7f..5cfbffc6c3f66 100644 --- a/clippy_lints/src/casts/needless_type_cast.rs +++ b/clippy_lints/src/casts/needless_type_cast.rs @@ -249,7 +249,7 @@ fn can_coerce_to_target_type(expr: &Expr<'_>) -> bool { fn check_binding_usages<'a>(cx: &LateContext<'a>, body: &Body<'a>, hir_id: HirId, binding_info: &BindingInfo<'a>) { let mut usages = Vec::new(); - for_each_expr(cx, body.value, |expr| { + for_each_expr(cx.tcx, body.value, |expr| { if let ExprKind::Path(ref qpath) = expr.kind && !expr.span.from_expansion() && let Res::Local(id) = cx.qpath_res(qpath, expr.hir_id) diff --git a/clippy_lints/src/collection_is_never_read.rs b/clippy_lints/src/collection_is_never_read.rs index ddd3e8b805d19..4ddd396c50ce4 100644 --- a/clippy_lints/src/collection_is_never_read.rs +++ b/clippy_lints/src/collection_is_never_read.rs @@ -79,7 +79,7 @@ fn has_no_read_access<'tcx, T: Visitable<'tcx>>(cx: &LateContext<'tcx>, id: HirI let mut has_read_access = false; // Inspect all expressions and sub-expressions in the block. - for_each_expr(cx, block, |expr| { + for_each_expr(cx.tcx, block, |expr| { // Ignore expressions that are not simply `id`. if expr.res_local_id() != Some(id) { return ControlFlow::Continue(()); diff --git a/clippy_lints/src/doc/missing_headers.rs b/clippy_lints/src/doc/missing_headers.rs index b164a9a99782b..4139df9cd7997 100644 --- a/clippy_lints/src/doc/missing_headers.rs +++ b/clippy_lints/src/doc/missing_headers.rs @@ -99,7 +99,7 @@ pub fn check( fn find_panic(cx: &LateContext<'_>, body_id: BodyId) -> Option { let mut panic_span = None; let typeck = cx.tcx.typeck_body(body_id); - for_each_expr(cx, cx.tcx.hir_body(body_id), |expr| { + for_each_expr(cx.tcx, cx.tcx.hir_body(body_id), |expr| { if is_inside_always_const_context(cx.tcx, expr.hir_id) { return ControlFlow::::Continue(()); } diff --git a/clippy_lints/src/entry.rs b/clippy_lints/src/entry.rs index a24cc957df070..cba40abf04e17 100644 --- a/clippy_lints/src/entry.rs +++ b/clippy_lints/src/entry.rs @@ -604,7 +604,7 @@ fn is_any_expr_in_map_used<'tcx>( map: &'tcx Expr<'tcx>, expr: &'tcx Expr<'tcx>, ) -> bool { - for_each_expr(cx, map, |e| { + for_each_expr(cx.tcx, map, |e| { if spanless_eq.eq_expr(ctxt, e, expr) { return ControlFlow::Break(()); } diff --git a/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs b/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs index e49dee4164b88..f3952b2687a56 100644 --- a/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs +++ b/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs @@ -50,7 +50,7 @@ fn check_raw_ptr<'tcx>( if !raw_ptrs.is_empty() { let typeck = cx.tcx.typeck_body(body.id()); - let _: Option = for_each_expr(cx, body.value, |e| { + let _: Option = for_each_expr(cx.tcx, body.value, |e| { match e.kind { hir::ExprKind::Call(f, args) if is_unsafe_fn(cx, typeck.expr_ty(f)) => { for arg in args { diff --git a/clippy_lints/src/loops/char_indices_as_byte_indices.rs b/clippy_lints/src/loops/char_indices_as_byte_indices.rs index 41022e6a5321b..f4d71d0524b22 100644 --- a/clippy_lints/src/loops/char_indices_as_byte_indices.rs +++ b/clippy_lints/src/loops/char_indices_as_byte_indices.rs @@ -48,7 +48,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, pat: &Pat<'_>, iterable: &Expr && let PatKind::Binding(_, binding_id, ..) = pat.kind { // Destructured iterator element `(idx, _)`, look for uses of the binding - for_each_expr(cx, body, |expr| { + for_each_expr(cx.tcx, body, |expr| { if expr.res_local_id() == Some(binding_id) { check_index_usage(cx, expr, pat, enumerate_span, chars_span, chars_recv); } @@ -56,7 +56,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, pat: &Pat<'_>, iterable: &Expr }); } else if let PatKind::Binding(_, binding_id, ..) = pat.kind { // Bound as a tuple, look for `tup.0` - for_each_expr(cx, body, |expr| { + for_each_expr(cx.tcx, body, |expr| { if let ExprKind::Field(e, field) = expr.kind && e.res_local_id() == Some(binding_id) && field.name == sym::integer(0) diff --git a/clippy_lints/src/methods/expect_fun_call.rs b/clippy_lints/src/methods/expect_fun_call.rs index 89b37d507b702..97a03f9868b1d 100644 --- a/clippy_lints/src/methods/expect_fun_call.rs +++ b/clippy_lints/src/methods/expect_fun_call.rs @@ -100,7 +100,7 @@ fn get_arg_root<'a>(cx: &LateContext<'_>, arg: &'a hir::Expr<'a>) -> &'a hir::Ex } fn contains_call<'a>(cx: &LateContext<'a>, arg: &'a hir::Expr<'a>) -> bool { - for_each_expr(cx, arg, |expr| { + for_each_expr(cx.tcx, arg, |expr| { if matches!(expr.kind, hir::ExprKind::MethodCall { .. } | hir::ExprKind::Call { .. }) && !is_inside_always_const_context(cx.tcx, expr.hir_id) { diff --git a/clippy_lints/src/methods/manual_inspect.rs b/clippy_lints/src/methods/manual_inspect.rs index bcda19e32e097..5ef8450da93bc 100644 --- a/clippy_lints/src/methods/manual_inspect.rs +++ b/clippy_lints/src/methods/manual_inspect.rs @@ -47,7 +47,7 @@ pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, name: let can_lint = for_each_expr_without_closures(block.stmts, |e| { if let ExprKind::Closure(c) = e.kind { // Nested closures don't need to treat returns specially. - let _: Option = for_each_expr(cx, cx.tcx.hir_body(c.body).value, |e| { + let _: Option = for_each_expr(cx.tcx, cx.tcx.hir_body(c.body).value, |e| { if e.res_local_id() == Some(arg_id) { let (kind, same_ctxt) = check_use(cx, ctxt, e); match (kind, same_ctxt && e.span.ctxt() == ctxt) { diff --git a/clippy_lints/src/methods/or_fun_call.rs b/clippy_lints/src/methods/or_fun_call.rs index a07cd5a8925ae..332411a00ede6 100644 --- a/clippy_lints/src/methods/or_fun_call.rs +++ b/clippy_lints/src/methods/or_fun_call.rs @@ -32,7 +32,7 @@ pub(super) fn check<'tcx>( ) { if let [arg] = args { let inner_arg = peel_blocks(arg); - for_each_expr(cx, inner_arg, |ex| { + for_each_expr(cx.tcx, inner_arg, |ex| { // `or_fun_call` lint needs to take nested expr into account, // but `unwrap_or_default` lint doesn't, we don't want something like: // `opt.unwrap_or(Foo { inner: String::default(), other: 1 })` to get replaced by @@ -72,7 +72,7 @@ pub(super) fn check<'tcx>( // `map_or` takes two arguments if let [arg, lambda] = args { let inner_arg = peel_blocks(arg); - for_each_expr(cx, inner_arg, |ex| { + for_each_expr(cx.tcx, inner_arg, |ex| { let is_top_most_expr = ex.hir_id == inner_arg.hir_id; match ex.kind { hir::ExprKind::Call(fun, fun_args) => { diff --git a/clippy_lints/src/methods/str_splitn.rs b/clippy_lints/src/methods/str_splitn.rs index fff203296bce9..13782a492cbc5 100644 --- a/clippy_lints/src/methods/str_splitn.rs +++ b/clippy_lints/src/methods/str_splitn.rs @@ -214,7 +214,7 @@ fn indirect_usage<'tcx>( }) = stmt.kind { let mut path_to_binding = None; - let _: Option = for_each_expr(cx, init_expr, |e| { + let _: Option = for_each_expr(cx.tcx, init_expr, |e| { if e.res_local_id() == Some(binding) { path_to_binding = Some(e); } diff --git a/clippy_lints/src/missing_fields_in_debug.rs b/clippy_lints/src/missing_fields_in_debug.rs index 332c19e140b3e..861105aa7317a 100644 --- a/clippy_lints/src/missing_fields_in_debug.rs +++ b/clippy_lints/src/missing_fields_in_debug.rs @@ -109,7 +109,7 @@ fn should_lint<'tcx>( // Is there a call to `DebugStruct::debug_struct`? Do lint if there is. let mut has_debug_struct = false; - for_each_expr(cx, block, |expr| { + for_each_expr(cx.tcx, block, |expr| { if let ExprKind::MethodCall(path, recv, ..) = &expr.kind { let recv_ty = typeck_results.expr_ty(recv).peel_refs(); @@ -166,7 +166,7 @@ fn check_struct<'tcx>( let mut has_direct_field_access = false; let mut field_accesses = FxHashSet::default(); - for_each_expr(cx, block, |expr| { + for_each_expr(cx.tcx, block, |expr| { if let ExprKind::Field(target, ident) = expr.kind && let target_ty = typeck_results.expr_ty_adjusted(target).peel_refs() && target_ty == self_ty diff --git a/clippy_lints/src/needless_late_init.rs b/clippy_lints/src/needless_late_init.rs index a2206102f053d..82ab15578e064 100644 --- a/clippy_lints/src/needless_late_init.rs +++ b/clippy_lints/src/needless_late_init.rs @@ -64,7 +64,7 @@ declare_clippy_lint! { declare_lint_pass!(NeedlessLateInit => [NEEDLESS_LATE_INIT]); fn contains_assign_expr<'tcx>(cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'tcx>) -> bool { - for_each_expr(cx, stmt, |e| { + for_each_expr(cx.tcx, stmt, |e| { if matches!(e.kind, ExprKind::Assign(..)) { ControlFlow::Break(()) } else { diff --git a/clippy_lints/src/needless_pass_by_ref_mut.rs b/clippy_lints/src/needless_pass_by_ref_mut.rs index dea88e592f2a5..0d5b2ee6ba29e 100644 --- a/clippy_lints/src/needless_pass_by_ref_mut.rs +++ b/clippy_lints/src/needless_pass_by_ref_mut.rs @@ -206,7 +206,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> { // We retrieve all the closures declared in the function because they will not be found // by `euv::Delegate`. let mut closures: FxIndexSet = FxIndexSet::default(); - for_each_expr(cx, body, |expr| { + for_each_expr(cx.tcx, body, |expr| { if let ExprKind::Closure(closure) = expr.kind { closures.insert(closure.def_id); } diff --git a/clippy_lints/src/non_std_lazy_statics.rs b/clippy_lints/src/non_std_lazy_statics.rs index 487eaecf18890..2755e3add760e 100644 --- a/clippy_lints/src/non_std_lazy_statics.rs +++ b/clippy_lints/src/non_std_lazy_statics.rs @@ -198,7 +198,7 @@ impl LazyInfo { // visit body to collect `Lazy::new` calls let mut new_fn_calls = FxIndexMap::default(); - for_each_expr::<(), ()>(cx, body, |ex| { + for_each_expr::<(), ()>(cx.tcx, body, |ex| { if let Some((fn_did, call_span)) = fn_def_id_and_span_from_body(cx, ex, body_id) && paths::ONCE_CELL_SYNC_LAZY_NEW.matches(cx, fn_did) { diff --git a/clippy_lints/src/panic_in_result_fn.rs b/clippy_lints/src/panic_in_result_fn.rs index cc147a4a84bdc..fa7a5d8feb380 100644 --- a/clippy_lints/src/panic_in_result_fn.rs +++ b/clippy_lints/src/panic_in_result_fn.rs @@ -64,7 +64,7 @@ impl<'tcx> LateLintPass<'tcx> for PanicInResultFn { fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, body: &'tcx hir::Body<'tcx>) { let mut panics = Vec::new(); - let _: Option = for_each_expr(cx, body.value, |e| { + let _: Option = for_each_expr(cx.tcx, body.value, |e| { let Some(macro_call) = root_macro_call_first_node(cx, e) else { return ControlFlow::Continue(Descend::Yes); }; diff --git a/clippy_lints/src/redundant_test_prefix.rs b/clippy_lints/src/redundant_test_prefix.rs index 602093259eaec..2dc03328fef86 100644 --- a/clippy_lints/src/redundant_test_prefix.rs +++ b/clippy_lints/src/redundant_test_prefix.rs @@ -144,7 +144,7 @@ fn name_conflicts<'tcx>(cx: &LateContext<'tcx>, body: &'tcx Body<'_>, fn_name: S // Also check that within the body of the function there is also no function call // with the same name (since it will result in recursion) - for_each_expr(cx, body, |expr| { + for_each_expr(cx.tcx, body, |expr| { if let ExprKind::Path(qpath) = &expr.kind && let Some(def_id) = cx.qpath_res(qpath, expr.hir_id).opt_def_id() && let Some(name) = tcx.opt_item_name(def_id) diff --git a/clippy_lints/src/returns/let_and_return.rs b/clippy_lints/src/returns/let_and_return.rs index 2ec921ed21c7d..c1a909fdde4e1 100644 --- a/clippy_lints/src/returns/let_and_return.rs +++ b/clippy_lints/src/returns/let_and_return.rs @@ -67,7 +67,7 @@ pub(super) fn check_block<'tcx>(cx: &LateContext<'tcx>, block: &'tcx Block<'_>) } } fn last_statement_borrows<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool { - for_each_expr(cx, expr, |e| { + for_each_expr(cx.tcx, expr, |e| { if let Some(def_id) = fn_def_id(cx, e) && cx .tcx diff --git a/clippy_lints/src/set_contains_or_insert.rs b/clippy_lints/src/set_contains_or_insert.rs index 4aba49071ee56..03acfb22c6c82 100644 --- a/clippy_lints/src/set_contains_or_insert.rs +++ b/clippy_lints/src/set_contains_or_insert.rs @@ -127,7 +127,7 @@ fn find_insert_calls<'tcx>( contains_expr: &OpExpr<'tcx>, expr: &'tcx Expr<'_>, ) -> Option> { - for_each_expr(cx, expr, |e| { + for_each_expr(cx.tcx, expr, |e| { if let Some((insert_expr, _)) = try_parse_op_call(cx, e, sym::insert) && SpanlessEq::new(cx).eq_expr(SyntaxContext::root(), contains_expr.receiver, insert_expr.receiver) && SpanlessEq::new(cx).eq_expr(SyntaxContext::root(), contains_expr.value, insert_expr.value) diff --git a/clippy_lints/src/shadow.rs b/clippy_lints/src/shadow.rs index 4ddf82773d872..5072e39afb8c1 100644 --- a/clippy_lints/src/shadow.rs +++ b/clippy_lints/src/shadow.rs @@ -199,7 +199,7 @@ pub fn is_local_used_except<'tcx>( id: HirId, except: Option, ) -> bool { - for_each_expr(cx, visitable, |e| { + for_each_expr(cx.tcx, visitable, |e| { if except.is_some_and(|it| it == e.hir_id) { ControlFlow::Continue(Descend::No) } else if e.res_local_id() == Some(id) { diff --git a/clippy_lints/src/string_patterns.rs b/clippy_lints/src/string_patterns.rs index b4eb8977bf0fb..cf7ac4ae2e0f0 100644 --- a/clippy_lints/src/string_patterns.rs +++ b/clippy_lints/src/string_patterns.rs @@ -147,7 +147,7 @@ fn check_manual_pattern_char_comparison(cx: &LateContext<'_>, method_arg: &Expr< // We want to retrieve all the comparisons done. // They are ordered in a nested way and so we need to traverse the AST to collect them all. - if for_each_expr(cx, body.value, |sub_expr| -> ControlFlow<(), Descend> { + if for_each_expr(cx.tcx, body.value, |sub_expr| -> ControlFlow<(), Descend> { match sub_expr.kind { ExprKind::Binary(op, left, right) if op.node == BinOpKind::Eq => { if left.res_local_id() == Some(binding) diff --git a/clippy_lints/src/undocumented_unsafe_blocks.rs b/clippy_lints/src/undocumented_unsafe_blocks.rs index 2bf1d8be46536..d35139f2f6b9b 100644 --- a/clippy_lints/src/undocumented_unsafe_blocks.rs +++ b/clippy_lints/src/undocumented_unsafe_blocks.rs @@ -393,7 +393,7 @@ fn expr_has_unnecessary_safety_comment<'tcx>( } // this should roughly be the reverse of `block_parents_have_safety_comment` - if for_each_expr(cx, expr, |expr| match expr.kind { + if for_each_expr(cx.tcx, expr, |expr| match expr.kind { hir::ExprKind::Block( Block { rules: BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided), diff --git a/clippy_lints_internal/src/repeated_is_diagnostic_item.rs b/clippy_lints_internal/src/repeated_is_diagnostic_item.rs index b300dfa27b0eb..e0148c79477c0 100644 --- a/clippy_lints_internal/src/repeated_is_diagnostic_item.rs +++ b/clippy_lints_internal/src/repeated_is_diagnostic_item.rs @@ -541,7 +541,7 @@ fn extract_nested_is_diag_item<'tcx>( cx: &LateContext<'tcx>, cond: &'tcx Expr<'_>, ) -> Option<(Span, (&'tcx Expr<'tcx>, &'tcx Expr<'tcx>, &'tcx Expr<'tcx>))> { - for_each_expr(cx, cond, |cond_part| { + for_each_expr(cx.tcx, cond, |cond_part| { if let Some(res) = extract_is_diag_item(cx, cond_part) { ControlFlow::Break((cond_part.span, res)) } else { @@ -554,7 +554,7 @@ fn extract_nested_is_diagnostic_item<'tcx>( cx: &LateContext<'tcx>, cond: &'tcx Expr<'_>, ) -> Option<(Span, (&'tcx Expr<'tcx>, &'tcx Expr<'tcx>, &'tcx Expr<'tcx>))> { - for_each_expr(cx, cond, |cond_part| { + for_each_expr(cx.tcx, cond, |cond_part| { if let Some(res) = extract_is_diagnostic_item(cx, cond_part) { ControlFlow::Break((cond_part.span, res)) } else { diff --git a/clippy_utils/src/msrvs.rs b/clippy_utils/src/msrvs.rs index daf9de05a2948..d9b34ebfe21e4 100644 --- a/clippy_utils/src/msrvs.rs +++ b/clippy_utils/src/msrvs.rs @@ -119,7 +119,7 @@ impl Msrv { /// nodes for that attribute, prefer to run this check after cheaper pattern matching operations pub fn current(self, cx: &LateContext<'_>) -> Option { if SEEN_MSRV_ATTR.load(Ordering::Relaxed) { - self.from_attrs(cx.tcx, cx.last_node_with_lint_attrs) + self.for_attrs(cx.tcx, cx.last_node_with_lint_attrs) } else { self.0 } @@ -131,13 +131,13 @@ impl Msrv { /// nodes for that attribute, prefer to run this check after cheaper pattern matching operations pub fn at(self, tcx: TyCtxt<'_>, node: HirId) -> Option { if SEEN_MSRV_ATTR.load(Ordering::Relaxed) { - self.from_attrs(tcx, node) + self.for_attrs(tcx, node) } else { self.0 } } - fn from_attrs(self, tcx: TyCtxt<'_>, node: HirId) -> Option { + fn for_attrs(self, tcx: TyCtxt<'_>, node: HirId) -> Option { once(node) .chain(tcx.hir_parent_id_iter(node)) .find_map(|id| parse_attrs(tcx.sess, tcx.hir_attrs(id))) diff --git a/clippy_utils/src/usage.rs b/clippy_utils/src/usage.rs index 4a1d24024915b..d644cd5a4aace 100644 --- a/clippy_utils/src/usage.rs +++ b/clippy_utils/src/usage.rs @@ -195,7 +195,7 @@ pub fn contains_return_break_continue_macro(expression: &Expr<'_>) -> bool { } pub fn local_used_in<'tcx>(cx: &LateContext<'tcx>, local_id: HirId, v: impl Visitable<'tcx>) -> bool { - for_each_expr(cx, v, |e| { + for_each_expr(cx.tcx, v, |e| { if e.res_local_id() == Some(local_id) { ControlFlow::Break(()) } else { @@ -220,7 +220,7 @@ pub fn local_used_after_expr(cx: &LateContext<'_>, local_id: HirId, after: &Expr let loop_start = get_enclosing_loop_or_multi_call_closure(cx, after).map(|e| e.hir_id); let mut past_expr = false; - for_each_expr(cx, block, |e| { + for_each_expr(cx.tcx, block, |e| { if past_expr { if e.res_local_id() == Some(local_id) { ControlFlow::Break(()) diff --git a/clippy_utils/src/visitors.rs b/clippy_utils/src/visitors.rs index 749c8c02a84b5..ca34d4a831c91 100644 --- a/clippy_utils/src/visitors.rs +++ b/clippy_utils/src/visitors.rs @@ -145,7 +145,7 @@ pub fn for_each_expr_without_closures<'tcx, B, C: Continue>( /// Calls the given function once for each expression contained. This will enter bodies, but not /// nested items. pub fn for_each_expr<'tcx, B, C: Continue>( - cx: &LateContext<'tcx>, + tcx: TyCtxt<'tcx>, node: impl Visitable<'tcx>, f: impl FnMut(&'tcx Expr<'tcx>) -> ControlFlow, ) -> Option { @@ -188,7 +188,7 @@ pub fn for_each_expr<'tcx, B, C: Continue>( ControlFlow::Continue(()) } } - let mut v = V { tcx: cx.tcx, f }; + let mut v = V { tcx, f }; node.visit(&mut v).break_value() } @@ -299,7 +299,7 @@ where /// Checks if the given resolved path is used in the given body. pub fn is_res_used(cx: &LateContext<'_>, res: Res, body: BodyId) -> bool { - for_each_expr(cx, cx.tcx.hir_body(body).value, |e| { + for_each_expr(cx.tcx, cx.tcx.hir_body(body).value, |e| { if let ExprKind::Path(p) = &e.kind && cx.qpath_res(p, e.hir_id) == res { @@ -312,7 +312,7 @@ pub fn is_res_used(cx: &LateContext<'_>, res: Res, body: BodyId) -> bool { /// Checks if the given local is used. pub fn is_local_used<'tcx>(cx: &LateContext<'tcx>, visitable: impl Visitable<'tcx>, id: HirId) -> bool { - for_each_expr(cx, visitable, |e| { + for_each_expr(cx.tcx, visitable, |e| { if e.res_local_id() == Some(id) { ControlFlow::Break(()) } else { @@ -785,7 +785,7 @@ pub fn local_used_once<'tcx>( ) -> Option<&'tcx Expr<'tcx>> { let mut expr = None; - let cf = for_each_expr(cx, visitable, |e| { + let cf = for_each_expr(cx.tcx, visitable, |e| { if e.res_local_id() == Some(id) && expr.replace(e).is_some() { ControlFlow::Break(()) } else { From 9deffbde3bc5861ca27406ad77d261bd24a1ade2 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Fri, 12 Jun 2026 10:29:16 -0400 Subject: [PATCH 57/77] Use `for_each_expr` in `is_const_evaluable`. --- clippy_utils/src/visitors.rs | 136 +++++++++++++++-------------------- 1 file changed, 58 insertions(+), 78 deletions(-) diff --git a/clippy_utils/src/visitors.rs b/clippy_utils/src/visitors.rs index ca34d4a831c91..ca1fa57cffc10 100644 --- a/clippy_utils/src/visitors.rs +++ b/clippy_utils/src/visitors.rs @@ -324,87 +324,67 @@ pub fn is_local_used<'tcx>(cx: &LateContext<'tcx>, visitable: impl Visitable<'tc /// Checks if the given expression can be evaluated as a constant at the specified node pub fn is_const_evaluatable<'tcx>(tcx: TyCtxt<'tcx>, typeck: &'tcx TypeckResults<'tcx>, e: &'tcx Expr<'_>) -> bool { - struct V<'tcx> { - tcx: TyCtxt<'tcx>, - typeck: &'tcx TypeckResults<'tcx>, - } - - impl<'tcx> Visitor<'tcx> for V<'tcx> { - type Result = ControlFlow<()>; - type NestedFilter = intravisit::nested_filter::None; - - fn visit_expr(&mut self, e: &'tcx Expr<'_>) -> Self::Result { - match e.kind { - ExprKind::ConstBlock(_) => return ControlFlow::Continue(()), - ExprKind::Call( - &Expr { - kind: ExprKind::Path(ref p), - hir_id, - .. - }, - _, - ) if self - .typeck - .qpath_res(p, hir_id) - .opt_def_id() - .is_some_and(|id| is_stable_const_fn_at(self.tcx, CRATE_HIR_ID, id, Msrv::default())) => {}, - ExprKind::MethodCall(..) - if self - .typeck - .type_dependent_def_id(e.hir_id) - .is_some_and(|id| is_stable_const_fn_at(self.tcx, CRATE_HIR_ID, id, Msrv::default())) => {}, - ExprKind::Binary(_, lhs, rhs) - if self.typeck.expr_ty(lhs).peel_refs().is_primitive_ty() - && self.typeck.expr_ty(rhs).peel_refs().is_primitive_ty() => {}, - ExprKind::Unary(UnOp::Deref, e) if self.typeck.expr_ty(e).is_raw_ptr() => (), - ExprKind::Unary(_, e) if self.typeck.expr_ty(e).peel_refs().is_primitive_ty() => (), - ExprKind::Index(base, _, _) - if matches!( - self.typeck.expr_ty(base).peel_refs().kind(), - ty::Slice(_) | ty::Array(..) - ) => {}, - ExprKind::Path(ref p) - if matches!( - self.typeck.qpath_res(p, e.hir_id), - Res::Def( - DefKind::Const { .. } - | DefKind::AssocConst { .. } - | DefKind::AnonConst - | DefKind::ConstParam - | DefKind::Ctor(..) - | DefKind::Fn - | DefKind::AssocFn, - _ - ) | Res::SelfCtor(_) - ) => {}, - - ExprKind::AddrOf(..) - | ExprKind::Array(_) - | ExprKind::Block(..) - | ExprKind::Cast(..) - | ExprKind::DropTemps(_) - | ExprKind::Field(..) - | ExprKind::If(..) - | ExprKind::Let(..) - | ExprKind::Lit(_) - | ExprKind::Match(..) - | ExprKind::Repeat(..) - | ExprKind::Struct(..) - | ExprKind::Tup(_) - | ExprKind::Type(..) - | ExprKind::UnsafeBinderCast(..) => (), - - _ => { - return ControlFlow::Break(()); + for_each_expr(tcx, e, move |e| { + match e.kind { + ExprKind::ConstBlock(_) => return ControlFlow::Continue(Descend::No), + ExprKind::Call( + &Expr { + kind: ExprKind::Path(ref p), + hir_id, + .. }, - } + _, + ) if typeck + .qpath_res(p, hir_id) + .opt_def_id() + .is_some_and(|id| is_stable_const_fn_at(tcx, CRATE_HIR_ID, id, Msrv::default())) => {}, + ExprKind::MethodCall(..) + if typeck + .type_dependent_def_id(e.hir_id) + .is_some_and(|id| is_stable_const_fn_at(tcx, CRATE_HIR_ID, id, Msrv::default())) => {}, + ExprKind::Binary(_, lhs, rhs) + if typeck.expr_ty(lhs).peel_refs().is_primitive_ty() + && typeck.expr_ty(rhs).peel_refs().is_primitive_ty() => {}, + ExprKind::Unary(UnOp::Deref, e) if typeck.expr_ty(e).is_raw_ptr() => (), + ExprKind::Unary(_, e) if typeck.expr_ty(e).peel_refs().is_primitive_ty() => (), + ExprKind::Index(base, _, _) + if matches!(typeck.expr_ty(base).peel_refs().kind(), ty::Slice(_) | ty::Array(..)) => {}, + ExprKind::Path(ref p) + if matches!( + typeck.qpath_res(p, e.hir_id), + Res::Def( + DefKind::Const { .. } + | DefKind::AssocConst { .. } + | DefKind::AnonConst + | DefKind::ConstParam + | DefKind::Ctor(..) + | DefKind::Fn + | DefKind::AssocFn, + _ + ) | Res::SelfCtor(_) + ) => {}, + + ExprKind::AddrOf(..) + | ExprKind::Array(_) + | ExprKind::Block(..) + | ExprKind::Cast(..) + | ExprKind::DropTemps(_) + | ExprKind::Field(..) + | ExprKind::If(..) + | ExprKind::Let(..) + | ExprKind::Lit(_) + | ExprKind::Match(..) + | ExprKind::Repeat(..) + | ExprKind::Struct(..) + | ExprKind::Tup(_) + | ExprKind::Type(..) + | ExprKind::UnsafeBinderCast(..) => {}, - walk_expr(self, e) + _ => return ControlFlow::Break(()), } - } - - let mut v = V { tcx, typeck }; - v.visit_expr(e).is_continue() + ControlFlow::Continue(Descend::Yes) + }) + .is_none() } /// Checks if the given expression performs an unsafe operation outside of an unsafe block. From aac767264fea18545aaeff61103f9750aa24df46 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Fri, 12 Jun 2026 11:25:01 -0400 Subject: [PATCH 58/77] Store the `ConstEvalCtxt` inside the `expr_eagerness` visitor. --- clippy_utils/src/consts.rs | 6 +- clippy_utils/src/eager_or_lazy.rs | 105 ++++++++++++++---------------- 2 files changed, 51 insertions(+), 60 deletions(-) diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs index 26aef9c1fc910..12e5adc6dfdaa 100644 --- a/clippy_utils/src/consts.rs +++ b/clippy_utils/src/consts.rs @@ -522,9 +522,9 @@ pub fn eval_int(cx: &LateContext<'_>, e: &Expr<'_>) -> Option { /// /// See the module level documentation for some context. pub struct ConstEvalCtxt<'tcx> { - tcx: TyCtxt<'tcx>, - typing_env: ty::TypingEnv<'tcx>, - typeck: &'tcx TypeckResults<'tcx>, + pub tcx: TyCtxt<'tcx>, + pub typing_env: ty::TypingEnv<'tcx>, + pub typeck: &'tcx TypeckResults<'tcx>, source: Cell, ctxt: Cell, } diff --git a/clippy_utils/src/eager_or_lazy.rs b/clippy_utils/src/eager_or_lazy.rs index 68f1d0c2bb9fd..1c133fccdb308 100644 --- a/clippy_utils/src/eager_or_lazy.rs +++ b/clippy_utils/src/eager_or_lazy.rs @@ -11,15 +11,15 @@ use crate::consts::{ConstEvalCtxt, FullInt}; use crate::sym; -use crate::ty::{all_predicates_of, is_copy}; +use crate::ty::all_predicates_of; use crate::visitors::is_const_evaluatable; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{Visitor, walk_expr}; use rustc_hir::{BinOpKind, Block, Expr, ExprKind, QPath, UnOp}; use rustc_lint::LateContext; -use rustc_middle::ty; use rustc_middle::ty::adjustment::{Adjust, DerefAdjustKind}; +use rustc_middle::ty::{self, TyCtxt}; use rustc_span::Symbol; use std::{cmp, ops}; @@ -48,17 +48,17 @@ impl ops::BitOrAssign for EagernessSuggestion { } /// Determine the eagerness of the given function call. -fn fn_eagerness(cx: &LateContext<'_>, fn_id: DefId, name: Symbol, have_one_arg: bool) -> EagernessSuggestion { +fn fn_eagerness(tcx: TyCtxt<'_>, fn_id: DefId, name: Symbol, have_one_arg: bool) -> EagernessSuggestion { use EagernessSuggestion::{Eager, Lazy, NoChange}; - let ty = match cx.tcx.impl_of_assoc(fn_id) { - Some(id) => cx.tcx.type_of(id).instantiate_identity().skip_norm_wip(), + let ty = match tcx.impl_of_assoc(fn_id) { + Some(id) => tcx.type_of(id).instantiate_identity().skip_norm_wip(), None => return Lazy, }; if (matches!(name, sym::is_empty | sym::len) || name.as_str().starts_with("as_")) && have_one_arg { if matches!( - cx.tcx.crate_name(fn_id.krate), + tcx.crate_name(fn_id.krate), sym::std | sym::core | sym::alloc | sym::proc_macro ) { Eager @@ -71,22 +71,20 @@ fn fn_eagerness(cx: &LateContext<'_>, fn_id: DefId, name: Symbol, have_one_arg: // Due to the limited operations on these types functions should be fairly cheap. if def.variants().iter().flat_map(|v| v.fields.iter()).any(|x| { matches!( - cx.tcx - .type_of(x.did) + tcx.type_of(x.did) .instantiate_identity() .skip_norm_wip() .peel_refs() .kind(), ty::Param(_) ) - }) && all_predicates_of(cx.tcx, fn_id).all(|(pred, _)| match pred.kind().skip_binder() { - ty::ClauseKind::Trait(pred) => cx.tcx.trait_def(pred.trait_ref.def_id).is_marker, + }) && all_predicates_of(tcx, fn_id).all(|(pred, _)| match pred.kind().skip_binder() { + ty::ClauseKind::Trait(pred) => tcx.trait_def(pred.trait_ref.def_id).is_marker, _ => true, }) && subs.types().all(|x| matches!(x.peel_refs().kind(), ty::Param(_))) { // Limit the function to either `(self) -> bool` or `(&self) -> bool` - match &**cx - .tcx + match &**tcx .fn_sig(fn_id) .instantiate_identity() .skip_norm_wip() @@ -104,14 +102,12 @@ fn fn_eagerness(cx: &LateContext<'_>, fn_id: DefId, name: Symbol, have_one_arg: } } -fn res_has_significant_drop(res: Res, cx: &LateContext<'_>, e: &Expr<'_>) -> bool { +fn res_has_significant_drop(res: Res, ecx: &ConstEvalCtxt<'_>, e: &Expr<'_>) -> bool { if let Res::Def(DefKind::Ctor(..) | DefKind::Variant | DefKind::Enum | DefKind::Struct, _) | Res::SelfCtor(_) | Res::SelfTyAlias { .. } = res { - cx.typeck_results() - .expr_ty(e) - .has_significant_drop(cx.tcx, cx.typing_env()) + ecx.typeck.expr_ty(e).has_significant_drop(ecx.tcx, ecx.typing_env) } else { false } @@ -119,12 +115,12 @@ fn res_has_significant_drop(res: Res, cx: &LateContext<'_>, e: &Expr<'_>) -> boo #[expect(clippy::too_many_lines)] fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessSuggestion { - struct V<'cx, 'tcx> { - cx: &'cx LateContext<'tcx>, + struct V<'tcx> { + ecx: ConstEvalCtxt<'tcx>, eagerness: EagernessSuggestion, } - impl<'tcx> Visitor<'tcx> for V<'_, 'tcx> { + impl<'tcx> Visitor<'tcx> for V<'tcx> { fn visit_expr(&mut self, e: &'tcx Expr<'_>) { use EagernessSuggestion::{ForceNoChange, Lazy, NoChange}; if self.eagerness == ForceNoChange { @@ -134,8 +130,8 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS // Autoderef through a user-defined `Deref` impl can have side-effects, // so don't suggest changing it. if self - .cx - .typeck_results() + .ecx + .typeck .expr_adjustments(e) .iter() .any(|adj| matches!(adj.kind, Adjust::Deref(DerefAdjustKind::Overloaded(_)))) @@ -152,58 +148,62 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS .. }, args, - ) => match self.cx.qpath_res(path, hir_id) { + ) => match self.ecx.typeck.qpath_res(path, hir_id) { res @ (Res::Def(DefKind::Ctor(..) | DefKind::Variant, _) | Res::SelfCtor(_)) => { - if res_has_significant_drop(res, self.cx, e) { + if res_has_significant_drop(res, &self.ecx, e) { self.eagerness = ForceNoChange; return; } }, - Res::Def(_, id) if self.cx.tcx.is_promotable_const_fn(id) => (), + Res::Def(_, id) if self.ecx.tcx.is_promotable_const_fn(id) => (), // No need to walk the arguments here, `is_const_evaluatable` already did - Res::Def(..) if is_const_evaluatable(self.cx.tcx, self.cx.typeck_results(), e) => { + Res::Def(..) if is_const_evaluatable(self.ecx.tcx, self.ecx.typeck, e) => { self.eagerness |= NoChange; return; }, Res::Def(_, id) => match path { QPath::Resolved(_, p) => { - self.eagerness |= - fn_eagerness(self.cx, id, p.segments.last().unwrap().ident.name, !args.is_empty()); + self.eagerness |= fn_eagerness( + self.ecx.tcx, + id, + p.segments.last().unwrap().ident.name, + !args.is_empty(), + ); }, QPath::TypeRelative(_, name) => { - self.eagerness |= fn_eagerness(self.cx, id, name.ident.name, !args.is_empty()); + self.eagerness |= fn_eagerness(self.ecx.tcx, id, name.ident.name, !args.is_empty()); }, }, _ => self.eagerness = Lazy, }, // No need to walk the arguments here, `is_const_evaluatable` already did - ExprKind::MethodCall(..) if is_const_evaluatable(self.cx.tcx, self.cx.typeck_results(), e) => { + ExprKind::MethodCall(..) if is_const_evaluatable(self.ecx.tcx, self.ecx.typeck, e) => { self.eagerness |= NoChange; return; }, #[expect(clippy::match_same_arms)] // arm pattern can't be merged due to `ref`, see rust#105778 ExprKind::Struct(path, ..) => { - if res_has_significant_drop(self.cx.qpath_res(path, e.hir_id), self.cx, e) { + if res_has_significant_drop(self.ecx.typeck.qpath_res(path, e.hir_id), &self.ecx, e) { self.eagerness = ForceNoChange; return; } }, ExprKind::Path(ref path) => { - if res_has_significant_drop(self.cx.qpath_res(path, e.hir_id), self.cx, e) { + if res_has_significant_drop(self.ecx.typeck.qpath_res(path, e.hir_id), &self.ecx, e) { self.eagerness = ForceNoChange; return; } }, ExprKind::MethodCall(name, ..) => { self.eagerness |= self - .cx - .typeck_results() + .ecx + .typeck .type_dependent_def_id(e.hir_id) - .map_or(Lazy, |id| fn_eagerness(self.cx, id, name.ident.name, true)); + .map_or(Lazy, |id| fn_eagerness(self.ecx.tcx, id, name.ident.name, true)); }, ExprKind::Index(_, e, _) => { - let ty = self.cx.typeck_results().expr_ty_adjusted(e); - if is_copy(self.cx, ty) && !ty.is_ref() { + let ty = self.ecx.typeck.expr_ty_adjusted(e); + if self.ecx.tcx.type_is_copy_modulo_regions(self.ecx.typing_env, ty) && !ty.is_ref() { self.eagerness |= NoChange; } else { self.eagerness = Lazy; @@ -211,24 +211,19 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS }, // `-i32::MIN` panics with overflow checks - ExprKind::Unary(UnOp::Neg, right) if ConstEvalCtxt::new(self.cx).eval(right).is_none() => { + ExprKind::Unary(UnOp::Neg, right) if self.ecx.eval(right).is_none() => { self.eagerness |= NoChange; }, // Custom `Deref` impl might have side effects - ExprKind::Unary(UnOp::Deref, e) - if self.cx.typeck_results().expr_ty(e).builtin_deref(true).is_none() => - { + ExprKind::Unary(UnOp::Deref, e) if self.ecx.typeck.expr_ty(e).builtin_deref(true).is_none() => { self.eagerness |= NoChange; }, // Dereferences should be cheap, but dereferencing a raw pointer earlier may not be safe. - ExprKind::Unary(UnOp::Deref, e) if !self.cx.typeck_results().expr_ty(e).is_raw_ptr() => (), + ExprKind::Unary(UnOp::Deref, e) if !self.ecx.typeck.expr_ty(e).is_raw_ptr() => (), ExprKind::Unary(UnOp::Deref, _) => self.eagerness |= NoChange, ExprKind::Unary(_, e) - if matches!( - self.cx.typeck_results().expr_ty(e).kind(), - ty::Bool | ty::Int(_) | ty::Uint(_), - ) => {}, + if matches!(self.ecx.typeck.expr_ty(e).kind(), ty::Bool | ty::Int(_) | ty::Uint(_),) => {}, // `>>` and `<<` panic when the right-hand side is greater than or equal to the number of bits in the // type of the left-hand side, or is negative. @@ -236,18 +231,16 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS // overflow with constants, the compiler emits an error for it and the programmer will have to fix it. // Thus, we would realistically only delay the lint. ExprKind::Binary(op, _, right) - if matches!(op.node, BinOpKind::Shl | BinOpKind::Shr) - && ConstEvalCtxt::new(self.cx).eval(right).is_none() => + if matches!(op.node, BinOpKind::Shl | BinOpKind::Shr) && self.ecx.eval(right).is_none() => { self.eagerness |= NoChange; }, ExprKind::Binary(op, left, right) if matches!(op.node, BinOpKind::Div | BinOpKind::Rem) - && let right_ty = self.cx.typeck_results().expr_ty(right) - && let ecx = ConstEvalCtxt::new(self.cx) - && let left = ecx.eval(left) - && let right = ecx.eval(right).and_then(|c| c.int_value(self.cx.tcx, right_ty)) + && let right_ty = self.ecx.typeck.expr_ty(right) + && let left = self.ecx.eval(left) + && let right = self.ecx.eval(right).and_then(|c| c.int_value(self.ecx.tcx, right_ty)) && matches!( (left, right), // `1 / x`: x might be zero @@ -265,16 +258,14 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS // error and it's good to have the eagerness warning up front when the user fixes the logic error. ExprKind::Binary(op, left, right) if matches!(op.node, BinOpKind::Add | BinOpKind::Sub | BinOpKind::Mul) - && !self.cx.typeck_results().expr_ty(e).is_floating_point() - && let ecx = ConstEvalCtxt::new(self.cx) - && (ecx.eval(left).is_none() || ecx.eval(right).is_none()) => + && !self.ecx.typeck.expr_ty(e).is_floating_point() + && (self.ecx.eval(left).is_none() || self.ecx.eval(right).is_none()) => { self.eagerness |= NoChange; }, ExprKind::Binary(_, lhs, rhs) - if self.cx.typeck_results().expr_ty(lhs).is_primitive() - && self.cx.typeck_results().expr_ty(rhs).is_primitive() => {}, + if self.ecx.typeck.expr_ty(lhs).is_primitive() && self.ecx.typeck.expr_ty(rhs).is_primitive() => {}, // Can't be moved into a closure ExprKind::Break(..) @@ -322,7 +313,7 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS } let mut v = V { - cx, + ecx: ConstEvalCtxt::new(cx), eagerness: EagernessSuggestion::Eager, }; v.visit_expr(e); From 2f89caf7dadb31ac43a4fd0141c6891ca9dc4ecb Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 12 Jun 2026 11:07:40 +1000 Subject: [PATCH 59/77] Put a box within `{Early,Late}LintPassFactory` That reflects how they're mostly used and avoids the need for some long signatures. And it matches `{Early,Late}LintPassObject` nicely. --- clippy_lints/src/lib.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 4a7659a9cc210..12d53e742f19a 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -454,7 +454,9 @@ pub fn register_lint_passes(store: &mut rustc_lint::LintStore, conf: &'static Co // NOTE: Do not add any more pre-expansion passes. These should be removed eventually. // Due to the architecture of the compiler, currently `cfg_attr` attributes on crate // level (i.e `#![cfg_attr(...)]`) will still be expanded even when using a pre-expansion pass. - store.register_pre_expansion_pass(move || Box::new(attrs::EarlyAttributes::new(conf))); + store.register_pre_expansion_pass( + Box::new(move || Box::new(attrs::EarlyAttributes::new(conf))) + ); let format_args_storage = FormatArgsStorage::default(); let attr_storage = AttrStorage::default(); From 48e7567d86742f5513ea61ee81e47595a983bad6 Mon Sep 17 00:00:00 2001 From: xmakro Date: Fri, 12 Jun 2026 15:42:38 -0700 Subject: [PATCH 60/77] perf: skip tokenizing in span_contains_cfg when no '#' is present --- clippy_utils/src/attrs.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/clippy_utils/src/attrs.rs b/clippy_utils/src/attrs.rs index 2341007cd49e8..ac727bf817ab1 100644 --- a/clippy_utils/src/attrs.rs +++ b/clippy_utils/src/attrs.rs @@ -108,6 +108,11 @@ pub fn has_non_exhaustive_attr(tcx: TyCtxt<'_>, adt: AdtDef<'_>) -> bool { /// Checks whether the given span contains a `#[cfg(..)]` attribute pub fn span_contains_cfg(cx: &LateContext<'_>, s: Span) -> bool { s.check_text(cx, |src| { + // PERF: A `#[cfg]` needs a literal `#`, so skip the lexer when the source has none. + if !src.contains('#') { + return false; + } + let mut iter = tokenize_with_text(src); // Search for the token sequence [`#`, `[`, `cfg`] From 161d0e2f23b37650de412f708bf2a105193e77e7 Mon Sep 17 00:00:00 2001 From: Gri-ffin Date: Fri, 19 Jun 2026 09:31:45 +0100 Subject: [PATCH 61/77] avoid const eval in items with impossible bounds --- clippy_utils/src/consts.rs | 19 ++++++++++++------- tests/ui/crashes/ice-16950.rs | 1 - 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs index 5b74abdb69ff1..148f89d3e918a 100644 --- a/clippy_utils/src/consts.rs +++ b/clippy_utils/src/consts.rs @@ -885,17 +885,22 @@ impl<'tcx> ConstEvalCtxt<'tcx> { _ => return None, }; - let args = self.typeck.node_args(id); - // We must use the const's own TypingEnv here. - // If we rely on the caller, a 'where Self: Sized' bound - // could trick us into thinking an unsized type is safe, triggering ICE later. - let const_typing_env = ty::TypingEnv::post_analysis(self.tcx, did); - if args.types().any(|ty| !ty.is_sized(self.tcx, const_typing_env)) { + let owner_def_id = self.typeck.hir_owner.def_id.to_def_id(); + let identity_args = ty::GenericArgs::identity_for_item(self.tcx, owner_def_id); + // Don't try to fully evaluate consts inside code whose bounds can't be satisfied. + if self + .tcx + .instantiate_and_check_impossible_predicates((owner_def_id, identity_args)) + { return None; } self.tcx - .const_eval_resolve(self.typing_env, mir::UnevaluatedConst::new(did, args), qpath.span()) + .const_eval_resolve( + self.typing_env, + mir::UnevaluatedConst::new(did, self.typeck.node_args(id)), + qpath.span(), + ) .ok() } diff --git a/tests/ui/crashes/ice-16950.rs b/tests/ui/crashes/ice-16950.rs index 7e3d979edea3e..414b34ebed348 100644 --- a/tests/ui/crashes/ice-16950.rs +++ b/tests/ui/crashes/ice-16950.rs @@ -1,6 +1,5 @@ //@check-pass #![feature(trivial_bounds)] -#![allow(dead_code)] struct Helper(T); From 7cfa29252b430c4a2349952673039ef56622e3d5 Mon Sep 17 00:00:00 2001 From: Gri-ffin Date: Fri, 19 Jun 2026 14:11:00 +0100 Subject: [PATCH 62/77] only check impossible bounds for generic const accesses --- clippy_utils/src/consts.rs | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs index 148f89d3e918a..f1ea32f5569a8 100644 --- a/clippy_utils/src/consts.rs +++ b/clippy_utils/src/consts.rs @@ -885,22 +885,22 @@ impl<'tcx> ConstEvalCtxt<'tcx> { _ => return None, }; - let owner_def_id = self.typeck.hir_owner.def_id.to_def_id(); - let identity_args = ty::GenericArgs::identity_for_item(self.tcx, owner_def_id); - // Don't try to fully evaluate consts inside code whose bounds can't be satisfied. - if self - .tcx - .instantiate_and_check_impossible_predicates((owner_def_id, identity_args)) - { - return None; + let args = self.typeck.node_args(id); + + if !args.is_empty() { + let owner_def_id = self.typeck.hir_owner.def_id.to_def_id(); + let identity_args = ty::GenericArgs::identity_for_item(self.tcx, owner_def_id); + // Don't try to fully evaluate consts inside code whose bounds can't be satisfied. + if self + .tcx + .instantiate_and_check_impossible_predicates((owner_def_id, identity_args)) + { + return None; + } } self.tcx - .const_eval_resolve( - self.typing_env, - mir::UnevaluatedConst::new(did, self.typeck.node_args(id)), - qpath.span(), - ) + .const_eval_resolve(self.typing_env, mir::UnevaluatedConst::new(did, args), qpath.span()) .ok() } From 642f0e3c89c40d64c1609b6cfc7b15518cfeb003 Mon Sep 17 00:00:00 2001 From: xmakro Date: Fri, 12 Jun 2026 15:07:55 -0700 Subject: [PATCH 63/77] perf: skip match_same_arms work when the lint is allowed --- clippy_lints/src/matches/mod.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/clippy_lints/src/matches/mod.rs b/clippy_lints/src/matches/mod.rs index 02b2d11d8aa61..459c2bf1fef73 100644 --- a/clippy_lints/src/matches/mod.rs +++ b/clippy_lints/src/matches/mod.rs @@ -27,7 +27,9 @@ mod wild_in_or_pats; use clippy_config::Conf; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::SpanExt; -use clippy_utils::{higher, is_direct_expn_of, is_in_const_context, is_span_match, sym, tokenize_with_text}; +use clippy_utils::{ + higher, is_direct_expn_of, is_in_const_context, is_lint_allowed, is_span_match, sym, tokenize_with_text, +}; use rustc_hir::{Arm, Expr, ExprKind, LetStmt, MatchSource, Pat, PatKind}; use rustc_lexer::{TokenKind, is_whitespace}; use rustc_lint::{LateContext, LateLintPass, LintContext}; @@ -1107,9 +1109,9 @@ impl<'tcx> LateLintPass<'tcx> for Matches { && !has_cfg { if source == MatchSource::Normal { - if !(self.msrv.meets(cx, msrvs::MATCHES_MACRO) - && match_like_matches::check_match(cx, expr, ex, arms)) - { + let is_match_like_matches = self.msrv.meets(cx, msrvs::MATCHES_MACRO) + && match_like_matches::check_match(cx, expr, ex, arms); + if !(is_match_like_matches || is_lint_allowed(cx, MATCH_SAME_ARMS, expr.hir_id)) { match_same_arms::check(cx, arms); } From dbfa2c3637661d8e0c9f9ea8fa61a39bc184cc9a Mon Sep 17 00:00:00 2001 From: xmakro Date: Fri, 12 Jun 2026 15:21:41 -0700 Subject: [PATCH 64/77] perf: run structural checks before const context queries in question_mark, manual_clamp and ranges --- clippy_lints/src/manual_clamp.rs | 30 +++++++++++++---- clippy_lints/src/question_mark.rs | 9 +++++- clippy_lints/src/ranges.rs | 53 +++++++++++++++++-------------- 3 files changed, 61 insertions(+), 31 deletions(-) diff --git a/clippy_lints/src/manual_clamp.rs b/clippy_lints/src/manual_clamp.rs index 6848af7748f3f..60ef785177485 100644 --- a/clippy_lints/src/manual_clamp.rs +++ b/clippy_lints/src/manual_clamp.rs @@ -140,7 +140,13 @@ struct InputMinMax<'tcx> { impl<'tcx> LateLintPass<'tcx> for ManualClamp { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { - if !expr.span.from_expansion() && !is_in_const_context(cx) { + // Cheap kind check before the costlier const context query. + if matches!( + expr.kind, + ExprKind::If(..) | ExprKind::Match(..) | ExprKind::MethodCall(..) | ExprKind::Call(..) + ) && !expr.span.from_expansion() + && !is_in_const_context(cx) + { let suggestion = is_if_elseif_else_pattern(cx, expr) .or_else(|| is_max_min_pattern(cx, expr)) .or_else(|| is_call_max_min_pattern(cx, expr)) @@ -155,6 +161,15 @@ impl<'tcx> LateLintPass<'tcx> for ManualClamp { } fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) { + // Cheap `if`-statement check before the costlier const context query. + if !block + .stmts + .iter() + .any(|stmt| matches!(stmt.kind, StmtKind::Expr(e) if matches!(e.kind, ExprKind::If(..)))) + { + return; + } + if is_in_const_context(cx) || !self.msrv.meets(cx, msrvs::CLAMP) { return; } @@ -293,18 +308,19 @@ fn is_if_elseif_else_pattern<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx /// ``` fn is_max_min_pattern<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option> { if let ExprKind::MethodCall(seg_second, receiver, [arg_second], _) = expr.kind + && let ExprKind::MethodCall(seg_first, input, [arg_first], _) = &receiver.kind + // Match method names before the costlier type queries. + && let Some((min, max)) = match (seg_first.ident.name, seg_second.ident.name) { + (sym::min, sym::max) => Some((arg_second, arg_first)), + (sym::max, sym::min) => Some((arg_first, arg_second)), + _ => None, + } && (cx.typeck_results().expr_ty_adjusted(receiver).is_floating_point() || cx.ty_based_def(expr).assoc_fn_parent(cx).is_diag_item(cx, sym::Ord)) - && let ExprKind::MethodCall(seg_first, input, [arg_first], _) = &receiver.kind && (cx.typeck_results().expr_ty_adjusted(input).is_floating_point() || cx.ty_based_def(receiver).assoc_fn_parent(cx).is_diag_item(cx, sym::Ord)) { let is_float = cx.typeck_results().expr_ty_adjusted(input).is_floating_point(); - let (min, max) = match (seg_first.ident.name, seg_second.ident.name) { - (sym::min, sym::max) => (arg_second, arg_first), - (sym::max, sym::min) => (arg_first, arg_second), - _ => return None, - }; Some(ClampSuggestion { params: InputMinMax { input, diff --git a/clippy_lints/src/question_mark.rs b/clippy_lints/src/question_mark.rs index cbfd1af1907b7..7f95adba870d7 100644 --- a/clippy_lints/src/question_mark.rs +++ b/clippy_lints/src/question_mark.rs @@ -629,6 +629,11 @@ fn is_inferred_ret_closure(expr: &Expr<'_>) -> bool { impl<'tcx> LateLintPass<'tcx> for QuestionMark { fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) { + // Cheap `let` check before the costlier lint level and const context queries. + if !matches!(stmt.kind, StmtKind::Let(..)) { + return; + } + if !is_lint_allowed(cx, QUESTION_MARK_USED, stmt.hir_id) || !self.msrv.meets(cx, msrvs::QUESTION_MARK_OPERATOR) { return; @@ -646,7 +651,9 @@ impl<'tcx> LateLintPass<'tcx> for QuestionMark { return; } - if !self.inside_try_block() + // Cheap `if`/`match` check before the costlier lint level and const context queries. + if matches!(expr.kind, ExprKind::If(..) | ExprKind::Match(..)) + && !self.inside_try_block() && !is_in_const_context(cx) && is_lint_allowed(cx, QUESTION_MARK_USED, expr.hir_id) && self.msrv.meets(cx, msrvs::QUESTION_MARK_OPERATOR) diff --git a/clippy_lints/src/ranges.rs b/clippy_lints/src/ranges.rs index 71965ee1e29f9..cd0b02940d068 100644 --- a/clippy_lints/src/ranges.rs +++ b/clippy_lints/src/ranges.rs @@ -191,14 +191,21 @@ impl Ranges { impl<'tcx> LateLintPass<'tcx> for Ranges { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if let ExprKind::Binary(ref op, l, r) = expr.kind + && matches!( + op.node, + BinOpKind::And | BinOpKind::BitAnd | BinOpKind::Or | BinOpKind::BitOr + ) && self.msrv.meets(cx, msrvs::RANGE_CONTAINS) + && !is_in_const_context(cx) { check_possible_range_contains(cx, op.node, l, r, expr, expr.span); } - check_exclusive_range_plus_one(cx, expr); - check_inclusive_range_minus_one(cx, expr); - check_reversed_empty_range(cx, expr); + if let Some(range) = higher::Range::hir(cx, expr) { + check_exclusive_range_plus_one(cx, expr, &range); + check_inclusive_range_minus_one(cx, expr, &range); + check_reversed_empty_range(cx, expr, &range); + } } } @@ -210,10 +217,6 @@ fn check_possible_range_contains( expr: &Expr<'_>, span: Span, ) { - if is_in_const_context(cx) { - return; - } - let combine_and = match op { BinOpKind::And | BinOpKind::BitAnd => true, BinOpKind::Or | BinOpKind::BitOr => false, @@ -481,54 +484,58 @@ fn can_switch_ranges<'tcx>( } // exclusive range plus one: `x..(y+1)` -fn check_exclusive_range_plus_one<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { +fn check_exclusive_range_plus_one<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, range: &higher::Range<'tcx>) { check_range_switch( cx, expr, + range, RangeLimits::HalfOpen, y_plus_one, RANGE_PLUS_ONE, "an inclusive range would be more readable", - "..=", ); } // inclusive range minus one: `x..=(y-1)` -fn check_inclusive_range_minus_one<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { +fn check_inclusive_range_minus_one<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, range: &higher::Range<'tcx>) { check_range_switch( cx, expr, + range, RangeLimits::Closed, y_minus_one, RANGE_MINUS_ONE, "an exclusive range would be more readable", - "..", ); } /// Check for a `kind` of range in `expr`, check for `predicate` on the end, -/// and emit the `lint` with `msg` and the `operator`. +/// and emit the `lint` with `msg`, suggesting the opposite range limits. fn check_range_switch<'tcx>( cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, + range: &higher::Range<'tcx>, kind: RangeLimits, predicate: impl for<'hir> FnOnce(&Expr<'hir>) -> Option<&'hir Expr<'hir>>, lint: &'static Lint, msg: &'static str, - operator: &str, ) { - if let Some(range) = higher::Range::hir(cx, expr) - && let higher::Range { - start, - end: Some(end), - limits, - span, - } = range + if let higher::Range { + start, + end: Some(end), + limits, + span, + } = *range && span.can_be_used_for_suggestions() && limits == kind && let Some(y) = predicate(end) && can_switch_ranges(cx, span.ctxt(), expr, kind, cx.typeck_results().expr_ty(y)) { + // Suggest the opposite range limits to the ones being checked. + let operator = match kind { + RangeLimits::HalfOpen => "..=", + RangeLimits::Closed => "..", + }; span_lint_and_then(cx, lint, span, msg, |diag| { let mut app = Applicability::MachineApplicable; let start = start.map_or(String::new(), |x| { @@ -550,7 +557,7 @@ fn check_range_switch<'tcx>( } } -fn check_reversed_empty_range(cx: &LateContext<'_>, expr: &Expr<'_>) { +fn check_reversed_empty_range(cx: &LateContext<'_>, expr: &Expr<'_>, range: &higher::Range<'_>) { fn inside_indexing_expr(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { matches!( get_parent_expr(cx, expr), @@ -580,12 +587,12 @@ fn check_reversed_empty_range(cx: &LateContext<'_>, expr: &Expr<'_>) { } } - if let Some(higher::Range { + if let higher::Range { start: Some(start), end: Some(end), limits, span, - }) = higher::Range::hir(cx, expr) + } = *range && let ty = cx.typeck_results().expr_ty(start) && let ty::Int(_) | ty::Uint(_) = ty.kind() && let ecx = ConstEvalCtxt::new(cx) From 6423f06385c3ea91614b536ddda156db8b56ff09 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Fri, 19 Jun 2026 17:12:37 -0700 Subject: [PATCH 65/77] Treat `!` the same as `-` in `unnecessary_cast` This change improves some of the suggestions, fixes the handling of precedence, and prevents it from removing the `as` cast when that's ambiguous. --- clippy_lints/src/casts/unnecessary_cast.rs | 4 +- tests/ui/unnecessary_cast-11882.fixed | 93 +++++++++++++ tests/ui/unnecessary_cast-11882.rs | 93 +++++++++++++ tests/ui/unnecessary_cast-11882.stderr | 149 +++++++++++++++++++++ 4 files changed, 337 insertions(+), 2 deletions(-) create mode 100644 tests/ui/unnecessary_cast-11882.fixed create mode 100644 tests/ui/unnecessary_cast-11882.rs create mode 100644 tests/ui/unnecessary_cast-11882.stderr diff --git a/clippy_lints/src/casts/unnecessary_cast.rs b/clippy_lints/src/casts/unnecessary_cast.rs index 83a6cab01f9d9..c14bd056de393 100644 --- a/clippy_lints/src/casts/unnecessary_cast.rs +++ b/clippy_lints/src/casts/unnecessary_cast.rs @@ -232,7 +232,7 @@ fn lint_unnecessary_cast( // (-1).foo() instead of -1.foo()) let sugg = if let Some(parent_expr) = get_parent_expr(cx, expr) && let ExprKind::MethodCall(..) = parent_expr.kind - && literal_str.starts_with('-') + && literal_str.starts_with(['-', '!']) { format!("({literal_str}_{cast_to})") } else { @@ -253,7 +253,7 @@ fn lint_unnecessary_cast( fn get_numeric_literal<'e>(expr: &'e Expr<'e>) -> Option { match expr.kind { ExprKind::Lit(lit) => Some(lit), - ExprKind::Unary(UnOp::Neg, e) => { + ExprKind::Unary(UnOp::Neg | UnOp::Not, e) => { if let ExprKind::Lit(lit) = e.kind { Some(lit) } else { diff --git a/tests/ui/unnecessary_cast-11882.fixed b/tests/ui/unnecessary_cast-11882.fixed new file mode 100644 index 0000000000000..6b2949248d8d1 --- /dev/null +++ b/tests/ui/unnecessary_cast-11882.fixed @@ -0,0 +1,93 @@ +//@ignore-bitwidth: 32 +#![feature(const_trait_impl, const_ops)] +#![warn(clippy::unnecessary_cast)] +#![allow(unused, clippy::identity_op)] + +const TEST: u64 = (!0_u64).overflowing_shr(1_u32).0; +//~^ unnecessary_cast +const TEST2: u64 = (!0_u64).overflowing_shr(1_u32).0; +//~^ unnecessary_cast +const TEST3: u64 = (not(0) as u64).overflowing_shr(1_u32).0; +const TEST4: u64 = not(0_u64).overflowing_shr(1_u32).0; +//~^ unnecessary_cast +const TEST5: u64 = (!not(!0_u64)).overflowing_shr(1_u32).0; +//~^ unnecessary_cast +const TEST6: u64 = 0xff_ff_ff_ff_ff_ff_ff_ff_u64.overflowing_shr(1_u32).0; +//~^ unnecessary_cast +const TEST7: u64 = (!0_u64 + 0).overflowing_shr(1_u32).0; +//~^ unnecessary_cast +const TEST8: u64 = (!(0_u64 + 0)).overflowing_shr(1_u32).0; +//~^ unnecessary_cast +const TEST9: u64 = (!((0 + 0) as u64)).overflowing_shr(1_u32).0; + +const CHK1: u64 = not(!0_u64).overflowing_shr(1_u32).0; +//~^ unnecessary_cast +const CHK2: u64 = (not(!0) as u64).overflowing_shr(1_u32).0; +const CHK3: u64 = (!not(0) as u64).overflowing_shr(1_u32).0; +const CHK4: u64 = (!not(0_u64)).overflowing_shr(1_u32).0; +//~^ unnecessary_cast +const CHK5: u64 = not(!0_u64).overflowing_shr(1_u32).0; +//~^ unnecessary_cast +const CHK6: u64 = (!(not(0) as u64)).overflowing_shr(1_u32).0; +const CHK7: u64 = (!not(0_u64)).overflowing_shr(1_u32).0; +//~^ unnecessary_cast +const CHK8: u64 = not(!0_u64 + 0).overflowing_shr(1_u32).0; +//~^ unnecessary_cast + +fn main() { + // make sure that the calculated value doesn't change + let _x: [(); 0x7f_ff_ff_ff_ff_ff_ff_ff] = [(); TEST as usize]; + let _x: [(); 0x7f_ff_ff_ff_ff_ff_ff_ff] = [(); TEST2 as usize]; + let _x: [(); 0x7f_ff_ff_ff_ff_ff_ff_ff] = [(); TEST3 as usize]; + let _x: [(); 0x7f_ff_ff_ff_ff_ff_ff_ff] = [(); TEST4 as usize]; + let _x: [(); 0x7f_ff_ff_ff_ff_ff_ff_ff] = [(); TEST5 as usize]; + let _x: [(); 0x7f_ff_ff_ff_ff_ff_ff_ff] = [(); TEST6 as usize]; + let _x: [(); 0x7f_ff_ff_ff_ff_ff_ff_ff] = [(); TEST7 as usize]; + let _x: [(); 0x7f_ff_ff_ff_ff_ff_ff_ff] = [(); TEST8 as usize]; + let _x: [(); 0x7f_ff_ff_ff_ff_ff_ff_ff] = [(); TEST9 as usize]; + + let _x: [(); 0] = [(); CHK1 as usize]; + let _x: [(); 0] = [(); CHK2 as usize]; + let _x: [(); 0] = [(); CHK3 as usize]; + let _x: [(); 0] = [(); CHK4 as usize]; + let _x: [(); 0] = [(); CHK5 as usize]; + let _x: [(); 0] = [(); CHK6 as usize]; + let _x: [(); 0] = [(); CHK7 as usize]; + let _x: [(); 0] = [(); CHK8 as usize]; + + // the non-const version of the tests + let test: u64 = (!0_u64).overflowing_shr(1_u32).0; + //~^ unnecessary_cast + let test2: u64 = (!0_u64).overflowing_shr(1_u32).0; + //~^ unnecessary_cast + let test3: u64 = (not(0) as u64).overflowing_shr(1_u32).0; + let test4: u64 = not(0_u64).overflowing_shr(1_u32).0; + //~^ unnecessary_cast + let test5: u64 = (!not(!0_u64)).overflowing_shr(1_u32).0; + //~^ unnecessary_cast + let test6: u64 = 0xff_ff_ff_ff_ff_ff_ff_ff_u64.overflowing_shr(1_u32).0; + //~^ unnecessary_cast + let test7: u64 = (!0_u64 + 0).overflowing_shr(1_u32).0; + //~^ unnecessary_cast + let test8: u64 = (!(0_u64 + 0)).overflowing_shr(1_u32).0; + //~^ unnecessary_cast + let test9: u64 = (!((0 + 0) as u64)).overflowing_shr(1_u32).0; + + let chk1: u64 = not(!0_u64).overflowing_shr(1_u32).0; + //~^ unnecessary_cast + let chk2: u64 = (not(!0) as u64).overflowing_shr(1_u32).0; + let chk3: u64 = (!not(0) as u64).overflowing_shr(1_u32).0; + let chk4: u64 = (!not(0_u64)).overflowing_shr(1_u32).0; + //~^ unnecessary_cast + let chk5: u64 = not(!0_u64).overflowing_shr(1_u32).0; + //~^ unnecessary_cast + let chk6: u64 = (!(not(0) as u64)).overflowing_shr(1_u32).0; + let chk7: u64 = (!not(0_u64)).overflowing_shr(1_u32).0; + //~^ unnecessary_cast + let chk8: u64 = not(!0_u64 + 0).overflowing_shr(1_u32).0; + //~^ unnecessary_cast +} + +const fn not>(x: T) -> T { + !x +} diff --git a/tests/ui/unnecessary_cast-11882.rs b/tests/ui/unnecessary_cast-11882.rs new file mode 100644 index 0000000000000..d8028308755f0 --- /dev/null +++ b/tests/ui/unnecessary_cast-11882.rs @@ -0,0 +1,93 @@ +//@ignore-bitwidth: 32 +#![feature(const_trait_impl, const_ops)] +#![warn(clippy::unnecessary_cast)] +#![allow(unused, clippy::identity_op)] + +const TEST: u64 = (!0 as u64).overflowing_shr(1_u32).0; +//~^ unnecessary_cast +const TEST2: u64 = (!0_u64 as u64).overflowing_shr(1_u32).0; +//~^ unnecessary_cast +const TEST3: u64 = (not(0) as u64).overflowing_shr(1_u32).0; +const TEST4: u64 = (not(0_u64) as u64).overflowing_shr(1_u32).0; +//~^ unnecessary_cast +const TEST5: u64 = (!not(!0_u64) as u64).overflowing_shr(1_u32).0; +//~^ unnecessary_cast +const TEST6: u64 = (0xff_ff_ff_ff_ff_ff_ff_ff as u64).overflowing_shr(1_u32).0; +//~^ unnecessary_cast +const TEST7: u64 = (!0 as u64 + 0).overflowing_shr(1_u32).0; +//~^ unnecessary_cast +const TEST8: u64 = (!(0 as u64 + 0)).overflowing_shr(1_u32).0; +//~^ unnecessary_cast +const TEST9: u64 = (!((0 + 0) as u64)).overflowing_shr(1_u32).0; + +const CHK1: u64 = not(!0 as u64).overflowing_shr(1_u32).0; +//~^ unnecessary_cast +const CHK2: u64 = (not(!0) as u64).overflowing_shr(1_u32).0; +const CHK3: u64 = (!not(0) as u64).overflowing_shr(1_u32).0; +const CHK4: u64 = (!not(0_u64) as u64).overflowing_shr(1_u32).0; +//~^ unnecessary_cast +const CHK5: u64 = (not(!0_u64) as u64).overflowing_shr(1_u32).0; +//~^ unnecessary_cast +const CHK6: u64 = (!(not(0) as u64)).overflowing_shr(1_u32).0; +const CHK7: u64 = (!not(0 as u64)).overflowing_shr(1_u32).0; +//~^ unnecessary_cast +const CHK8: u64 = not(!0 as u64 + 0).overflowing_shr(1_u32).0; +//~^ unnecessary_cast + +fn main() { + // make sure that the calculated value doesn't change + let _x: [(); 0x7f_ff_ff_ff_ff_ff_ff_ff] = [(); TEST as usize]; + let _x: [(); 0x7f_ff_ff_ff_ff_ff_ff_ff] = [(); TEST2 as usize]; + let _x: [(); 0x7f_ff_ff_ff_ff_ff_ff_ff] = [(); TEST3 as usize]; + let _x: [(); 0x7f_ff_ff_ff_ff_ff_ff_ff] = [(); TEST4 as usize]; + let _x: [(); 0x7f_ff_ff_ff_ff_ff_ff_ff] = [(); TEST5 as usize]; + let _x: [(); 0x7f_ff_ff_ff_ff_ff_ff_ff] = [(); TEST6 as usize]; + let _x: [(); 0x7f_ff_ff_ff_ff_ff_ff_ff] = [(); TEST7 as usize]; + let _x: [(); 0x7f_ff_ff_ff_ff_ff_ff_ff] = [(); TEST8 as usize]; + let _x: [(); 0x7f_ff_ff_ff_ff_ff_ff_ff] = [(); TEST9 as usize]; + + let _x: [(); 0] = [(); CHK1 as usize]; + let _x: [(); 0] = [(); CHK2 as usize]; + let _x: [(); 0] = [(); CHK3 as usize]; + let _x: [(); 0] = [(); CHK4 as usize]; + let _x: [(); 0] = [(); CHK5 as usize]; + let _x: [(); 0] = [(); CHK6 as usize]; + let _x: [(); 0] = [(); CHK7 as usize]; + let _x: [(); 0] = [(); CHK8 as usize]; + + // the non-const version of the tests + let test: u64 = (!0 as u64).overflowing_shr(1_u32).0; + //~^ unnecessary_cast + let test2: u64 = (!0_u64 as u64).overflowing_shr(1_u32).0; + //~^ unnecessary_cast + let test3: u64 = (not(0) as u64).overflowing_shr(1_u32).0; + let test4: u64 = (not(0_u64) as u64).overflowing_shr(1_u32).0; + //~^ unnecessary_cast + let test5: u64 = (!not(!0_u64) as u64).overflowing_shr(1_u32).0; + //~^ unnecessary_cast + let test6: u64 = (0xff_ff_ff_ff_ff_ff_ff_ff as u64).overflowing_shr(1_u32).0; + //~^ unnecessary_cast + let test7: u64 = (!0 as u64 + 0).overflowing_shr(1_u32).0; + //~^ unnecessary_cast + let test8: u64 = (!(0 as u64 + 0)).overflowing_shr(1_u32).0; + //~^ unnecessary_cast + let test9: u64 = (!((0 + 0) as u64)).overflowing_shr(1_u32).0; + + let chk1: u64 = not(!0 as u64).overflowing_shr(1_u32).0; + //~^ unnecessary_cast + let chk2: u64 = (not(!0) as u64).overflowing_shr(1_u32).0; + let chk3: u64 = (!not(0) as u64).overflowing_shr(1_u32).0; + let chk4: u64 = (!not(0_u64) as u64).overflowing_shr(1_u32).0; + //~^ unnecessary_cast + let chk5: u64 = (not(!0_u64) as u64).overflowing_shr(1_u32).0; + //~^ unnecessary_cast + let chk6: u64 = (!(not(0) as u64)).overflowing_shr(1_u32).0; + let chk7: u64 = (!not(0 as u64)).overflowing_shr(1_u32).0; + //~^ unnecessary_cast + let chk8: u64 = not(!0 as u64 + 0).overflowing_shr(1_u32).0; + //~^ unnecessary_cast +} + +const fn not>(x: T) -> T { + !x +} diff --git a/tests/ui/unnecessary_cast-11882.stderr b/tests/ui/unnecessary_cast-11882.stderr new file mode 100644 index 0000000000000..056f04c65ed35 --- /dev/null +++ b/tests/ui/unnecessary_cast-11882.stderr @@ -0,0 +1,149 @@ +error: casting integer literal to `u64` is unnecessary + --> tests/ui/unnecessary_cast-11882.rs:6:19 + | +LL | const TEST: u64 = (!0 as u64).overflowing_shr(1_u32).0; + | ^^^^^^^^^^^ help: try: `(!0_u64)` + | + = note: `-D clippy::unnecessary-cast` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unnecessary_cast)]` + +error: casting to the same type is unnecessary (`u64` -> `u64`) + --> tests/ui/unnecessary_cast-11882.rs:8:20 + | +LL | const TEST2: u64 = (!0_u64 as u64).overflowing_shr(1_u32).0; + | ^^^^^^^^^^^^^^^ help: try: `(!0_u64)` + +error: casting to the same type is unnecessary (`u64` -> `u64`) + --> tests/ui/unnecessary_cast-11882.rs:11:20 + | +LL | const TEST4: u64 = (not(0_u64) as u64).overflowing_shr(1_u32).0; + | ^^^^^^^^^^^^^^^^^^^ help: try: `not(0_u64)` + +error: casting to the same type is unnecessary (`u64` -> `u64`) + --> tests/ui/unnecessary_cast-11882.rs:13:20 + | +LL | const TEST5: u64 = (!not(!0_u64) as u64).overflowing_shr(1_u32).0; + | ^^^^^^^^^^^^^^^^^^^^^ help: try: `(!not(!0_u64))` + +error: casting integer literal to `u64` is unnecessary + --> tests/ui/unnecessary_cast-11882.rs:15:20 + | +LL | const TEST6: u64 = (0xff_ff_ff_ff_ff_ff_ff_ff as u64).overflowing_shr(1_u32).0; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `0xff_ff_ff_ff_ff_ff_ff_ff_u64` + +error: casting integer literal to `u64` is unnecessary + --> tests/ui/unnecessary_cast-11882.rs:17:21 + | +LL | const TEST7: u64 = (!0 as u64 + 0).overflowing_shr(1_u32).0; + | ^^^^^^^^^ help: try: `!0_u64` + +error: casting integer literal to `u64` is unnecessary + --> tests/ui/unnecessary_cast-11882.rs:19:23 + | +LL | const TEST8: u64 = (!(0 as u64 + 0)).overflowing_shr(1_u32).0; + | ^^^^^^^^ help: try: `0_u64` + +error: casting integer literal to `u64` is unnecessary + --> tests/ui/unnecessary_cast-11882.rs:23:23 + | +LL | const CHK1: u64 = not(!0 as u64).overflowing_shr(1_u32).0; + | ^^^^^^^^^ help: try: `!0_u64` + +error: casting to the same type is unnecessary (`u64` -> `u64`) + --> tests/ui/unnecessary_cast-11882.rs:27:19 + | +LL | const CHK4: u64 = (!not(0_u64) as u64).overflowing_shr(1_u32).0; + | ^^^^^^^^^^^^^^^^^^^^ help: try: `(!not(0_u64))` + +error: casting to the same type is unnecessary (`u64` -> `u64`) + --> tests/ui/unnecessary_cast-11882.rs:29:19 + | +LL | const CHK5: u64 = (not(!0_u64) as u64).overflowing_shr(1_u32).0; + | ^^^^^^^^^^^^^^^^^^^^ help: try: `not(!0_u64)` + +error: casting integer literal to `u64` is unnecessary + --> tests/ui/unnecessary_cast-11882.rs:32:25 + | +LL | const CHK7: u64 = (!not(0 as u64)).overflowing_shr(1_u32).0; + | ^^^^^^^^ help: try: `0_u64` + +error: casting integer literal to `u64` is unnecessary + --> tests/ui/unnecessary_cast-11882.rs:34:23 + | +LL | const CHK8: u64 = not(!0 as u64 + 0).overflowing_shr(1_u32).0; + | ^^^^^^^^^ help: try: `!0_u64` + +error: casting integer literal to `u64` is unnecessary + --> tests/ui/unnecessary_cast-11882.rs:59:21 + | +LL | let test: u64 = (!0 as u64).overflowing_shr(1_u32).0; + | ^^^^^^^^^^^ help: try: `(!0_u64)` + +error: casting to the same type is unnecessary (`u64` -> `u64`) + --> tests/ui/unnecessary_cast-11882.rs:61:22 + | +LL | let test2: u64 = (!0_u64 as u64).overflowing_shr(1_u32).0; + | ^^^^^^^^^^^^^^^ help: try: `(!0_u64)` + +error: casting to the same type is unnecessary (`u64` -> `u64`) + --> tests/ui/unnecessary_cast-11882.rs:64:22 + | +LL | let test4: u64 = (not(0_u64) as u64).overflowing_shr(1_u32).0; + | ^^^^^^^^^^^^^^^^^^^ help: try: `not(0_u64)` + +error: casting to the same type is unnecessary (`u64` -> `u64`) + --> tests/ui/unnecessary_cast-11882.rs:66:22 + | +LL | let test5: u64 = (!not(!0_u64) as u64).overflowing_shr(1_u32).0; + | ^^^^^^^^^^^^^^^^^^^^^ help: try: `(!not(!0_u64))` + +error: casting integer literal to `u64` is unnecessary + --> tests/ui/unnecessary_cast-11882.rs:68:22 + | +LL | let test6: u64 = (0xff_ff_ff_ff_ff_ff_ff_ff as u64).overflowing_shr(1_u32).0; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `0xff_ff_ff_ff_ff_ff_ff_ff_u64` + +error: casting integer literal to `u64` is unnecessary + --> tests/ui/unnecessary_cast-11882.rs:70:23 + | +LL | let test7: u64 = (!0 as u64 + 0).overflowing_shr(1_u32).0; + | ^^^^^^^^^ help: try: `!0_u64` + +error: casting integer literal to `u64` is unnecessary + --> tests/ui/unnecessary_cast-11882.rs:72:25 + | +LL | let test8: u64 = (!(0 as u64 + 0)).overflowing_shr(1_u32).0; + | ^^^^^^^^ help: try: `0_u64` + +error: casting integer literal to `u64` is unnecessary + --> tests/ui/unnecessary_cast-11882.rs:76:25 + | +LL | let chk1: u64 = not(!0 as u64).overflowing_shr(1_u32).0; + | ^^^^^^^^^ help: try: `!0_u64` + +error: casting to the same type is unnecessary (`u64` -> `u64`) + --> tests/ui/unnecessary_cast-11882.rs:80:21 + | +LL | let chk4: u64 = (!not(0_u64) as u64).overflowing_shr(1_u32).0; + | ^^^^^^^^^^^^^^^^^^^^ help: try: `(!not(0_u64))` + +error: casting to the same type is unnecessary (`u64` -> `u64`) + --> tests/ui/unnecessary_cast-11882.rs:82:21 + | +LL | let chk5: u64 = (not(!0_u64) as u64).overflowing_shr(1_u32).0; + | ^^^^^^^^^^^^^^^^^^^^ help: try: `not(!0_u64)` + +error: casting integer literal to `u64` is unnecessary + --> tests/ui/unnecessary_cast-11882.rs:85:27 + | +LL | let chk7: u64 = (!not(0 as u64)).overflowing_shr(1_u32).0; + | ^^^^^^^^ help: try: `0_u64` + +error: casting integer literal to `u64` is unnecessary + --> tests/ui/unnecessary_cast-11882.rs:87:25 + | +LL | let chk8: u64 = not(!0 as u64 + 0).overflowing_shr(1_u32).0; + | ^^^^^^^^^ help: try: `!0_u64` + +error: aborting due to 24 previous errors + From 55dc5523e535ac76223bfd0dfe1adcb823cca2bd Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Sat, 20 Jun 2026 21:35:03 -0700 Subject: [PATCH 66/77] Clean up unrelated tests --- tests/ui/unnecessary_cast-11882.rs | 83 ++++++++++-------------------- 1 file changed, 28 insertions(+), 55 deletions(-) diff --git a/tests/ui/unnecessary_cast-11882.rs b/tests/ui/unnecessary_cast-11882.rs index d8028308755f0..2c84b2f21635a 100644 --- a/tests/ui/unnecessary_cast-11882.rs +++ b/tests/ui/unnecessary_cast-11882.rs @@ -1,4 +1,3 @@ -//@ignore-bitwidth: 32 #![feature(const_trait_impl, const_ops)] #![warn(clippy::unnecessary_cast)] #![allow(unused, clippy::identity_op)] @@ -7,84 +6,58 @@ const TEST: u64 = (!0 as u64).overflowing_shr(1_u32).0; //~^ unnecessary_cast const TEST2: u64 = (!0_u64 as u64).overflowing_shr(1_u32).0; //~^ unnecessary_cast -const TEST3: u64 = (not(0) as u64).overflowing_shr(1_u32).0; -const TEST4: u64 = (not(0_u64) as u64).overflowing_shr(1_u32).0; +const TEST3: u64 = (!not(!0_u64) as u64).overflowing_shr(1_u32).0; //~^ unnecessary_cast -const TEST5: u64 = (!not(!0_u64) as u64).overflowing_shr(1_u32).0; +const TEST4: u64 = (!0 as u64 + 0).overflowing_shr(1_u32).0; //~^ unnecessary_cast -const TEST6: u64 = (0xff_ff_ff_ff_ff_ff_ff_ff as u64).overflowing_shr(1_u32).0; +const TEST5: u64 = (!(0 as u64 + 0)).overflowing_shr(1_u32).0; //~^ unnecessary_cast -const TEST7: u64 = (!0 as u64 + 0).overflowing_shr(1_u32).0; -//~^ unnecessary_cast -const TEST8: u64 = (!(0 as u64 + 0)).overflowing_shr(1_u32).0; -//~^ unnecessary_cast -const TEST9: u64 = (!((0 + 0) as u64)).overflowing_shr(1_u32).0; +const TEST6: u64 = (!((0 + 0) as u64)).overflowing_shr(1_u32).0; const CHK1: u64 = not(!0 as u64).overflowing_shr(1_u32).0; //~^ unnecessary_cast -const CHK2: u64 = (not(!0) as u64).overflowing_shr(1_u32).0; -const CHK3: u64 = (!not(0) as u64).overflowing_shr(1_u32).0; -const CHK4: u64 = (!not(0_u64) as u64).overflowing_shr(1_u32).0; -//~^ unnecessary_cast -const CHK5: u64 = (not(!0_u64) as u64).overflowing_shr(1_u32).0; +const CHK2: u64 = (!not(0_u64) as u64).overflowing_shr(1_u32).0; //~^ unnecessary_cast -const CHK6: u64 = (!(not(0) as u64)).overflowing_shr(1_u32).0; -const CHK7: u64 = (!not(0 as u64)).overflowing_shr(1_u32).0; +const CHK3: u64 = (!not(0 as u64)).overflowing_shr(1_u32).0; //~^ unnecessary_cast -const CHK8: u64 = not(!0 as u64 + 0).overflowing_shr(1_u32).0; +const CHK4: u64 = not(!0 as u64 + 0).overflowing_shr(1_u32).0; //~^ unnecessary_cast -fn main() { - // make sure that the calculated value doesn't change - let _x: [(); 0x7f_ff_ff_ff_ff_ff_ff_ff] = [(); TEST as usize]; - let _x: [(); 0x7f_ff_ff_ff_ff_ff_ff_ff] = [(); TEST2 as usize]; - let _x: [(); 0x7f_ff_ff_ff_ff_ff_ff_ff] = [(); TEST3 as usize]; - let _x: [(); 0x7f_ff_ff_ff_ff_ff_ff_ff] = [(); TEST4 as usize]; - let _x: [(); 0x7f_ff_ff_ff_ff_ff_ff_ff] = [(); TEST5 as usize]; - let _x: [(); 0x7f_ff_ff_ff_ff_ff_ff_ff] = [(); TEST6 as usize]; - let _x: [(); 0x7f_ff_ff_ff_ff_ff_ff_ff] = [(); TEST7 as usize]; - let _x: [(); 0x7f_ff_ff_ff_ff_ff_ff_ff] = [(); TEST8 as usize]; - let _x: [(); 0x7f_ff_ff_ff_ff_ff_ff_ff] = [(); TEST9 as usize]; - - let _x: [(); 0] = [(); CHK1 as usize]; - let _x: [(); 0] = [(); CHK2 as usize]; - let _x: [(); 0] = [(); CHK3 as usize]; - let _x: [(); 0] = [(); CHK4 as usize]; - let _x: [(); 0] = [(); CHK5 as usize]; - let _x: [(); 0] = [(); CHK6 as usize]; - let _x: [(); 0] = [(); CHK7 as usize]; - let _x: [(); 0] = [(); CHK8 as usize]; +// Make sure that the calculated values aren't changed by the fixes. +const _: () = { + assert_eq!(0x7f_ff_ff_ff_ff_ff_ff_ffu64, TEST); + assert_eq!(0x7f_ff_ff_ff_ff_ff_ff_ffu64, TEST2); + assert_eq!(0x7f_ff_ff_ff_ff_ff_ff_ffu64, TEST3); + assert_eq!(0x7f_ff_ff_ff_ff_ff_ff_ffu64, TEST4); + assert_eq!(0x7f_ff_ff_ff_ff_ff_ff_ffu64, TEST5); + assert_eq!(0x7f_ff_ff_ff_ff_ff_ff_ffu64, TEST6); + assert_eq!(0, CHK1); + assert_eq!(0, CHK2); + assert_eq!(0, CHK3); + assert_eq!(0, CHK4); +}; +fn main() { // the non-const version of the tests let test: u64 = (!0 as u64).overflowing_shr(1_u32).0; //~^ unnecessary_cast let test2: u64 = (!0_u64 as u64).overflowing_shr(1_u32).0; //~^ unnecessary_cast - let test3: u64 = (not(0) as u64).overflowing_shr(1_u32).0; - let test4: u64 = (not(0_u64) as u64).overflowing_shr(1_u32).0; - //~^ unnecessary_cast - let test5: u64 = (!not(!0_u64) as u64).overflowing_shr(1_u32).0; + let test3: u64 = (!not(!0_u64) as u64).overflowing_shr(1_u32).0; //~^ unnecessary_cast - let test6: u64 = (0xff_ff_ff_ff_ff_ff_ff_ff as u64).overflowing_shr(1_u32).0; + let test4: u64 = (!0 as u64 + 0).overflowing_shr(1_u32).0; //~^ unnecessary_cast - let test7: u64 = (!0 as u64 + 0).overflowing_shr(1_u32).0; + let test5: u64 = (!(0 as u64 + 0)).overflowing_shr(1_u32).0; //~^ unnecessary_cast - let test8: u64 = (!(0 as u64 + 0)).overflowing_shr(1_u32).0; - //~^ unnecessary_cast - let test9: u64 = (!((0 + 0) as u64)).overflowing_shr(1_u32).0; + let test6: u64 = (!((0 + 0) as u64)).overflowing_shr(1_u32).0; let chk1: u64 = not(!0 as u64).overflowing_shr(1_u32).0; //~^ unnecessary_cast - let chk2: u64 = (not(!0) as u64).overflowing_shr(1_u32).0; - let chk3: u64 = (!not(0) as u64).overflowing_shr(1_u32).0; - let chk4: u64 = (!not(0_u64) as u64).overflowing_shr(1_u32).0; - //~^ unnecessary_cast - let chk5: u64 = (not(!0_u64) as u64).overflowing_shr(1_u32).0; + let chk2: u64 = (!not(0_u64) as u64).overflowing_shr(1_u32).0; //~^ unnecessary_cast - let chk6: u64 = (!(not(0) as u64)).overflowing_shr(1_u32).0; - let chk7: u64 = (!not(0 as u64)).overflowing_shr(1_u32).0; + let chk3: u64 = (!not(0 as u64)).overflowing_shr(1_u32).0; //~^ unnecessary_cast - let chk8: u64 = not(!0 as u64 + 0).overflowing_shr(1_u32).0; + let chk4: u64 = not(!0 as u64 + 0).overflowing_shr(1_u32).0; //~^ unnecessary_cast } From 53e0ed0098b8217ad598d57d8dae512e4a7e4600 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Sat, 20 Jun 2026 21:39:50 -0700 Subject: [PATCH 67/77] Move issue 11882 tests into same unnecessary_cast --- tests/ui/unnecessary_cast-11882.fixed | 93 ---------- tests/ui/unnecessary_cast-11882.rs | 66 ------- tests/ui/unnecessary_cast-11882.stderr | 149 --------------- tests/ui/unnecessary_cast.fixed | 65 +++++++ tests/ui/unnecessary_cast.rs | 65 +++++++ tests/ui/unnecessary_cast.stderr | 240 ++++++++++++++++++------- 6 files changed, 304 insertions(+), 374 deletions(-) delete mode 100644 tests/ui/unnecessary_cast-11882.fixed delete mode 100644 tests/ui/unnecessary_cast-11882.rs delete mode 100644 tests/ui/unnecessary_cast-11882.stderr diff --git a/tests/ui/unnecessary_cast-11882.fixed b/tests/ui/unnecessary_cast-11882.fixed deleted file mode 100644 index 6b2949248d8d1..0000000000000 --- a/tests/ui/unnecessary_cast-11882.fixed +++ /dev/null @@ -1,93 +0,0 @@ -//@ignore-bitwidth: 32 -#![feature(const_trait_impl, const_ops)] -#![warn(clippy::unnecessary_cast)] -#![allow(unused, clippy::identity_op)] - -const TEST: u64 = (!0_u64).overflowing_shr(1_u32).0; -//~^ unnecessary_cast -const TEST2: u64 = (!0_u64).overflowing_shr(1_u32).0; -//~^ unnecessary_cast -const TEST3: u64 = (not(0) as u64).overflowing_shr(1_u32).0; -const TEST4: u64 = not(0_u64).overflowing_shr(1_u32).0; -//~^ unnecessary_cast -const TEST5: u64 = (!not(!0_u64)).overflowing_shr(1_u32).0; -//~^ unnecessary_cast -const TEST6: u64 = 0xff_ff_ff_ff_ff_ff_ff_ff_u64.overflowing_shr(1_u32).0; -//~^ unnecessary_cast -const TEST7: u64 = (!0_u64 + 0).overflowing_shr(1_u32).0; -//~^ unnecessary_cast -const TEST8: u64 = (!(0_u64 + 0)).overflowing_shr(1_u32).0; -//~^ unnecessary_cast -const TEST9: u64 = (!((0 + 0) as u64)).overflowing_shr(1_u32).0; - -const CHK1: u64 = not(!0_u64).overflowing_shr(1_u32).0; -//~^ unnecessary_cast -const CHK2: u64 = (not(!0) as u64).overflowing_shr(1_u32).0; -const CHK3: u64 = (!not(0) as u64).overflowing_shr(1_u32).0; -const CHK4: u64 = (!not(0_u64)).overflowing_shr(1_u32).0; -//~^ unnecessary_cast -const CHK5: u64 = not(!0_u64).overflowing_shr(1_u32).0; -//~^ unnecessary_cast -const CHK6: u64 = (!(not(0) as u64)).overflowing_shr(1_u32).0; -const CHK7: u64 = (!not(0_u64)).overflowing_shr(1_u32).0; -//~^ unnecessary_cast -const CHK8: u64 = not(!0_u64 + 0).overflowing_shr(1_u32).0; -//~^ unnecessary_cast - -fn main() { - // make sure that the calculated value doesn't change - let _x: [(); 0x7f_ff_ff_ff_ff_ff_ff_ff] = [(); TEST as usize]; - let _x: [(); 0x7f_ff_ff_ff_ff_ff_ff_ff] = [(); TEST2 as usize]; - let _x: [(); 0x7f_ff_ff_ff_ff_ff_ff_ff] = [(); TEST3 as usize]; - let _x: [(); 0x7f_ff_ff_ff_ff_ff_ff_ff] = [(); TEST4 as usize]; - let _x: [(); 0x7f_ff_ff_ff_ff_ff_ff_ff] = [(); TEST5 as usize]; - let _x: [(); 0x7f_ff_ff_ff_ff_ff_ff_ff] = [(); TEST6 as usize]; - let _x: [(); 0x7f_ff_ff_ff_ff_ff_ff_ff] = [(); TEST7 as usize]; - let _x: [(); 0x7f_ff_ff_ff_ff_ff_ff_ff] = [(); TEST8 as usize]; - let _x: [(); 0x7f_ff_ff_ff_ff_ff_ff_ff] = [(); TEST9 as usize]; - - let _x: [(); 0] = [(); CHK1 as usize]; - let _x: [(); 0] = [(); CHK2 as usize]; - let _x: [(); 0] = [(); CHK3 as usize]; - let _x: [(); 0] = [(); CHK4 as usize]; - let _x: [(); 0] = [(); CHK5 as usize]; - let _x: [(); 0] = [(); CHK6 as usize]; - let _x: [(); 0] = [(); CHK7 as usize]; - let _x: [(); 0] = [(); CHK8 as usize]; - - // the non-const version of the tests - let test: u64 = (!0_u64).overflowing_shr(1_u32).0; - //~^ unnecessary_cast - let test2: u64 = (!0_u64).overflowing_shr(1_u32).0; - //~^ unnecessary_cast - let test3: u64 = (not(0) as u64).overflowing_shr(1_u32).0; - let test4: u64 = not(0_u64).overflowing_shr(1_u32).0; - //~^ unnecessary_cast - let test5: u64 = (!not(!0_u64)).overflowing_shr(1_u32).0; - //~^ unnecessary_cast - let test6: u64 = 0xff_ff_ff_ff_ff_ff_ff_ff_u64.overflowing_shr(1_u32).0; - //~^ unnecessary_cast - let test7: u64 = (!0_u64 + 0).overflowing_shr(1_u32).0; - //~^ unnecessary_cast - let test8: u64 = (!(0_u64 + 0)).overflowing_shr(1_u32).0; - //~^ unnecessary_cast - let test9: u64 = (!((0 + 0) as u64)).overflowing_shr(1_u32).0; - - let chk1: u64 = not(!0_u64).overflowing_shr(1_u32).0; - //~^ unnecessary_cast - let chk2: u64 = (not(!0) as u64).overflowing_shr(1_u32).0; - let chk3: u64 = (!not(0) as u64).overflowing_shr(1_u32).0; - let chk4: u64 = (!not(0_u64)).overflowing_shr(1_u32).0; - //~^ unnecessary_cast - let chk5: u64 = not(!0_u64).overflowing_shr(1_u32).0; - //~^ unnecessary_cast - let chk6: u64 = (!(not(0) as u64)).overflowing_shr(1_u32).0; - let chk7: u64 = (!not(0_u64)).overflowing_shr(1_u32).0; - //~^ unnecessary_cast - let chk8: u64 = not(!0_u64 + 0).overflowing_shr(1_u32).0; - //~^ unnecessary_cast -} - -const fn not>(x: T) -> T { - !x -} diff --git a/tests/ui/unnecessary_cast-11882.rs b/tests/ui/unnecessary_cast-11882.rs deleted file mode 100644 index 2c84b2f21635a..0000000000000 --- a/tests/ui/unnecessary_cast-11882.rs +++ /dev/null @@ -1,66 +0,0 @@ -#![feature(const_trait_impl, const_ops)] -#![warn(clippy::unnecessary_cast)] -#![allow(unused, clippy::identity_op)] - -const TEST: u64 = (!0 as u64).overflowing_shr(1_u32).0; -//~^ unnecessary_cast -const TEST2: u64 = (!0_u64 as u64).overflowing_shr(1_u32).0; -//~^ unnecessary_cast -const TEST3: u64 = (!not(!0_u64) as u64).overflowing_shr(1_u32).0; -//~^ unnecessary_cast -const TEST4: u64 = (!0 as u64 + 0).overflowing_shr(1_u32).0; -//~^ unnecessary_cast -const TEST5: u64 = (!(0 as u64 + 0)).overflowing_shr(1_u32).0; -//~^ unnecessary_cast -const TEST6: u64 = (!((0 + 0) as u64)).overflowing_shr(1_u32).0; - -const CHK1: u64 = not(!0 as u64).overflowing_shr(1_u32).0; -//~^ unnecessary_cast -const CHK2: u64 = (!not(0_u64) as u64).overflowing_shr(1_u32).0; -//~^ unnecessary_cast -const CHK3: u64 = (!not(0 as u64)).overflowing_shr(1_u32).0; -//~^ unnecessary_cast -const CHK4: u64 = not(!0 as u64 + 0).overflowing_shr(1_u32).0; -//~^ unnecessary_cast - -// Make sure that the calculated values aren't changed by the fixes. -const _: () = { - assert_eq!(0x7f_ff_ff_ff_ff_ff_ff_ffu64, TEST); - assert_eq!(0x7f_ff_ff_ff_ff_ff_ff_ffu64, TEST2); - assert_eq!(0x7f_ff_ff_ff_ff_ff_ff_ffu64, TEST3); - assert_eq!(0x7f_ff_ff_ff_ff_ff_ff_ffu64, TEST4); - assert_eq!(0x7f_ff_ff_ff_ff_ff_ff_ffu64, TEST5); - assert_eq!(0x7f_ff_ff_ff_ff_ff_ff_ffu64, TEST6); - assert_eq!(0, CHK1); - assert_eq!(0, CHK2); - assert_eq!(0, CHK3); - assert_eq!(0, CHK4); -}; - -fn main() { - // the non-const version of the tests - let test: u64 = (!0 as u64).overflowing_shr(1_u32).0; - //~^ unnecessary_cast - let test2: u64 = (!0_u64 as u64).overflowing_shr(1_u32).0; - //~^ unnecessary_cast - let test3: u64 = (!not(!0_u64) as u64).overflowing_shr(1_u32).0; - //~^ unnecessary_cast - let test4: u64 = (!0 as u64 + 0).overflowing_shr(1_u32).0; - //~^ unnecessary_cast - let test5: u64 = (!(0 as u64 + 0)).overflowing_shr(1_u32).0; - //~^ unnecessary_cast - let test6: u64 = (!((0 + 0) as u64)).overflowing_shr(1_u32).0; - - let chk1: u64 = not(!0 as u64).overflowing_shr(1_u32).0; - //~^ unnecessary_cast - let chk2: u64 = (!not(0_u64) as u64).overflowing_shr(1_u32).0; - //~^ unnecessary_cast - let chk3: u64 = (!not(0 as u64)).overflowing_shr(1_u32).0; - //~^ unnecessary_cast - let chk4: u64 = not(!0 as u64 + 0).overflowing_shr(1_u32).0; - //~^ unnecessary_cast -} - -const fn not>(x: T) -> T { - !x -} diff --git a/tests/ui/unnecessary_cast-11882.stderr b/tests/ui/unnecessary_cast-11882.stderr deleted file mode 100644 index 056f04c65ed35..0000000000000 --- a/tests/ui/unnecessary_cast-11882.stderr +++ /dev/null @@ -1,149 +0,0 @@ -error: casting integer literal to `u64` is unnecessary - --> tests/ui/unnecessary_cast-11882.rs:6:19 - | -LL | const TEST: u64 = (!0 as u64).overflowing_shr(1_u32).0; - | ^^^^^^^^^^^ help: try: `(!0_u64)` - | - = note: `-D clippy::unnecessary-cast` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::unnecessary_cast)]` - -error: casting to the same type is unnecessary (`u64` -> `u64`) - --> tests/ui/unnecessary_cast-11882.rs:8:20 - | -LL | const TEST2: u64 = (!0_u64 as u64).overflowing_shr(1_u32).0; - | ^^^^^^^^^^^^^^^ help: try: `(!0_u64)` - -error: casting to the same type is unnecessary (`u64` -> `u64`) - --> tests/ui/unnecessary_cast-11882.rs:11:20 - | -LL | const TEST4: u64 = (not(0_u64) as u64).overflowing_shr(1_u32).0; - | ^^^^^^^^^^^^^^^^^^^ help: try: `not(0_u64)` - -error: casting to the same type is unnecessary (`u64` -> `u64`) - --> tests/ui/unnecessary_cast-11882.rs:13:20 - | -LL | const TEST5: u64 = (!not(!0_u64) as u64).overflowing_shr(1_u32).0; - | ^^^^^^^^^^^^^^^^^^^^^ help: try: `(!not(!0_u64))` - -error: casting integer literal to `u64` is unnecessary - --> tests/ui/unnecessary_cast-11882.rs:15:20 - | -LL | const TEST6: u64 = (0xff_ff_ff_ff_ff_ff_ff_ff as u64).overflowing_shr(1_u32).0; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `0xff_ff_ff_ff_ff_ff_ff_ff_u64` - -error: casting integer literal to `u64` is unnecessary - --> tests/ui/unnecessary_cast-11882.rs:17:21 - | -LL | const TEST7: u64 = (!0 as u64 + 0).overflowing_shr(1_u32).0; - | ^^^^^^^^^ help: try: `!0_u64` - -error: casting integer literal to `u64` is unnecessary - --> tests/ui/unnecessary_cast-11882.rs:19:23 - | -LL | const TEST8: u64 = (!(0 as u64 + 0)).overflowing_shr(1_u32).0; - | ^^^^^^^^ help: try: `0_u64` - -error: casting integer literal to `u64` is unnecessary - --> tests/ui/unnecessary_cast-11882.rs:23:23 - | -LL | const CHK1: u64 = not(!0 as u64).overflowing_shr(1_u32).0; - | ^^^^^^^^^ help: try: `!0_u64` - -error: casting to the same type is unnecessary (`u64` -> `u64`) - --> tests/ui/unnecessary_cast-11882.rs:27:19 - | -LL | const CHK4: u64 = (!not(0_u64) as u64).overflowing_shr(1_u32).0; - | ^^^^^^^^^^^^^^^^^^^^ help: try: `(!not(0_u64))` - -error: casting to the same type is unnecessary (`u64` -> `u64`) - --> tests/ui/unnecessary_cast-11882.rs:29:19 - | -LL | const CHK5: u64 = (not(!0_u64) as u64).overflowing_shr(1_u32).0; - | ^^^^^^^^^^^^^^^^^^^^ help: try: `not(!0_u64)` - -error: casting integer literal to `u64` is unnecessary - --> tests/ui/unnecessary_cast-11882.rs:32:25 - | -LL | const CHK7: u64 = (!not(0 as u64)).overflowing_shr(1_u32).0; - | ^^^^^^^^ help: try: `0_u64` - -error: casting integer literal to `u64` is unnecessary - --> tests/ui/unnecessary_cast-11882.rs:34:23 - | -LL | const CHK8: u64 = not(!0 as u64 + 0).overflowing_shr(1_u32).0; - | ^^^^^^^^^ help: try: `!0_u64` - -error: casting integer literal to `u64` is unnecessary - --> tests/ui/unnecessary_cast-11882.rs:59:21 - | -LL | let test: u64 = (!0 as u64).overflowing_shr(1_u32).0; - | ^^^^^^^^^^^ help: try: `(!0_u64)` - -error: casting to the same type is unnecessary (`u64` -> `u64`) - --> tests/ui/unnecessary_cast-11882.rs:61:22 - | -LL | let test2: u64 = (!0_u64 as u64).overflowing_shr(1_u32).0; - | ^^^^^^^^^^^^^^^ help: try: `(!0_u64)` - -error: casting to the same type is unnecessary (`u64` -> `u64`) - --> tests/ui/unnecessary_cast-11882.rs:64:22 - | -LL | let test4: u64 = (not(0_u64) as u64).overflowing_shr(1_u32).0; - | ^^^^^^^^^^^^^^^^^^^ help: try: `not(0_u64)` - -error: casting to the same type is unnecessary (`u64` -> `u64`) - --> tests/ui/unnecessary_cast-11882.rs:66:22 - | -LL | let test5: u64 = (!not(!0_u64) as u64).overflowing_shr(1_u32).0; - | ^^^^^^^^^^^^^^^^^^^^^ help: try: `(!not(!0_u64))` - -error: casting integer literal to `u64` is unnecessary - --> tests/ui/unnecessary_cast-11882.rs:68:22 - | -LL | let test6: u64 = (0xff_ff_ff_ff_ff_ff_ff_ff as u64).overflowing_shr(1_u32).0; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `0xff_ff_ff_ff_ff_ff_ff_ff_u64` - -error: casting integer literal to `u64` is unnecessary - --> tests/ui/unnecessary_cast-11882.rs:70:23 - | -LL | let test7: u64 = (!0 as u64 + 0).overflowing_shr(1_u32).0; - | ^^^^^^^^^ help: try: `!0_u64` - -error: casting integer literal to `u64` is unnecessary - --> tests/ui/unnecessary_cast-11882.rs:72:25 - | -LL | let test8: u64 = (!(0 as u64 + 0)).overflowing_shr(1_u32).0; - | ^^^^^^^^ help: try: `0_u64` - -error: casting integer literal to `u64` is unnecessary - --> tests/ui/unnecessary_cast-11882.rs:76:25 - | -LL | let chk1: u64 = not(!0 as u64).overflowing_shr(1_u32).0; - | ^^^^^^^^^ help: try: `!0_u64` - -error: casting to the same type is unnecessary (`u64` -> `u64`) - --> tests/ui/unnecessary_cast-11882.rs:80:21 - | -LL | let chk4: u64 = (!not(0_u64) as u64).overflowing_shr(1_u32).0; - | ^^^^^^^^^^^^^^^^^^^^ help: try: `(!not(0_u64))` - -error: casting to the same type is unnecessary (`u64` -> `u64`) - --> tests/ui/unnecessary_cast-11882.rs:82:21 - | -LL | let chk5: u64 = (not(!0_u64) as u64).overflowing_shr(1_u32).0; - | ^^^^^^^^^^^^^^^^^^^^ help: try: `not(!0_u64)` - -error: casting integer literal to `u64` is unnecessary - --> tests/ui/unnecessary_cast-11882.rs:85:27 - | -LL | let chk7: u64 = (!not(0 as u64)).overflowing_shr(1_u32).0; - | ^^^^^^^^ help: try: `0_u64` - -error: casting integer literal to `u64` is unnecessary - --> tests/ui/unnecessary_cast-11882.rs:87:25 - | -LL | let chk8: u64 = not(!0 as u64 + 0).overflowing_shr(1_u32).0; - | ^^^^^^^^^ help: try: `!0_u64` - -error: aborting due to 24 previous errors - diff --git a/tests/ui/unnecessary_cast.fixed b/tests/ui/unnecessary_cast.fixed index 1ecc3ecf57a00..5016ce3470672 100644 --- a/tests/ui/unnecessary_cast.fixed +++ b/tests/ui/unnecessary_cast.fixed @@ -1,7 +1,9 @@ //@aux-build:extern_fake_libc.rs +#![feature(const_trait_impl, const_ops)] #![warn(clippy::unnecessary_cast)] #![allow( clippy::borrow_as_ptr, + clippy::identity_op, clippy::multiple_bound_locations, clippy::no_effect, clippy::nonstandard_macro_braces, @@ -656,3 +658,66 @@ fn issue16475() -> *const u8 { //~^ unnecessary_cast } } + +const ISSUE_11882_TEST: u64 = (!0_u64).overflowing_shr(1_u32).0; +//~^ unnecessary_cast +const ISSUE_11882_TEST2: u64 = (!0_u64).overflowing_shr(1_u32).0; +//~^ unnecessary_cast +const ISSUE_11882_TEST3: u64 = (!not(!0_u64)).overflowing_shr(1_u32).0; +//~^ unnecessary_cast +const ISSUE_11882_TEST4: u64 = (!0_u64 + 0).overflowing_shr(1_u32).0; +//~^ unnecessary_cast +const ISSUE_11882_TEST5: u64 = (!(0_u64 + 0)).overflowing_shr(1_u32).0; +//~^ unnecessary_cast +const ISSUE_11882_TEST6: u64 = (!((0 + 0) as u64)).overflowing_shr(1_u32).0; + +const ISSUE_11882_CHK1: u64 = not(!0_u64).overflowing_shr(1_u32).0; +//~^ unnecessary_cast +const ISSUE_11882_CHK2: u64 = (!not(0_u64)).overflowing_shr(1_u32).0; +//~^ unnecessary_cast +const ISSUE_11882_CHK3: u64 = (!not(0_u64)).overflowing_shr(1_u32).0; +//~^ unnecessary_cast +const ISSUE_11882_CHK4: u64 = not(!0_u64 + 0).overflowing_shr(1_u32).0; +//~^ unnecessary_cast + +// Make sure that the calculated values aren't changed by the fixes. +const _: () = { + assert!(0x7f_ff_ff_ff_ff_ff_ff_ffu64 == ISSUE_11882_TEST); + assert!(0x7f_ff_ff_ff_ff_ff_ff_ffu64 == ISSUE_11882_TEST2); + assert!(0x7f_ff_ff_ff_ff_ff_ff_ffu64 == ISSUE_11882_TEST3); + assert!(0x7f_ff_ff_ff_ff_ff_ff_ffu64 == ISSUE_11882_TEST4); + assert!(0x7f_ff_ff_ff_ff_ff_ff_ffu64 == ISSUE_11882_TEST5); + assert!(0x7f_ff_ff_ff_ff_ff_ff_ffu64 == ISSUE_11882_TEST6); + assert!(0 == ISSUE_11882_CHK1); + assert!(0 == ISSUE_11882_CHK2); + assert!(0 == ISSUE_11882_CHK3); + assert!(0 == ISSUE_11882_CHK4); +}; + +fn issue_11882() { + // the non-const version of the tests + let issue_11882_test: u64 = (!0_u64).overflowing_shr(1_u32).0; + //~^ unnecessary_cast + let issue_11882_test2: u64 = (!0_u64).overflowing_shr(1_u32).0; + //~^ unnecessary_cast + let issue_11882_test3: u64 = (!not(!0_u64)).overflowing_shr(1_u32).0; + //~^ unnecessary_cast + let issue_11882_test4: u64 = (!0_u64 + 0).overflowing_shr(1_u32).0; + //~^ unnecessary_cast + let issue_11882_test5: u64 = (!(0_u64 + 0)).overflowing_shr(1_u32).0; + //~^ unnecessary_cast + let issue_11882_test6: u64 = (!((0 + 0) as u64)).overflowing_shr(1_u32).0; + + let issue_11882_chk1: u64 = not(!0_u64).overflowing_shr(1_u32).0; + //~^ unnecessary_cast + let issue_11882_chk2: u64 = (!not(0_u64)).overflowing_shr(1_u32).0; + //~^ unnecessary_cast + let issue_11882_chk3: u64 = (!not(0_u64)).overflowing_shr(1_u32).0; + //~^ unnecessary_cast + let issue_11882_chk4: u64 = not(!0_u64 + 0).overflowing_shr(1_u32).0; + //~^ unnecessary_cast +} + +const fn not>(x: T) -> T { + !x +} diff --git a/tests/ui/unnecessary_cast.rs b/tests/ui/unnecessary_cast.rs index 1a6cc831aa4b8..00a2687387140 100644 --- a/tests/ui/unnecessary_cast.rs +++ b/tests/ui/unnecessary_cast.rs @@ -1,7 +1,9 @@ //@aux-build:extern_fake_libc.rs +#![feature(const_trait_impl, const_ops)] #![warn(clippy::unnecessary_cast)] #![allow( clippy::borrow_as_ptr, + clippy::identity_op, clippy::multiple_bound_locations, clippy::no_effect, clippy::nonstandard_macro_braces, @@ -656,3 +658,66 @@ fn issue16475() -> *const u8 { //~^ unnecessary_cast } } + +const ISSUE_11882_TEST: u64 = (!0 as u64).overflowing_shr(1_u32).0; +//~^ unnecessary_cast +const ISSUE_11882_TEST2: u64 = (!0_u64 as u64).overflowing_shr(1_u32).0; +//~^ unnecessary_cast +const ISSUE_11882_TEST3: u64 = (!not(!0_u64) as u64).overflowing_shr(1_u32).0; +//~^ unnecessary_cast +const ISSUE_11882_TEST4: u64 = (!0 as u64 + 0).overflowing_shr(1_u32).0; +//~^ unnecessary_cast +const ISSUE_11882_TEST5: u64 = (!(0 as u64 + 0)).overflowing_shr(1_u32).0; +//~^ unnecessary_cast +const ISSUE_11882_TEST6: u64 = (!((0 + 0) as u64)).overflowing_shr(1_u32).0; + +const ISSUE_11882_CHK1: u64 = not(!0 as u64).overflowing_shr(1_u32).0; +//~^ unnecessary_cast +const ISSUE_11882_CHK2: u64 = (!not(0_u64) as u64).overflowing_shr(1_u32).0; +//~^ unnecessary_cast +const ISSUE_11882_CHK3: u64 = (!not(0 as u64)).overflowing_shr(1_u32).0; +//~^ unnecessary_cast +const ISSUE_11882_CHK4: u64 = not(!0 as u64 + 0).overflowing_shr(1_u32).0; +//~^ unnecessary_cast + +// Make sure that the calculated values aren't changed by the fixes. +const _: () = { + assert!(0x7f_ff_ff_ff_ff_ff_ff_ffu64 == ISSUE_11882_TEST); + assert!(0x7f_ff_ff_ff_ff_ff_ff_ffu64 == ISSUE_11882_TEST2); + assert!(0x7f_ff_ff_ff_ff_ff_ff_ffu64 == ISSUE_11882_TEST3); + assert!(0x7f_ff_ff_ff_ff_ff_ff_ffu64 == ISSUE_11882_TEST4); + assert!(0x7f_ff_ff_ff_ff_ff_ff_ffu64 == ISSUE_11882_TEST5); + assert!(0x7f_ff_ff_ff_ff_ff_ff_ffu64 == ISSUE_11882_TEST6); + assert!(0 == ISSUE_11882_CHK1); + assert!(0 == ISSUE_11882_CHK2); + assert!(0 == ISSUE_11882_CHK3); + assert!(0 == ISSUE_11882_CHK4); +}; + +fn issue_11882() { + // the non-const version of the tests + let issue_11882_test: u64 = (!0 as u64).overflowing_shr(1_u32).0; + //~^ unnecessary_cast + let issue_11882_test2: u64 = (!0_u64 as u64).overflowing_shr(1_u32).0; + //~^ unnecessary_cast + let issue_11882_test3: u64 = (!not(!0_u64) as u64).overflowing_shr(1_u32).0; + //~^ unnecessary_cast + let issue_11882_test4: u64 = (!0 as u64 + 0).overflowing_shr(1_u32).0; + //~^ unnecessary_cast + let issue_11882_test5: u64 = (!(0 as u64 + 0)).overflowing_shr(1_u32).0; + //~^ unnecessary_cast + let issue_11882_test6: u64 = (!((0 + 0) as u64)).overflowing_shr(1_u32).0; + + let issue_11882_chk1: u64 = not(!0 as u64).overflowing_shr(1_u32).0; + //~^ unnecessary_cast + let issue_11882_chk2: u64 = (!not(0_u64) as u64).overflowing_shr(1_u32).0; + //~^ unnecessary_cast + let issue_11882_chk3: u64 = (!not(0 as u64)).overflowing_shr(1_u32).0; + //~^ unnecessary_cast + let issue_11882_chk4: u64 = not(!0 as u64 + 0).overflowing_shr(1_u32).0; + //~^ unnecessary_cast +} + +const fn not>(x: T) -> T { + !x +} diff --git a/tests/ui/unnecessary_cast.stderr b/tests/ui/unnecessary_cast.stderr index 19d2afcb4f255..eb710ba1fee29 100644 --- a/tests/ui/unnecessary_cast.stderr +++ b/tests/ui/unnecessary_cast.stderr @@ -1,5 +1,5 @@ error: casting raw pointers to the same type and constness is unnecessary (`*const T` -> `*const T`) - --> tests/ui/unnecessary_cast.rs:19:5 + --> tests/ui/unnecessary_cast.rs:21:5 | LL | ptr as *const T | ^^^^^^^^^^^^^^^ help: try: `ptr` @@ -8,388 +8,496 @@ LL | ptr as *const T = help: to override `-D warnings` add `#[allow(clippy::unnecessary_cast)]` error: casting integer literal to `i32` is unnecessary - --> tests/ui/unnecessary_cast.rs:55:5 + --> tests/ui/unnecessary_cast.rs:57:5 | LL | 1i32 as i32; | ^^^^^^^^^^^ help: try: `1_i32` error: casting float literal to `f32` is unnecessary - --> tests/ui/unnecessary_cast.rs:57:5 + --> tests/ui/unnecessary_cast.rs:59:5 | LL | 1f32 as f32; | ^^^^^^^^^^^ help: try: `1_f32` error: casting to the same type is unnecessary (`bool` -> `bool`) - --> tests/ui/unnecessary_cast.rs:59:5 + --> tests/ui/unnecessary_cast.rs:61:5 | LL | false as bool; | ^^^^^^^^^^^^^ help: try: `false` error: casting integer literal to `i32` is unnecessary - --> tests/ui/unnecessary_cast.rs:63:5 + --> tests/ui/unnecessary_cast.rs:65:5 | LL | -1_i32 as i32; | ^^^^^^^^^^^^^ help: try: `-1_i32` error: casting integer literal to `i32` is unnecessary - --> tests/ui/unnecessary_cast.rs:65:5 + --> tests/ui/unnecessary_cast.rs:67:5 | LL | - 1_i32 as i32; | ^^^^^^^^^^^^^^ help: try: `- 1_i32` error: casting float literal to `f32` is unnecessary - --> tests/ui/unnecessary_cast.rs:67:5 + --> tests/ui/unnecessary_cast.rs:69:5 | LL | -1f32 as f32; | ^^^^^^^^^^^^ help: try: `-1_f32` error: casting integer literal to `i32` is unnecessary - --> tests/ui/unnecessary_cast.rs:69:5 + --> tests/ui/unnecessary_cast.rs:71:5 | LL | 1_i32 as i32; | ^^^^^^^^^^^^ help: try: `1_i32` error: casting float literal to `f32` is unnecessary - --> tests/ui/unnecessary_cast.rs:71:5 + --> tests/ui/unnecessary_cast.rs:73:5 | LL | 1_f32 as f32; | ^^^^^^^^^^^^ help: try: `1_f32` error: casting raw pointers to the same type and constness is unnecessary (`*const u8` -> `*const u8`) - --> tests/ui/unnecessary_cast.rs:74:22 + --> tests/ui/unnecessary_cast.rs:76:22 | LL | let _: *mut u8 = [1u8, 2].as_ptr() as *const u8 as *mut u8; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `[1u8, 2].as_ptr()` error: casting raw pointers to the same type and constness is unnecessary (`*const u8` -> `*const u8`) - --> tests/ui/unnecessary_cast.rs:77:5 + --> tests/ui/unnecessary_cast.rs:79:5 | LL | [1u8, 2].as_ptr() as *const u8; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `[1u8, 2].as_ptr()` error: casting raw pointers to the same type and constness is unnecessary (`*mut u8` -> `*mut u8`) - --> tests/ui/unnecessary_cast.rs:80:5 + --> tests/ui/unnecessary_cast.rs:82:5 | LL | [1u8, 2].as_mut_ptr() as *mut u8; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `[1u8, 2].as_mut_ptr()` error: casting raw pointers to the same type and constness is unnecessary (`*const u32` -> `*const u32`) - --> tests/ui/unnecessary_cast.rs:92:5 + --> tests/ui/unnecessary_cast.rs:94:5 | LL | owo::([1u32].as_ptr()) as *const u32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `owo::([1u32].as_ptr())` error: casting raw pointers to the same type and constness is unnecessary (`*const u8` -> `*const u8`) - --> tests/ui/unnecessary_cast.rs:94:5 + --> tests/ui/unnecessary_cast.rs:96:5 | LL | uwu::([1u32].as_ptr()) as *const u8; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `uwu::([1u32].as_ptr())` error: casting raw pointers to the same type and constness is unnecessary (`*const u32` -> `*const u32`) - --> tests/ui/unnecessary_cast.rs:97:5 + --> tests/ui/unnecessary_cast.rs:99:5 | LL | uwu::([1u32].as_ptr()) as *const u32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `uwu::([1u32].as_ptr())` error: casting to the same type is unnecessary (`u32` -> `u32`) - --> tests/ui/unnecessary_cast.rs:133:5 + --> tests/ui/unnecessary_cast.rs:135:5 | LL | aaa() as u32; | ^^^^^^^^^^^^ help: try: `aaa()` error: casting to the same type is unnecessary (`u32` -> `u32`) - --> tests/ui/unnecessary_cast.rs:136:5 + --> tests/ui/unnecessary_cast.rs:138:5 | LL | x as u32; | ^^^^^^^^ help: try: `x` error: casting to the same type is unnecessary (`u32` -> `u32`) - --> tests/ui/unnecessary_cast.rs:138:5 + --> tests/ui/unnecessary_cast.rs:140:5 | LL | bbb() as u32; | ^^^^^^^^^^^^ help: try: `bbb()` error: casting to the same type is unnecessary (`u32` -> `u32`) - --> tests/ui/unnecessary_cast.rs:141:5 + --> tests/ui/unnecessary_cast.rs:143:5 | LL | x as u32; | ^^^^^^^^ help: try: `x` error: casting integer literal to `f32` is unnecessary - --> tests/ui/unnecessary_cast.rs:174:9 + --> tests/ui/unnecessary_cast.rs:176:9 | LL | 100 as f32; | ^^^^^^^^^^ help: try: `100_f32` error: casting integer literal to `f64` is unnecessary - --> tests/ui/unnecessary_cast.rs:176:9 + --> tests/ui/unnecessary_cast.rs:178:9 | LL | 100 as f64; | ^^^^^^^^^^ help: try: `100_f64` error: casting integer literal to `f64` is unnecessary - --> tests/ui/unnecessary_cast.rs:178:9 + --> tests/ui/unnecessary_cast.rs:180:9 | LL | 100_i32 as f64; | ^^^^^^^^^^^^^^ help: try: `100_f64` error: casting integer literal to `f32` is unnecessary - --> tests/ui/unnecessary_cast.rs:180:17 + --> tests/ui/unnecessary_cast.rs:182:17 | LL | let _ = -100 as f32; | ^^^^^^^^^^^ help: try: `-100_f32` error: casting integer literal to `f64` is unnecessary - --> tests/ui/unnecessary_cast.rs:182:17 + --> tests/ui/unnecessary_cast.rs:184:17 | LL | let _ = -100 as f64; | ^^^^^^^^^^^ help: try: `-100_f64` error: casting integer literal to `f64` is unnecessary - --> tests/ui/unnecessary_cast.rs:184:17 + --> tests/ui/unnecessary_cast.rs:186:17 | LL | let _ = -100_i32 as f64; | ^^^^^^^^^^^^^^^ help: try: `-100_f64` error: casting float literal to `f32` is unnecessary - --> tests/ui/unnecessary_cast.rs:186:9 + --> tests/ui/unnecessary_cast.rs:188:9 | LL | 100. as f32; | ^^^^^^^^^^^ help: try: `100_f32` error: casting float literal to `f64` is unnecessary - --> tests/ui/unnecessary_cast.rs:188:9 + --> tests/ui/unnecessary_cast.rs:190:9 | LL | 100. as f64; | ^^^^^^^^^^^ help: try: `100_f64` error: casting integer literal to `u32` is unnecessary - --> tests/ui/unnecessary_cast.rs:201:9 + --> tests/ui/unnecessary_cast.rs:203:9 | LL | 1 as u32; | ^^^^^^^^ help: try: `1_u32` error: casting integer literal to `i32` is unnecessary - --> tests/ui/unnecessary_cast.rs:203:9 + --> tests/ui/unnecessary_cast.rs:205:9 | LL | 0x10 as i32; | ^^^^^^^^^^^ help: try: `0x10_i32` error: casting integer literal to `usize` is unnecessary - --> tests/ui/unnecessary_cast.rs:205:9 + --> tests/ui/unnecessary_cast.rs:207:9 | LL | 0b10 as usize; | ^^^^^^^^^^^^^ help: try: `0b10_usize` error: casting integer literal to `u16` is unnecessary - --> tests/ui/unnecessary_cast.rs:207:9 + --> tests/ui/unnecessary_cast.rs:209:9 | LL | 0o73 as u16; | ^^^^^^^^^^^ help: try: `0o73_u16` error: casting integer literal to `u32` is unnecessary - --> tests/ui/unnecessary_cast.rs:209:9 + --> tests/ui/unnecessary_cast.rs:211:9 | LL | 1_000_000_000 as u32; | ^^^^^^^^^^^^^^^^^^^^ help: try: `1_000_000_000_u32` error: casting float literal to `f64` is unnecessary - --> tests/ui/unnecessary_cast.rs:212:9 + --> tests/ui/unnecessary_cast.rs:214:9 | LL | 1.0 as f64; | ^^^^^^^^^^ help: try: `1.0_f64` error: casting float literal to `f32` is unnecessary - --> tests/ui/unnecessary_cast.rs:214:9 + --> tests/ui/unnecessary_cast.rs:216:9 | LL | 0.5 as f32; | ^^^^^^^^^^ help: try: `0.5_f32` error: casting integer literal to `i32` is unnecessary - --> tests/ui/unnecessary_cast.rs:219:17 + --> tests/ui/unnecessary_cast.rs:221:17 | LL | let _ = -1 as i32; | ^^^^^^^^^ help: try: `-1_i32` error: casting float literal to `f32` is unnecessary - --> tests/ui/unnecessary_cast.rs:221:17 + --> tests/ui/unnecessary_cast.rs:223:17 | LL | let _ = -1.0 as f32; | ^^^^^^^^^^^ help: try: `-1.0_f32` error: casting to the same type is unnecessary (`i32` -> `i32`) - --> tests/ui/unnecessary_cast.rs:228:18 + --> tests/ui/unnecessary_cast.rs:230:18 | LL | let _ = &(x as i32); | ^^^^^^^^^^ help: try: `{ x }` error: casting integer literal to `i32` is unnecessary - --> tests/ui/unnecessary_cast.rs:235:22 + --> tests/ui/unnecessary_cast.rs:237:22 | LL | let _: i32 = -(1) as i32; | ^^^^^^^^^^^ help: try: `-1_i32` error: casting integer literal to `i64` is unnecessary - --> tests/ui/unnecessary_cast.rs:238:22 + --> tests/ui/unnecessary_cast.rs:240:22 | LL | let _: i64 = -(1) as i64; | ^^^^^^^^^^^ help: try: `-1_i64` error: casting float literal to `f64` is unnecessary - --> tests/ui/unnecessary_cast.rs:246:22 + --> tests/ui/unnecessary_cast.rs:248:22 | LL | let _: f64 = (-8.0 as f64).exp(); | ^^^^^^^^^^^^^ help: try: `(-8.0_f64)` error: casting float literal to `f64` is unnecessary - --> tests/ui/unnecessary_cast.rs:249:23 + --> tests/ui/unnecessary_cast.rs:251:23 | LL | let _: f64 = -(8.0 as f64).exp(); // should suggest `-8.0_f64.exp()` here not to change code behavior | ^^^^^^^^^^^^ help: try: `8.0_f64` error: casting to the same type is unnecessary (`f32` -> `f32`) - --> tests/ui/unnecessary_cast.rs:259:20 + --> tests/ui/unnecessary_cast.rs:261:20 | LL | let _num = foo() as f32; | ^^^^^^^^^^^^ help: try: `foo()` error: casting to the same type is unnecessary (`usize` -> `usize`) - --> tests/ui/unnecessary_cast.rs:270:9 + --> tests/ui/unnecessary_cast.rs:272:9 | LL | (*x as usize).pow(2) | ^^^^^^^^^^^^^ help: try: `(*x)` error: casting to the same type is unnecessary (`usize` -> `usize`) - --> tests/ui/unnecessary_cast.rs:278:31 + --> tests/ui/unnecessary_cast.rs:280:31 | LL | assert_eq!(vec.len(), x as usize); | ^^^^^^^^^^ help: try: `x` error: casting to the same type is unnecessary (`i64` -> `i64`) - --> tests/ui/unnecessary_cast.rs:281:17 + --> tests/ui/unnecessary_cast.rs:283:17 | LL | let _ = (5i32 as i64 as i64).abs(); | ^^^^^^^^^^^^^^^^^^^^ help: try: `(5i32 as i64)` error: casting to the same type is unnecessary (`i64` -> `i64`) - --> tests/ui/unnecessary_cast.rs:284:17 + --> tests/ui/unnecessary_cast.rs:286:17 | LL | let _ = 5i32 as i64 as i64; | ^^^^^^^^^^^^^^^^^^ help: try: `5i32 as i64` error: casting to the same type is unnecessary (`f64` -> `f64`) - --> tests/ui/unnecessary_cast.rs:563:24 + --> tests/ui/unnecessary_cast.rs:565:24 | LL | id::>(1.0_f64.pow_like(2) as f64 * &a).view(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `1.0_f64.pow_like(2)` error: casting to the same type is unnecessary (`f64` -> `f64`) - --> tests/ui/unnecessary_cast.rs:567:26 + --> tests/ui/unnecessary_cast.rs:569:26 | LL | s.id::>(1.0_f64.pow_like(2) as f64 * &a).view(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `1.0_f64.pow_like(2)` error: casting to the same type is unnecessary (`f64` -> `f64`) - --> tests/ui/unnecessary_cast.rs:571:26 + --> tests/ui/unnecessary_cast.rs:573:26 | LL | wrap::>(1.0_f64.pow_like(2) as f64 * &a).inner.view(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `1.0_f64.pow_like(2)` error: casting to the same type is unnecessary (`f64` -> `f64`) - --> tests/ui/unnecessary_cast.rs:575:28 + --> tests/ui/unnecessary_cast.rs:577:28 | LL | s.wrap::>(1.0_f64.pow_like(2) as f64 * &a).inner.view(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `1.0_f64.pow_like(2)` error: casting to the same type is unnecessary (`f64` -> `f64`) - --> tests/ui/unnecessary_cast.rs:591:31 + --> tests/ui/unnecessary_cast.rs:593:31 | LL | let _ = receiver.take(1.0_f64.pow_like_single_impl(2) as f64).abs(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `1.0_f64.pow_like_single_impl(2)` error: casting to the same type is unnecessary (`f64` -> `f64`) - --> tests/ui/unnecessary_cast.rs:601:20 + --> tests/ui/unnecessary_cast.rs:603:20 | LL | let _ = id(1.0_f64.powi(2) as f64).abs(); | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `1.0_f64.powi(2)` error: casting to the same type is unnecessary (`f64` -> `f64`) - --> tests/ui/unnecessary_cast.rs:604:22 + --> tests/ui/unnecessary_cast.rs:606:22 | LL | let _ = wrap(1.0_f64.powi(2) as f64).inner.abs(); | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `1.0_f64.powi(2)` error: casting to the same type is unnecessary (`f64` -> `f64`) - --> tests/ui/unnecessary_cast.rs:607:22 + --> tests/ui/unnecessary_cast.rs:609:22 | LL | let _ = s.id(1.0_f64.powi(2) as f64).abs(); | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `1.0_f64.powi(2)` error: casting to the same type is unnecessary (`f64` -> `f64`) - --> tests/ui/unnecessary_cast.rs:610:24 + --> tests/ui/unnecessary_cast.rs:612:24 | LL | let _ = s.wrap(1.0_f64.powi(2) as f64).inner.abs(); | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `1.0_f64.powi(2)` error: casting to the same type is unnecessary (`f64` -> `f64`) - --> tests/ui/unnecessary_cast.rs:613:20 + --> tests/ui/unnecessary_cast.rs:615:20 | LL | let _ = id(1.0_f64.powi(2) as f64 * &a); | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `1.0_f64.powi(2)` error: casting to the same type is unnecessary (`f64` -> `f64`) - --> tests/ui/unnecessary_cast.rs:616:22 + --> tests/ui/unnecessary_cast.rs:618:22 | LL | let _ = s.id(1.0_f64.powi(2) as f64 * &a); | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `1.0_f64.powi(2)` error: casting to the same type is unnecessary (`f64` -> `f64`) - --> tests/ui/unnecessary_cast.rs:629:17 + --> tests/ui/unnecessary_cast.rs:631:17 | LL | let _ = 1.0_f64.pow_like(0.5) as f64; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `1.0_f64.pow_like(0.5)` error: casting to the same type is unnecessary (`f64` -> `f64`) - --> tests/ui/unnecessary_cast.rs:632:17 + --> tests/ui/unnecessary_cast.rs:634:17 | LL | let _ = 1.0_f64.pow_like(2) as f64; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `1.0_f64.pow_like(2)` error: casting to the same type is unnecessary (`f64` -> `f64`) - --> tests/ui/unnecessary_cast.rs:635:17 + --> tests/ui/unnecessary_cast.rs:637:17 | LL | let _ = (1.0_f64.powi(2) as f64).abs(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `1.0_f64.powi(2)` error: casting to the same type is unnecessary (`f64` -> `f64`) - --> tests/ui/unnecessary_cast.rs:638:17 + --> tests/ui/unnecessary_cast.rs:640:17 | LL | let _ = ((Y + 2) as f64).abs(); | ^^^^^^^^^^^^^^^^ help: try: `((Y + 2))` error: casting to the same type is unnecessary (`f64` -> `f64`) - --> tests/ui/unnecessary_cast.rs:641:18 + --> tests/ui/unnecessary_cast.rs:643:18 | LL | let _ = (1.0_f64.pow_like_single_impl(2) as f64 + 1.0_f64).abs(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `1.0_f64.pow_like_single_impl(2)` error: casting to the same type is unnecessary (`f64` -> `f64`) - --> tests/ui/unnecessary_cast.rs:644:18 + --> tests/ui/unnecessary_cast.rs:646:18 | LL | let _ = (1.0_f64.pow_like_single_impl(2) as f64 + ONE).abs(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `1.0_f64.pow_like_single_impl(2)` error: casting to the same type is unnecessary (`f64` -> `f64`) - --> tests/ui/unnecessary_cast.rs:647:18 + --> tests/ui/unnecessary_cast.rs:649:18 | LL | let _ = (1.0_f64.pow_like_single_impl(2) as f64 + one).abs(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `1.0_f64.pow_like_single_impl(2)` error: casting raw pointers to the same type and constness is unnecessary (`*const *const u8` -> `*const *const u8`) - --> tests/ui/unnecessary_cast.rs:655:10 + --> tests/ui/unnecessary_cast.rs:657:10 | LL | *(&NONE as *const _ as *const _ as *const *const u8 as *const *const u8) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(&NONE as *const _ as *const _ as *const *const u8)` -error: aborting due to 65 previous errors +error: casting integer literal to `u64` is unnecessary + --> tests/ui/unnecessary_cast.rs:662:31 + | +LL | const ISSUE_11882_TEST: u64 = (!0 as u64).overflowing_shr(1_u32).0; + | ^^^^^^^^^^^ help: try: `(!0_u64)` + +error: casting to the same type is unnecessary (`u64` -> `u64`) + --> tests/ui/unnecessary_cast.rs:664:32 + | +LL | const ISSUE_11882_TEST2: u64 = (!0_u64 as u64).overflowing_shr(1_u32).0; + | ^^^^^^^^^^^^^^^ help: try: `(!0_u64)` + +error: casting to the same type is unnecessary (`u64` -> `u64`) + --> tests/ui/unnecessary_cast.rs:666:32 + | +LL | const ISSUE_11882_TEST3: u64 = (!not(!0_u64) as u64).overflowing_shr(1_u32).0; + | ^^^^^^^^^^^^^^^^^^^^^ help: try: `(!not(!0_u64))` + +error: casting integer literal to `u64` is unnecessary + --> tests/ui/unnecessary_cast.rs:668:33 + | +LL | const ISSUE_11882_TEST4: u64 = (!0 as u64 + 0).overflowing_shr(1_u32).0; + | ^^^^^^^^^ help: try: `!0_u64` + +error: casting integer literal to `u64` is unnecessary + --> tests/ui/unnecessary_cast.rs:670:35 + | +LL | const ISSUE_11882_TEST5: u64 = (!(0 as u64 + 0)).overflowing_shr(1_u32).0; + | ^^^^^^^^ help: try: `0_u64` + +error: casting integer literal to `u64` is unnecessary + --> tests/ui/unnecessary_cast.rs:674:35 + | +LL | const ISSUE_11882_CHK1: u64 = not(!0 as u64).overflowing_shr(1_u32).0; + | ^^^^^^^^^ help: try: `!0_u64` + +error: casting to the same type is unnecessary (`u64` -> `u64`) + --> tests/ui/unnecessary_cast.rs:676:31 + | +LL | const ISSUE_11882_CHK2: u64 = (!not(0_u64) as u64).overflowing_shr(1_u32).0; + | ^^^^^^^^^^^^^^^^^^^^ help: try: `(!not(0_u64))` + +error: casting integer literal to `u64` is unnecessary + --> tests/ui/unnecessary_cast.rs:678:37 + | +LL | const ISSUE_11882_CHK3: u64 = (!not(0 as u64)).overflowing_shr(1_u32).0; + | ^^^^^^^^ help: try: `0_u64` + +error: casting integer literal to `u64` is unnecessary + --> tests/ui/unnecessary_cast.rs:680:35 + | +LL | const ISSUE_11882_CHK4: u64 = not(!0 as u64 + 0).overflowing_shr(1_u32).0; + | ^^^^^^^^^ help: try: `!0_u64` + +error: casting integer literal to `u64` is unnecessary + --> tests/ui/unnecessary_cast.rs:699:33 + | +LL | let issue_11882_test: u64 = (!0 as u64).overflowing_shr(1_u32).0; + | ^^^^^^^^^^^ help: try: `(!0_u64)` + +error: casting to the same type is unnecessary (`u64` -> `u64`) + --> tests/ui/unnecessary_cast.rs:701:34 + | +LL | let issue_11882_test2: u64 = (!0_u64 as u64).overflowing_shr(1_u32).0; + | ^^^^^^^^^^^^^^^ help: try: `(!0_u64)` + +error: casting to the same type is unnecessary (`u64` -> `u64`) + --> tests/ui/unnecessary_cast.rs:703:34 + | +LL | let issue_11882_test3: u64 = (!not(!0_u64) as u64).overflowing_shr(1_u32).0; + | ^^^^^^^^^^^^^^^^^^^^^ help: try: `(!not(!0_u64))` + +error: casting integer literal to `u64` is unnecessary + --> tests/ui/unnecessary_cast.rs:705:35 + | +LL | let issue_11882_test4: u64 = (!0 as u64 + 0).overflowing_shr(1_u32).0; + | ^^^^^^^^^ help: try: `!0_u64` + +error: casting integer literal to `u64` is unnecessary + --> tests/ui/unnecessary_cast.rs:707:37 + | +LL | let issue_11882_test5: u64 = (!(0 as u64 + 0)).overflowing_shr(1_u32).0; + | ^^^^^^^^ help: try: `0_u64` + +error: casting integer literal to `u64` is unnecessary + --> tests/ui/unnecessary_cast.rs:711:37 + | +LL | let issue_11882_chk1: u64 = not(!0 as u64).overflowing_shr(1_u32).0; + | ^^^^^^^^^ help: try: `!0_u64` + +error: casting to the same type is unnecessary (`u64` -> `u64`) + --> tests/ui/unnecessary_cast.rs:713:33 + | +LL | let issue_11882_chk2: u64 = (!not(0_u64) as u64).overflowing_shr(1_u32).0; + | ^^^^^^^^^^^^^^^^^^^^ help: try: `(!not(0_u64))` + +error: casting integer literal to `u64` is unnecessary + --> tests/ui/unnecessary_cast.rs:715:39 + | +LL | let issue_11882_chk3: u64 = (!not(0 as u64)).overflowing_shr(1_u32).0; + | ^^^^^^^^ help: try: `0_u64` + +error: casting integer literal to `u64` is unnecessary + --> tests/ui/unnecessary_cast.rs:717:37 + | +LL | let issue_11882_chk4: u64 = not(!0 as u64 + 0).overflowing_shr(1_u32).0; + | ^^^^^^^^^ help: try: `!0_u64` + +error: aborting due to 83 previous errors From 01458a74a958e372ab6ed13d2deecf1b410ef4e4 Mon Sep 17 00:00:00 2001 From: Aliaksei Semianiuk Date: Sat, 20 Jun 2026 23:59:59 +0500 Subject: [PATCH 68/77] Update actions/checkout to v7 --- .github/workflows/clippy_dev.yml | 2 +- .github/workflows/clippy_mq.yml | 8 ++++---- .github/workflows/clippy_pr.yml | 2 +- .github/workflows/deploy.yml | 4 ++-- .github/workflows/lintcheck.yml | 6 +++--- .github/workflows/remark.yml | 2 +- book/src/continuous_integration/github_actions.md | 2 +- 7 files changed, 13 insertions(+), 13 deletions(-) diff --git a/.github/workflows/clippy_dev.yml b/.github/workflows/clippy_dev.yml index 3a99d65233d38..cd90bb0a25f5f 100644 --- a/.github/workflows/clippy_dev.yml +++ b/.github/workflows/clippy_dev.yml @@ -16,7 +16,7 @@ jobs: steps: # Setup - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 with: # Unsetting this would make so that any malicious package could get our Github Token persist-credentials: false diff --git a/.github/workflows/clippy_mq.yml b/.github/workflows/clippy_mq.yml index b612ea4611a9f..7d313ece05b80 100644 --- a/.github/workflows/clippy_mq.yml +++ b/.github/workflows/clippy_mq.yml @@ -34,7 +34,7 @@ jobs: steps: # Setup - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 with: persist-credentials: false @@ -94,7 +94,7 @@ jobs: steps: # Setup - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 with: persist-credentials: false @@ -112,7 +112,7 @@ jobs: steps: # Setup - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 with: persist-credentials: false @@ -168,7 +168,7 @@ jobs: steps: # Setup - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 with: persist-credentials: false diff --git a/.github/workflows/clippy_pr.yml b/.github/workflows/clippy_pr.yml index f9e882d9757ce..5658e041e03cf 100644 --- a/.github/workflows/clippy_pr.yml +++ b/.github/workflows/clippy_pr.yml @@ -24,7 +24,7 @@ jobs: steps: # Setup - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 with: # Unsetting this would make so that any malicious package could get our Github Token persist-credentials: false diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 872931160c35f..b95cbbddd4b32 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -25,13 +25,13 @@ jobs: steps: # Setup - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 with: # Unsetting this would make so that any malicious package could get our Github Token persist-credentials: false - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 with: ref: ${{ env.TARGET_BRANCH }} path: 'out' diff --git a/.github/workflows/lintcheck.yml b/.github/workflows/lintcheck.yml index 981fecd17c988..210f10b7b8804 100644 --- a/.github/workflows/lintcheck.yml +++ b/.github/workflows/lintcheck.yml @@ -24,7 +24,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 with: fetch-depth: 2 # Unsetting this would make so that any malicious package could get our Github Token @@ -80,7 +80,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 with: # Unsetting this would make so that any malicious package could get our Github Token persist-credentials: false @@ -113,7 +113,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 with: # Unsetting this would make so that any malicious package could get our Github Token persist-credentials: false diff --git a/.github/workflows/remark.yml b/.github/workflows/remark.yml index d4dc80efe79de..532af9dff83f2 100644 --- a/.github/workflows/remark.yml +++ b/.github/workflows/remark.yml @@ -14,7 +14,7 @@ jobs: steps: # Setup - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 with: # Unsetting this would make so that any malicious package could get our Github Token persist-credentials: false diff --git a/book/src/continuous_integration/github_actions.md b/book/src/continuous_integration/github_actions.md index bed0f66bab33a..e198a13b38d24 100644 --- a/book/src/continuous_integration/github_actions.md +++ b/book/src/continuous_integration/github_actions.md @@ -15,7 +15,7 @@ jobs: clippy_check: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - name: Run Clippy run: cargo clippy --all-targets --all-features ``` From 0556e4cc0a227e14b361e9b5d60459ae05b6b075 Mon Sep 17 00:00:00 2001 From: khyperia <953151+khyperia@users.noreply.github.com> Date: Sun, 21 Jun 2026 13:32:47 +0200 Subject: [PATCH 69/77] remove AliasTy::def_id() --- clippy_lints/src/functions/must_use.rs | 5 +--- clippy_lints/src/functions/result.rs | 9 +------ clippy_lints/src/len_without_is_empty.rs | 7 ++++-- clippy_lints/src/methods/needless_collect.rs | 6 +---- clippy_lints/src/no_effect.rs | 9 +------ clippy_utils/src/ty/mod.rs | 26 ++++++-------------- 6 files changed, 17 insertions(+), 45 deletions(-) diff --git a/clippy_lints/src/functions/must_use.rs b/clippy_lints/src/functions/must_use.rs index a3e982bb09430..39b53e02831c4 100644 --- a/clippy_lints/src/functions/must_use.rs +++ b/clippy_lints/src/functions/must_use.rs @@ -4,7 +4,6 @@ use rustc_errors::Applicability; use rustc_hir::def::Res; use rustc_hir::def_id::DefIdSet; use rustc_hir::{self as hir, Attribute, QPath, find_attr}; -use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, LintContext}; use rustc_middle::ty::{self, Ty}; use rustc_span::{Span, sym}; @@ -16,7 +15,6 @@ use clippy_utils::ty::is_must_use_ty; use clippy_utils::visitors::for_each_expr_without_closures; use clippy_utils::{is_entrypoint_fn, return_ty, trait_ref_of_method}; use rustc_span::Symbol; -use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use core::ops::ControlFlow; @@ -166,8 +164,7 @@ fn check_needless_must_use( } else if reason.is_none() && is_must_use_ty(cx, return_ty(cx, item_id)) { // Ignore async functions unless Future::Output type is a must_use type if sig.header.is_async() { - let infcx = cx.tcx.infer_ctxt().build(cx.typing_mode()); - if let Some(future_ty) = infcx.err_ctxt().get_impl_future_output_ty(return_ty(cx, item_id)) + if let Some(future_ty) = cx.tcx.get_impl_future_output_ty(return_ty(cx, item_id)) && !is_must_use_ty(cx, future_ty) { return; diff --git a/clippy_lints/src/functions/result.rs b/clippy_lints/src/functions/result.rs index 331c6e23bddd7..816f2cac8429b 100644 --- a/clippy_lints/src/functions/result.rs +++ b/clippy_lints/src/functions/result.rs @@ -2,12 +2,10 @@ use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::res::MaybeDef; use rustc_errors::Diag; use rustc_hir as hir; -use rustc_infer::infer::TyCtxtInferExt as _; use rustc_lint::{LateContext, LintContext}; use rustc_middle::ty::{self, Ty}; use rustc_span::def_id::DefIdSet; use rustc_span::{Span, sym}; -use rustc_trait_selection::error_reporting::InferCtxtErrorExt as _; use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then}; use clippy_utils::ty::{AdtVariantInfo, approx_ty_size}; @@ -32,12 +30,7 @@ fn result_err_ty<'tcx>( // for async functions, peel through `impl Future` to get `T` if cx.tcx.ty_is_opaque_future(ty) - && let Some(future_output_ty) = cx - .tcx - .infer_ctxt() - .build(cx.typing_mode()) - .err_ctxt() - .get_impl_future_output_ty(ty) + && let Some(future_output_ty) = cx.tcx.get_impl_future_output_ty(ty) { ty = future_output_ty; } diff --git a/clippy_lints/src/len_without_is_empty.rs b/clippy_lints/src/len_without_is_empty.rs index 4b188709a8be3..34730dbb098c4 100644 --- a/clippy_lints/src/len_without_is_empty.rs +++ b/clippy_lints/src/len_without_is_empty.rs @@ -149,8 +149,11 @@ fn check_trait_items(cx: &LateContext<'_>, visited_trait: &Item<'_>, ident: Iden } fn extract_future_output<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<&'tcx PathSegment<'tcx>> { - if let ty::Alias(alias_ty) = ty.kind() - && let Some(Node::OpaqueTy(opaque)) = cx.tcx.hir_get_if_local(alias_ty.kind.def_id()) + if let ty::Alias(ty::AliasTy { + kind: ty::Opaque { def_id }, + .. + }) = *ty.kind() + && let Some(Node::OpaqueTy(opaque)) = cx.tcx.hir_get_if_local(def_id) && let OpaqueTyOrigin::AsyncFn { .. } = opaque.origin && let [GenericBound::Trait(trait_ref)] = &opaque.bounds && let Some(segment) = trait_ref.trait_ref.path.segments.last() diff --git a/clippy_lints/src/methods/needless_collect.rs b/clippy_lints/src/methods/needless_collect.rs index 4f281d745a94e..62a192b7f770f 100644 --- a/clippy_lints/src/methods/needless_collect.rs +++ b/clippy_lints/src/methods/needless_collect.rs @@ -247,11 +247,7 @@ fn iterates_same_ty<'tcx>(cx: &LateContext<'tcx>, iter_ty: Ty<'tcx>, collect_ty: && let Some(into_iter_item_proj) = make_projection(cx.tcx, into_iter_trait, sym::Item, [collect_ty]) && let Ok(into_iter_item_ty) = cx.tcx.try_normalize_erasing_regions( cx.typing_env(), - Unnormalized::new_wip(Ty::new_projection_from_args( - cx.tcx, - into_iter_item_proj.kind.def_id(), - into_iter_item_proj.args, - )), + Unnormalized::new_wip(Ty::new_alias(cx.tcx, into_iter_item_proj)), ) { iter_item_ty == into_iter_item_ty diff --git a/clippy_lints/src/no_effect.rs b/clippy_lints/src/no_effect.rs index f2a54b99170e9..9e6fc68116d4f 100644 --- a/clippy_lints/src/no_effect.rs +++ b/clippy_lints/src/no_effect.rs @@ -9,11 +9,9 @@ use rustc_hir::{ BinOpKind, BlockCheckMode, Expr, ExprKind, HirId, HirIdMap, ItemKind, LocalSource, Node, PatKind, Stmt, StmtKind, StructTailExpr, UnsafeSource, is_range_literal, }; -use rustc_infer::infer::TyCtxtInferExt as _; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::impl_lint_pass; use rustc_span::Span; -use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use std::ops::Deref; declare_clippy_lint! { @@ -162,12 +160,7 @@ impl NoEffect { // Remove `impl Future` to get `T` if cx.tcx.ty_is_opaque_future(ret_ty) - && let Some(true_ret_ty) = cx - .tcx - .infer_ctxt() - .build(cx.typing_mode()) - .err_ctxt() - .get_impl_future_output_ty(ret_ty) + && let Some(true_ret_ty) = cx.tcx.get_impl_future_output_ty(ret_ty) { ret_ty = true_ret_ty; } diff --git a/clippy_utils/src/ty/mod.rs b/clippy_utils/src/ty/mod.rs index 60d19ecf68bb5..8cded245fac22 100644 --- a/clippy_utils/src/ty/mod.rs +++ b/clippy_utils/src/ty/mod.rs @@ -20,8 +20,9 @@ use rustc_middle::ty::adjustment::{Adjust, Adjustment, DerefAdjustKind}; use rustc_middle::ty::layout::ValidityRequirement; use rustc_middle::ty::{ self, AdtDef, AliasTy, AssocItem, AssocTag, Binder, BoundRegion, BoundVarIndexKind, FnSig, GenericArg, - GenericArgKind, GenericArgsRef, IntTy, Region, RegionKind, TraitRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, - TypeVisitableExt, TypeVisitor, UintTy, Unnormalized, Upcast, VariantDef, VariantDiscr, + GenericArgKind, GenericArgsRef, IntTy, ProjectionAliasTy, Region, RegionKind, TraitRef, Ty, TyCtxt, + TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, UintTy, Unnormalized, Upcast, VariantDef, + VariantDiscr, }; use rustc_span::symbol::Ident; use rustc_span::{DUMMY_SP, Span, Symbol}; @@ -669,12 +670,7 @@ pub fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option None, } }, - ty::Alias( - proj @ AliasTy { - kind: ty::Projection { .. }, - .. - }, - ) => match cx + ty::Alias(alias) if let Some(proj) = alias.try_to_projection() => match cx .tcx .try_normalize_erasing_regions(cx.typing_env(), Unnormalized::new_wip(ty)) { @@ -728,14 +724,14 @@ fn sig_from_bounds<'tcx>( inputs.map(|ty| ExprFnSig::Trait(ty, output, predicates_id)) } -fn sig_for_projection<'tcx>(cx: &LateContext<'tcx>, ty: AliasTy<'tcx>) -> Option> { +fn sig_for_projection<'tcx>(cx: &LateContext<'tcx>, ty: ProjectionAliasTy<'tcx>) -> Option> { let mut inputs = None; let mut output = None; let lang_items = cx.tcx.lang_items(); for (pred, _) in cx .tcx - .explicit_item_bounds(ty.kind.def_id()) + .explicit_item_bounds(ty.kind) .iter_instantiated_copied(cx.tcx, ty.args) .map(Unnormalized::skip_norm_wip) { @@ -1097,10 +1093,7 @@ pub fn make_normalized_projection<'tcx>( ); return None; } - match tcx.try_normalize_erasing_regions( - typing_env, - Unnormalized::new_wip(Ty::new_projection_from_args(tcx, ty.kind.def_id(), ty.args)), - ) { + match tcx.try_normalize_erasing_regions(typing_env, Unnormalized::new_wip(Ty::new_alias(tcx, ty))) { Ok(ty) => Some(ty), Err(e) => { debug_assert!(false, "failed to normalize type `{ty}`: {e:#?}"); @@ -1254,10 +1247,7 @@ pub fn make_normalized_projection_with_regions<'tcx>( } let cause = ObligationCause::dummy(); let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(typing_env); - match infcx - .at(&cause, param_env) - .query_normalize(Ty::new_projection_from_args(tcx, ty.kind.def_id(), ty.args)) - { + match infcx.at(&cause, param_env).query_normalize(Ty::new_alias(tcx, ty)) { Ok(ty) => Some(ty.value), Err(e) => { debug_assert!(false, "failed to normalize type `{ty}`: {e:#?}"); From ca7ffdd0b148be35325976781c41c503563bf942 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Sun, 21 Jun 2026 15:56:43 -0700 Subject: [PATCH 70/77] Move all test cases out of named constants --- tests/ui/unnecessary_cast.fixed | 65 ++++-------------- tests/ui/unnecessary_cast.rs | 65 ++++-------------- tests/ui/unnecessary_cast.stderr | 110 +++++++------------------------ 3 files changed, 46 insertions(+), 194 deletions(-) diff --git a/tests/ui/unnecessary_cast.fixed b/tests/ui/unnecessary_cast.fixed index 5016ce3470672..9e07c52e82e67 100644 --- a/tests/ui/unnecessary_cast.fixed +++ b/tests/ui/unnecessary_cast.fixed @@ -659,65 +659,24 @@ fn issue16475() -> *const u8 { } } -const ISSUE_11882_TEST: u64 = (!0_u64).overflowing_shr(1_u32).0; -//~^ unnecessary_cast -const ISSUE_11882_TEST2: u64 = (!0_u64).overflowing_shr(1_u32).0; -//~^ unnecessary_cast -const ISSUE_11882_TEST3: u64 = (!not(!0_u64)).overflowing_shr(1_u32).0; -//~^ unnecessary_cast -const ISSUE_11882_TEST4: u64 = (!0_u64 + 0).overflowing_shr(1_u32).0; -//~^ unnecessary_cast -const ISSUE_11882_TEST5: u64 = (!(0_u64 + 0)).overflowing_shr(1_u32).0; -//~^ unnecessary_cast -const ISSUE_11882_TEST6: u64 = (!((0 + 0) as u64)).overflowing_shr(1_u32).0; - -const ISSUE_11882_CHK1: u64 = not(!0_u64).overflowing_shr(1_u32).0; -//~^ unnecessary_cast -const ISSUE_11882_CHK2: u64 = (!not(0_u64)).overflowing_shr(1_u32).0; -//~^ unnecessary_cast -const ISSUE_11882_CHK3: u64 = (!not(0_u64)).overflowing_shr(1_u32).0; -//~^ unnecessary_cast -const ISSUE_11882_CHK4: u64 = not(!0_u64 + 0).overflowing_shr(1_u32).0; -//~^ unnecessary_cast - // Make sure that the calculated values aren't changed by the fixes. const _: () = { - assert!(0x7f_ff_ff_ff_ff_ff_ff_ffu64 == ISSUE_11882_TEST); - assert!(0x7f_ff_ff_ff_ff_ff_ff_ffu64 == ISSUE_11882_TEST2); - assert!(0x7f_ff_ff_ff_ff_ff_ff_ffu64 == ISSUE_11882_TEST3); - assert!(0x7f_ff_ff_ff_ff_ff_ff_ffu64 == ISSUE_11882_TEST4); - assert!(0x7f_ff_ff_ff_ff_ff_ff_ffu64 == ISSUE_11882_TEST5); - assert!(0x7f_ff_ff_ff_ff_ff_ff_ffu64 == ISSUE_11882_TEST6); - assert!(0 == ISSUE_11882_CHK1); - assert!(0 == ISSUE_11882_CHK2); - assert!(0 == ISSUE_11882_CHK3); - assert!(0 == ISSUE_11882_CHK4); -}; - -fn issue_11882() { - // the non-const version of the tests - let issue_11882_test: u64 = (!0_u64).overflowing_shr(1_u32).0; - //~^ unnecessary_cast - let issue_11882_test2: u64 = (!0_u64).overflowing_shr(1_u32).0; - //~^ unnecessary_cast - let issue_11882_test3: u64 = (!not(!0_u64)).overflowing_shr(1_u32).0; + use std::convert::identity; + assert!(0x7f_ff_ff_ff_ff_ff_ff_ffu64 == (!0_u64).overflowing_shr(1_u32).0); //~^ unnecessary_cast - let issue_11882_test4: u64 = (!0_u64 + 0).overflowing_shr(1_u32).0; + assert!(0x7f_ff_ff_ff_ff_ff_ff_ffu64 == (!0_u64).overflowing_shr(1_u32).0); //~^ unnecessary_cast - let issue_11882_test5: u64 = (!(0_u64 + 0)).overflowing_shr(1_u32).0; + assert!(0 == (!identity(!0_u64) as u64).overflowing_shr(1_u32).0); + assert!(0x7f_ff_ff_ff_ff_ff_ff_ffu64 == (!0_u64 + 0).overflowing_shr(1_u32).0); //~^ unnecessary_cast - let issue_11882_test6: u64 = (!((0 + 0) as u64)).overflowing_shr(1_u32).0; - - let issue_11882_chk1: u64 = not(!0_u64).overflowing_shr(1_u32).0; + assert!(0x7f_ff_ff_ff_ff_ff_ff_ffu64 == (!(0_u64 + 0)).overflowing_shr(1_u32).0); //~^ unnecessary_cast - let issue_11882_chk2: u64 = (!not(0_u64)).overflowing_shr(1_u32).0; + assert!(0x7f_ff_ff_ff_ff_ff_ff_ffu64 == (!((0 + 0) as u64)).overflowing_shr(1_u32).0); + assert!(0x7f_ff_ff_ff_ff_ff_ff_ffu64 == identity(!0_u64).overflowing_shr(1_u32).0); //~^ unnecessary_cast - let issue_11882_chk3: u64 = (!not(0_u64)).overflowing_shr(1_u32).0; + assert!(0x7f_ff_ff_ff_ff_ff_ff_ffu64 == (!identity(0_u64) as u64).overflowing_shr(1_u32).0); + assert!(0x7f_ff_ff_ff_ff_ff_ff_ffu64 == (!identity(0_u64)).overflowing_shr(1_u32).0); //~^ unnecessary_cast - let issue_11882_chk4: u64 = not(!0_u64 + 0).overflowing_shr(1_u32).0; + assert!(0x7f_ff_ff_ff_ff_ff_ff_ffu64 == identity(!0_u64 + 0).overflowing_shr(1_u32).0); //~^ unnecessary_cast -} - -const fn not>(x: T) -> T { - !x -} +}; diff --git a/tests/ui/unnecessary_cast.rs b/tests/ui/unnecessary_cast.rs index 00a2687387140..43d3e56e365a2 100644 --- a/tests/ui/unnecessary_cast.rs +++ b/tests/ui/unnecessary_cast.rs @@ -659,65 +659,24 @@ fn issue16475() -> *const u8 { } } -const ISSUE_11882_TEST: u64 = (!0 as u64).overflowing_shr(1_u32).0; -//~^ unnecessary_cast -const ISSUE_11882_TEST2: u64 = (!0_u64 as u64).overflowing_shr(1_u32).0; -//~^ unnecessary_cast -const ISSUE_11882_TEST3: u64 = (!not(!0_u64) as u64).overflowing_shr(1_u32).0; -//~^ unnecessary_cast -const ISSUE_11882_TEST4: u64 = (!0 as u64 + 0).overflowing_shr(1_u32).0; -//~^ unnecessary_cast -const ISSUE_11882_TEST5: u64 = (!(0 as u64 + 0)).overflowing_shr(1_u32).0; -//~^ unnecessary_cast -const ISSUE_11882_TEST6: u64 = (!((0 + 0) as u64)).overflowing_shr(1_u32).0; - -const ISSUE_11882_CHK1: u64 = not(!0 as u64).overflowing_shr(1_u32).0; -//~^ unnecessary_cast -const ISSUE_11882_CHK2: u64 = (!not(0_u64) as u64).overflowing_shr(1_u32).0; -//~^ unnecessary_cast -const ISSUE_11882_CHK3: u64 = (!not(0 as u64)).overflowing_shr(1_u32).0; -//~^ unnecessary_cast -const ISSUE_11882_CHK4: u64 = not(!0 as u64 + 0).overflowing_shr(1_u32).0; -//~^ unnecessary_cast - // Make sure that the calculated values aren't changed by the fixes. const _: () = { - assert!(0x7f_ff_ff_ff_ff_ff_ff_ffu64 == ISSUE_11882_TEST); - assert!(0x7f_ff_ff_ff_ff_ff_ff_ffu64 == ISSUE_11882_TEST2); - assert!(0x7f_ff_ff_ff_ff_ff_ff_ffu64 == ISSUE_11882_TEST3); - assert!(0x7f_ff_ff_ff_ff_ff_ff_ffu64 == ISSUE_11882_TEST4); - assert!(0x7f_ff_ff_ff_ff_ff_ff_ffu64 == ISSUE_11882_TEST5); - assert!(0x7f_ff_ff_ff_ff_ff_ff_ffu64 == ISSUE_11882_TEST6); - assert!(0 == ISSUE_11882_CHK1); - assert!(0 == ISSUE_11882_CHK2); - assert!(0 == ISSUE_11882_CHK3); - assert!(0 == ISSUE_11882_CHK4); -}; - -fn issue_11882() { - // the non-const version of the tests - let issue_11882_test: u64 = (!0 as u64).overflowing_shr(1_u32).0; - //~^ unnecessary_cast - let issue_11882_test2: u64 = (!0_u64 as u64).overflowing_shr(1_u32).0; - //~^ unnecessary_cast - let issue_11882_test3: u64 = (!not(!0_u64) as u64).overflowing_shr(1_u32).0; + use std::convert::identity; + assert!(0x7f_ff_ff_ff_ff_ff_ff_ffu64 == (!0 as u64).overflowing_shr(1_u32).0); //~^ unnecessary_cast - let issue_11882_test4: u64 = (!0 as u64 + 0).overflowing_shr(1_u32).0; + assert!(0x7f_ff_ff_ff_ff_ff_ff_ffu64 == (!0_u64 as u64).overflowing_shr(1_u32).0); //~^ unnecessary_cast - let issue_11882_test5: u64 = (!(0 as u64 + 0)).overflowing_shr(1_u32).0; + assert!(0 == (!identity(!0_u64) as u64).overflowing_shr(1_u32).0); + assert!(0x7f_ff_ff_ff_ff_ff_ff_ffu64 == (!0 as u64 + 0).overflowing_shr(1_u32).0); //~^ unnecessary_cast - let issue_11882_test6: u64 = (!((0 + 0) as u64)).overflowing_shr(1_u32).0; - - let issue_11882_chk1: u64 = not(!0 as u64).overflowing_shr(1_u32).0; + assert!(0x7f_ff_ff_ff_ff_ff_ff_ffu64 == (!(0 as u64 + 0)).overflowing_shr(1_u32).0); //~^ unnecessary_cast - let issue_11882_chk2: u64 = (!not(0_u64) as u64).overflowing_shr(1_u32).0; + assert!(0x7f_ff_ff_ff_ff_ff_ff_ffu64 == (!((0 + 0) as u64)).overflowing_shr(1_u32).0); + assert!(0x7f_ff_ff_ff_ff_ff_ff_ffu64 == identity(!0 as u64).overflowing_shr(1_u32).0); //~^ unnecessary_cast - let issue_11882_chk3: u64 = (!not(0 as u64)).overflowing_shr(1_u32).0; + assert!(0x7f_ff_ff_ff_ff_ff_ff_ffu64 == (!identity(0_u64) as u64).overflowing_shr(1_u32).0); + assert!(0x7f_ff_ff_ff_ff_ff_ff_ffu64 == (!identity(0 as u64)).overflowing_shr(1_u32).0); //~^ unnecessary_cast - let issue_11882_chk4: u64 = not(!0 as u64 + 0).overflowing_shr(1_u32).0; + assert!(0x7f_ff_ff_ff_ff_ff_ff_ffu64 == identity(!0 as u64 + 0).overflowing_shr(1_u32).0); //~^ unnecessary_cast -} - -const fn not>(x: T) -> T { - !x -} +}; diff --git a/tests/ui/unnecessary_cast.stderr b/tests/ui/unnecessary_cast.stderr index eb710ba1fee29..9807ae0341421 100644 --- a/tests/ui/unnecessary_cast.stderr +++ b/tests/ui/unnecessary_cast.stderr @@ -392,112 +392,46 @@ LL | *(&NONE as *const _ as *const _ as *const *const u8 as *const *cons | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(&NONE as *const _ as *const _ as *const *const u8)` error: casting integer literal to `u64` is unnecessary - --> tests/ui/unnecessary_cast.rs:662:31 + --> tests/ui/unnecessary_cast.rs:665:45 | -LL | const ISSUE_11882_TEST: u64 = (!0 as u64).overflowing_shr(1_u32).0; - | ^^^^^^^^^^^ help: try: `(!0_u64)` +LL | assert!(0x7f_ff_ff_ff_ff_ff_ff_ffu64 == (!0 as u64).overflowing_shr(1_u32).0); + | ^^^^^^^^^^^ help: try: `(!0_u64)` error: casting to the same type is unnecessary (`u64` -> `u64`) - --> tests/ui/unnecessary_cast.rs:664:32 + --> tests/ui/unnecessary_cast.rs:667:45 | -LL | const ISSUE_11882_TEST2: u64 = (!0_u64 as u64).overflowing_shr(1_u32).0; - | ^^^^^^^^^^^^^^^ help: try: `(!0_u64)` - -error: casting to the same type is unnecessary (`u64` -> `u64`) - --> tests/ui/unnecessary_cast.rs:666:32 - | -LL | const ISSUE_11882_TEST3: u64 = (!not(!0_u64) as u64).overflowing_shr(1_u32).0; - | ^^^^^^^^^^^^^^^^^^^^^ help: try: `(!not(!0_u64))` +LL | assert!(0x7f_ff_ff_ff_ff_ff_ff_ffu64 == (!0_u64 as u64).overflowing_shr(1_u32).0); + | ^^^^^^^^^^^^^^^ help: try: `(!0_u64)` error: casting integer literal to `u64` is unnecessary - --> tests/ui/unnecessary_cast.rs:668:33 + --> tests/ui/unnecessary_cast.rs:670:46 | -LL | const ISSUE_11882_TEST4: u64 = (!0 as u64 + 0).overflowing_shr(1_u32).0; - | ^^^^^^^^^ help: try: `!0_u64` +LL | assert!(0x7f_ff_ff_ff_ff_ff_ff_ffu64 == (!0 as u64 + 0).overflowing_shr(1_u32).0); + | ^^^^^^^^^ help: try: `!0_u64` error: casting integer literal to `u64` is unnecessary - --> tests/ui/unnecessary_cast.rs:670:35 - | -LL | const ISSUE_11882_TEST5: u64 = (!(0 as u64 + 0)).overflowing_shr(1_u32).0; - | ^^^^^^^^ help: try: `0_u64` - -error: casting integer literal to `u64` is unnecessary - --> tests/ui/unnecessary_cast.rs:674:35 - | -LL | const ISSUE_11882_CHK1: u64 = not(!0 as u64).overflowing_shr(1_u32).0; - | ^^^^^^^^^ help: try: `!0_u64` - -error: casting to the same type is unnecessary (`u64` -> `u64`) - --> tests/ui/unnecessary_cast.rs:676:31 + --> tests/ui/unnecessary_cast.rs:672:48 | -LL | const ISSUE_11882_CHK2: u64 = (!not(0_u64) as u64).overflowing_shr(1_u32).0; - | ^^^^^^^^^^^^^^^^^^^^ help: try: `(!not(0_u64))` +LL | assert!(0x7f_ff_ff_ff_ff_ff_ff_ffu64 == (!(0 as u64 + 0)).overflowing_shr(1_u32).0); + | ^^^^^^^^ help: try: `0_u64` error: casting integer literal to `u64` is unnecessary - --> tests/ui/unnecessary_cast.rs:678:37 - | -LL | const ISSUE_11882_CHK3: u64 = (!not(0 as u64)).overflowing_shr(1_u32).0; - | ^^^^^^^^ help: try: `0_u64` - -error: casting integer literal to `u64` is unnecessary - --> tests/ui/unnecessary_cast.rs:680:35 - | -LL | const ISSUE_11882_CHK4: u64 = not(!0 as u64 + 0).overflowing_shr(1_u32).0; - | ^^^^^^^^^ help: try: `!0_u64` - -error: casting integer literal to `u64` is unnecessary - --> tests/ui/unnecessary_cast.rs:699:33 - | -LL | let issue_11882_test: u64 = (!0 as u64).overflowing_shr(1_u32).0; - | ^^^^^^^^^^^ help: try: `(!0_u64)` - -error: casting to the same type is unnecessary (`u64` -> `u64`) - --> tests/ui/unnecessary_cast.rs:701:34 - | -LL | let issue_11882_test2: u64 = (!0_u64 as u64).overflowing_shr(1_u32).0; - | ^^^^^^^^^^^^^^^ help: try: `(!0_u64)` - -error: casting to the same type is unnecessary (`u64` -> `u64`) - --> tests/ui/unnecessary_cast.rs:703:34 - | -LL | let issue_11882_test3: u64 = (!not(!0_u64) as u64).overflowing_shr(1_u32).0; - | ^^^^^^^^^^^^^^^^^^^^^ help: try: `(!not(!0_u64))` - -error: casting integer literal to `u64` is unnecessary - --> tests/ui/unnecessary_cast.rs:705:35 - | -LL | let issue_11882_test4: u64 = (!0 as u64 + 0).overflowing_shr(1_u32).0; - | ^^^^^^^^^ help: try: `!0_u64` - -error: casting integer literal to `u64` is unnecessary - --> tests/ui/unnecessary_cast.rs:707:37 - | -LL | let issue_11882_test5: u64 = (!(0 as u64 + 0)).overflowing_shr(1_u32).0; - | ^^^^^^^^ help: try: `0_u64` - -error: casting integer literal to `u64` is unnecessary - --> tests/ui/unnecessary_cast.rs:711:37 - | -LL | let issue_11882_chk1: u64 = not(!0 as u64).overflowing_shr(1_u32).0; - | ^^^^^^^^^ help: try: `!0_u64` - -error: casting to the same type is unnecessary (`u64` -> `u64`) - --> tests/ui/unnecessary_cast.rs:713:33 + --> tests/ui/unnecessary_cast.rs:675:54 | -LL | let issue_11882_chk2: u64 = (!not(0_u64) as u64).overflowing_shr(1_u32).0; - | ^^^^^^^^^^^^^^^^^^^^ help: try: `(!not(0_u64))` +LL | assert!(0x7f_ff_ff_ff_ff_ff_ff_ffu64 == identity(!0 as u64).overflowing_shr(1_u32).0); + | ^^^^^^^^^ help: try: `!0_u64` error: casting integer literal to `u64` is unnecessary - --> tests/ui/unnecessary_cast.rs:715:39 + --> tests/ui/unnecessary_cast.rs:678:56 | -LL | let issue_11882_chk3: u64 = (!not(0 as u64)).overflowing_shr(1_u32).0; - | ^^^^^^^^ help: try: `0_u64` +LL | assert!(0x7f_ff_ff_ff_ff_ff_ff_ffu64 == (!identity(0 as u64)).overflowing_shr(1_u32).0); + | ^^^^^^^^ help: try: `0_u64` error: casting integer literal to `u64` is unnecessary - --> tests/ui/unnecessary_cast.rs:717:37 + --> tests/ui/unnecessary_cast.rs:680:54 | -LL | let issue_11882_chk4: u64 = not(!0 as u64 + 0).overflowing_shr(1_u32).0; - | ^^^^^^^^^ help: try: `!0_u64` +LL | assert!(0x7f_ff_ff_ff_ff_ff_ff_ffu64 == identity(!0 as u64 + 0).overflowing_shr(1_u32).0); + | ^^^^^^^^^ help: try: `!0_u64` -error: aborting due to 83 previous errors +error: aborting due to 72 previous errors From 76418128dc4c6c50067df392cc8419b747b11396 Mon Sep 17 00:00:00 2001 From: Hamdan-Khan Date: Mon, 22 Jun 2026 13:02:26 +0500 Subject: [PATCH 71/77] Do not trigger `manual_option_zip` when map receiver is a lazy evaluated expression --- clippy_lints/src/methods/manual_option_zip.rs | 3 ++ tests/ui/manual_option_zip.fixed | 28 +++++++++++++++---- tests/ui/manual_option_zip.rs | 28 +++++++++++++++---- tests/ui/manual_option_zip.stderr | 16 ++++------- 4 files changed, 54 insertions(+), 21 deletions(-) diff --git a/clippy_lints/src/methods/manual_option_zip.rs b/clippy_lints/src/methods/manual_option_zip.rs index aa23b9deff45b..538f8a2fe93dc 100644 --- a/clippy_lints/src/methods/manual_option_zip.rs +++ b/clippy_lints/src/methods/manual_option_zip.rs @@ -1,4 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::eager_or_lazy::switch_to_eager_eval; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::peel_blocks; use clippy_utils::res::{MaybeDef, MaybeResPath}; @@ -29,6 +30,8 @@ pub(super) fn check<'tcx>( && let ExprKind::MethodCall(method_path, map_recv, [map_arg], _) = peel_blocks(outer_value).kind && method_path.ident.name == sym::map && cx.typeck_results().expr_ty(map_recv).is_diag_item(cx, sym::Option) + // `b` is not lazy evaluated + && switch_to_eager_eval(cx, map_recv) // `b` does not reference the outer closure parameter `a`. && !local_used_in(cx, outer_param_id, map_recv) // `|b| (a, b)` diff --git a/tests/ui/manual_option_zip.fixed b/tests/ui/manual_option_zip.fixed index 0a903fb784075..8b821f8737cbb 100644 --- a/tests/ui/manual_option_zip.fixed +++ b/tests/ui/manual_option_zip.fixed @@ -21,11 +21,6 @@ fn should_lint() { let _ = None::.zip(b); //~^ manual_option_zip - // with function call as map receiver - let a: Option = Some(1); - let _ = a.zip(get_option()); - //~^ manual_option_zip - // tuple order reversed: (inner, outer) instead of (outer, inner) let a: Option = Some(1); let b: Option = Some(2); @@ -123,3 +118,26 @@ fn issue16968() { let opts = [1, 2]; let _ = a.and_then(|a| opts.into_iter().find(|b| *b == a).map(|b| (a, b))); } + +fn issue17253() { + // don't trigger the lint if map receiver is a lazy evaluated expression + // because `a.zip(b_func())` requires eager evaluation of the argument, + // preventing the otherwise conditional execution of `b_func()` + + use std::hint::black_box; + let a: Option = Some(1); + + // conditional function call + let _ = a.and_then(|a| black_box(get_option()).map(|b| (a, b))); + + let mut b = 2; + + // conditional side effects + let _ = a.and_then(|a| { + { + b /= 2; + Some(b) + } + .map(|b| (a, b)) + }); +} diff --git a/tests/ui/manual_option_zip.rs b/tests/ui/manual_option_zip.rs index 942d8aea3e835..5d059a98ee12c 100644 --- a/tests/ui/manual_option_zip.rs +++ b/tests/ui/manual_option_zip.rs @@ -21,11 +21,6 @@ fn should_lint() { let _ = None::.and_then(|a| b.map(|b| (a, b))); //~^ manual_option_zip - // with function call as map receiver - let a: Option = Some(1); - let _ = a.and_then(|a| get_option().map(|b| (a, b))); - //~^ manual_option_zip - // tuple order reversed: (inner, outer) instead of (outer, inner) let a: Option = Some(1); let b: Option = Some(2); @@ -123,3 +118,26 @@ fn issue16968() { let opts = [1, 2]; let _ = a.and_then(|a| opts.into_iter().find(|b| *b == a).map(|b| (a, b))); } + +fn issue17253() { + // don't trigger the lint if map receiver is a lazy evaluated expression + // because `a.zip(b_func())` requires eager evaluation of the argument, + // preventing the otherwise conditional execution of `b_func()` + + use std::hint::black_box; + let a: Option = Some(1); + + // conditional function call + let _ = a.and_then(|a| black_box(get_option()).map(|b| (a, b))); + + let mut b = 2; + + // conditional side effects + let _ = a.and_then(|a| { + { + b /= 2; + Some(b) + } + .map(|b| (a, b)) + }); +} diff --git a/tests/ui/manual_option_zip.stderr b/tests/ui/manual_option_zip.stderr index 473f21702654c..55175660b7a26 100644 --- a/tests/ui/manual_option_zip.stderr +++ b/tests/ui/manual_option_zip.stderr @@ -20,34 +20,28 @@ LL | let _ = None::.and_then(|a| b.map(|b| (a, b))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `None::.zip(b)` error: manual implementation of `Option::zip` - --> tests/ui/manual_option_zip.rs:26:13 - | -LL | let _ = a.and_then(|a| get_option().map(|b| (a, b))); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `a.zip(get_option())` - -error: manual implementation of `Option::zip` - --> tests/ui/manual_option_zip.rs:32:13 + --> tests/ui/manual_option_zip.rs:27:13 | LL | let _ = a.and_then(|a| b.map(|b| (b, a))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `b.zip(a)` error: manual implementation of `Option::zip` - --> tests/ui/manual_option_zip.rs:39:13 + --> tests/ui/manual_option_zip.rs:34:13 | LL | let _ = a.and_then(|a| { b.map(|b| (a, b)) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `a.zip(b)` error: manual implementation of `Option::zip` - --> tests/ui/manual_option_zip.rs:42:13 + --> tests/ui/manual_option_zip.rs:37:13 | LL | let _ = a.and_then(|a| b.map(|b| { (a, b) })); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `a.zip(b)` error: manual implementation of `Option::zip` - --> tests/ui/manual_option_zip.rs:45:13 + --> tests/ui/manual_option_zip.rs:40:13 | LL | let _ = a.and_then(|a| { b.map(|b| { (a, b) }) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `a.zip(b)` -error: aborting due to 8 previous errors +error: aborting due to 7 previous errors From 6e6921c9d88dcb8b20146059a78d0014659c7b3f Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Mon, 22 Jun 2026 13:45:16 -0400 Subject: [PATCH 72/77] Simplify `missing_inline_in_public_items`. --- clippy_lints/src/missing_inline.rs | 151 ++++------------------ tests/ui/missing_inline.stderr | 12 +- tests/ui/missing_inline_executable.stderr | 2 +- 3 files changed, 35 insertions(+), 130 deletions(-) diff --git a/clippy_lints/src/missing_inline.rs b/clippy_lints/src/missing_inline.rs index 93cfed38c43ed..32a86db67c194 100644 --- a/clippy_lints/src/missing_inline.rs +++ b/clippy_lints/src/missing_inline.rs @@ -1,8 +1,6 @@ -use clippy_utils::diagnostics::{span_lint, span_lint_hir}; -use rustc_hir::def_id::DefId; -use rustc_hir::{self as hir, Attribute, find_attr}; -use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_middle::ty::AssocContainer; +use clippy_utils::diagnostics::span_lint; +use rustc_hir::{ImplItem, ImplItemKind, Item, ItemKind, OwnerId, TraitFn, TraitItem, TraitItemKind, find_attr}; +use rustc_lint::{LateContext, LateLintPass}; use rustc_session::config::CrateType; use rustc_session::declare_lint_pass; use rustc_span::Span; @@ -66,134 +64,41 @@ declare_clippy_lint! { declare_lint_pass!(MissingInline => [MISSING_INLINE_IN_PUBLIC_ITEMS]); -fn check_missing_inline_attrs( - cx: &LateContext<'_>, - attrs: &[Attribute], - sp: Span, - desc: &'static str, - hir_id: Option, -) { - if !find_attr!(attrs, Inline(..)) { - let msg = format!("missing `#[inline]` for {desc}"); - if let Some(hir_id) = hir_id { - span_lint_hir(cx, MISSING_INLINE_IN_PUBLIC_ITEMS, hir_id, sp, msg); - } else { - span_lint(cx, MISSING_INLINE_IN_PUBLIC_ITEMS, sp, msg); - } +fn check(cx: &LateContext<'_>, item: OwnerId, sp: Span) { + if cx.effective_visibilities.is_exported(item.def_id) + && !find_attr!(cx.tcx.hir_attrs(item.into()), Inline(..)) + // Rust `inline` doesn't mean anything with external linkage. + && !cx.tcx.codegen_fn_attrs(item.def_id).contains_extern_indicator() + && !cx.tcx.crate_types().iter().any(|&t| matches!(t, CrateType::ProcMacro)) + && !sp.in_external_macro(cx.tcx.sess.source_map()) + { + span_lint( + cx, + MISSING_INLINE_IN_PUBLIC_ITEMS, + sp, + "missing `#[inline]` on a publicly callable function", + ); } } impl<'tcx> LateLintPass<'tcx> for MissingInline { - fn check_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx hir::Item<'_>) { - if it.span.in_external_macro(cx.sess().source_map()) { - return; - } - - if cx - .tcx - .crate_types() - .iter() - .any(|t: &CrateType| matches!(t, CrateType::ProcMacro)) - { - return; - } - - if !cx.effective_visibilities.is_exported(it.owner_id.def_id) { - return; - } - match it.kind { - hir::ItemKind::Fn { .. } => { - if fn_is_externally_exported(cx, it.owner_id.to_def_id()) { - return; - } - - let desc = "a function"; - let attrs = cx.tcx.hir_attrs(it.hir_id()); - check_missing_inline_attrs(cx, attrs, it.span, desc, None); - }, - hir::ItemKind::Trait { items: trait_items, .. } => { - // note: we need to check if the trait is exported so we can't use - // `LateLintPass::check_trait_item` here. - for &tit in trait_items { - let tit_ = cx.tcx.hir_trait_item(tit); - match tit_.kind { - hir::TraitItemKind::Const(..) | hir::TraitItemKind::Type(..) => {}, - hir::TraitItemKind::Fn(..) => { - if cx.tcx.defaultness(tit.owner_id).has_value() { - // trait method with default body needs inline in case - // an impl is not provided - let desc = "a default trait method"; - let item = cx.tcx.hir_trait_item(tit); - let attrs = cx.tcx.hir_attrs(item.hir_id()); - check_missing_inline_attrs(cx, attrs, item.span, desc, Some(tit.hir_id())); - } - }, - } - } - }, - hir::ItemKind::Const(..) - | hir::ItemKind::Enum(..) - | hir::ItemKind::Macro(..) - | hir::ItemKind::Mod(..) - | hir::ItemKind::Static(..) - | hir::ItemKind::Struct(..) - | hir::ItemKind::TraitAlias(..) - | hir::ItemKind::GlobalAsm { .. } - | hir::ItemKind::TyAlias(..) - | hir::ItemKind::Union(..) - | hir::ItemKind::ExternCrate(..) - | hir::ItemKind::ForeignMod { .. } - | hir::ItemKind::Impl { .. } - | hir::ItemKind::Use(..) => {}, + fn check_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx Item<'_>) { + if let ItemKind::Fn { .. } = it.kind { + check(cx, it.owner_id, it.span); } } - fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::ImplItem<'_>) { - if impl_item.span.in_external_macro(cx.sess().source_map()) - || cx - .tcx - .crate_types() - .iter() - .any(|t: &CrateType| matches!(t, CrateType::ProcMacro)) + fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) { + if let TraitItemKind::Fn(_, f) = item.kind + && let TraitFn::Provided(_) = f { - return; + check(cx, item.owner_id, item.span); } + } - // If the item being implemented is not exported, then we don't need #[inline] - if !cx.effective_visibilities.is_exported(impl_item.owner_id.def_id) { - return; - } - - let desc = match impl_item.kind { - hir::ImplItemKind::Fn(..) => "a method", - hir::ImplItemKind::Const(..) | hir::ImplItemKind::Type(_) => return, - }; - - let assoc_item = cx.tcx.associated_item(impl_item.owner_id); - let container_id = assoc_item.container_id(cx.tcx); - let trait_def_id = match assoc_item.container { - AssocContainer::Trait => Some(container_id), - AssocContainer::TraitImpl(_) => Some(cx.tcx.impl_trait_id(container_id)), - AssocContainer::InherentImpl => None, - }; - - if let Some(trait_def_id) = trait_def_id - && trait_def_id.is_local() - && !cx.effective_visibilities.is_exported(impl_item.owner_id.def_id) - { - // If a trait is being implemented for an item, and the - // trait is not exported, we don't need #[inline] - return; + fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>) { + if let ImplItemKind::Fn(..) = item.kind { + check(cx, item.owner_id, item.span); } - - let attrs = cx.tcx.hir_attrs(impl_item.hir_id()); - check_missing_inline_attrs(cx, attrs, impl_item.span, desc, None); } } - -/// Checks if this function is externally exported, where #[inline] wouldn't have the desired effect -/// and a rustc warning would be triggered, see #15301 -fn fn_is_externally_exported(cx: &LateContext<'_>, def_id: DefId) -> bool { - let attrs = cx.tcx.codegen_fn_attrs(def_id); - attrs.contains_extern_indicator() -} diff --git a/tests/ui/missing_inline.stderr b/tests/ui/missing_inline.stderr index 99ee828e805ca..9f5987fb8e79b 100644 --- a/tests/ui/missing_inline.stderr +++ b/tests/ui/missing_inline.stderr @@ -1,4 +1,4 @@ -error: missing `#[inline]` for a function +error: missing `#[inline]` on a publicly callable function --> tests/ui/missing_inline.rs:20:1 | LL | pub fn pub_foo() {} @@ -7,31 +7,31 @@ LL | pub fn pub_foo() {} = note: `-D clippy::missing-inline-in-public-items` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::missing_inline_in_public_items)]` -error: missing `#[inline]` for a default trait method +error: missing `#[inline]` on a publicly callable function --> tests/ui/missing_inline.rs:39:5 | LL | fn PubBar_b() {} | ^^^^^^^^^^^^^^^^ -error: missing `#[inline]` for a method +error: missing `#[inline]` on a publicly callable function --> tests/ui/missing_inline.rs:56:5 | LL | fn PubBar_a() {} | ^^^^^^^^^^^^^^^^ -error: missing `#[inline]` for a method +error: missing `#[inline]` on a publicly callable function --> tests/ui/missing_inline.rs:60:5 | LL | fn PubBar_b() {} | ^^^^^^^^^^^^^^^^ -error: missing `#[inline]` for a method +error: missing `#[inline]` on a publicly callable function --> tests/ui/missing_inline.rs:64:5 | LL | fn PubBar_c() {} | ^^^^^^^^^^^^^^^^ -error: missing `#[inline]` for a method +error: missing `#[inline]` on a publicly callable function --> tests/ui/missing_inline.rs:76:5 | LL | pub fn PubFooImpl() {} diff --git a/tests/ui/missing_inline_executable.stderr b/tests/ui/missing_inline_executable.stderr index 3108e4e490659..d083cb2b54915 100644 --- a/tests/ui/missing_inline_executable.stderr +++ b/tests/ui/missing_inline_executable.stderr @@ -1,4 +1,4 @@ -error: missing `#[inline]` for a function +error: missing `#[inline]` on a publicly callable function --> tests/ui/missing_inline_executable.rs:3:1 | LL | pub fn foo() {} From 753b3a9c4e8e0eab34fce4ed414f52ac6eee2521 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Tue, 23 Jun 2026 12:05:08 -0400 Subject: [PATCH 73/77] Move `empty_enums` to the nursery --- clippy_lints/src/empty_enums.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/empty_enums.rs b/clippy_lints/src/empty_enums.rs index f96854411fe6f..2cac6597949de 100644 --- a/clippy_lints/src/empty_enums.rs +++ b/clippy_lints/src/empty_enums.rs @@ -51,7 +51,7 @@ declare_clippy_lint! { /// [visibility]: https://doc.rust-lang.org/reference/visibility-and-privacy.html #[clippy::version = "pre 1.29.0"] pub EMPTY_ENUMS, - pedantic, + nursery, "enum with no variants" } From e0588c2ecf346aaa867d7113b01a10e0d0625bf0 Mon Sep 17 00:00:00 2001 From: linshuy2 Date: Thu, 12 Mar 2026 21:37:19 +0000 Subject: [PATCH 74/77] fix: `needless_late_init` FN for if/match in block expr --- clippy_lints/src/needless_late_init.rs | 24 +++++++++++++++++------- tests/ui/manual_abs_diff.fixed | 1 + tests/ui/manual_abs_diff.rs | 1 + tests/ui/manual_abs_diff.stderr | 2 +- tests/ui/needless_late_init.fixed | 10 ++++++++++ tests/ui/needless_late_init.rs | 10 ++++++++++ tests/ui/needless_late_init.stderr | 19 ++++++++++++++++++- 7 files changed, 58 insertions(+), 9 deletions(-) diff --git a/clippy_lints/src/needless_late_init.rs b/clippy_lints/src/needless_late_init.rs index 82ab15578e064..42a59113c7296 100644 --- a/clippy_lints/src/needless_late_init.rs +++ b/clippy_lints/src/needless_late_init.rs @@ -204,7 +204,7 @@ fn assignment_suggestions<'tcx>( } struct Usage<'tcx> { - stmt: &'tcx Stmt<'tcx>, + span: Span, expr: &'tcx Expr<'tcx>, needs_semi: bool, } @@ -226,17 +226,27 @@ fn first_usage<'tcx>( .find(|&stmt| is_local_used(cx, stmt, binding_id)) .and_then(|stmt| match stmt.kind { StmtKind::Expr(expr) => Some(Usage { - stmt, + span: stmt.span, expr, needs_semi: true, }), StmtKind::Semi(expr) => Some(Usage { - stmt, + span: stmt.span, expr, needs_semi: false, }), _ => None, }) + .or_else(|| { + block + .expr + .filter(|expr| is_local_used(cx, *expr, binding_id)) + .map(|expr| Usage { + span: expr.span, + expr, + needs_semi: true, + }) + }) } fn local_snippet_without_semicolon(cx: &LateContext<'_>, local: &LetStmt<'_>) -> Option { @@ -300,10 +310,10 @@ fn check<'tcx>( "unneeded late initialization", |diag| { suggestions.push((local_stmt.span, String::new())); - suggestions.push((usage.stmt.span.shrink_to_lo(), format!("{let_snippet} = "))); + suggestions.push((usage.span.shrink_to_lo(), format!("{let_snippet} = "))); if usage.needs_semi { - suggestions.push((usage.stmt.span.shrink_to_hi(), ";".to_owned())); + suggestions.push((usage.span.shrink_to_hi(), ";".to_owned())); } diag.multipart_suggestion( @@ -327,10 +337,10 @@ fn check<'tcx>( "unneeded late initialization", |diag| { suggestions.push((local_stmt.span, String::new())); - suggestions.push((usage.stmt.span.shrink_to_lo(), format!("{let_snippet} = "))); + suggestions.push((usage.span.shrink_to_lo(), format!("{let_snippet} = "))); if usage.needs_semi { - suggestions.push((usage.stmt.span.shrink_to_hi(), ";".to_owned())); + suggestions.push((usage.span.shrink_to_hi(), ";".to_owned())); } diag.multipart_suggestion( diff --git a/tests/ui/manual_abs_diff.fixed b/tests/ui/manual_abs_diff.fixed index 2766942140ce4..3b5cac5dfc986 100644 --- a/tests/ui/manual_abs_diff.fixed +++ b/tests/ui/manual_abs_diff.fixed @@ -51,6 +51,7 @@ fn main() { } // FIXME: bunch of patterns that should be linted +#[expect(clippy::needless_late_init)] fn fixme() { let a: usize = 5; let b: usize = 3; diff --git a/tests/ui/manual_abs_diff.rs b/tests/ui/manual_abs_diff.rs index 2c408f2be3754..f845dd9b149a9 100644 --- a/tests/ui/manual_abs_diff.rs +++ b/tests/ui/manual_abs_diff.rs @@ -61,6 +61,7 @@ fn main() { } // FIXME: bunch of patterns that should be linted +#[expect(clippy::needless_late_init)] fn fixme() { let a: usize = 5; let b: usize = 3; diff --git a/tests/ui/manual_abs_diff.stderr b/tests/ui/manual_abs_diff.stderr index bb6d312b435f8..b441ac9751f05 100644 --- a/tests/ui/manual_abs_diff.stderr +++ b/tests/ui/manual_abs_diff.stderr @@ -80,7 +80,7 @@ LL | let _ = if a > b { (a - b) as u32 } else { (b - a) as u32 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with `abs_diff`: `a.abs_diff(b)` error: manual absolute difference pattern without using `abs_diff` - --> tests/ui/manual_abs_diff.rs:119:5 + --> tests/ui/manual_abs_diff.rs:120:5 | LL | / if a < b { LL | | diff --git a/tests/ui/needless_late_init.fixed b/tests/ui/needless_late_init.fixed index b686a8e9f1a06..fff5bc00d4278 100644 --- a/tests/ui/needless_late_init.fixed +++ b/tests/ui/needless_late_init.fixed @@ -299,3 +299,13 @@ fn issue9895() { //~^ needless_late_init let r = 5; } + +fn if_or_match_in_block_expr() { + + //~^ needless_late_init + let z = if true { + 1 + } else { + 2 + }; +} diff --git a/tests/ui/needless_late_init.rs b/tests/ui/needless_late_init.rs index 23772ff702931..327de94570ca2 100644 --- a/tests/ui/needless_late_init.rs +++ b/tests/ui/needless_late_init.rs @@ -299,3 +299,13 @@ fn issue9895() { //~^ needless_late_init (r = 5); } + +fn if_or_match_in_block_expr() { + let z; + //~^ needless_late_init + if true { + z = 1; + } else { + z = 2; + } +} diff --git a/tests/ui/needless_late_init.stderr b/tests/ui/needless_late_init.stderr index e3e25cdc8d769..1623bc032a255 100644 --- a/tests/ui/needless_late_init.stderr +++ b/tests/ui/needless_late_init.stderr @@ -291,5 +291,22 @@ LL | LL ~ let r = 5; | -error: aborting due to 17 previous errors +error: unneeded late initialization + --> tests/ui/needless_late_init.rs:304:5 + | +LL | let z; + | ^^^^^^ + | +help: move the declaration `z` here and remove the assignments from the branches + | +LL ~ +LL | +LL ~ let z = if true { +LL ~ 1 +LL | } else { +LL ~ 2 +LL ~ }; + | + +error: aborting due to 18 previous errors From 6d4ad6330073eebdd137aac55f2b0b2f1ad8907e Mon Sep 17 00:00:00 2001 From: linshuy2 Date: Sun, 22 Mar 2026 23:24:06 +0000 Subject: [PATCH 75/77] Extend `needless_late_init` to cover grouped assignments --- CHANGELOG.md | 1 + book/src/lint_configuration.md | 31 + clippy_config/src/conf.rs | 24 + clippy_lints/src/lib.rs | 2 +- clippy_lints/src/needless_late_init.rs | 529 +++++++++++------- tests/ui-toml/needless_late_init/clippy.toml | 1 + .../needless_late_init/needless_late_init.rs | 64 +++ .../toml_unknown_key/conf_unknown_key.stderr | 3 + tests/ui/needless_late_init.fixed | 181 +++++- tests/ui/needless_late_init.rs | 173 +++++- tests/ui/needless_late_init.stderr | 180 +++++- 11 files changed, 977 insertions(+), 212 deletions(-) create mode 100644 tests/ui-toml/needless_late_init/clippy.toml create mode 100644 tests/ui-toml/needless_late_init/needless_late_init.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 91c5cbcd7bbf4..689d56d0fb7c6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7574,6 +7574,7 @@ Released 2018-09-13 [`avoid-breaking-exported-api`]: https://doc.rust-lang.org/clippy/lint_configuration.html#avoid-breaking-exported-api [`await-holding-invalid-types`]: https://doc.rust-lang.org/clippy/lint_configuration.html#await-holding-invalid-types [`cargo-ignore-publish`]: https://doc.rust-lang.org/clippy/lint_configuration.html#cargo-ignore-publish +[`check-grouped-late-init`]: https://doc.rust-lang.org/clippy/lint_configuration.html#check-grouped-late-init [`check-incompatible-msrv-in-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#check-incompatible-msrv-in-tests [`check-inconsistent-struct-field-initializers`]: https://doc.rust-lang.org/clippy/lint_configuration.html#check-inconsistent-struct-field-initializers [`check-private-items`]: https://doc.rust-lang.org/clippy/lint_configuration.html#check-private-items diff --git a/book/src/lint_configuration.md b/book/src/lint_configuration.md index dd10ef0538c25..6c6ccd4747c1f 100644 --- a/book/src/lint_configuration.md +++ b/book/src/lint_configuration.md @@ -452,6 +452,37 @@ For internal testing only, ignores the current `publish` settings in the Cargo m * [`cargo_common_metadata`](https://rust-lang.github.io/rust-clippy/master/index.html#cargo_common_metadata) +## `check-grouped-late-init` +Whether to check for grouped late initializations from multiple `let` statements. + +#### Example +```rust +let a; +let b; +if true { + a = 1; + b = 2; +} else { + a = 3; + b = 4; +} +``` +Use instead: +```rust +let (a, b) = if true { + (1, 2) +} else { + (3, 4) +}; +``` + +**Default Value:** `true` + +--- +**Affected lints:** +* [`needless_late_init`](https://rust-lang.github.io/rust-clippy/master/index.html#needless_late_init) + + ## `check-incompatible-msrv-in-tests` Whether to check MSRV compatibility in `#[test]` and `#[cfg(test)]` code. diff --git a/clippy_config/src/conf.rs b/clippy_config/src/conf.rs index 5a06cb477c304..d910eb47752b5 100644 --- a/clippy_config/src/conf.rs +++ b/clippy_config/src/conf.rs @@ -554,6 +554,30 @@ define_Conf! { /// For internal testing only, ignores the current `publish` settings in the Cargo manifest. #[lints(cargo_common_metadata)] cargo_ignore_publish: bool = false, + /// Whether to check for grouped late initializations from multiple `let` statements. + /// + /// #### Example + /// ```rust + /// let a; + /// let b; + /// if true { + /// a = 1; + /// b = 2; + /// } else { + /// a = 3; + /// b = 4; + /// } + /// ``` + /// Use instead: + /// ```rust + /// let (a, b) = if true { + /// (1, 2) + /// } else { + /// (3, 4) + /// }; + /// ``` + #[lints(needless_late_init)] + check_grouped_late_init: bool = true, /// Whether to check MSRV compatibility in `#[test]` and `#[cfg(test)]` code. #[lints(incompatible_msrv)] check_incompatible_msrv_in_tests: bool = false, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 600b37c4204c0..175f01e8f81fa 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -731,7 +731,7 @@ rustc_lint::late_lint_methods!( UndocumentedUnsafeBlocks: undocumented_unsafe_blocks::UndocumentedUnsafeBlocks = undocumented_unsafe_blocks::UndocumentedUnsafeBlocks::new(conf), FormatArgs: format_args::FormatArgs<'tcx> = format_args::FormatArgs::new(tcx, conf, format_args.clone()), TrailingEmptyArray: trailing_empty_array::TrailingEmptyArray = trailing_empty_array::TrailingEmptyArray, - NeedlessLateInit: needless_late_init::NeedlessLateInit = needless_late_init::NeedlessLateInit, + NeedlessLateInit: needless_late_init::NeedlessLateInit<'tcx> = needless_late_init::NeedlessLateInit::new(conf), ReturnSelfNotMustUse: return_self_not_must_use::ReturnSelfNotMustUse = return_self_not_must_use::ReturnSelfNotMustUse, NumberedFields: init_numbered_fields::NumberedFields = init_numbered_fields::NumberedFields, ManualBits: manual_bits::ManualBits = manual_bits::ManualBits::new(conf), diff --git a/clippy_lints/src/needless_late_init.rs b/clippy_lints/src/needless_late_init.rs index 42a59113c7296..69184d1894025 100644 --- a/clippy_lints/src/needless_late_init.rs +++ b/clippy_lints/src/needless_late_init.rs @@ -1,16 +1,19 @@ +use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::res::MaybeResPath; -use clippy_utils::source::{SourceText, SpanExt, snippet}; +use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::needs_ordered_drop; use clippy_utils::visitors::{for_each_expr, for_each_expr_without_closures, is_local_used}; use core::ops::ControlFlow; use rustc_errors::{Applicability, MultiSpan}; use rustc_hir::{ - BindingMode, Block, Expr, ExprKind, HirId, LetStmt, LocalSource, MatchSource, Node, Pat, PatKind, Stmt, StmtKind, + BindingMode, Block, Expr, ExprKind, HirId, HirIdMap, HirIdSet, LetStmt, LocalSource, MatchSource, Node, Pat, + PatKind, Stmt, StmtKind, }; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::declare_lint_pass; +use rustc_session::impl_lint_pass; use rustc_span::Span; +use std::borrow::Cow; declare_clippy_lint! { /// ### What it does @@ -61,17 +64,126 @@ declare_clippy_lint! { "late initializations that can be replaced by a `let` statement with an initializer" } -declare_lint_pass!(NeedlessLateInit => [NEEDLESS_LATE_INIT]); +impl_lint_pass!(NeedlessLateInit<'_> => [NEEDLESS_LATE_INIT]); -fn contains_assign_expr<'tcx>(cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'tcx>) -> bool { - for_each_expr(cx.tcx, stmt, |e| { - if matches!(e.kind, ExprKind::Assign(..)) { - ControlFlow::Break(()) - } else { - ControlFlow::Continue(()) +pub struct NeedlessLateInit<'tcx> { + check_grouped_late_init: bool, + grouped_late_inits: Vec<(HirId, HirIdMap>)>, +} + +impl<'tcx> NeedlessLateInit<'tcx> { + pub fn new(conf: &'static Conf) -> Self { + Self { + check_grouped_late_init: conf.check_grouped_late_init, + grouped_late_inits: Vec::default(), } - }) - .is_some() + } + + fn check_if_or_match( + &mut self, + cx: &LateContext<'tcx>, + local_stmt: &'tcx LetStmt<'tcx>, + block: &'tcx Block<'tcx>, + binding_id: HirId, + usage: Usage<'tcx>, + exprs: impl IntoIterator>, + ) { + let mut assigns: Vec> = Vec::new(); + for expr in exprs { + let ty = cx.typeck_results().expr_ty(expr); + if ty.is_never() { + continue; + } + if !ty.is_unit() { + return; + } + + let Some(assign_group) = LocalAssignGroup::new(cx, expr) else { + return; + }; + + if let Some(last_group) = assigns.last() + && !assign_group.is_parallel(last_group) + { + return; + } + + assigns.push(assign_group); + } + + let Some(first_group) = assigns.first() else { + return; + }; + // If there are multiple assignments grouped together, lazyly check them after processing the block. + if first_group.0.len() > 1 { + if self.check_grouped_late_init { + let late_inits = if let Some((hir_id, late_inits)) = self.grouped_late_inits.last_mut() + && *hir_id == block.hir_id + { + late_inits + } else { + &mut self.grouped_late_inits.push_mut((block.hir_id, HirIdMap::default())).1 + }; + + let mut decls = HirIdMap::default(); + decls.insert(binding_id, local_stmt); + late_inits.insert(usage.expr.hir_id, GroupedLateInit { usage, assigns, decls }); + } + + return; + } + + if first_group.0[0].lhs_id == binding_id { + span_lint_and_then( + cx, + NEEDLESS_LATE_INIT, + local_stmt.span, + "unneeded late initialization", + |diag| { + let mut suggestions = vec![]; + for group in assigns { + suggestions.extend( + group + .0 + .iter() + .flat_map(|assign| { + let rhs_span = assign.rhs.span.source_callsite(); + let mut spans = vec![assign.span.until(rhs_span)]; + + if rhs_span.hi() != assign.span.hi() { + spans.push(rhs_span.shrink_to_hi().with_hi(assign.span.hi())); + } + + spans + }) + .map(|span| (span, String::new())), + ); + } + + suggestions.push((local_stmt.span, String::new())); + let mut applicability = Applicability::MachineApplicable; + let let_snippet = local_snippet_without_semicolon(cx, local_stmt, &mut applicability); + suggestions.push((usage.span.shrink_to_lo(), format!("{let_snippet} = "))); + if usage.needs_semi { + suggestions.push((usage.span.shrink_to_hi(), ";".to_owned())); + } + let binding_name = cx.tcx.hir_name(binding_id); + let descriptor = if matches!(usage.expr.kind, ExprKind::If(..)) { + "branches" + } else { + "`match` arms" + }; + diag.multipart_suggestion( + format!( + "move the declaration `{binding_name}` here and remove the assignments from the {descriptor}", + ), + suggestions, + applicability, + ); + }, + ); + } + } } fn contains_let(cond: &Expr<'_>) -> bool { @@ -99,110 +211,33 @@ fn stmt_needs_ordered_drop(cx: &LateContext<'_>, stmt: &Stmt<'_>) -> bool { } #[derive(Debug)] -struct LocalAssign { +struct LocalAssign<'tcx> { lhs_id: HirId, - rhs_span: Span, + rhs: &'tcx Expr<'tcx>, span: Span, } -impl LocalAssign { - fn from_expr(expr: &Expr<'_>, span: Span) -> Option { +impl<'tcx> LocalAssign<'tcx> { + fn new(expr: &'tcx Expr<'tcx>, span: Span) -> Option { if expr.span.from_expansion() { return None; } - if let ExprKind::Assign(lhs, rhs, _) = expr.kind { - if lhs.span.from_expansion() { - return None; - } - - Some(Self { + if let ExprKind::Assign(lhs, rhs, _) = expr.kind + && !lhs.span.from_expansion() + { + return Some(Self { lhs_id: lhs.res_local_id()?, - rhs_span: rhs.span.source_callsite(), + rhs, span, - }) - } else { - None + }); } - } - - fn new<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, binding_id: HirId) -> Option { - let assign = match expr.kind { - ExprKind::Block(Block { expr: Some(expr), .. }, _) => Self::from_expr(expr, expr.span), - ExprKind::Block(block, _) => { - if let Some((last, other_stmts)) = block.stmts.split_last() - && let StmtKind::Expr(expr) | StmtKind::Semi(expr) = last.kind - - && let assign = Self::from_expr(expr, last.span)? - // avoid visiting if not needed - && assign.lhs_id == binding_id - && other_stmts.iter().all(|stmt| !contains_assign_expr(cx, stmt)) - { - Some(assign) - } else { - None - } - }, - ExprKind::Assign(..) => Self::from_expr(expr, expr.span), - _ => None, - }?; - - if assign.lhs_id == binding_id { - Some(assign) - } else { - None - } - } -} - -fn assignment_suggestions<'tcx>( - cx: &LateContext<'tcx>, - binding_id: HirId, - exprs: impl IntoIterator>, -) -> Option<(Applicability, Vec<(Span, String)>)> { - let mut assignments = Vec::new(); - - for expr in exprs { - let ty = cx.typeck_results().expr_ty(expr); - - if ty.is_never() { - continue; - } - if !ty.is_unit() { - return None; - } - - let assign = LocalAssign::new(cx, expr, binding_id)?; - - assignments.push(assign); - } - - let suggestions = assignments - .iter() - .flat_map(|assignment| { - let mut spans = vec![assignment.span.until(assignment.rhs_span)]; - - if assignment.rhs_span.hi() != assignment.span.hi() { - spans.push(assignment.rhs_span.shrink_to_hi().with_hi(assignment.span.hi())); - } - - spans - }) - .map(|span| (span, String::new())) - .collect::>(); - - match suggestions.len() { - // All of `exprs` are never types - // https://github.com/rust-lang/rust-clippy/issues/8911 - 0 => None, - 1 => Some((Applicability::MachineApplicable, suggestions)), - // multiple suggestions don't work with rustfix in multipart_suggest - // https://github.com/rust-lang/rustfix/issues/141 - _ => Some((Applicability::Unspecified, suggestions)), + None } } +#[derive(Debug)] struct Usage<'tcx> { span: Span, expr: &'tcx Expr<'tcx>, @@ -249,7 +284,11 @@ fn first_usage<'tcx>( }) } -fn local_snippet_without_semicolon(cx: &LateContext<'_>, local: &LetStmt<'_>) -> Option { +fn local_snippet_without_semicolon<'a>( + cx: &LateContext<'_>, + local: &LetStmt<'_>, + applicability: &mut Applicability, +) -> Cow<'a, str> { let span = local.span.with_hi(match local.ty { // let : ; // ~~~~~~~~~~~~~~~ @@ -259,105 +298,70 @@ fn local_snippet_without_semicolon(cx: &LateContext<'_>, local: &LetStmt<'_>) -> None => local.pat.span.hi(), }); - span.get_text(cx) + snippet_with_applicability(cx, span, "..", applicability) } -fn check<'tcx>( - cx: &LateContext<'tcx>, - local: &'tcx LetStmt<'tcx>, - local_stmt: &'tcx Stmt<'tcx>, - block: &'tcx Block<'tcx>, - binding_id: HirId, -) -> Option<()> { - let usage = first_usage(cx, binding_id, local_stmt.hir_id, block)?; - let binding_name = cx.tcx.hir_opt_name(binding_id)?; - let let_snippet = local_snippet_without_semicolon(cx, local)?; - - match usage.expr.kind { - ExprKind::Assign(..) => { - let assign = LocalAssign::new(cx, usage.expr, binding_id)?; - let mut msg_span = MultiSpan::from_spans(vec![local_stmt.span, assign.span]); - msg_span.push_span_label(local_stmt.span, "created here"); - msg_span.push_span_label(assign.span, "initialised here"); - - span_lint_and_then( - cx, - NEEDLESS_LATE_INIT, - msg_span, - "unneeded late initialization", - |diag| { - diag.multipart_suggestion( - format!("move the declaration `{binding_name}` here"), - vec![ - (local_stmt.span, String::new()), - ( - assign.span, - let_snippet.to_owned() + " = " + &snippet(cx, assign.rhs_span, ".."), - ), - ], - Applicability::MachineApplicable, - ); - }, - ); - }, - ExprKind::If(cond, then_expr, Some(else_expr)) if !contains_let(cond) => { - let (applicability, mut suggestions) = assignment_suggestions(cx, binding_id, [then_expr, else_expr])?; - - span_lint_and_then( - cx, - NEEDLESS_LATE_INIT, - local_stmt.span, - "unneeded late initialization", - |diag| { - suggestions.push((local_stmt.span, String::new())); - suggestions.push((usage.span.shrink_to_lo(), format!("{let_snippet} = "))); - - if usage.needs_semi { - suggestions.push((usage.span.shrink_to_hi(), ";".to_owned())); +#[derive(Debug)] +struct LocalAssignGroup<'tcx>(Vec>); + +impl<'tcx> LocalAssignGroup<'tcx> { + fn new(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option { + match expr.kind { + ExprKind::Block(Block { expr: Some(expr), .. }, _) + if let Some(assign) = LocalAssign::new(expr, expr.span) => + { + Some(LocalAssignGroup(vec![assign])) + }, + ExprKind::Block(Block { expr: None, stmts, .. }, _) => { + let mut assign_group = Vec::new(); + // Avoid cases when the assignee is used or reassigned in the subsequent assignments + let mut used_locals = HirIdSet::default(); + for stmt in stmts.iter().rev() { + if let StmtKind::Semi(expr) | StmtKind::Expr(expr) = stmt.kind + && let Some(assign) = LocalAssign::new(expr, stmt.span) + && !used_locals.contains(&assign.lhs_id) + { + used_locals.insert(assign.lhs_id); + for_each_expr(cx.tcx, assign.rhs, |e| { + if let Some(id) = e.res_local_id() { + used_locals.insert(id); + } + ControlFlow::<()>::Continue(()) + }); + assign_group.push(assign); + continue; } - diag.multipart_suggestion( - format!( - "move the declaration `{binding_name}` here and remove the assignments from the branches" - ), - suggestions, - applicability, - ); - }, - ); - }, - ExprKind::Match(_, arms, MatchSource::Normal) => { - let (applicability, mut suggestions) = - assignment_suggestions(cx, binding_id, arms.iter().map(|arm| arm.body))?; - - span_lint_and_then( - cx, - NEEDLESS_LATE_INIT, - local_stmt.span, - "unneeded late initialization", - |diag| { - suggestions.push((local_stmt.span, String::new())); - suggestions.push((usage.span.shrink_to_lo(), format!("{let_snippet} = "))); - - if usage.needs_semi { - suggestions.push((usage.span.shrink_to_hi(), ";".to_owned())); - } + break; + } + if assign_group.is_empty() { + None + } else { + Some(LocalAssignGroup(assign_group)) + } + }, + ExprKind::Assign(..) if let Some(assign) = LocalAssign::new(expr, expr.span) => { + Some(LocalAssignGroup(vec![assign])) + }, + _ => None, + } + } - diag.multipart_suggestion( - format!("move the declaration `{binding_name}` here and remove the assignments from the `match` arms"), - suggestions, - applicability, - ); - }, - ); - }, - _ => {}, + /// Checks if the assignments in `self` and `other` are parallel, i.e. they have the same number + /// of assignments and the same assignees in the same order. + fn is_parallel(&self, other: &Self) -> bool { + self.0.len() == other.0.len() && self.0.iter().zip(other.0.iter()).all(|(a, b)| a.lhs_id == b.lhs_id) } +} - Some(()) +#[derive(Debug)] +struct GroupedLateInit<'tcx> { + usage: Usage<'tcx>, + assigns: Vec>, + decls: HirIdMap<&'tcx LetStmt<'tcx>>, } -impl<'tcx> LateLintPass<'tcx> for NeedlessLateInit { +impl<'tcx> LateLintPass<'tcx> for NeedlessLateInit<'tcx> { fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx LetStmt<'tcx>) { let mut parents = cx.tcx.hir_parent_iter(local.hir_id); if let LetStmt { @@ -372,8 +376,147 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessLateInit { } = local && let Some((_, Node::Stmt(local_stmt))) = parents.next() && let Some((_, Node::Block(block))) = parents.next() + && let Some(usage) = first_usage(cx, *binding_id, local_stmt.hir_id, block) { - check(cx, local, local_stmt, block, *binding_id); + if self.check_grouped_late_init + && let Some((hir_id, late_inits)) = self.grouped_late_inits.last_mut() + && *hir_id == block.hir_id + && let Some(late_init) = late_inits.get_mut(&usage.expr.hir_id) + { + late_init.decls.insert(*binding_id, local); + return; + } + + match usage.expr.kind { + ExprKind::Assign(..) + if let Some(assign) = LocalAssign::new(usage.expr, usage.expr.span) + && assign.lhs_id == *binding_id => + { + let mut applicability = Applicability::MachineApplicable; + let let_snippet = local_snippet_without_semicolon(cx, local, &mut applicability); + let binding_name = cx.tcx.hir_name(*binding_id); + let mut msg_span = MultiSpan::from_spans(vec![local_stmt.span, assign.span]); + msg_span.push_span_label(local_stmt.span, "created here"); + msg_span.push_span_label(assign.span, "initialised here"); + + span_lint_and_then( + cx, + NEEDLESS_LATE_INIT, + msg_span, + "unneeded late initialization", + |diag| { + let mut applicability = Applicability::MachineApplicable; + let rhs_snippet = snippet_with_applicability( + cx, + assign.rhs.span.source_callsite(), + "..", + &mut applicability, + ); + diag.multipart_suggestion( + format!("move the declaration `{binding_name}` here"), + vec![ + (local_stmt.span, String::new()), + (assign.span, format!("{let_snippet} = {rhs_snippet}")), + ], + applicability, + ); + }, + ); + }, + ExprKind::If(cond, then_expr, Some(mut else_expr)) if !contains_let(cond) => { + // Flatten multiple if branches + let mut exprs = vec![then_expr]; + while let ExprKind::If(cond, then, Some(else_)) = else_expr.kind { + if contains_let(cond) { + return; + } + exprs.push(then); + else_expr = else_; + } + exprs.push(else_expr); + self.check_if_or_match(cx, local, block, *binding_id, usage, exprs); + }, + ExprKind::Match(_, arms, MatchSource::Normal) => { + self.check_if_or_match(cx, local, block, *binding_id, usage, arms.iter().map(|arm| arm.body)); + }, + _ => {}, + } + } + } + + fn check_block_post(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) { + if self.check_grouped_late_init + && let Some((_, late_inits)) = self.grouped_late_inits.pop_if(|(hir_id, _)| *hir_id == block.hir_id) + { + 'outer: for (_, late_init) in late_inits { + if late_init.decls.len() < late_init.assigns[0].0.len() { + continue; + } + + let mut suggestions = vec![]; + for assign in &late_init.assigns[0].0 { + if let Some(local) = late_init.decls.get(&assign.lhs_id) + // If the local has a type annotation, skip it since removing the annotation might cause type + // inference issues while annotating the tuple makes the suggestion harder to read. + && local.ty.is_none() + { + suggestions.push((local.span, String::new())); + } else { + continue 'outer; + } + } + + span_lint_and_then( + cx, + NEEDLESS_LATE_INIT, + late_init.usage.span, + "unneeded late initialization", + |diag| { + let mut applicability = Applicability::MachineApplicable; + for group in &late_init.assigns { + let rhs_snippet = group + .0 + .iter() + .rev() + .map(|assign| { + snippet_with_applicability( + cx, + assign.rhs.span.source_callsite(), + "..", + &mut applicability, + ) + }) + .intersperse(", ".into()) + .collect::(); + suggestions.push(( + group.0.last().unwrap().span.to(group.0[0].span), + format!("({rhs_snippet})"), + )); + } + let let_snippet = late_init.assigns[0] + .0 + .iter() + .rev() + .map(|assign| cx.tcx.hir_name(assign.lhs_id).to_string()) + .intersperse(", ".to_owned()) + .collect::(); + suggestions.push((late_init.usage.span.shrink_to_lo(), format!("let ({let_snippet}) = "))); + if late_init.usage.needs_semi { + suggestions.push((late_init.usage.span.shrink_to_hi(), ";".to_owned())); + } + let descriptor = if matches!(late_init.usage.expr.kind, ExprKind::If(..)) { + "branches" + } else { + "`match` arms" + }; + diag.multipart_suggestion( + format!("move the declarations here and remove the assignments from the {descriptor}"), + suggestions, + applicability, + ); + }, + ); + } } } } diff --git a/tests/ui-toml/needless_late_init/clippy.toml b/tests/ui-toml/needless_late_init/clippy.toml new file mode 100644 index 0000000000000..2ff5a13e893be --- /dev/null +++ b/tests/ui-toml/needless_late_init/clippy.toml @@ -0,0 +1 @@ +check-grouped-late-init = false diff --git a/tests/ui-toml/needless_late_init/needless_late_init.rs b/tests/ui-toml/needless_late_init/needless_late_init.rs new file mode 100644 index 0000000000000..5a5e657b295c3 --- /dev/null +++ b/tests/ui-toml/needless_late_init/needless_late_init.rs @@ -0,0 +1,64 @@ +//@check-pass + +fn main() {} + +fn issue16330() { + let a; + let b; + if true { + a = 1; + b = 2; + } else { + a = 3; + b = 4; + } + + let a; + let mut b = 1; + let c; + if true { + b = 1; + a = 2; + c = 3; + } else { + b = 6; + a = 4; + c = 5; + } + + let b; + { + let a; + let c; + if true { + b = 1; + a = 2; + c = 3; + } else { + b = 6; + a = 4; + c = 5; + } + } + + let a; + let b; + let c; + match 1 { + 1 => { + a = 1; + b = 2; + c = 3; + }, + _ if false => { + a = 4; + b = 5; + c = 6; + }, + _ => { + a = 7; + b = 8; + c = 9; + }, + } +} diff --git a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr index 6bb3db8db67f0..528e2f1089c04 100644 --- a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr +++ b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr @@ -33,6 +33,7 @@ error: error reading Clippy's configuration file: unknown field `foobar`, expect avoid-breaking-exported-api await-holding-invalid-types cargo-ignore-publish + check-grouped-late-init check-incompatible-msrv-in-tests check-inconsistent-struct-field-initializers check-private-items @@ -134,6 +135,7 @@ error: error reading Clippy's configuration file: unknown field `barfoo`, expect avoid-breaking-exported-api await-holding-invalid-types cargo-ignore-publish + check-grouped-late-init check-incompatible-msrv-in-tests check-inconsistent-struct-field-initializers check-private-items @@ -235,6 +237,7 @@ error: error reading Clippy's configuration file: unknown field `allow_mixed_uni avoid-breaking-exported-api await-holding-invalid-types cargo-ignore-publish + check-grouped-late-init check-incompatible-msrv-in-tests check-inconsistent-struct-field-initializers check-private-items diff --git a/tests/ui/needless_late_init.fixed b/tests/ui/needless_late_init.fixed index fff5bc00d4278..a5c9d435b3eea 100644 --- a/tests/ui/needless_late_init.fixed +++ b/tests/ui/needless_late_init.fixed @@ -185,25 +185,24 @@ fn does_not_lint() { }; // using tuples would be possible, but not always preferable - let x; - let y; - if true { - x = 1; - y = 2; + + + let (x, y) = if true { + //~^ needless_late_init + (1, 2) } else { - x = 3; - y = 4; - } + (3, 4) + }; - // could match with a smarter heuristic to avoid multiple assignments - let x; - if true { + + //~^ needless_late_init + let x = if true { let mut y = 5; y = 6; - x = y; + y } else { - x = 2; - } + 2 + }; let (x, y); if true { @@ -309,3 +308,157 @@ fn if_or_match_in_block_expr() { 2 }; } + +fn issue16330() { + // Late init in both if branches, should lint + + + let (a, b) = if true { + //~^ needless_late_init + (1, 2) + } else { + (3, 4) + }; + + // One of the variables is not late init, should not lint + let a; + let mut b = 1; + let c; + if true { + b = 1; + a = 2; + c = 3; + } else { + b = 6; + a = 4; + c = 5; + } + + // One of the variables is defined outside the block, should not lint + let b; + { + let a; + let c; + if true { + b = 1; + a = 2; + c = 3; + } else { + b = 6; + a = 4; + c = 5; + } + } + + // Late init in all match arms, should lint + + + + let (a, b, c) = match 1 { + //~^ needless_late_init + 1 => { + (1, 2, 3) + }, + _ if false => { + (4, 5, 6) + }, + _ => { + (7, 8, 9) + }, + }; + + // Late init in all if branches, should lint + + + + let (a, b, c) = if true { + //~^ needless_late_init + (1, 2, 3) + } else if false { + (4, 5, 6) + } else { + (7, 8, 9) + }; + + // One of the variables is not assigned in all branches, should not lint + let a; + let b; + let c; + if true { + a = 1; + b = 2; + c = 3; + } else if false { + a = 4; + c = 6; + } else { + a = 7; + b = 8; + c = 9; + } + + // One of the variables is assigned multiple times, should not lint + let mut a; + let b; + if true { + a = 1; + b = 2; + a = 3; + } else { + a = 4; + b = 5; + } + + // One of the variables is assigned in a nested block, should not lint + let a; + let b; + if true { + a = 1; + b = 2; + } else { + a = 4; + { + b = 5; + } + } + + // The order of the variables is different in different branches, should not lint + let a; + let b; + if true { + a = 1; + b = 2; + } else { + b = 5; + a = 4; + } + + // Later assignments depend on the earlier ones, should only lint the last ones + let a; + let b; + + //~^ needless_late_init + let c = if true { + a = 1; + b = a + 1; + b + 1 + } else { + a = 4; + b = a + 2; + b + 2 + }; + let a; + let b; + + + let (c, d) = if true { + //~^ needless_late_init + a = 1; + b = a + 1; + (b + 1, 1) + } else { + a = 4; + b = a + 2; + (b + 2, 2) + }; +} diff --git a/tests/ui/needless_late_init.rs b/tests/ui/needless_late_init.rs index 327de94570ca2..ee413814750c7 100644 --- a/tests/ui/needless_late_init.rs +++ b/tests/ui/needless_late_init.rs @@ -188,6 +188,7 @@ fn does_not_lint() { let x; let y; if true { + //~^ needless_late_init x = 1; y = 2; } else { @@ -195,8 +196,8 @@ fn does_not_lint() { y = 4; } - // could match with a smarter heuristic to avoid multiple assignments let x; + //~^ needless_late_init if true { let mut y = 5; y = 6; @@ -309,3 +310,173 @@ fn if_or_match_in_block_expr() { z = 2; } } + +fn issue16330() { + // Late init in both if branches, should lint + let a; + let b; + if true { + //~^ needless_late_init + a = 1; + b = 2; + } else { + a = 3; + b = 4; + } + + // One of the variables is not late init, should not lint + let a; + let mut b = 1; + let c; + if true { + b = 1; + a = 2; + c = 3; + } else { + b = 6; + a = 4; + c = 5; + } + + // One of the variables is defined outside the block, should not lint + let b; + { + let a; + let c; + if true { + b = 1; + a = 2; + c = 3; + } else { + b = 6; + a = 4; + c = 5; + } + } + + // Late init in all match arms, should lint + let a; + let b; + let c; + match 1 { + //~^ needless_late_init + 1 => { + a = 1; + b = 2; + c = 3; + }, + _ if false => { + a = 4; + b = 5; + c = 6; + }, + _ => { + a = 7; + b = 8; + c = 9; + }, + } + + // Late init in all if branches, should lint + let a; + let b; + let c; + if true { + //~^ needless_late_init + a = 1; + b = 2; + c = 3; + } else if false { + a = 4; + b = 5; + c = 6; + } else { + a = 7; + b = 8; + c = 9; + } + + // One of the variables is not assigned in all branches, should not lint + let a; + let b; + let c; + if true { + a = 1; + b = 2; + c = 3; + } else if false { + a = 4; + c = 6; + } else { + a = 7; + b = 8; + c = 9; + } + + // One of the variables is assigned multiple times, should not lint + let mut a; + let b; + if true { + a = 1; + b = 2; + a = 3; + } else { + a = 4; + b = 5; + } + + // One of the variables is assigned in a nested block, should not lint + let a; + let b; + if true { + a = 1; + b = 2; + } else { + a = 4; + { + b = 5; + } + } + + // The order of the variables is different in different branches, should not lint + let a; + let b; + if true { + a = 1; + b = 2; + } else { + b = 5; + a = 4; + } + + // Later assignments depend on the earlier ones, should only lint the last ones + let a; + let b; + let c; + //~^ needless_late_init + if true { + a = 1; + b = a + 1; + c = b + 1; + } else { + a = 4; + b = a + 2; + c = b + 2; + } + let a; + let b; + let c; + let d; + if true { + //~^ needless_late_init + a = 1; + b = a + 1; + c = b + 1; + d = 1; + } else { + a = 4; + b = a + 2; + c = b + 2; + d = 2; + } +} diff --git a/tests/ui/needless_late_init.stderr b/tests/ui/needless_late_init.stderr index 1623bc032a255..12bfc029d9488 100644 --- a/tests/ui/needless_late_init.stderr +++ b/tests/ui/needless_late_init.stderr @@ -276,7 +276,50 @@ LL ~ }; | error: unneeded late initialization - --> tests/ui/needless_late_init.rs:298:5 + --> tests/ui/needless_late_init.rs:199:5 + | +LL | let x; + | ^^^^^^ + | +help: move the declaration `x` here and remove the assignments from the branches + | +LL ~ +LL | +LL ~ let x = if true { +LL | let mut y = 5; +LL | y = 6; +LL ~ y +LL | } else { +LL ~ 2 +LL ~ }; + | + +error: unneeded late initialization + --> tests/ui/needless_late_init.rs:190:5 + | +LL | / if true { +LL | | +LL | | x = 1; +LL | | y = 2; +... | +LL | | y = 4; +LL | | } + | |_____^ + | +help: move the declarations here and remove the assignments from the branches + | +LL ~ +LL ~ +LL ~ let (x, y) = if true { +LL | +LL ~ (1, 2) +LL | } else { +LL ~ (3, 4) +LL ~ }; + | + +error: unneeded late initialization + --> tests/ui/needless_late_init.rs:299:5 | LL | let r; | ^^^^^^ created here @@ -292,7 +335,7 @@ LL ~ let r = 5; | error: unneeded late initialization - --> tests/ui/needless_late_init.rs:304:5 + --> tests/ui/needless_late_init.rs:305:5 | LL | let z; | ^^^^^^ @@ -308,5 +351,136 @@ LL ~ 2 LL ~ }; | -error: aborting due to 18 previous errors +error: unneeded late initialization + --> tests/ui/needless_late_init.rs:455:5 + | +LL | let c; + | ^^^^^^ + | +help: move the declaration `c` here and remove the assignments from the branches + | +LL ~ +LL | +LL ~ let c = if true { +LL | a = 1; +LL | b = a + 1; +LL ~ b + 1 +LL | } else { +LL | a = 4; +LL | b = a + 2; +LL ~ b + 2 +LL ~ }; + | + +error: unneeded late initialization + --> tests/ui/needless_late_init.rs:318:5 + | +LL | / if true { +LL | | +LL | | a = 1; +LL | | b = 2; +... | +LL | | b = 4; +LL | | } + | |_____^ + | +help: move the declarations here and remove the assignments from the branches + | +LL ~ +LL ~ +LL ~ let (a, b) = if true { +LL | +LL ~ (1, 2) +LL | } else { +LL ~ (3, 4) +LL ~ }; + | + +error: unneeded late initialization + --> tests/ui/needless_late_init.rs:361:5 + | +LL | / match 1 { +LL | | +LL | | 1 => { +LL | | a = 1; +... | +LL | | }, +LL | | } + | |_____^ + | +help: move the declarations here and remove the assignments from the `match` arms + | +LL ~ +LL ~ +LL ~ +LL ~ let (a, b, c) = match 1 { +LL | +LL | 1 => { +LL ~ (1, 2, 3) +LL | }, +LL | _ if false => { +LL ~ (4, 5, 6) +LL | }, +LL | _ => { +LL ~ (7, 8, 9) +LL | }, +LL ~ }; + | + +error: unneeded late initialization + --> tests/ui/needless_late_init.rs:384:5 + | +LL | / if true { +LL | | +LL | | a = 1; +LL | | b = 2; +... | +LL | | c = 9; +LL | | } + | |_____^ + | +help: move the declarations here and remove the assignments from the branches + | +LL ~ +LL ~ +LL ~ +LL ~ let (a, b, c) = if true { +LL | +LL ~ (1, 2, 3) +LL | } else if false { +LL ~ (4, 5, 6) +LL | } else { +LL ~ (7, 8, 9) +LL ~ }; + | + +error: unneeded late initialization + --> tests/ui/needless_late_init.rs:470:5 + | +LL | / if true { +LL | | +LL | | a = 1; +LL | | b = a + 1; +... | +LL | | d = 2; +LL | | } + | |_____^ + | +help: move the declarations here and remove the assignments from the branches + | +LL ~ +LL ~ +LL ~ let (c, d) = if true { +LL | +LL | a = 1; +LL | b = a + 1; +LL ~ (b + 1, 1) +LL | } else { +LL | a = 4; +LL | b = a + 2; +LL ~ (b + 2, 2) +LL ~ }; + | + +error: aborting due to 25 previous errors From bf8aa084e58b94f18ff987e90f8315dd9f186902 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Thu, 25 Jun 2026 16:10:58 +0200 Subject: [PATCH 76/77] Bump nightly version -> 2026-06-25 --- clippy_utils/README.md | 2 +- rust-toolchain.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/clippy_utils/README.md b/clippy_utils/README.md index 95b8bdde5cd91..f322d03f18795 100644 --- a/clippy_utils/README.md +++ b/clippy_utils/README.md @@ -8,7 +8,7 @@ This crate is only guaranteed to build with this `nightly` toolchain: ``` -nightly-2026-06-11 +nightly-2026-06-25 ``` diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 3afa9da1f947d..ac044327aafe9 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,6 +1,6 @@ [toolchain] # begin autogenerated nightly -channel = "nightly-2026-06-11" +channel = "nightly-2026-06-25" # end autogenerated nightly components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] profile = "minimal" From 91c04dfcad15fc8d72681f5578a1183f5f29b332 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Thu, 25 Jun 2026 18:50:36 +0200 Subject: [PATCH 77/77] cg_gcc: Fix Clippy lint fallout --- compiler/rustc_codegen_gcc/src/common.rs | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_codegen_gcc/src/common.rs b/compiler/rustc_codegen_gcc/src/common.rs index dd0064d34bc4a..b9b6e51d3b82c 100644 --- a/compiler/rustc_codegen_gcc/src/common.rs +++ b/compiler/rustc_codegen_gcc/src/common.rs @@ -58,13 +58,19 @@ pub fn bytes_in_context<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, bytes: &[u8]) -> // or is it using a more efficient representation? match bytes.len() % 8 { 0 => { + debug_assert_eq!( + bytes.len() % 8, + 0, + "bytes length is not a multiple of 8, so bytes.as_chunks will have a remainder" + ); let context = &cx.context; let byte_type = context.new_type::(); let typ = new_array_type(context, None, byte_type, bytes.len() as u64 / 8); let elements: Vec<_> = bytes - .chunks_exact(8) - .map(|arr| { - let arr: [u8; 8] = arr.try_into().unwrap(); + .as_chunks::<8>() + .0 + .iter() + .map(|&arr| { context.new_rvalue_from_long( byte_type, // Since we are representing arbitrary byte runs as integers, we need to follow the target @@ -79,13 +85,19 @@ pub fn bytes_in_context<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, bytes: &[u8]) -> context.new_array_constructor(None, typ, &elements) } 4 => { + debug_assert_eq!( + bytes.len() % 4, + 0, + "bytes length is not a multiple of 4, so bytes.as_chunks will have a remainder" + ); let context = &cx.context; let byte_type = context.new_type::(); let typ = new_array_type(context, None, byte_type, bytes.len() as u64 / 4); let elements: Vec<_> = bytes - .chunks_exact(4) - .map(|arr| { - let arr: [u8; 4] = arr.try_into().unwrap(); + .as_chunks::<4>() + .0 + .iter() + .map(|&arr| { context.new_rvalue_from_int( byte_type, match cx.sess().target.options.endian {