feat(manual_assert_eq): new lint

This commit is contained in:
Ada Alakbarova
2025-10-28 20:30:40 +01:00
parent 31a89ea47b
commit 6f8aee0157
25 changed files with 529 additions and 78 deletions
+1
View File
@@ -6878,6 +6878,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
+1
View File
@@ -298,6 +298,7 @@
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_checked_ops::MANUAL_CHECKED_OPS_INFO,
+1 -1
View File
@@ -373,7 +373,7 @@ fn check_ty(from_ty: Ty<'_>, to_ty: Ty<'_>) -> bool {
}
}
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()
@@ -57,7 +57,7 @@ fn new<I1, I2>(default_idents: &mut I1, current_idents: &mut I2) -> Self
{
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>| {
ident
+2
View File
@@ -196,6 +196,7 @@
mod main_recursion;
mod manual_abs_diff;
mod manual_assert;
mod manual_assert_eq;
mod manual_async_fn;
mod manual_bits;
mod manual_checked_ops;
@@ -867,6 +868,7 @@ pub fn register_lint_passes(store: &mut rustc_lint::LintStore, conf: &'static Co
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)),
// add late passes here, used by `cargo dev new_lint`
];
store.late_passes.extend(late_lints);
+122
View File
@@ -0,0 +1,122 @@
use clippy_utils::consts::ConstEvalCtxt;
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::macros::{PanicCall, 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.97.0"]
pub MANUAL_ASSERT_EQ,
pedantic,
"checks for assertions consisting of an (in)equality check"
}
declare_lint_pass!(ManualAssertEq => [MANUAL_ASSERT_EQ]);
#[derive(Clone, Copy, PartialEq, Eq)]
enum EqKind {
Eq,
Ne,
}
impl EqKind {
fn postfix(self) -> &'static str {
match self {
Self::Eq => "_eq",
Self::Ne => "_ne",
}
}
}
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,
}
&& !is_in_const_context(cx)
&& let Some((cond, panic_expn)) = find_assert_args(cx, expr, macro_call.expn)
// Don't lint if the user has a painstakingly written assertion message
&& !matches!(panic_expn, PanicCall::Display(_) | PanicCall::Format(_))
&& let ExprKind::Binary(op, lhs, rhs) = cond.kind
&& let eq_kind = match op.node {
BinOpKind::Eq => EqKind::Eq,
BinOpKind::Ne => EqKind::Ne,
_ => return,
}
&& !cond.span.from_expansion()
&& let Some(debug_trait) = cx.tcx.get_diagnostic_item(sym::Debug)
&& let lhs_ty = cx.typeck_results().expr_ty(lhs)
&& let rhs_ty = cx.typeck_results().expr_ty(rhs)
// Can't print the values unless the types implement `Debug`
&& implements_trait(cx, lhs_ty, debug_trait, &[])
&& implements_trait(cx, rhs_ty, debug_trait, &[])
// Printing raw pointers isn't very useful
&& !lhs_ty.is_raw_ptr()
&& !rhs_ty.is_raw_ptr()
// The output of `(debug_)assert_eq` isn't very useful when one of the sides is a constant value
&& if eq_kind == EqKind::Ne {
let ecx = ConstEvalCtxt::new(cx);
ecx.eval(lhs).is_none() && ecx.eval(rhs).is_none()
} else {
true
}
{
span_lint_and_then(
cx,
MANUAL_ASSERT_EQ,
macro_call.span,
format!("used `{macro_name}!` with an equality comparison"),
|diag| {
let postfix = eq_kind.postfix();
let new_name = format_args!("{macro_name}{postfix}");
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(), postfix.to_string()),
(eq_span, ", ".to_string()),
];
diag.multipart_suggestion(msg, suggestions, Applicability::MachineApplicable);
} else {
diag.span_help(expr.span, msg);
}
},
);
}
}
}
+2 -2
View File
@@ -228,8 +228,8 @@ fn print_stats(old_stats: HashMap<String, usize>, 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:");
+1
View File
@@ -1,4 +1,5 @@
#![allow(non_fmt_panics, clippy::needless_bool, clippy::eq_op)]
#![expect(clippy::manual_assert_eq)]
macro_rules! assert_const {
($len:expr) => {
+17 -17
View File
@@ -1,5 +1,5 @@
error: this assertion is always `true`
--> tests/ui/assertions_on_constants.rs:10:5
--> tests/ui/assertions_on_constants.rs:11:5
|
LL | assert!(true);
| ^^^^^^^^^^^^^
@@ -9,7 +9,7 @@ LL | assert!(true);
= help: to override `-D warnings` add `#[allow(clippy::assertions_on_constants)]`
error: this assertion is always `false`
--> tests/ui/assertions_on_constants.rs:13:5
--> tests/ui/assertions_on_constants.rs:14:5
|
LL | assert!(false);
| ^^^^^^^^^^^^^^
@@ -17,7 +17,7 @@ LL | assert!(false);
= help: replace this with `panic!()` or `unreachable!()`
error: this assertion is always `true`
--> tests/ui/assertions_on_constants.rs:16:5
--> tests/ui/assertions_on_constants.rs:17:5
|
LL | assert!(true, "true message");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -25,7 +25,7 @@ LL | assert!(true, "true message");
= help: remove the assertion
error: this assertion is always `false`
--> tests/ui/assertions_on_constants.rs:19:5
--> tests/ui/assertions_on_constants.rs:20:5
|
LL | assert!(false, "false message");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -33,7 +33,7 @@ LL | assert!(false, "false message");
= help: replace this with `panic!()` or `unreachable!()`
error: this assertion is always `false`
--> tests/ui/assertions_on_constants.rs:23:5
--> tests/ui/assertions_on_constants.rs:24:5
|
LL | assert!(false, "{}", msg.to_uppercase());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -41,7 +41,7 @@ LL | assert!(false, "{}", msg.to_uppercase());
= help: replace this with `panic!()` or `unreachable!()`
error: this assertion has a constant value
--> tests/ui/assertions_on_constants.rs:27:5
--> tests/ui/assertions_on_constants.rs:28:5
|
LL | assert!(B);
| ^^^^^^^^^^
@@ -49,7 +49,7 @@ LL | assert!(B);
= help: consider moving this into a const block: `const { assert!(..) }`
error: this assertion has a constant value
--> tests/ui/assertions_on_constants.rs:31:5
--> tests/ui/assertions_on_constants.rs:32:5
|
LL | assert!(C);
| ^^^^^^^^^^
@@ -57,7 +57,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:34:5
--> tests/ui/assertions_on_constants.rs:35:5
|
LL | assert!(C, "C message");
| ^^^^^^^^^^^^^^^^^^^^^^^
@@ -65,7 +65,7 @@ LL | assert!(C, "C message");
= help: consider moving this into a const block: `const { assert!(..) }`
error: this assertion is always `true`
--> tests/ui/assertions_on_constants.rs:37:5
--> tests/ui/assertions_on_constants.rs:38:5
|
LL | debug_assert!(true);
| ^^^^^^^^^^^^^^^^^^^
@@ -73,7 +73,7 @@ LL | debug_assert!(true);
= help: remove the assertion
error: this assertion has a constant value
--> tests/ui/assertions_on_constants.rs:45:5
--> tests/ui/assertions_on_constants.rs:46:5
|
LL | assert!(cfg!(feature = "hey") || cfg!(not(feature = "asdf")));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -81,7 +81,7 @@ LL | assert!(cfg!(feature = "hey") || cfg!(not(feature = "asdf")));
= help: consider moving this into a const block: `const { assert!(..) }`
error: this assertion is always `true`
--> tests/ui/assertions_on_constants.rs:54:19
--> tests/ui/assertions_on_constants.rs:55:19
|
LL | const _: () = assert!(true);
| ^^^^^^^^^^^^^
@@ -89,7 +89,7 @@ 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:58:5
|
LL | assert!(8 == (7 + 1));
| ^^^^^^^^^^^^^^^^^^^^^
@@ -97,7 +97,7 @@ 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:69:5
|
LL | assert!(true);
| ^^^^^^^^^^^^^
@@ -105,7 +105,7 @@ 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:72:5
|
LL | assert!(8 == (7 + 1));
| ^^^^^^^^^^^^^^^^^^^^^
@@ -113,7 +113,7 @@ 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:80: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:91: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:97:5
|
LL | assert!(C);
| ^^^^^^^^^^
+1
View File
@@ -1,4 +1,5 @@
#![warn(clippy::cmp_null)]
#![allow(clippy::manual_assert_eq)]
use std::ptr;
+1
View File
@@ -1,4 +1,5 @@
#![warn(clippy::cmp_null)]
#![allow(clippy::manual_assert_eq)]
use std::ptr;
+7 -7
View File
@@ -1,5 +1,5 @@
error: comparing with null is better expressed by the `.is_null()` method
--> tests/ui/cmp_null.rs:8:8
--> tests/ui/cmp_null.rs:9:8
|
LL | if p == ptr::null() {
| ^^^^^^^^^^^^^^^^ help: try: `p.is_null()`
@@ -8,37 +8,37 @@ LL | if p == ptr::null() {
= help: to override `-D warnings` add `#[allow(clippy::cmp_null)]`
error: comparing with null is better expressed by the `.is_null()` method
--> tests/ui/cmp_null.rs:13:8
--> tests/ui/cmp_null.rs:14:8
|
LL | if ptr::null() == p {
| ^^^^^^^^^^^^^^^^ help: try: `p.is_null()`
error: comparing with null is better expressed by the `.is_null()` method
--> tests/ui/cmp_null.rs:21:8
--> tests/ui/cmp_null.rs:22:8
|
LL | if m == ptr::null_mut() {
| ^^^^^^^^^^^^^^^^^^^^ help: try: `m.is_null()`
error: comparing with null is better expressed by the `.is_null()` method
--> tests/ui/cmp_null.rs:26:8
--> tests/ui/cmp_null.rs:27:8
|
LL | if ptr::null_mut() == m {
| ^^^^^^^^^^^^^^^^^^^^ help: try: `m.is_null()`
error: comparing with null is better expressed by the `.is_null()` method
--> tests/ui/cmp_null.rs:32:13
--> tests/ui/cmp_null.rs:33:13
|
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:39:19
|
LL | debug_assert!(f != std::ptr::null_mut());
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `!f.is_null()`
error: comparing with null is better expressed by the `.is_null()` method
--> tests/ui/cmp_null.rs:56:8
--> tests/ui/cmp_null.rs:57:8
|
LL | if dot_value!(x) == ptr::null() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `dot_value!(x).is_null()`
+2 -2
View File
@@ -295,7 +295,7 @@ fn panic_like_macros_1() {
}
fn panic_like_macros_2() {
let mut x = 0;
let mut x: i32 = 0;
loop {
do_something();
@@ -310,7 +310,7 @@ fn panic_like_macros_2() {
}
loop {
do_something();
assert!(x % 2 == 0);
assert!(x.is_positive());
}
loop {
do_something();
+114
View File
@@ -0,0 +1,114 @@
//@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() {
let a = "a";
assert_eq!(a, "a".to_ascii_lowercase());
//~^ manual_assert_eq
assert_ne!(a, "a".to_ascii_uppercase());
//~^ manual_assert_eq
debug_assert_eq!(a, "a".to_ascii_lowercase());
//~^ manual_assert_eq
debug_assert_ne!(a, "a".to_ascii_uppercase());
//~^ manual_assert_eq
// macros
let v = vec![];
assert_eq!(v, vec![1, 2, 3]);
//~^ manual_assert_eq
assert_eq!(vec![1, 2, 3], v);
//~^ manual_assert_eq
assert_eq!(vec![1], vec![1, 2, 3]);
//~^ manual_assert_eq
// Don't lint: has assert message
assert!(a == "a".to_ascii_lowercase(), "{a}");
assert!(a == "a".to_ascii_lowercase(), "a==a");
assert!(a == "a".to_ascii_lowercase(), "{a}==a");
assert!(a != "a".to_ascii_uppercase(), "a!=A");
debug_assert!(a == "a".to_ascii_lowercase(), "a==a");
debug_assert!(a != "a".to_ascii_uppercase(), "a!=A");
// Don't lint: `!=`, and at least one of the sides is a constant value
assert!(a != "A");
assert!("A" != a);
assert!("A" != "A");
// Don't lint: comparison of ptrs
fn cmp_ptrs(a: *const u8, b: *const u8) {
assert!(a == b);
}
// Don't lint: one of the sides isn't `Debug`
{
#[derive(PartialEq)]
struct NotDebug;
#[derive(PartialEq)]
struct NotDebug2;
impl PartialEq<NotDebug2> for NotDebug {
fn eq(&self, other: &NotDebug2) -> bool {
unimplemented!()
}
}
impl PartialEq<NotDebug> for NotDebug2 {
fn eq(&self, other: &NotDebug) -> bool {
unimplemented!()
}
}
#[derive(Debug)]
struct IsDebug;
impl PartialEq<IsDebug> for NotDebug {
fn eq(&self, other: &IsDebug) -> bool {
unimplemented!()
}
}
impl PartialEq<NotDebug> 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));
};
+114
View File
@@ -0,0 +1,114 @@
//@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() {
let a = "a";
assert!(a == "a".to_ascii_lowercase());
//~^ manual_assert_eq
assert!(a != "a".to_ascii_uppercase());
//~^ manual_assert_eq
debug_assert!(a == "a".to_ascii_lowercase());
//~^ manual_assert_eq
debug_assert!(a != "a".to_ascii_uppercase());
//~^ manual_assert_eq
// macros
let v = vec![];
assert!(v == vec![1, 2, 3]);
//~^ manual_assert_eq
assert!(vec![1, 2, 3] == v);
//~^ manual_assert_eq
assert!(vec![1] == vec![1, 2, 3]);
//~^ manual_assert_eq
// Don't lint: has assert message
assert!(a == "a".to_ascii_lowercase(), "{a}");
assert!(a == "a".to_ascii_lowercase(), "a==a");
assert!(a == "a".to_ascii_lowercase(), "{a}==a");
assert!(a != "a".to_ascii_uppercase(), "a!=A");
debug_assert!(a == "a".to_ascii_lowercase(), "a==a");
debug_assert!(a != "a".to_ascii_uppercase(), "a!=A");
// Don't lint: `!=`, and at least one of the sides is a constant value
assert!(a != "A");
assert!("A" != a);
assert!("A" != "A");
// Don't lint: comparison of ptrs
fn cmp_ptrs(a: *const u8, b: *const u8) {
assert!(a == b);
}
// Don't lint: one of the sides isn't `Debug`
{
#[derive(PartialEq)]
struct NotDebug;
#[derive(PartialEq)]
struct NotDebug2;
impl PartialEq<NotDebug2> for NotDebug {
fn eq(&self, other: &NotDebug2) -> bool {
unimplemented!()
}
}
impl PartialEq<NotDebug> for NotDebug2 {
fn eq(&self, other: &NotDebug) -> bool {
unimplemented!()
}
}
#[derive(Debug)]
struct IsDebug;
impl PartialEq<IsDebug> for NotDebug {
fn eq(&self, other: &IsDebug) -> bool {
unimplemented!()
}
}
impl PartialEq<NotDebug> 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));
};
+88
View File
@@ -0,0 +1,88 @@
error: used `assert!` with an equality comparison
--> tests/ui/manual_assert_eq.rs:8: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:10:5
|
LL | assert!(a != "a".to_ascii_uppercase());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: replace it with `assert_ne!(..)`
|
LL - assert!(a != "a".to_ascii_uppercase());
LL + assert_ne!(a, "a".to_ascii_uppercase());
|
error: used `debug_assert!` with an equality comparison
--> tests/ui/manual_assert_eq.rs:12: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:14:5
|
LL | debug_assert!(a != "a".to_ascii_uppercase());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: replace it with `debug_assert_ne!(..)`
|
LL - debug_assert!(a != "a".to_ascii_uppercase());
LL + debug_assert_ne!(a, "a".to_ascii_uppercase());
|
error: used `assert!` with an equality comparison
--> tests/ui/manual_assert_eq.rs:19:5
|
LL | assert!(v == vec![1, 2, 3]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: replace it with `assert_eq!(..)`
|
LL - assert!(v == vec![1, 2, 3]);
LL + assert_eq!(v, vec![1, 2, 3]);
|
error: used `assert!` with an equality comparison
--> tests/ui/manual_assert_eq.rs:21:5
|
LL | assert!(vec![1, 2, 3] == v);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: replace it with `assert_eq!(..)`
|
LL - assert!(vec![1, 2, 3] == v);
LL + assert_eq!(vec![1, 2, 3], v);
|
error: used `assert!` with an equality comparison
--> tests/ui/manual_assert_eq.rs:23:5
|
LL | assert!(vec![1] == vec![1, 2, 3]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: replace it with `assert_eq!(..)`
|
LL - assert!(vec![1] == vec![1, 2, 3]);
LL + assert_eq!(vec![1], vec![1, 2, 3]);
|
error: aborting due to 7 previous errors
+1 -1
View File
@@ -1,4 +1,4 @@
#![allow(unused)]
#![expect(clippy::manual_assert_eq)]
#![warn(clippy::missing_asserts_for_indexing)]
// ok
+1 -1
View File
@@ -1,4 +1,4 @@
#![allow(unused)]
#![expect(clippy::manual_assert_eq)]
#![warn(clippy::missing_asserts_for_indexing)]
// ok
+2 -2
View File
@@ -7,7 +7,7 @@ impl A {
fn result_with_assert_with_message(x: i32) -> Result<bool, String> // should emit lint
//~^ panic_in_result_fn
{
assert!(x == 5, "wrong argument");
assert!(x.is_positive(), "wrong argument");
Ok(true)
}
@@ -27,7 +27,7 @@ fn result_with_assert_ne(x: i32) -> Result<bool, String> // should emit lint
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
@@ -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<bool, String> // 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)]`
@@ -9,7 +9,7 @@
impl A {
fn result_with_debug_assert_with_message(x: i32) -> Result<bool, String> {
debug_assert!(x == 5, "wrong argument");
debug_assert!(x.is_positive(), "wrong argument");
Ok(true)
}
@@ -24,7 +24,7 @@ fn result_with_debug_assert_ne(x: i32) -> Result<bool, String> {
}
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) {
+1 -1
View File
@@ -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
+7 -4
View File
@@ -1,9 +1,12 @@
//@aux-build:proc_macros.rs
#![warn(clippy::unnecessary_map_or)]
#![allow(clippy::no_effect)]
#![allow(clippy::eq_op)]
#![allow(clippy::unnecessary_lazy_evaluations)]
#![allow(clippy::nonminimal_bool)]
#![allow(
clippy::no_effect,
clippy::eq_op,
clippy::unnecessary_lazy_evaluations,
clippy::nonminimal_bool,
clippy::manual_assert_eq
)]
#[clippy::msrv = "1.70.0"]
#[macro_use]
extern crate proc_macros;
+7 -4
View File
@@ -1,9 +1,12 @@
//@aux-build:proc_macros.rs
#![warn(clippy::unnecessary_map_or)]
#![allow(clippy::no_effect)]
#![allow(clippy::eq_op)]
#![allow(clippy::unnecessary_lazy_evaluations)]
#![allow(clippy::nonminimal_bool)]
#![allow(
clippy::no_effect,
clippy::eq_op,
clippy::unnecessary_lazy_evaluations,
clippy::nonminimal_bool,
clippy::manual_assert_eq
)]
#[clippy::msrv = "1.70.0"]
#[macro_use]
extern crate proc_macros;
+30 -30
View File
@@ -1,5 +1,5 @@
error: this `map_or` can be simplified
--> tests/ui/unnecessary_map_or.rs:13:13
--> tests/ui/unnecessary_map_or.rs:16:13
|
LL | let _ = Some(5).map_or(false, |n| n == 5);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -13,7 +13,7 @@ LL + let _ = Some(5) == Some(5);
|
error: this `map_or` can be simplified
--> tests/ui/unnecessary_map_or.rs:15:13
--> tests/ui/unnecessary_map_or.rs:18:13
|
LL | let _ = Some(5).map_or(true, |n| n != 5);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -25,7 +25,7 @@ LL + let _ = Some(5) != Some(5);
|
error: this `map_or` can be simplified
--> tests/ui/unnecessary_map_or.rs:17:13
--> tests/ui/unnecessary_map_or.rs:20:13
|
LL | let _ = Some(5).map_or(false, |n| {
| _____________^
@@ -46,7 +46,7 @@ LL + let _ = Some(5) == Some(5);
|
error: this `map_or` can be simplified
--> tests/ui/unnecessary_map_or.rs:22:13
--> tests/ui/unnecessary_map_or.rs:25:13
|
LL | let _ = Some(5).map_or(false, |n| {
| _____________^
@@ -63,7 +63,7 @@ LL + let _ = Some(5).is_some_and(|n| {
|
error: this `map_or` can be simplified
--> tests/ui/unnecessary_map_or.rs:27:13
--> tests/ui/unnecessary_map_or.rs:30:13
|
LL | let _ = Some(vec![5]).map_or(false, |n| n == [5]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -75,7 +75,7 @@ LL + let _ = Some(vec![5]).is_some_and(|n| n == [5]);
|
error: this `map_or` can be simplified
--> tests/ui/unnecessary_map_or.rs:29:13
--> tests/ui/unnecessary_map_or.rs:32:13
|
LL | let _ = Some(vec![1]).map_or(false, |n| vec![2] == n);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -87,7 +87,7 @@ LL + let _ = Some(vec![1]).is_some_and(|n| vec![2] == n);
|
error: this `map_or` can be simplified
--> tests/ui/unnecessary_map_or.rs:31:13
--> tests/ui/unnecessary_map_or.rs:34:13
|
LL | let _ = Some(5).map_or(false, |n| n == n);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -99,7 +99,7 @@ LL + let _ = Some(5).is_some_and(|n| n == n);
|
error: this `map_or` can be simplified
--> tests/ui/unnecessary_map_or.rs:33:13
--> tests/ui/unnecessary_map_or.rs:36:13
|
LL | let _ = Some(5).map_or(false, |n| n == if 2 > 1 { n } else { 0 });
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -111,7 +111,7 @@ LL + let _ = Some(5).is_some_and(|n| n == if 2 > 1 { n } else { 0 });
|
error: this `map_or` can be simplified
--> tests/ui/unnecessary_map_or.rs:35:13
--> tests/ui/unnecessary_map_or.rs:38:13
|
LL | let _ = Ok::<Vec<i32>, i32>(vec![5]).map_or(false, |n| n == [5]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -123,7 +123,7 @@ LL + let _ = Ok::<Vec<i32>, i32>(vec![5]).is_ok_and(|n| n == [5]);
|
error: this `map_or` can be simplified
--> tests/ui/unnecessary_map_or.rs:37:13
--> tests/ui/unnecessary_map_or.rs:40:13
|
LL | let _ = Ok::<i32, i32>(5).map_or(false, |n| n == 5);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -135,7 +135,7 @@ LL + let _ = Ok::<i32, i32>(5) == Ok(5);
|
error: this `map_or` can be simplified
--> tests/ui/unnecessary_map_or.rs:39:13
--> tests/ui/unnecessary_map_or.rs:42:13
|
LL | let _ = Some(5).map_or(false, |n| n == 5).then(|| 1);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -147,7 +147,7 @@ LL + let _ = (Some(5) == Some(5)).then(|| 1);
|
error: this `map_or` can be simplified
--> tests/ui/unnecessary_map_or.rs:41:13
--> tests/ui/unnecessary_map_or.rs:44:13
|
LL | let _ = Some(5).map_or(true, |n| n == 5);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -159,7 +159,7 @@ LL + let _ = Some(5).is_none_or(|n| n == 5);
|
error: this `map_or` can be simplified
--> tests/ui/unnecessary_map_or.rs:43:13
--> tests/ui/unnecessary_map_or.rs:46:13
|
LL | let _ = Some(5).map_or(true, |n| 5 == n);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -171,7 +171,7 @@ LL + let _ = Some(5).is_none_or(|n| 5 == n);
|
error: this `map_or` can be simplified
--> tests/ui/unnecessary_map_or.rs:45:14
--> tests/ui/unnecessary_map_or.rs:48:14
|
LL | let _ = !Some(5).map_or(false, |n| n == 5);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -183,7 +183,7 @@ LL + let _ = !(Some(5) == Some(5));
|
error: this `map_or` can be simplified
--> tests/ui/unnecessary_map_or.rs:47:13
--> tests/ui/unnecessary_map_or.rs:50:13
|
LL | let _ = Some(5).map_or(false, |n| n == 5) || false;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -195,7 +195,7 @@ LL + let _ = (Some(5) == Some(5)) || false;
|
error: this `map_or` can be simplified
--> tests/ui/unnecessary_map_or.rs:49:13
--> tests/ui/unnecessary_map_or.rs:52:13
|
LL | let _ = Some(5).map_or(false, |n| n == 5) as usize;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -207,7 +207,7 @@ LL + let _ = (Some(5) == Some(5)) as usize;
|
error: this `map_or` can be simplified
--> tests/ui/unnecessary_map_or.rs:74:13
--> tests/ui/unnecessary_map_or.rs:77:13
|
LL | let _ = r.map_or(false, |x| x == 7);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -219,7 +219,7 @@ LL + let _ = r.is_ok_and(|x| x == 7);
|
error: this `map_or` can be simplified
--> tests/ui/unnecessary_map_or.rs:80:13
--> tests/ui/unnecessary_map_or.rs:83:13
|
LL | let _ = r.map_or(false, func);
| ^^^^^^^^^^^^^^^^^^^^^
@@ -231,7 +231,7 @@ LL + let _ = r.is_ok_and(func);
|
error: this `map_or` can be simplified
--> tests/ui/unnecessary_map_or.rs:82:13
--> tests/ui/unnecessary_map_or.rs:85:13
|
LL | let _ = Some(5).map_or(false, func);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -243,7 +243,7 @@ LL + let _ = Some(5).is_some_and(func);
|
error: this `map_or` can be simplified
--> tests/ui/unnecessary_map_or.rs:84:13
--> tests/ui/unnecessary_map_or.rs:87:13
|
LL | let _ = Some(5).map_or(true, func);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -255,7 +255,7 @@ LL + let _ = Some(5).is_none_or(func);
|
error: this `map_or` can be simplified
--> tests/ui/unnecessary_map_or.rs:90:13
--> tests/ui/unnecessary_map_or.rs:93:13
|
LL | let _ = r.map_or(false, |x| x == 8);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -267,7 +267,7 @@ LL + let _ = r == Ok(8);
|
error: this `map_or` can be simplified
--> tests/ui/unnecessary_map_or.rs:111:5
--> tests/ui/unnecessary_map_or.rs:114:5
|
LL | o.map_or(true, |n| n > 5) || (o as &Option<u32>).map_or(true, |n| n < 5)
| ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -279,7 +279,7 @@ LL + o.is_none_or(|n| n > 5) || (o as &Option<u32>).map_or(true, |n| n < 5)
|
error: this `map_or` can be simplified
--> tests/ui/unnecessary_map_or.rs:111:34
--> tests/ui/unnecessary_map_or.rs:114:34
|
LL | o.map_or(true, |n| n > 5) || (o as &Option<u32>).map_or(true, |n| n < 5)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -291,7 +291,7 @@ LL + o.map_or(true, |n| n > 5) || (o as &Option<u32>).is_none_or(|n| n < 5)
|
error: this `map_or` can be simplified
--> tests/ui/unnecessary_map_or.rs:126:5
--> tests/ui/unnecessary_map_or.rs:129:5
|
LL | o.map_or(true, |n| n > 5)
| ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -303,7 +303,7 @@ LL + o.is_none_or(|n| n > 5)
|
error: this `map_or` can be simplified
--> tests/ui/unnecessary_map_or.rs:131:13
--> tests/ui/unnecessary_map_or.rs:134:13
|
LL | let x = a.map_or(false, |a| a == *s);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -315,7 +315,7 @@ LL + let x = a.is_some_and(|a| a == *s);
|
error: this `map_or` can be simplified
--> tests/ui/unnecessary_map_or.rs:133:13
--> tests/ui/unnecessary_map_or.rs:136:13
|
LL | let y = b.map_or(true, |b| b == *s);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -327,7 +327,7 @@ 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:142:13
|
LL | assert!(Some("test").map_or(false, |x| x == "test"));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -339,7 +339,7 @@ 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");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^