auto-fix if_not_else (#13809)
fix #13411 The `if_not_else` lint can be fixed automatically, but the issue above reports that there is no implementation to do so. Therefore, this PR implements it. ---- changelog: [`if_not_else`]: make suggestions for modified code
This commit is contained in:
commit
85b609419b
4 changed files with 279 additions and 6 deletions
|
|
@ -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
|
||||
|
|
@ -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
|
||||
{
|
||||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue