Skip to content

[else_if_without_else]: Fix duplicate diagnostics #12441

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

Merged
merged 1 commit into from
Mar 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 12 additions & 14 deletions clippy_lints/src/else_if_without_else.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,24 +49,22 @@ declare_clippy_lint! {
declare_lint_pass!(ElseIfWithoutElse => [ELSE_IF_WITHOUT_ELSE]);

impl EarlyLintPass for ElseIfWithoutElse {
fn check_expr(&mut self, cx: &EarlyContext<'_>, mut item: &Expr) {
fn check_expr(&mut self, cx: &EarlyContext<'_>, item: &Expr) {
if in_external_macro(cx.sess(), item.span) {
return;
}

while let ExprKind::If(_, _, Some(ref els)) = item.kind {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm guessing this is to lint nested blocks (albeit weirdly?). Can you help to also add a test case for this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This caused the lint to emit on any if-else-if-else... chain that did not end with an else. The lint would flag at the top of the chain, and then also flag each time EarlyLintPass::check_expr was called on the subsequent expressions in the chain.

I added a test with 4 chains:

if bla1() {
     println!("if");
} else if bla2() {
     println!("else if 1");
} else if bla3() {
     println!("else if 2");
} else if bla4() {
     println!("else if 3");
} else if bla5() {
      //~^ ERROR: `if` expression with an `else if`, but without a final `else`
      println!("else if 4");
}

Before this fix, four duplicate lints are emitted for this if-else-if... chain.

Also added a passing case four chain test, and fail/pass cases which contain suppressed [collapsible_else_if] blocks.

if let ExprKind::If(_, _, None) = els.kind {
span_lint_and_help(
cx,
ELSE_IF_WITHOUT_ELSE,
els.span,
"`if` expression with an `else if`, but without a final `else`",
None,
"add an `else` block here",
);
}

item = els;
if let ExprKind::If(_, _, Some(ref els)) = item.kind
&& let ExprKind::If(_, _, None) = els.kind
{
span_lint_and_help(
cx,
ELSE_IF_WITHOUT_ELSE,
els.span,
"`if` expression with an `else if`, but without a final `else`",
None,
"add an `else` block here",
);
}
}
}
68 changes: 65 additions & 3 deletions tests/ui/else_if_without_else.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
//@compile-flags: -Zdeduplicate-diagnostics=yes

#![warn(clippy::all)]
#![warn(clippy::else_if_without_else)]
#![allow(clippy::collapsible_else_if)]

fn bla1() -> bool {
unimplemented!()
Expand All @@ -12,6 +10,12 @@ fn bla2() -> bool {
fn bla3() -> bool {
unimplemented!()
}
fn bla4() -> bool {
unimplemented!()
}
fn bla5() -> bool {
unimplemented!()
}

fn main() {
if bla1() {
Expand Down Expand Up @@ -57,4 +61,62 @@ fn main() {
//~^ ERROR: `if` expression with an `else if`, but without a final `else`
println!("else if 2");
}

if bla1() {
println!("if");
} else if bla2() {
println!("else if 1");
} else if bla3() {
println!("else if 2");
} else if bla4() {
println!("else if 3");
} else if bla5() {
println!("else if 4");
} else {
println!("else");
}

if bla1() {
println!("if");
} else if bla2() {
println!("else if 1");
} else if bla3() {
println!("else if 2");
} else if bla4() {
println!("else if 3");
} else if bla5() {
//~^ ERROR: `if` expression with an `else if`, but without a final `else`
println!("else if 4");
}

if bla1() {
println!("if");
} else if bla2() {
println!("else if 1");
} else {
if bla3() {
println!("else if 2");
} else if bla4() {
println!("else if 3");
} else if bla5() {
println!("else if 4");
} else {
println!("else");
}
}

if bla1() {
println!("if");
} else if bla2() {
println!("else if 1");
} else {
if bla3() {
println!("else if 2");
} else if bla4() {
println!("else if 3");
} else if bla5() {
//~^ ERROR: `if` expression with an `else if`, but without a final `else`
println!("else if 4");
}
}
}
30 changes: 27 additions & 3 deletions tests/ui/else_if_without_else.stderr
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error: `if` expression with an `else if`, but without a final `else`
--> tests/ui/else_if_without_else.rs:47:12
--> tests/ui/else_if_without_else.rs:51:12
|
LL | } else if bla2() {
| ____________^
Expand All @@ -13,7 +13,7 @@ LL | | }
= help: to override `-D warnings` add `#[allow(clippy::else_if_without_else)]`

error: `if` expression with an `else if`, but without a final `else`
--> tests/ui/else_if_without_else.rs:56:12
--> tests/ui/else_if_without_else.rs:60:12
|
LL | } else if bla3() {
| ____________^
Expand All @@ -24,5 +24,29 @@ LL | | }
|
= help: add an `else` block here

error: aborting due to 2 previous errors
error: `if` expression with an `else if`, but without a final `else`
--> tests/ui/else_if_without_else.rs:87:12
|
LL | } else if bla5() {
| ____________^
LL | |
LL | | println!("else if 4");
LL | | }
| |_____^
|
= help: add an `else` block here

error: `if` expression with an `else if`, but without a final `else`
--> tests/ui/else_if_without_else.rs:117:16
|
LL | } else if bla5() {
| ________________^
LL | |
LL | | println!("else if 4");
LL | | }
| |_________^
|
= help: add an `else` block here

error: aborting due to 4 previous errors