Skip to content

Commit 25c2b79

Browse files
committed
add new lint, matches_instead_of_eq
1 parent 40bead0 commit 25c2b79

File tree

6 files changed

+115
-0
lines changed

6 files changed

+115
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6016,6 +6016,7 @@ Released 2018-09-13
60166016
[`match_str_case_mismatch`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_str_case_mismatch
60176017
[`match_wild_err_arm`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_wild_err_arm
60186018
[`match_wildcard_for_single_variants`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_wildcard_for_single_variants
6019+
[`matches_instead_of_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#matches_instead_of_eq
60196020
[`maybe_infinite_iter`]: https://rust-lang.github.io/rust-clippy/master/index.html#maybe_infinite_iter
60206021
[`maybe_misused_cfg`]: https://rust-lang.github.io/rust-clippy/master/index.html#maybe_misused_cfg
60216022
[`mem_discriminant_non_enum`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_discriminant_non_enum

clippy_lints/src/declared_lints.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,7 @@ pub static LINTS: &[&crate::LintInfo] = &[
320320
crate::matches::MANUAL_OK_ERR_INFO,
321321
crate::matches::MANUAL_UNWRAP_OR_INFO,
322322
crate::matches::MANUAL_UNWRAP_OR_DEFAULT_INFO,
323+
crate::matches::MATCHES_INSTEAD_OF_EQ_INFO,
323324
crate::matches::MATCH_AS_REF_INFO,
324325
crate::matches::MATCH_BOOL_INFO,
325326
crate::matches::MATCH_LIKE_MATCHES_MACRO_INFO,
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
use clippy_utils::diagnostics::span_lint_and_help;
2+
use clippy_utils::macros::HirNode;
3+
use clippy_utils::sym;
4+
use clippy_utils::ty::implements_trait;
5+
use rustc_hir::PatKind;
6+
use rustc_lint::LateContext;
7+
8+
use super::MATCHES_INSTEAD_OF_EQ;
9+
10+
// TODO: Adjust the parameters as necessary
11+
pub(super) fn check(
12+
cx: &LateContext<'_>,
13+
expr: &rustc_hir::Expr<'_>,
14+
ex: &rustc_hir::Expr<'_>,
15+
arms: &[rustc_hir::Arm<'_>],
16+
) {
17+
let Some(partialeq) = cx.tcx.get_diagnostic_item(sym::PartialEq) else {
18+
return;
19+
};
20+
let expr_type = cx.typeck_results().expr_ty(ex);
21+
if !implements_trait(cx, expr_type, partialeq, &[expr_type.into()]) {
22+
return;
23+
}
24+
if arms.into_iter().all(|arm| {
25+
!matches!(
26+
arm.pat.kind,
27+
PatKind::Or(..) | PatKind::Struct(..) | PatKind::TupleStruct(..)
28+
)
29+
}) {
30+
span_lint_and_help(
31+
cx,
32+
MATCHES_INSTEAD_OF_EQ,
33+
expr.span(),
34+
"This expression can be replaced with a == comparison",
35+
None,
36+
"This type implements PartialEq, so you can use == instead of matches!()",
37+
);
38+
}
39+
}

clippy_lints/src/matches/mod.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ mod match_single_binding;
1414
mod match_str_case_mismatch;
1515
mod match_wild_enum;
1616
mod match_wild_err_arm;
17+
mod matches_instead_of_eq;
1718
mod needless_match;
1819
mod overlapping_arms;
1920
mod redundant_guards;
@@ -1006,6 +1007,25 @@ declare_clippy_lint! {
10061007
"find manual implementations of `.ok()` or `.err()` on `Result`"
10071008
}
10081009

1010+
declare_clippy_lint! {
1011+
/// ### What it does
1012+
///
1013+
/// ### Why is this bad?
1014+
///
1015+
/// ### Example
1016+
/// ```no_run
1017+
/// // example code where clippy issues a warning
1018+
/// ```
1019+
/// Use instead:
1020+
/// ```no_run
1021+
/// // example code which does not raise clippy warning
1022+
/// ```
1023+
#[clippy::version = "1.88.0"]
1024+
pub MATCHES_INSTEAD_OF_EQ,
1025+
pedantic,
1026+
"default lint description"
1027+
}
1028+
10091029
pub struct Matches {
10101030
msrv: Msrv,
10111031
infallible_destructuring_match_linted: bool,
@@ -1048,6 +1068,7 @@ impl_lint_pass!(Matches => [
10481068
MANUAL_FILTER,
10491069
REDUNDANT_GUARDS,
10501070
MANUAL_OK_ERR,
1071+
MATCHES_INSTEAD_OF_EQ,
10511072
]);
10521073

10531074
impl<'tcx> LateLintPass<'tcx> for Matches {
@@ -1064,6 +1085,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
10641085
{
10651086
redundant_pattern_match::check_match(cx, expr, ex, arms);
10661087
redundant_pattern_match::check_matches_true(cx, expr, arm, ex);
1088+
matches_instead_of_eq::check(cx, expr, ex, arms);
10671089
}
10681090

10691091
if source == MatchSource::Normal && !is_span_match(cx, expr.span) {

tests/ui/matches_instead_of_eq.rs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
#![warn(clippy::matches_instead_of_eq)]
2+
3+
enum Foo {
4+
Bar,
5+
Baz,
6+
}
7+
8+
#[derive(PartialEq)]
9+
enum EvenOdd {
10+
Even,
11+
Odd,
12+
Unknown,
13+
}
14+
15+
#[derive(PartialEq)]
16+
enum Foo2 {
17+
Bar(u8, u8),
18+
Baz { x: u8, y: u8 },
19+
}
20+
21+
fn main() {
22+
let x = Foo::Bar;
23+
let val = matches!(x, Foo::Bar); // No error as Foo does not implement PartialEq
24+
25+
let x = EvenOdd::Even;
26+
let val = matches!(x, EvenOdd::Even);
27+
//~^ matches_instead_of_eq
28+
29+
let x = EvenOdd::Odd;
30+
let val = matches!(x, EvenOdd::Even | EvenOdd::Odd); // No error
31+
32+
let x = Foo2::Bar(1, 2);
33+
let val = matches!(x, Foo2::Bar(_, _)); // No error
34+
35+
let x = Foo2::Baz { x: 1, y: 2 };
36+
let val = matches!(x, Foo2::Baz { .. }); // No Error
37+
38+
let val = matches!(x, Foo2::Bar(..) | Foo2::Baz { .. }); // No error
39+
}

tests/ui/matches_instead_of_eq.stderr

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
error: This expression can be replaced with a == comparison
2+
--> tests/ui/matches_instead_of_eq.rs:26:15
3+
|
4+
LL | let val = matches!(x, EvenOdd::Even);
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
6+
|
7+
= help: This type implements PartialEq, so you can use == instead of matches!()
8+
= note: `-D clippy::matches-instead-of-eq` implied by `-D warnings`
9+
= help: to override `-D warnings` add `#[allow(clippy::matches_instead_of_eq)]`
10+
= note: this error originates in the macro `matches` (in Nightly builds, run with -Z macro-backtrace for more info)
11+
12+
error: aborting due to 1 previous error
13+

0 commit comments

Comments
 (0)