Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 30fb822

Browse files
committed
add tests, add base bone for the new lint
1 parent 7b2896a commit 30fb822

File tree

9 files changed

+251
-0
lines changed

9 files changed

+251
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3348,6 +3348,7 @@ Released 2018-09-13
33483348
[`nonminimal_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#nonminimal_bool
33493349
[`nonsensical_open_options`]: https://rust-lang.github.io/rust-clippy/master/index.html#nonsensical_open_options
33503350
[`nonstandard_macro_braces`]: https://rust-lang.github.io/rust-clippy/master/index.html#nonstandard_macro_braces
3351+
[`nop_match`]: https://rust-lang.github.io/rust-clippy/master/index.html#nop_match
33513352
[`not_unsafe_ptr_arg_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#not_unsafe_ptr_arg_deref
33523353
[`octal_escapes`]: https://rust-lang.github.io/rust-clippy/master/index.html#octal_escapes
33533354
[`ok_expect`]: https://rust-lang.github.io/rust-clippy/master/index.html#ok_expect

clippy_lints/src/lib.register_all.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
134134
LintId::of(matches::MATCH_OVERLAPPING_ARM),
135135
LintId::of(matches::MATCH_REF_PATS),
136136
LintId::of(matches::MATCH_SINGLE_BINDING),
137+
LintId::of(matches::NOP_MATCH),
137138
LintId::of(matches::REDUNDANT_PATTERN_MATCHING),
138139
LintId::of(matches::SINGLE_MATCH),
139140
LintId::of(matches::WILDCARD_IN_OR_PATTERNS),

clippy_lints/src/lib.register_correctness.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ store.register_group(true, "clippy::correctness", Some("clippy_correctness"), ve
3737
LintId::of(loops::NEVER_LOOP),
3838
LintId::of(loops::WHILE_IMMUTABLE_CONDITION),
3939
LintId::of(match_str_case_mismatch::MATCH_STR_CASE_MISMATCH),
40+
LintId::of(matches::NOP_MATCH),
4041
LintId::of(mem_replace::MEM_REPLACE_WITH_UNINIT),
4142
LintId::of(methods::CLONE_DOUBLE_REF),
4243
LintId::of(methods::ITERATOR_STEP_BY_ZERO),

clippy_lints/src/lib.register_lints.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,7 @@ store.register_lints(&[
253253
matches::MATCH_SINGLE_BINDING,
254254
matches::MATCH_WILDCARD_FOR_SINGLE_VARIANTS,
255255
matches::MATCH_WILD_ERR_ARM,
256+
matches::NOP_MATCH,
256257
matches::REDUNDANT_PATTERN_MATCHING,
257258
matches::REST_PAT_IN_FULLY_BOUND_STRUCTS,
258259
matches::SINGLE_MATCH,

clippy_lints/src/matches/mod.rs

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ mod redundant_pattern_match;
2121
mod rest_pat_in_fully_bound_struct;
2222
mod single_match;
2323
mod wild_in_or_pats;
24+
mod nop_match;
2425

2526
declare_clippy_lint! {
2627
/// ### What it does
@@ -566,6 +567,49 @@ declare_clippy_lint! {
566567
"`match` with identical arm bodies"
567568
}
568569

570+
declare_clippy_lint! {
571+
/// ### What it does
572+
/// Checks for unnecessary `match` or match-like `if let` returns for `Option` and `Result`
573+
/// when function signatures are the same.
574+
///
575+
/// ### Why is this bad?
576+
/// This `match` block does nothing and might not be what the coder intended.
577+
///
578+
/// ### Example
579+
/// ```rust,ignore
580+
/// fn foo() -> Result<(), i32> {
581+
/// match result {
582+
/// Ok(val) => Ok(val),
583+
/// Err(err) => Err(err),
584+
/// }
585+
/// }
586+
///
587+
/// fn bar() -> Option<i32> {
588+
/// if let Some(val) = option {
589+
/// Some(val)
590+
/// } else {
591+
/// None
592+
/// }
593+
/// }
594+
/// ```
595+
///
596+
/// Could be replaced as
597+
///
598+
/// ```rust,ignore
599+
/// fn foo() -> Result<(), i32> {
600+
/// result
601+
/// }
602+
///
603+
/// fn bar() -> Option<i32> {
604+
/// option
605+
/// }
606+
/// ```
607+
#[clippy::version = "1.61.0"]
608+
pub NOP_MATCH,
609+
correctness,
610+
"`match` or match-like `if let` that are unnecessary"
611+
}
612+
569613
#[derive(Default)]
570614
pub struct Matches {
571615
msrv: Option<RustcVersion>,
@@ -599,6 +643,7 @@ impl_lint_pass!(Matches => [
599643
REDUNDANT_PATTERN_MATCHING,
600644
MATCH_LIKE_MATCHES_MACRO,
601645
MATCH_SAME_ARMS,
646+
NOP_MATCH,
602647
]);
603648

604649
impl<'tcx> LateLintPass<'tcx> for Matches {
@@ -622,6 +667,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
622667
overlapping_arms::check(cx, ex, arms);
623668
match_wild_enum::check(cx, ex, arms);
624669
match_as_ref::check(cx, ex, arms, expr);
670+
nop_match::check_match(cx, ex, arms);
625671

626672
if self.infallible_destructuring_match_linted {
627673
self.infallible_destructuring_match_linted = false;
@@ -640,6 +686,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
640686
match_like_matches::check(cx, expr);
641687
}
642688
redundant_pattern_match::check(cx, expr);
689+
nop_match::check(cx, expr);
643690
}
644691
}
645692

clippy_lints/src/matches/nop_match.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#![allow(unused_variables)]
2+
use clippy_utils::diagnostics::span_lint_and_sugg;
3+
use rustc_lint::LateContext;
4+
use rustc_hir::{Arm, Expr};
5+
use rustc_errors::Applicability;
6+
use super::NOP_MATCH;
7+
8+
pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>) {
9+
if false {
10+
span_lint_and_sugg(
11+
cx,
12+
NOP_MATCH,
13+
ex.span,
14+
"this if-let expression is unnecessary",
15+
"replace it with",
16+
"".to_string(),
17+
Applicability::MachineApplicable,
18+
);
19+
}
20+
}
21+
22+
pub(crate) fn check_match(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) {
23+
if false {
24+
span_lint_and_sugg(
25+
cx,
26+
NOP_MATCH,
27+
ex.span,
28+
"this match expression is unnecessary",
29+
"replace it with",
30+
"".to_string(),
31+
Applicability::MachineApplicable,
32+
);
33+
}
34+
}

tests/ui/nop_match.fixed

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
// run-rustfix
2+
#![warn(clippy::nop_match)]
3+
#![allow(clippy::manual_map)]
4+
#![allow(clippy::question_mark)]
5+
#![allow(dead_code)]
6+
7+
fn option_match() -> Option<i32> {
8+
match Some(1) {
9+
Some(a) => Some(a),
10+
None => None
11+
}
12+
}
13+
14+
fn result_match() -> Result<i32, i32> {
15+
match Ok(1) {
16+
Ok(a) => Ok(a),
17+
Err(err) => Err(err)
18+
}
19+
}
20+
21+
fn option_check() -> Option<i32> {
22+
if let Some(a) = Some(1) {
23+
Some(a)
24+
} else {
25+
None
26+
}
27+
}
28+
29+
fn option_check_no_else() -> Option<i32> {
30+
if let Some(a) = Some(1) {
31+
return Some(a);
32+
}
33+
None
34+
}
35+
36+
fn func_ret_err<T>(err: T) -> Result<(), T> {
37+
Err(err)
38+
}
39+
40+
fn result_check_no_else() -> Result<(), i32> {
41+
if let Err(e) = func_ret_err(0_i32) {
42+
return Err(e);
43+
}
44+
Ok(())
45+
}
46+
47+
fn result_check_a() -> Result<(), i32> {
48+
if let Err(e) = func_ret_err(0_i32) {
49+
Err(e)
50+
} else {
51+
Ok(())
52+
}
53+
}
54+
55+
// Don't trigger
56+
fn result_check_b() -> Result<(), i32> {
57+
if let Err(e) = Ok(1) {
58+
Err(e)
59+
} else {
60+
Ok(())
61+
}
62+
}
63+
64+
fn result_check_c() -> Result<(), i32> {
65+
let example = Ok(());
66+
if let Err(e) = example {
67+
Err(e)
68+
} else {
69+
example
70+
}
71+
}
72+
73+
// Don't trigger
74+
fn result_check_d() -> Result<(), i32> {
75+
let example = Ok(1);
76+
if let Err(e) = example {
77+
Err(e)
78+
} else {
79+
Ok(())
80+
}
81+
}
82+
83+
fn main() { }

tests/ui/nop_match.rs

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
// run-rustfix
2+
#![warn(clippy::nop_match)]
3+
#![allow(clippy::manual_map)]
4+
#![allow(clippy::question_mark)]
5+
#![allow(dead_code)]
6+
7+
fn option_match() -> Option<i32> {
8+
match Some(1) {
9+
Some(a) => Some(a),
10+
None => None
11+
}
12+
}
13+
14+
fn result_match() -> Result<i32, i32> {
15+
match Ok(1) {
16+
Ok(a) => Ok(a),
17+
Err(err) => Err(err)
18+
}
19+
}
20+
21+
fn option_check() -> Option<i32> {
22+
if let Some(a) = Some(1) {
23+
Some(a)
24+
} else {
25+
None
26+
}
27+
}
28+
29+
fn option_check_no_else() -> Option<i32> {
30+
if let Some(a) = Some(1) {
31+
return Some(a);
32+
}
33+
None
34+
}
35+
36+
fn func_ret_err<T>(err: T) -> Result<(), T> {
37+
Err(err)
38+
}
39+
40+
fn result_check_no_else() -> Result<(), i32> {
41+
if let Err(e) = func_ret_err(0_i32) {
42+
return Err(e);
43+
}
44+
Ok(())
45+
}
46+
47+
fn result_check_a() -> Result<(), i32> {
48+
if let Err(e) = func_ret_err(0_i32) {
49+
Err(e)
50+
} else {
51+
Ok(())
52+
}
53+
}
54+
55+
// Don't trigger
56+
fn result_check_b() -> Result<(), i32> {
57+
if let Err(e) = Ok(1) {
58+
Err(e)
59+
} else {
60+
Ok(())
61+
}
62+
}
63+
64+
fn result_check_c() -> Result<(), i32> {
65+
let example = Ok(());
66+
if let Err(e) = example {
67+
Err(e)
68+
} else {
69+
example
70+
}
71+
}
72+
73+
// Don't trigger
74+
fn result_check_d() -> Result<(), i32> {
75+
let example = Ok(1);
76+
if let Err(e) = example {
77+
Err(e)
78+
} else {
79+
Ok(())
80+
}
81+
}
82+
83+
fn main() { }

tests/ui/nop_match.stderr

Whitespace-only changes.

0 commit comments

Comments
 (0)