diff --git a/CHANGELOG.md b/CHANGELOG.md index 6cb2755be0ee..09a223ca6d5e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6526,6 +6526,7 @@ Released 2018-09-13 [`main_recursion`]: https://rust-lang.github.io/rust-clippy/master/index.html#main_recursion [`manual_abs_diff`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_abs_diff [`manual_assert`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_assert +[`manual_assert_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_assert_eq [`manual_async_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_async_fn [`manual_bits`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_bits [`manual_c_str_literals`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_c_str_literals diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index a754eea31165..1d563228046a 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -292,6 +292,7 @@ pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[ crate::main_recursion::MAIN_RECURSION_INFO, crate::manual_abs_diff::MANUAL_ABS_DIFF_INFO, crate::manual_assert::MANUAL_ASSERT_INFO, + crate::manual_assert_eq::MANUAL_ASSERT_EQ_INFO, crate::manual_async_fn::MANUAL_ASYNC_FN_INFO, crate::manual_bits::MANUAL_BITS_INFO, crate::manual_clamp::MANUAL_CLAMP_INFO, diff --git a/clippy_lints/src/eta_reduction.rs b/clippy_lints/src/eta_reduction.rs index 21385ee4fdc7..c5482ac8fcc7 100644 --- a/clippy_lints/src/eta_reduction.rs +++ b/clippy_lints/src/eta_reduction.rs @@ -371,7 +371,7 @@ fn has_late_bound_to_non_late_bound_regions(from_sig: FnSig<'_>, to_sig: FnSig<' } } - assert!(from_sig.inputs_and_output.len() == to_sig.inputs_and_output.len()); + assert_eq!(from_sig.inputs_and_output.len(), to_sig.inputs_and_output.len()); from_sig .inputs_and_output .iter() diff --git a/clippy_lints/src/functions/renamed_function_params.rs b/clippy_lints/src/functions/renamed_function_params.rs index e25611d48817..2d330835a037 100644 --- a/clippy_lints/src/functions/renamed_function_params.rs +++ b/clippy_lints/src/functions/renamed_function_params.rs @@ -57,7 +57,7 @@ impl RenamedFnArgs { { let mut renamed: Vec<(Span, String)> = vec![]; - debug_assert!(default_idents.size_hint() == current_idents.size_hint()); + debug_assert_eq!(default_idents.size_hint(), current_idents.size_hint()); for (default_ident, current_ident) in iter::zip(default_idents, current_idents) { let has_name_to_check = |ident: Option| { ident diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 033f85e70ef0..41e96da5da85 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -195,6 +195,7 @@ mod macro_use; mod main_recursion; mod manual_abs_diff; mod manual_assert; +mod manual_assert_eq; mod manual_async_fn; mod manual_bits; mod manual_clamp; @@ -819,5 +820,6 @@ pub fn register_lint_passes(store: &mut rustc_lint::LintStore, conf: &'static Co store.register_late_pass(|_| Box::new(toplevel_ref_arg::ToplevelRefArg)); store.register_late_pass(|_| Box::new(volatile_composites::VolatileComposites)); store.register_late_pass(|_| Box::new(replace_box::ReplaceBox::default())); + store.register_late_pass(|_| Box::new(manual_assert_eq::ManualAssertEq)); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/clippy_lints/src/manual_assert_eq.rs b/clippy_lints/src/manual_assert_eq.rs new file mode 100644 index 000000000000..2a6bda694800 --- /dev/null +++ b/clippy_lints/src/manual_assert_eq.rs @@ -0,0 +1,88 @@ +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::macros::{find_assert_args, root_macro_call_first_node}; +use clippy_utils::source::walk_span_to_context; +use clippy_utils::ty::implements_trait; +use clippy_utils::{is_in_const_context, sym}; +use rustc_errors::Applicability; +use rustc_hir::{BinOpKind, Expr, ExprKind}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_session::declare_lint_pass; + +declare_clippy_lint! { + /// ### What it does + /// Checks for `assert!` and `debug_assert!` that consist of only an (in)equality check + /// + /// ### Why is this bad? + /// `assert_{eq,ne}!` and `debug_assert_{eq,ne}!` achieves the same goal, and provides some + /// additional debug information + /// + /// ### Example + /// ```no_run + /// assert!(2 * 2 == 4); + /// assert!(2 * 2 != 5); + /// debug_assert!(2 * 2 == 4); + /// debug_assert!(2 * 2 != 5); + /// ``` + /// Use instead: + /// ```no_run + /// assert_eq!(2 * 2, 4); + /// assert_ne!(2 * 2, 5); + /// debug_assert_eq!(2 * 2, 4); + /// debug_assert_ne!(2 * 2, 5); + /// ``` + #[clippy::version = "1.92.0"] + pub MANUAL_ASSERT_EQ, + complexity, + "checks for assertions consisting of an (in)equality check" +} +declare_lint_pass!(ManualAssertEq => [MANUAL_ASSERT_EQ]); + +impl LateLintPass<'_> for ManualAssertEq { + fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { + if let Some(macro_call) = root_macro_call_first_node(cx, expr) + && let macro_name = match cx.tcx.get_diagnostic_name(macro_call.def_id) { + Some(sym::assert_macro) => "assert", + Some(sym::debug_assert_macro) => "debug_assert", + _ => return, + } + // `assert_eq` isn't allowed in const context because it calls non-const `core::panicking::assert_failed` + // XXX: this might change in the future, so might want to relax this restriction + && !is_in_const_context(cx) + && let Some((cond, _)) = find_assert_args(cx, expr, macro_call.expn) + && let ExprKind::Binary(op, lhs, rhs) = cond.kind + && matches!(op.node, BinOpKind::Eq | BinOpKind::Ne) + && !cond.span.from_expansion() + && let Some(debug_trait) = cx.tcx.get_diagnostic_item(sym::Debug) + && implements_trait(cx, cx.typeck_results().expr_ty(lhs), debug_trait, &[]) + && implements_trait(cx, cx.typeck_results().expr_ty(rhs), debug_trait, &[]) + { + span_lint_and_then( + cx, + MANUAL_ASSERT_EQ, + macro_call.span, + format!("used `{macro_name}!` with an equality comparison"), + |diag| { + let kind = if op.node == BinOpKind::Eq { "eq" } else { "ne" }; + let new_name = format!("{macro_name}_{kind}"); + let msg = format!("replace it with `{new_name}!(..)`"); + + let ctxt = cond.span.ctxt(); + if let Some(lhs_span) = walk_span_to_context(lhs.span, ctxt) + && let Some(rhs_span) = walk_span_to_context(rhs.span, ctxt) + { + let macro_name_span = cx.sess().source_map().span_until_char(macro_call.span, '!'); + let eq_span = cond.span.with_lo(lhs_span.hi()).with_hi(rhs_span.lo()); + let suggestions = vec![ + (macro_name_span.shrink_to_hi(), format!("_{kind}")), + (eq_span, ", ".to_string()), + ]; + + diag.multipart_suggestion(msg, suggestions, Applicability::MachineApplicable); + } else { + diag.span_help(expr.span, msg); + } + }, + ); + } + } +} diff --git a/clippy_utils/src/ty/mod.rs b/clippy_utils/src/ty/mod.rs index a90d64e972c1..354307daf5c5 100644 --- a/clippy_utils/src/ty/mod.rs +++ b/clippy_utils/src/ty/mod.rs @@ -915,14 +915,20 @@ fn assert_generic_args_match<'tcx>(tcx: TyCtxt<'tcx>, did: DefId, args: &[Generi .chain(&g.own_params) .map(|x| &x.kind); - assert!( - count == args.len(), - "wrong number of arguments for `{did:?}`: expected `{count}`, found {}\n\ + #[expect( + clippy::manual_assert_eq, + reason = "the message contains `assert_eq!`-like formatting itself" + )] + { + assert!( + count == args.len(), + "wrong number of arguments for `{did:?}`: expected `{count}`, found {}\n\ note: the expected arguments are: `[{}]`\n\ the given arguments are: `{args:#?}`", - args.len(), - params.clone().map(ty::GenericParamDefKind::descr).format(", "), - ); + args.len(), + params.clone().map(ty::GenericParamDefKind::descr).format(", "), + ); + } if let Some((idx, (param, arg))) = params diff --git a/lintcheck/src/output.rs b/lintcheck/src/output.rs index 1ecc3f7c2494..dfba1804642e 100644 --- a/lintcheck/src/output.rs +++ b/lintcheck/src/output.rs @@ -228,8 +228,8 @@ fn print_stats(old_stats: HashMap, new_stats: HashMap<&String, us // remove duplicates from both hashmaps for (k, v) in &same_in_both_hashmaps { - assert!(old_stats_deduped.remove(k) == Some(*v)); - assert!(new_stats_deduped.remove(k) == Some(*v)); + assert_eq!(old_stats_deduped.remove(k), Some(*v)); + assert_eq!(new_stats_deduped.remove(k), Some(*v)); } println!("\nStats:"); diff --git a/tests/ui/assertions_on_constants.rs b/tests/ui/assertions_on_constants.rs index f467d4966aef..775eb40e33a2 100644 --- a/tests/ui/assertions_on_constants.rs +++ b/tests/ui/assertions_on_constants.rs @@ -54,8 +54,11 @@ fn main() { const _: () = assert!(true); //~^ assertions_on_constants - assert!(8 == (7 + 1)); - //~^ assertions_on_constants + #[allow(clippy::manual_assert_eq, reason = "tests `assert!` specifically")] + { + assert!(8 == (7 + 1)); + //~^ assertions_on_constants + } // Don't lint if the value is dependent on a defined constant: const N: usize = 1024; @@ -68,8 +71,11 @@ const _: () = { assert!(true); //~^ assertions_on_constants - assert!(8 == (7 + 1)); - //~^ assertions_on_constants + #[allow(clippy::manual_assert_eq, reason = "tests `assert!` specifically")] + { + assert!(8 == (7 + 1)); + //~^ assertions_on_constants + } assert!(C); }; diff --git a/tests/ui/assertions_on_constants.stderr b/tests/ui/assertions_on_constants.stderr index a996c41b6942..b99f34fd741b 100644 --- a/tests/ui/assertions_on_constants.stderr +++ b/tests/ui/assertions_on_constants.stderr @@ -89,15 +89,15 @@ LL | const _: () = assert!(true); = help: remove the assertion error: this assertion is always `true` - --> tests/ui/assertions_on_constants.rs:57:5 + --> tests/ui/assertions_on_constants.rs:59:9 | -LL | assert!(8 == (7 + 1)); - | ^^^^^^^^^^^^^^^^^^^^^ +LL | assert!(8 == (7 + 1)); + | ^^^^^^^^^^^^^^^^^^^^^ | = help: remove the assertion error: this assertion is always `true` - --> tests/ui/assertions_on_constants.rs:68:5 + --> tests/ui/assertions_on_constants.rs:71:5 | LL | assert!(true); | ^^^^^^^^^^^^^ @@ -105,15 +105,15 @@ LL | assert!(true); = help: remove the assertion error: this assertion is always `true` - --> tests/ui/assertions_on_constants.rs:71:5 + --> tests/ui/assertions_on_constants.rs:76:9 | -LL | assert!(8 == (7 + 1)); - | ^^^^^^^^^^^^^^^^^^^^^ +LL | assert!(8 == (7 + 1)); + | ^^^^^^^^^^^^^^^^^^^^^ | = help: remove the assertion error: this assertion has a constant value - --> tests/ui/assertions_on_constants.rs:79:5 + --> tests/ui/assertions_on_constants.rs:85:5 | LL | assert!(C); | ^^^^^^^^^^ @@ -121,7 +121,7 @@ LL | assert!(C); = help: consider moving this to an anonymous constant: `const _: () = { assert!(..); }` error: this assertion has a constant value - --> tests/ui/assertions_on_constants.rs:90:5 + --> tests/ui/assertions_on_constants.rs:96:5 | LL | assert!(C); | ^^^^^^^^^^ @@ -129,7 +129,7 @@ LL | assert!(C); = help: consider moving this into a const block: `const { assert!(..) }` error: this assertion has a constant value - --> tests/ui/assertions_on_constants.rs:96:5 + --> tests/ui/assertions_on_constants.rs:102:5 | LL | assert!(C); | ^^^^^^^^^^ diff --git a/tests/ui/cmp_null.fixed b/tests/ui/cmp_null.fixed index c12279cf12e6..13cda7d4e0cf 100644 --- a/tests/ui/cmp_null.fixed +++ b/tests/ui/cmp_null.fixed @@ -33,6 +33,10 @@ fn main() { //~^ cmp_null } +#[allow( + clippy::manual_assert_eq, + reason = "the lint only works on `assert`, not `assert_eq`" +)] fn issue15010() { let f: *mut i32 = std::ptr::null_mut(); debug_assert!(!f.is_null()); diff --git a/tests/ui/cmp_null.rs b/tests/ui/cmp_null.rs index 2771a16e00c5..38be1168384c 100644 --- a/tests/ui/cmp_null.rs +++ b/tests/ui/cmp_null.rs @@ -33,6 +33,10 @@ fn main() { //~^ cmp_null } +#[allow( + clippy::manual_assert_eq, + reason = "the lint only works on `assert`, not `assert_eq`" +)] fn issue15010() { let f: *mut i32 = std::ptr::null_mut(); debug_assert!(f != std::ptr::null_mut()); diff --git a/tests/ui/cmp_null.stderr b/tests/ui/cmp_null.stderr index 381747cb3c65..50bdde523478 100644 --- a/tests/ui/cmp_null.stderr +++ b/tests/ui/cmp_null.stderr @@ -32,7 +32,7 @@ LL | let _ = x as *const () == ptr::null(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(x as *const ()).is_null()` error: comparing with null is better expressed by the `.is_null()` method - --> tests/ui/cmp_null.rs:38:19 + --> tests/ui/cmp_null.rs:42:19 | LL | debug_assert!(f != std::ptr::null_mut()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `!f.is_null()` diff --git a/tests/ui/infinite_loops.rs b/tests/ui/infinite_loops.rs index 0bde31aca030..7c278f44de91 100644 --- a/tests/ui/infinite_loops.rs +++ b/tests/ui/infinite_loops.rs @@ -294,9 +294,7 @@ fn panic_like_macros_1() { } } -fn panic_like_macros_2() { - let mut x = 0; - +fn panic_like_macros_2(mut x: i32) { loop { do_something(); if true { @@ -310,7 +308,7 @@ fn panic_like_macros_2() { } loop { do_something(); - assert!(x % 2 == 0); + assert!(x.is_positive()); } loop { do_something(); diff --git a/tests/ui/infinite_loops.stderr b/tests/ui/infinite_loops.stderr index 319f1e5012b6..b910235e0364 100644 --- a/tests/ui/infinite_loops.stderr +++ b/tests/ui/infinite_loops.stderr @@ -197,7 +197,7 @@ LL | fn match_like() -> ! { | ++++ error: infinite loop detected - --> tests/ui/infinite_loops.rs:334:9 + --> tests/ui/infinite_loops.rs:332:9 | LL | / loop { LL | | @@ -211,7 +211,7 @@ LL | fn problematic_trait_method() -> ! { | ++++ error: infinite loop detected - --> tests/ui/infinite_loops.rs:344:9 + --> tests/ui/infinite_loops.rs:342:9 | LL | / loop { LL | | @@ -225,7 +225,7 @@ LL | fn could_be_problematic() -> ! { | ++++ error: infinite loop detected - --> tests/ui/infinite_loops.rs:353:9 + --> tests/ui/infinite_loops.rs:351:9 | LL | / loop { LL | | @@ -239,7 +239,7 @@ LL | let _loop_forever = || -> ! { | ++++ error: infinite loop detected - --> tests/ui/infinite_loops.rs:367:8 + --> tests/ui/infinite_loops.rs:365:8 | LL | Ok(loop { | ________^ @@ -251,7 +251,7 @@ LL | | }) = help: if this is not intended, try adding a `break` or `return` condition in the loop error: infinite loop detected - --> tests/ui/infinite_loops.rs:410:5 + --> tests/ui/infinite_loops.rs:408:5 | LL | / 'infinite: loop { LL | | @@ -267,7 +267,7 @@ LL | fn continue_outer() -> ! { | ++++ error: infinite loop detected - --> tests/ui/infinite_loops.rs:417:5 + --> tests/ui/infinite_loops.rs:415:5 | LL | / loop { LL | | @@ -282,7 +282,7 @@ LL | fn continue_outer() -> ! { | ++++ error: infinite loop detected - --> tests/ui/infinite_loops.rs:419:9 + --> tests/ui/infinite_loops.rs:417:9 | LL | / 'inner: loop { LL | | @@ -298,7 +298,7 @@ LL | fn continue_outer() -> ! { | ++++ error: infinite loop detected - --> tests/ui/infinite_loops.rs:428:5 + --> tests/ui/infinite_loops.rs:426:5 | LL | / loop { LL | | @@ -312,7 +312,7 @@ LL | fn continue_outer() -> ! { | ++++ error: infinite loop detected - --> tests/ui/infinite_loops.rs:459:13 + --> tests/ui/infinite_loops.rs:457:13 | LL | / loop { LL | | @@ -323,7 +323,7 @@ LL | | } = help: if this is not intended, try adding a `break` or `return` condition in the loop error: infinite loop detected - --> tests/ui/infinite_loops.rs:466:13 + --> tests/ui/infinite_loops.rs:464:13 | LL | / loop { LL | | @@ -334,7 +334,7 @@ LL | | } = help: if this is not intended, try adding a `break` or `return` condition in the loop error: infinite loop detected - --> tests/ui/infinite_loops.rs:533:9 + --> tests/ui/infinite_loops.rs:531:9 | LL | / loop { LL | | std::future::pending().await diff --git a/tests/ui/manual_assert_eq.fixed b/tests/ui/manual_assert_eq.fixed new file mode 100644 index 000000000000..dbf176d749b2 --- /dev/null +++ b/tests/ui/manual_assert_eq.fixed @@ -0,0 +1,102 @@ +//@aux-build:proc_macros.rs +#![warn(clippy::manual_assert_eq)] +#![allow(clippy::manual_ignore_case_cmp)] // only raised before the fix +#![expect(clippy::eq_op, clippy::assertions_on_constants)] + +fn main() { + assert_eq!("a", "a".to_ascii_lowercase()); + //~^ manual_assert_eq + assert_eq!("a", "a".to_ascii_lowercase(), "a==a"); + //~^ manual_assert_eq + assert_ne!("A", "A".to_ascii_lowercase()); + //~^ manual_assert_eq + assert_ne!("A", "A".to_ascii_lowercase(), "A!=a"); + //~^ manual_assert_eq + debug_assert_eq!("a", "a".to_ascii_lowercase()); + //~^ manual_assert_eq + debug_assert_eq!("a", "a".to_ascii_lowercase(), "a==a"); + //~^ manual_assert_eq + debug_assert_ne!("A", "A".to_ascii_lowercase()); + //~^ manual_assert_eq + debug_assert_ne!("A", "A".to_ascii_lowercase(), "A!=a"); + //~^ manual_assert_eq + + // macros + let v = vec![]; + assert_eq!(v, vec![1, 2, 3], "v!=vec"); + //~^ manual_assert_eq + assert_eq!(vec![1, 2, 3], v, "v!=vec"); + //~^ manual_assert_eq + assert_eq!(vec![1], vec![1, 2, 3], "v!=vec"); + //~^ manual_assert_eq + + { + #[derive(PartialEq)] + struct NotDebug; + + #[derive(PartialEq)] + struct NotDebug2; + + impl PartialEq for NotDebug { + fn eq(&self, other: &NotDebug2) -> bool { + unimplemented!() + } + } + impl PartialEq for NotDebug2 { + fn eq(&self, other: &NotDebug) -> bool { + unimplemented!() + } + } + + #[derive(Debug)] + struct IsDebug; + + impl PartialEq for NotDebug { + fn eq(&self, other: &IsDebug) -> bool { + unimplemented!() + } + } + impl PartialEq for IsDebug { + fn eq(&self, other: &NotDebug) -> bool { + unimplemented!() + } + } + + let nd = NotDebug; + assert!(nd == nd); + + let nd2 = NotDebug2; + assert!(nd == nd2); + assert!(nd2 == nd); + + let id = IsDebug; + assert!(id == nd); + assert!(nd == id); + } + + // Don't lint: in const context + const { + assert!(5 == 2 + 3); + } + + // Don't lint: in external macro + { + // NOTE: this only works because `root_macro_call_first_node` returns `external!`, + // which then gets rejected by the macro name check + proc_macros::external!(assert!('a' == 'b')); + proc_macros::external!({ + let some_padding_before = 'a'; + assert!('a' == 'b'); + let some_padding_after = 'b'; + }); + + // .. which also means that the following is _technically_ a FN -- but surely no one would write + // code like this (diverging/unit expression as a child expression of a macro call) + vec![(), assert!('a' == 'b'), ()]; + } +} + +// Don't lint: in const context +const _: () = { + assert!(8 == (7 + 1)); +}; diff --git a/tests/ui/manual_assert_eq.rs b/tests/ui/manual_assert_eq.rs new file mode 100644 index 000000000000..ea2a79054379 --- /dev/null +++ b/tests/ui/manual_assert_eq.rs @@ -0,0 +1,102 @@ +//@aux-build:proc_macros.rs +#![warn(clippy::manual_assert_eq)] +#![allow(clippy::manual_ignore_case_cmp)] // only raised before the fix +#![expect(clippy::eq_op, clippy::assertions_on_constants)] + +fn main() { + assert!("a" == "a".to_ascii_lowercase()); + //~^ manual_assert_eq + assert!("a" == "a".to_ascii_lowercase(), "a==a"); + //~^ manual_assert_eq + assert!("A" != "A".to_ascii_lowercase()); + //~^ manual_assert_eq + assert!("A" != "A".to_ascii_lowercase(), "A!=a"); + //~^ manual_assert_eq + debug_assert!("a" == "a".to_ascii_lowercase()); + //~^ manual_assert_eq + debug_assert!("a" == "a".to_ascii_lowercase(), "a==a"); + //~^ manual_assert_eq + debug_assert!("A" != "A".to_ascii_lowercase()); + //~^ manual_assert_eq + debug_assert!("A" != "A".to_ascii_lowercase(), "A!=a"); + //~^ manual_assert_eq + + // macros + let v = vec![]; + assert!(v == vec![1, 2, 3], "v!=vec"); + //~^ manual_assert_eq + assert!(vec![1, 2, 3] == v, "v!=vec"); + //~^ manual_assert_eq + assert!(vec![1] == vec![1, 2, 3], "v!=vec"); + //~^ manual_assert_eq + + { + #[derive(PartialEq)] + struct NotDebug; + + #[derive(PartialEq)] + struct NotDebug2; + + impl PartialEq for NotDebug { + fn eq(&self, other: &NotDebug2) -> bool { + unimplemented!() + } + } + impl PartialEq for NotDebug2 { + fn eq(&self, other: &NotDebug) -> bool { + unimplemented!() + } + } + + #[derive(Debug)] + struct IsDebug; + + impl PartialEq for NotDebug { + fn eq(&self, other: &IsDebug) -> bool { + unimplemented!() + } + } + impl PartialEq for IsDebug { + fn eq(&self, other: &NotDebug) -> bool { + unimplemented!() + } + } + + let nd = NotDebug; + assert!(nd == nd); + + let nd2 = NotDebug2; + assert!(nd == nd2); + assert!(nd2 == nd); + + let id = IsDebug; + assert!(id == nd); + assert!(nd == id); + } + + // Don't lint: in const context + const { + assert!(5 == 2 + 3); + } + + // Don't lint: in external macro + { + // NOTE: this only works because `root_macro_call_first_node` returns `external!`, + // which then gets rejected by the macro name check + proc_macros::external!(assert!('a' == 'b')); + proc_macros::external!({ + let some_padding_before = 'a'; + assert!('a' == 'b'); + let some_padding_after = 'b'; + }); + + // .. which also means that the following is _technically_ a FN -- but surely no one would write + // code like this (diverging/unit expression as a child expression of a macro call) + vec![(), assert!('a' == 'b'), ()]; + } +} + +// Don't lint: in const context +const _: () = { + assert!(8 == (7 + 1)); +}; diff --git a/tests/ui/manual_assert_eq.stderr b/tests/ui/manual_assert_eq.stderr new file mode 100644 index 000000000000..73b1e2d5129d --- /dev/null +++ b/tests/ui/manual_assert_eq.stderr @@ -0,0 +1,136 @@ +error: used `assert!` with an equality comparison + --> tests/ui/manual_assert_eq.rs:7:5 + | +LL | assert!("a" == "a".to_ascii_lowercase()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::manual-assert-eq` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::manual_assert_eq)]` +help: replace it with `assert_eq!(..)` + | +LL - assert!("a" == "a".to_ascii_lowercase()); +LL + assert_eq!("a", "a".to_ascii_lowercase()); + | + +error: used `assert!` with an equality comparison + --> tests/ui/manual_assert_eq.rs:9:5 + | +LL | assert!("a" == "a".to_ascii_lowercase(), "a==a"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: replace it with `assert_eq!(..)` + | +LL - assert!("a" == "a".to_ascii_lowercase(), "a==a"); +LL + assert_eq!("a", "a".to_ascii_lowercase(), "a==a"); + | + +error: used `assert!` with an equality comparison + --> tests/ui/manual_assert_eq.rs:11:5 + | +LL | assert!("A" != "A".to_ascii_lowercase()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: replace it with `assert_ne!(..)` + | +LL - assert!("A" != "A".to_ascii_lowercase()); +LL + assert_ne!("A", "A".to_ascii_lowercase()); + | + +error: used `assert!` with an equality comparison + --> tests/ui/manual_assert_eq.rs:13:5 + | +LL | assert!("A" != "A".to_ascii_lowercase(), "A!=a"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: replace it with `assert_ne!(..)` + | +LL - assert!("A" != "A".to_ascii_lowercase(), "A!=a"); +LL + assert_ne!("A", "A".to_ascii_lowercase(), "A!=a"); + | + +error: used `debug_assert!` with an equality comparison + --> tests/ui/manual_assert_eq.rs:15:5 + | +LL | debug_assert!("a" == "a".to_ascii_lowercase()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: replace it with `debug_assert_eq!(..)` + | +LL - debug_assert!("a" == "a".to_ascii_lowercase()); +LL + debug_assert_eq!("a", "a".to_ascii_lowercase()); + | + +error: used `debug_assert!` with an equality comparison + --> tests/ui/manual_assert_eq.rs:17:5 + | +LL | debug_assert!("a" == "a".to_ascii_lowercase(), "a==a"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: replace it with `debug_assert_eq!(..)` + | +LL - debug_assert!("a" == "a".to_ascii_lowercase(), "a==a"); +LL + debug_assert_eq!("a", "a".to_ascii_lowercase(), "a==a"); + | + +error: used `debug_assert!` with an equality comparison + --> tests/ui/manual_assert_eq.rs:19:5 + | +LL | debug_assert!("A" != "A".to_ascii_lowercase()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: replace it with `debug_assert_ne!(..)` + | +LL - debug_assert!("A" != "A".to_ascii_lowercase()); +LL + debug_assert_ne!("A", "A".to_ascii_lowercase()); + | + +error: used `debug_assert!` with an equality comparison + --> tests/ui/manual_assert_eq.rs:21:5 + | +LL | debug_assert!("A" != "A".to_ascii_lowercase(), "A!=a"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: replace it with `debug_assert_ne!(..)` + | +LL - debug_assert!("A" != "A".to_ascii_lowercase(), "A!=a"); +LL + debug_assert_ne!("A", "A".to_ascii_lowercase(), "A!=a"); + | + +error: used `assert!` with an equality comparison + --> tests/ui/manual_assert_eq.rs:26:5 + | +LL | assert!(v == vec![1, 2, 3], "v!=vec"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: replace it with `assert_eq!(..)` + | +LL - assert!(v == vec![1, 2, 3], "v!=vec"); +LL + assert_eq!(v, vec![1, 2, 3], "v!=vec"); + | + +error: used `assert!` with an equality comparison + --> tests/ui/manual_assert_eq.rs:28:5 + | +LL | assert!(vec![1, 2, 3] == v, "v!=vec"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: replace it with `assert_eq!(..)` + | +LL - assert!(vec![1, 2, 3] == v, "v!=vec"); +LL + assert_eq!(vec![1, 2, 3], v, "v!=vec"); + | + +error: used `assert!` with an equality comparison + --> tests/ui/manual_assert_eq.rs:30:5 + | +LL | assert!(vec![1] == vec![1, 2, 3], "v!=vec"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: replace it with `assert_eq!(..)` + | +LL - assert!(vec![1] == vec![1, 2, 3], "v!=vec"); +LL + assert_eq!(vec![1], vec![1, 2, 3], "v!=vec"); + | + +error: aborting due to 11 previous errors + diff --git a/tests/ui/missing_asserts_for_indexing.fixed b/tests/ui/missing_asserts_for_indexing.fixed index 9018f38100ef..c02504659390 100644 --- a/tests/ui/missing_asserts_for_indexing.fixed +++ b/tests/ui/missing_asserts_for_indexing.fixed @@ -122,6 +122,7 @@ fn index_different_slice_in_same_expr(v1: &[u8], v2: &[u8]) { let _ = v1[0] + v2[1]; } +#[allow(clippy::manual_assert_eq, reason = "specifically testing `assert!` + `==`")] fn issue11835(v1: &[u8], v2: &[u8], v3: &[u8], v4: &[u8]) { assert!(v1.len() == 3); assert!(v2.len() == 4); @@ -149,6 +150,10 @@ fn highest_index_first(v1: &[u8]) { let _ = v1[2] + v1[1] + v1[0]; } +#[allow( + clippy::manual_assert_eq, + reason = "`assert_eq!` will get replaced by `assert!` in fix. This is arguably a bug in lint, see #16026" +)] fn issue14255(v1: &[u8], v2: &[u8], v3: &[u8], v4: &[u8]) { assert!(v1.len() == 3); assert_eq!(v2.len(), 4); diff --git a/tests/ui/missing_asserts_for_indexing.rs b/tests/ui/missing_asserts_for_indexing.rs index 44c5eddf3d8b..8e3dd8765e16 100644 --- a/tests/ui/missing_asserts_for_indexing.rs +++ b/tests/ui/missing_asserts_for_indexing.rs @@ -122,6 +122,7 @@ fn index_different_slice_in_same_expr(v1: &[u8], v2: &[u8]) { let _ = v1[0] + v2[1]; } +#[allow(clippy::manual_assert_eq, reason = "specifically testing `assert!` + `==`")] fn issue11835(v1: &[u8], v2: &[u8], v3: &[u8], v4: &[u8]) { assert!(v1.len() == 2); assert!(v2.len() == 4); @@ -149,6 +150,10 @@ fn highest_index_first(v1: &[u8]) { let _ = v1[2] + v1[1] + v1[0]; } +#[allow( + clippy::manual_assert_eq, + reason = "`assert_eq!` will get replaced by `assert!` in fix. This is arguably a bug in lint, see #16026" +)] fn issue14255(v1: &[u8], v2: &[u8], v3: &[u8], v4: &[u8]) { assert_eq!(v1.len(), 2); assert_eq!(v2.len(), 4); diff --git a/tests/ui/missing_asserts_for_indexing.stderr b/tests/ui/missing_asserts_for_indexing.stderr index b610de94b530..1d3e8d8978e1 100644 --- a/tests/ui/missing_asserts_for_indexing.stderr +++ b/tests/ui/missing_asserts_for_indexing.stderr @@ -250,7 +250,7 @@ LL | let _ = v1[0] + v1[12]; = note: asserting the length before indexing will elide bounds checks error: indexing into a slice multiple times with an `assert` that does not cover the highest index - --> tests/ui/missing_asserts_for_indexing.rs:131:13 + --> tests/ui/missing_asserts_for_indexing.rs:132:13 | LL | assert!(v1.len() == 2); | ---------------------- help: provide the highest index that is indexed with: `assert!(v1.len() == 3)` @@ -259,24 +259,24 @@ LL | let _ = v1[0] + v1[1] + v1[2]; | ^^^^^^^^^^^^^^^^^^^^^ | note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:131:13 + --> tests/ui/missing_asserts_for_indexing.rs:132:13 | LL | let _ = v1[0] + v1[1] + v1[2]; | ^^^^^ note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:131:21 + --> tests/ui/missing_asserts_for_indexing.rs:132:21 | LL | let _ = v1[0] + v1[1] + v1[2]; | ^^^^^ note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:131:29 + --> tests/ui/missing_asserts_for_indexing.rs:132:29 | LL | let _ = v1[0] + v1[1] + v1[2]; | ^^^^^ = note: asserting the length before indexing will elide bounds checks error: indexing into a slice multiple times with an `assert` that does not cover the highest index - --> tests/ui/missing_asserts_for_indexing.rs:136:13 + --> tests/ui/missing_asserts_for_indexing.rs:137:13 | LL | assert!(2 == v3.len()); | ---------------------- help: provide the highest index that is indexed with: `assert!(v3.len() == 3)` @@ -285,24 +285,24 @@ LL | let _ = v3[0] + v3[1] + v3[2]; | ^^^^^^^^^^^^^^^^^^^^^ | note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:136:13 + --> tests/ui/missing_asserts_for_indexing.rs:137:13 | LL | let _ = v3[0] + v3[1] + v3[2]; | ^^^^^ note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:136:21 + --> tests/ui/missing_asserts_for_indexing.rs:137:21 | LL | let _ = v3[0] + v3[1] + v3[2]; | ^^^^^ note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:136:29 + --> tests/ui/missing_asserts_for_indexing.rs:137:29 | LL | let _ = v3[0] + v3[1] + v3[2]; | ^^^^^ = note: asserting the length before indexing will elide bounds checks error: indexing into a slice multiple times with an `assert` that does not cover the highest index - --> tests/ui/missing_asserts_for_indexing.rs:158:13 + --> tests/ui/missing_asserts_for_indexing.rs:163:13 | LL | assert_eq!(v1.len(), 2); | ----------------------- help: provide the highest index that is indexed with: `assert!(v1.len() == 3)` @@ -311,24 +311,24 @@ LL | let _ = v1[0] + v1[1] + v1[2]; | ^^^^^^^^^^^^^^^^^^^^^ | note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:158:13 + --> tests/ui/missing_asserts_for_indexing.rs:163:13 | LL | let _ = v1[0] + v1[1] + v1[2]; | ^^^^^ note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:158:21 + --> tests/ui/missing_asserts_for_indexing.rs:163:21 | LL | let _ = v1[0] + v1[1] + v1[2]; | ^^^^^ note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:158:29 + --> tests/ui/missing_asserts_for_indexing.rs:163:29 | LL | let _ = v1[0] + v1[1] + v1[2]; | ^^^^^ = note: asserting the length before indexing will elide bounds checks error: indexing into a slice multiple times with an `assert` that does not cover the highest index - --> tests/ui/missing_asserts_for_indexing.rs:163:13 + --> tests/ui/missing_asserts_for_indexing.rs:168:13 | LL | assert_eq!(2, v3.len()); | ----------------------- help: provide the highest index that is indexed with: `assert!(v3.len() == 3)` @@ -337,17 +337,17 @@ LL | let _ = v3[0] + v3[1] + v3[2]; | ^^^^^^^^^^^^^^^^^^^^^ | note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:163:13 + --> tests/ui/missing_asserts_for_indexing.rs:168:13 | LL | let _ = v3[0] + v3[1] + v3[2]; | ^^^^^ note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:163:21 + --> tests/ui/missing_asserts_for_indexing.rs:168:21 | LL | let _ = v3[0] + v3[1] + v3[2]; | ^^^^^ note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:163:29 + --> tests/ui/missing_asserts_for_indexing.rs:168:29 | LL | let _ = v3[0] + v3[1] + v3[2]; | ^^^^^ diff --git a/tests/ui/panic_in_result_fn_assertions.rs b/tests/ui/panic_in_result_fn_assertions.rs index 4e7028241579..17b221044b1f 100644 --- a/tests/ui/panic_in_result_fn_assertions.rs +++ b/tests/ui/panic_in_result_fn_assertions.rs @@ -7,7 +7,7 @@ impl A { fn result_with_assert_with_message(x: i32) -> Result // should emit lint //~^ panic_in_result_fn { - assert!(x == 5, "wrong argument"); + assert!(x.is_positive(), "wrong argument"); Ok(true) } @@ -27,7 +27,7 @@ impl A { fn other_with_assert_with_message(x: i32) // should not emit lint { - assert!(x == 5, "wrong argument"); + assert!(x.is_positive(), "wrong argument"); } fn other_with_assert_eq(x: i32) // should not emit lint diff --git a/tests/ui/panic_in_result_fn_assertions.stderr b/tests/ui/panic_in_result_fn_assertions.stderr index cdb7762510d9..db881da06ba8 100644 --- a/tests/ui/panic_in_result_fn_assertions.stderr +++ b/tests/ui/panic_in_result_fn_assertions.stderr @@ -4,7 +4,7 @@ error: used `panic!()` or assertion in a function that returns `Result` LL | / fn result_with_assert_with_message(x: i32) -> Result // should emit lint LL | | LL | | { -LL | | assert!(x == 5, "wrong argument"); +LL | | assert!(x.is_positive(), "wrong argument"); LL | | Ok(true) LL | | } | |_____^ @@ -13,8 +13,8 @@ LL | | } note: return Err() instead of panicking --> tests/ui/panic_in_result_fn_assertions.rs:10:9 | -LL | assert!(x == 5, "wrong argument"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | assert!(x.is_positive(), "wrong argument"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: `-D clippy::panic-in-result-fn` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::panic_in_result_fn)]` diff --git a/tests/ui/panic_in_result_fn_debug_assertions.rs b/tests/ui/panic_in_result_fn_debug_assertions.rs index c4549c6b8412..9cce339f4d60 100644 --- a/tests/ui/panic_in_result_fn_debug_assertions.rs +++ b/tests/ui/panic_in_result_fn_debug_assertions.rs @@ -9,7 +9,7 @@ struct A; impl A { fn result_with_debug_assert_with_message(x: i32) -> Result { - debug_assert!(x == 5, "wrong argument"); + debug_assert!(x.is_positive(), "wrong argument"); Ok(true) } @@ -24,7 +24,7 @@ impl A { } fn other_with_debug_assert_with_message(x: i32) { - debug_assert!(x == 5, "wrong argument"); + debug_assert!(x.is_positive(), "wrong argument"); } fn other_with_debug_assert_eq(x: i32) { diff --git a/tests/ui/uninit_vec.rs b/tests/ui/uninit_vec.rs index eeb281322da9..a0bac28e8729 100644 --- a/tests/ui/uninit_vec.rs +++ b/tests/ui/uninit_vec.rs @@ -87,7 +87,7 @@ fn main() { unsafe { // test the case where there are other statements in the following unsafe block vec.set_len(200); - assert!(vec.len() == 200); + assert_eq!(vec.len(), 200); } // handle vec stored in the field of a struct diff --git a/tests/ui/uninlined_format_args_panic.edition2018.fixed b/tests/ui/uninlined_format_args_panic.edition2018.fixed index 3710036c0589..697515f3cab2 100644 --- a/tests/ui/uninlined_format_args_panic.edition2018.fixed +++ b/tests/ui/uninlined_format_args_panic.edition2018.fixed @@ -31,8 +31,11 @@ fn main() { } } - assert!(var == 1, "p5 {}", var); - //~[edition2021]^ uninlined_format_args - debug_assert!(var == 1, "p6 {}", var); - //~[edition2021]^ uninlined_format_args + #[allow(clippy::manual_assert_eq)] + { + assert!(var == 1, "p5 {}", var); + //~[edition2021]^ uninlined_format_args + debug_assert!(var == 1, "p6 {}", var); + //~[edition2021]^ uninlined_format_args + } } diff --git a/tests/ui/uninlined_format_args_panic.edition2021.fixed b/tests/ui/uninlined_format_args_panic.edition2021.fixed index 8a754d313806..dee93f49b3fd 100644 --- a/tests/ui/uninlined_format_args_panic.edition2021.fixed +++ b/tests/ui/uninlined_format_args_panic.edition2021.fixed @@ -31,8 +31,11 @@ fn main() { } } - assert!(var == 1, "p5 {var}"); - //~[edition2021]^ uninlined_format_args - debug_assert!(var == 1, "p6 {var}"); - //~[edition2021]^ uninlined_format_args + #[allow(clippy::manual_assert_eq)] + { + assert!(var == 1, "p5 {var}"); + //~[edition2021]^ uninlined_format_args + debug_assert!(var == 1, "p6 {var}"); + //~[edition2021]^ uninlined_format_args + } } diff --git a/tests/ui/uninlined_format_args_panic.edition2021.stderr b/tests/ui/uninlined_format_args_panic.edition2021.stderr index 4db6e6a99312..97b772a4e694 100644 --- a/tests/ui/uninlined_format_args_panic.edition2021.stderr +++ b/tests/ui/uninlined_format_args_panic.edition2021.stderr @@ -49,27 +49,27 @@ LL + panic!("p3 {var}"); | error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args_panic.rs:34:5 + --> tests/ui/uninlined_format_args_panic.rs:36:9 | -LL | assert!(var == 1, "p5 {}", var); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | assert!(var == 1, "p5 {}", var); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: change this to | -LL - assert!(var == 1, "p5 {}", var); -LL + assert!(var == 1, "p5 {var}"); +LL - assert!(var == 1, "p5 {}", var); +LL + assert!(var == 1, "p5 {var}"); | error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args_panic.rs:36:5 + --> tests/ui/uninlined_format_args_panic.rs:38:9 | -LL | debug_assert!(var == 1, "p6 {}", var); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | debug_assert!(var == 1, "p6 {}", var); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: change this to | -LL - debug_assert!(var == 1, "p6 {}", var); -LL + debug_assert!(var == 1, "p6 {var}"); +LL - debug_assert!(var == 1, "p6 {}", var); +LL + debug_assert!(var == 1, "p6 {var}"); | error: aborting due to 6 previous errors diff --git a/tests/ui/uninlined_format_args_panic.rs b/tests/ui/uninlined_format_args_panic.rs index 94de4f057e99..c06a2ad64377 100644 --- a/tests/ui/uninlined_format_args_panic.rs +++ b/tests/ui/uninlined_format_args_panic.rs @@ -31,8 +31,11 @@ fn main() { } } - assert!(var == 1, "p5 {}", var); - //~[edition2021]^ uninlined_format_args - debug_assert!(var == 1, "p6 {}", var); - //~[edition2021]^ uninlined_format_args + #[allow(clippy::manual_assert_eq)] + { + assert!(var == 1, "p5 {}", var); + //~[edition2021]^ uninlined_format_args + debug_assert!(var == 1, "p6 {}", var); + //~[edition2021]^ uninlined_format_args + } } diff --git a/tests/ui/unnecessary_map_or.fixed b/tests/ui/unnecessary_map_or.fixed index 10552431d65d..dc695ae29b8d 100644 --- a/tests/ui/unnecessary_map_or.fixed +++ b/tests/ui/unnecessary_map_or.fixed @@ -132,8 +132,11 @@ fn issue14201(a: Option, b: Option, s: &String) -> bool { } fn issue14714() { - assert!(Some("test") == Some("test")); - //~^ unnecessary_map_or + #[allow(clippy::manual_assert_eq, reason = "will fire after the fix")] + { + assert!(Some("test") == Some("test")); + //~^ unnecessary_map_or + }; // even though we're in a macro context, we still need to parenthesise because of the `then` assert!((Some("test") == Some("test")).then(|| 1).is_some()); diff --git a/tests/ui/unnecessary_map_or.rs b/tests/ui/unnecessary_map_or.rs index 4b406ec2998b..322d3c35bd3d 100644 --- a/tests/ui/unnecessary_map_or.rs +++ b/tests/ui/unnecessary_map_or.rs @@ -136,8 +136,11 @@ fn issue14201(a: Option, b: Option, s: &String) -> bool { } fn issue14714() { - assert!(Some("test").map_or(false, |x| x == "test")); - //~^ unnecessary_map_or + #[allow(clippy::manual_assert_eq, reason = "will fire after the fix")] + { + assert!(Some("test").map_or(false, |x| x == "test")); + //~^ unnecessary_map_or + }; // even though we're in a macro context, we still need to parenthesise because of the `then` assert!(Some("test").map_or(false, |x| x == "test").then(|| 1).is_some()); diff --git a/tests/ui/unnecessary_map_or.stderr b/tests/ui/unnecessary_map_or.stderr index b8a22346c378..bc3329d25950 100644 --- a/tests/ui/unnecessary_map_or.stderr +++ b/tests/ui/unnecessary_map_or.stderr @@ -327,19 +327,19 @@ LL + let y = b.is_none_or(|b| b == *s); | error: this `map_or` can be simplified - --> tests/ui/unnecessary_map_or.rs:139:13 + --> tests/ui/unnecessary_map_or.rs:141:17 | -LL | assert!(Some("test").map_or(false, |x| x == "test")); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | assert!(Some("test").map_or(false, |x| x == "test")); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: use a standard comparison instead | -LL - assert!(Some("test").map_or(false, |x| x == "test")); -LL + assert!(Some("test") == Some("test")); +LL - assert!(Some("test").map_or(false, |x| x == "test")); +LL + assert!(Some("test") == Some("test")); | error: this `map_or` can be simplified - --> tests/ui/unnecessary_map_or.rs:143:13 + --> tests/ui/unnecessary_map_or.rs:146:13 | LL | assert!(Some("test").map_or(false, |x| x == "test").then(|| 1).is_some()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -351,7 +351,7 @@ LL + assert!((Some("test") == Some("test")).then(|| 1).is_some()); | error: this `map_or` can be simplified - --> tests/ui/unnecessary_map_or.rs:160:9 + --> tests/ui/unnecessary_map_or.rs:163:9 | LL | _ = s.lock().unwrap().map_or(false, |s| s == "foo"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -363,7 +363,7 @@ LL + _ = s.lock().unwrap().is_some_and(|s| s == "foo"); | error: this `map_or` can be simplified - --> tests/ui/unnecessary_map_or.rs:164:9 + --> tests/ui/unnecessary_map_or.rs:167:9 | LL | _ = s.map_or(false, |s| s == "foo"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^