-
Notifications
You must be signed in to change notification settings - Fork 1.8k
WIP: New lint: duplicate_match_guards
#14986
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
bd9de96
to
c7f0188
Compare
c7f0188
to
71c4b42
Compare
8bd7cbe
to
a86397c
Compare
duplicate_match_guard
duplicate_match_guards
fab6b13
to
1a5e31b
Compare
1a5e31b
to
d6e58a9
Compare
}; | ||
|
||
if let ExprKind::If(cond, then, None) = arm_body_expr.kind | ||
&& eq_expr_value(cx, guard, cond.peel_drop_temps()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since the lint is directed at copy-paste errors, maybe we should make this stricter, and make sure that the expr are "syntactically" equal, and don't just evaluate to the result.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
eq_expr_value
already does that (it uses SpanlessEq
, which checks for syntactic equality). Or how do you mean this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No yes, that's what I meant. If that's the case though, how is the following able to pass?
rust-clippy/tests/ui/duplicate_match_guards.rs
Lines 22 to 28 in 3e4ace9
// not _identical_, but the meaning is the same | |
0 if a > b => { | |
if b < a { | |
//~^ duplicate_match_guards | |
return; | |
} | |
}, |
d6e58a9
to
3e4ace9
Compare
This comment has been minimized.
This comment has been minimized.
}; | ||
|
||
if let ExprKind::If(cond, then, None) = arm_body_expr.kind | ||
&& eq_expr_value(cx, guard, cond.peel_drop_temps()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
eq_expr_value
already does that (it uses SpanlessEq
, which checks for syntactic equality). Or how do you mean this?
/// False negatives: if the condition is an impure function, it could've been called twice on | ||
/// purpose for its side effects |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm slightly confused by this section. This says "false negative", but then describes what sounds like would be a false positive ("the lint falsely warns if the condition has impure function calls which would change semantics"), but this case is actually handled by the lint anyway given that there's a test for it (so there's no issue at all)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're absolutely right. I think that's a remnant of another lint I took inspiration from.
/// ``` | ||
#[clippy::version = "1.89.0"] | ||
pub DUPLICATE_MATCH_GUARDS, | ||
nursery, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think suspicious
would be fine for the category
(arm.body, false) | ||
}; | ||
|
||
if let ExprKind::If(cond, then, None) = arm_body_expr.kind |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a reason to not also lint if there's an else
? It still seems just as (arguably even more) wrong if there's an else {}
because the block will additionally just be unreachable, wouldn't it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think there is, no. It's just that my motivating case in particular didn't have an else
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(arguably even more) wrong
Given this, maybe it would make sense to lint the else is Some
case with a separate lint, placed into the correctness
group?
if block.stmts.is_empty() | ||
&& let Some(trailing_expr) = block.expr |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see this is already making sure that there are no other statements, but we might also want to check that there's no #[cfg]
'd out code in between. So e.g. I assume the following is currently a false positive:
match () {
() if condition {
#[cfg(...)]
condition = true;
if condition {
}
}
}
/// } | ||
/// ``` | ||
#[clippy::version = "1.89.0"] | ||
pub DUPLICATE_MATCH_GUARDS, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Couldn't this lint in principle apply to regular if conditions too? E.g. this currently has no warning
let x = 1;
if x > 1 {
if x > 1 {
// always executes
} else {
// this block of code is simply unreachable
todo!()
}
} else { todo!() }
I'm not saying that this PR should implement that, but it makes me wonder if we should make the lint name a bit more general, like duplicate_nested_conditions
or something so it could be extended in the future without needing a name change?
3e4ace9
to
e7acebc
Compare
This PR was rebased onto a different master commit. Here's a range-diff highlighting what actually changed. Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers. |
e7acebc
to
568f730
Compare
Fixes #14971
WIP because:
eq_expr_value
takes care of impure function calls?changelog: new lint: [
duplicate_match_guards
]