Skip to content

Commit

Permalink
suggest if_not_else
Browse files Browse the repository at this point in the history
  • Loading branch information
lapla-cogito committed Dec 11, 2024
1 parent d5059d8 commit 654c288
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 5 deletions.
54 changes: 51 additions & 3 deletions clippy_lints/src/if_not_else.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
use clippy_utils::consts::{ConstEvalCtxt, Constant};
use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg};
use clippy_utils::is_else_clause;
use clippy_utils::source::{HasSession, indent_of, reindent_multiline, snippet};
use rustc_errors::Applicability;
use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::declare_lint_pass;
use rustc_span::Span;
use std::borrow::Cow;

declare_clippy_lint! {
/// ### What it does
Expand Down Expand Up @@ -54,7 +58,7 @@ fn is_zero_const(expr: &Expr<'_>, cx: &LateContext<'_>) -> bool {

impl LateLintPass<'_> for IfNotElse {
fn check_expr(&mut self, cx: &LateContext<'_>, e: &Expr<'_>) {
if let ExprKind::If(cond, _, Some(els)) = e.kind
if let ExprKind::If(cond, cond_inner, Some(els)) = e.kind
&& let ExprKind::DropTemps(cond) = cond.kind
&& let ExprKind::Block(..) = els.kind
{
Expand All @@ -79,8 +83,52 @@ impl LateLintPass<'_> for IfNotElse {
// }
// ```
if !e.span.from_expansion() && !is_else_clause(cx.tcx, e) {
span_lint_and_help(cx, IF_NOT_ELSE, e.span, msg, None, help);
match cond.kind {
ExprKind::Unary(UnOp::Not, _) | ExprKind::Binary(_, _, _) => span_lint_and_sugg(
cx,
IF_NOT_ELSE,
e.span,
msg,
"try",
make_sugg(cx, &cond.kind, cond_inner.span, els.span, "..", Some(e.span)).to_string(),
Applicability::MachineApplicable,
),
_ => span_lint_and_help(cx, IF_NOT_ELSE, e.span, msg, None, help),
}
}
}
}
}

fn make_sugg<'a>(
sess: &impl HasSession,
cond_kind: &'a ExprKind<'a>,
cond_inner: Span,
els_span: Span,
default: &'a str,
indent_relative_to: Option<Span>,
) -> Cow<'a, str> {
let cond_inner_snip = snippet(sess, cond_inner, default);
let els_snip = snippet(sess, els_span, default);
let indent = indent_relative_to.and_then(|s| indent_of(sess, s));

let suggestion = match cond_kind {
ExprKind::Unary(UnOp::Not, cond_rest) => {
format!(
"if {} {} else {}",
snippet(sess, cond_rest.span, default),
els_snip,
cond_inner_snip
)
},
ExprKind::Binary(_, lhs, rhs) => {
let lhs_snip = snippet(sess, lhs.span, default);
let rhs_snip = snippet(sess, rhs.span, default);

format!("if {lhs_snip} == {rhs_snip} {els_snip} else {cond_inner_snip}")
},
_ => String::new(),
};

reindent_multiline(suggestion.into(), true, indent)
}
31 changes: 31 additions & 0 deletions tests/ui/if_not_else.fixed
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#![warn(clippy::all)]
#![warn(clippy::if_not_else)]

fn foo() -> bool {
unimplemented!()
}
fn bla() -> bool {
unimplemented!()
}

fn main() {
if bla() {
println!("Bunny");
} else {
//~^ ERROR: unnecessary boolean `not` operation
println!("Bugs");
}
if 4 == 5 {
println!("Bunny");
} else {
//~^ ERROR: unnecessary `!=` operation
println!("Bugs");
}
if !foo() {
println!("Foo");
} else if !bla() {
println!("Bugs");
} else {
println!("Bunny");
}
}
20 changes: 18 additions & 2 deletions tests/ui/if_not_else.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,17 @@ LL | | println!("Bunny");
LL | | }
| |_____^
|
= help: remove the `!` and swap the blocks of the `if`/`else`
= note: `-D clippy::if-not-else` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::if_not_else)]`
help: try
|
LL ~ if bla() {
LL + println!("Bunny");
LL + } else {
LL +
LL + println!("Bugs");
LL + }
|

error: unnecessary `!=` operation
--> tests/ui/if_not_else.rs:18:5
Expand All @@ -24,7 +32,15 @@ LL | | println!("Bunny");
LL | | }
| |_____^
|
= help: change to `==` and swap the blocks of the `if`/`else`
help: try
|
LL ~ if 4 == 5 {
LL + println!("Bunny");
LL + } else {
LL +
LL + println!("Bugs");
LL + }
|

error: aborting due to 2 previous errors

0 comments on commit 654c288

Please sign in to comment.