Skip to content

Commit f65c481

Browse files
committed
it works
1 parent 6bb0c97 commit f65c481

File tree

6 files changed

+161
-0
lines changed

6 files changed

+161
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5748,6 +5748,7 @@ Released 2018-09-13
57485748
[`drop_copy`]: https://rust-lang.github.io/rust-clippy/master/index.html#drop_copy
57495749
[`drop_non_drop`]: https://rust-lang.github.io/rust-clippy/master/index.html#drop_non_drop
57505750
[`drop_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#drop_ref
5751+
[`duplicate_match_guard`]: https://rust-lang.github.io/rust-clippy/master/index.html#duplicate_match_guard
57515752
[`duplicate_mod`]: https://rust-lang.github.io/rust-clippy/master/index.html#duplicate_mod
57525753
[`duplicate_underscore_argument`]: https://rust-lang.github.io/rust-clippy/master/index.html#duplicate_underscore_argument
57535754
[`duplicated_attributes`]: https://rust-lang.github.io/rust-clippy/master/index.html#duplicated_attributes

clippy_lints/src/declared_lints.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ pub static LINTS: &[&crate::LintInfo] = &[
134134
crate::drop_forget_ref::DROP_NON_DROP_INFO,
135135
crate::drop_forget_ref::FORGET_NON_DROP_INFO,
136136
crate::drop_forget_ref::MEM_FORGET_INFO,
137+
crate::duplicate_match_guard::DUPLICATE_MATCH_GUARD_INFO,
137138
crate::duplicate_mod::DUPLICATE_MOD_INFO,
138139
crate::else_if_without_else::ELSE_IF_WITHOUT_ELSE_INFO,
139140
crate::empty_drop::EMPTY_DROP_INFO,
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
use clippy_utils::diagnostics::span_lint;
2+
use clippy_utils::eq_expr_value;
3+
use rustc_hir::{Arm, ExprKind};
4+
use rustc_lint::{LateContext, LateLintPass};
5+
use rustc_session::declare_lint_pass;
6+
7+
declare_clippy_lint! {
8+
/// ### What it does
9+
/// Checks for the same condition being checked in a match guard and in the match body
10+
///
11+
/// ### Why is this bad?
12+
/// This is usually just a typo or a copy and paste error.
13+
///
14+
/// ### Known problems
15+
/// False negatives: if the condition is an impure function, it could've been called twice on
16+
/// purpose for its side effects
17+
///
18+
/// ### Example
19+
/// ```no_run
20+
/// # let n = 0;
21+
/// # let a = 3;
22+
/// # let b = 4;
23+
/// match n {
24+
/// 0 if a > b => {
25+
/// if a > b {
26+
/// return;
27+
/// }
28+
/// }
29+
/// _ => {}
30+
/// }
31+
/// ```
32+
/// Use instead:
33+
/// ```no_run
34+
/// # let n = 0;
35+
/// # let a = 3;
36+
/// # let b = 4;
37+
/// match n {
38+
/// 0 if a > b => {
39+
/// return;
40+
/// }
41+
/// _ => {}
42+
/// }
43+
/// ```
44+
#[clippy::version = "1.89.0"]
45+
pub DUPLICATE_MATCH_GUARD,
46+
nursery,
47+
"a condition in match body duplicating the match guard"
48+
}
49+
declare_lint_pass!(DuplicateMatchGuard => [DUPLICATE_MATCH_GUARD]);
50+
51+
impl<'tcx> LateLintPass<'tcx> for DuplicateMatchGuard {
52+
fn check_arm(&mut self, cx: &LateContext<'tcx>, arm: &'tcx Arm<'tcx>) {
53+
if let Some(guard) = arm.guard
54+
&& let ExprKind::Block(block, _) = arm.body.kind
55+
&& block.stmts.is_empty()
56+
&& let Some(trailing_expr) = block.expr
57+
&& let ExprKind::If(cond, _, None) = trailing_expr.kind
58+
&& eq_expr_value(cx, guard, cond.peel_drop_temps())
59+
{
60+
span_lint(cx, DUPLICATE_MATCH_GUARD, cond.span, "condition duplicates match guard");
61+
}
62+
}
63+
}

clippy_lints/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ mod disallowed_types;
122122
mod doc;
123123
mod double_parens;
124124
mod drop_forget_ref;
125+
mod duplicate_match_guard;
125126
mod duplicate_mod;
126127
mod else_if_without_else;
127128
mod empty_drop;
@@ -951,5 +952,6 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
951952
store.register_late_pass(|_| Box::new(cloned_ref_to_slice_refs::ClonedRefToSliceRefs::new(conf)));
952953
store.register_late_pass(|_| Box::new(infallible_try_from::InfallibleTryFrom));
953954
store.register_late_pass(|_| Box::new(coerce_container_to_any::CoerceContainerToAny));
955+
store.register_late_pass(|_| Box::new(duplicate_match_guard::DuplicateMatchGuard));
954956
// add lints here, do not remove this comment, it's used in `new_lint`
955957
}

tests/ui/duplicate_match_guard.rs

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
#![allow(clippy::needless_return, clippy::needless_else)]
2+
#![warn(clippy::duplicate_match_guard)]
3+
4+
fn main() {
5+
let mut a = 5;
6+
let b = 4;
7+
let mut v: Vec<u32> = vec![];
8+
9+
match 0u32 {
10+
0 if true => {
11+
if true {
12+
//~^ duplicate_match_guard
13+
return;
14+
}
15+
},
16+
0 if a > b => {
17+
if a > b {
18+
//~^ duplicate_match_guard
19+
return;
20+
}
21+
},
22+
// not _identical_, but the meaning is the same
23+
0 if a > b => {
24+
if b < a {
25+
//~^ duplicate_match_guard
26+
return;
27+
}
28+
},
29+
// a bit more complicated
30+
0 if a > 0 && b > 0 => {
31+
if a > 0 && b > 0 {
32+
//~^ duplicate_match_guard
33+
return;
34+
}
35+
},
36+
37+
// no warnings
38+
0 if true => {
39+
if false {
40+
return;
41+
}
42+
},
43+
// has side effects, so don't lint
44+
0 if v.pop().is_some() => {
45+
if v.pop().is_some() {
46+
return;
47+
}
48+
},
49+
// there's _something_ in the else branch
50+
0 if a > b => {
51+
if a > b {
52+
a += b;
53+
} else {
54+
}
55+
},
56+
// body has statements before the if
57+
0 if a > b => {
58+
a += b;
59+
if a > b {
60+
return;
61+
}
62+
},
63+
_ => todo!(),
64+
};
65+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
error: condition duplicates match guard
2+
--> tests/ui/duplicate_match_guard.rs:11:16
3+
|
4+
LL | if true {
5+
| ^^^^
6+
|
7+
= note: `-D clippy::duplicate-match-guard` implied by `-D warnings`
8+
= help: to override `-D warnings` add `#[allow(clippy::duplicate_match_guard)]`
9+
10+
error: condition duplicates match guard
11+
--> tests/ui/duplicate_match_guard.rs:17:16
12+
|
13+
LL | if a > b {
14+
| ^^^^^
15+
16+
error: condition duplicates match guard
17+
--> tests/ui/duplicate_match_guard.rs:24:16
18+
|
19+
LL | if b < a {
20+
| ^^^^^
21+
22+
error: condition duplicates match guard
23+
--> tests/ui/duplicate_match_guard.rs:31:16
24+
|
25+
LL | if a > 0 && b > 0 {
26+
| ^^^^^^^^^^^^^^
27+
28+
error: aborting due to 4 previous errors
29+

0 commit comments

Comments
 (0)