Make COLLAPSIBLE_IF
consider if let
This commit is contained in:
parent
f6ba217c1c
commit
ea76ac5562
@ -53,37 +53,64 @@ impl EarlyLintPass for CollapsibleIf {
|
||||
}
|
||||
}
|
||||
|
||||
fn check_if(cx: &EarlyContext, e: &ast::Expr) {
|
||||
if let ast::ExprKind::If(ref check, ref then, ref else_) = e.node {
|
||||
if let Some(ref else_) = *else_ {
|
||||
if_let_chain! {[
|
||||
let ast::ExprKind::Block(ref block) = else_.node,
|
||||
block.stmts.is_empty(),
|
||||
let Some(ref else_) = block.expr,
|
||||
let ast::ExprKind::If(_, _, _) = else_.node
|
||||
], {
|
||||
fn check_if(cx: &EarlyContext, expr: &ast::Expr) {
|
||||
match expr.node {
|
||||
ast::ExprKind::If(ref check, ref then, ref else_) => {
|
||||
if let Some(ref else_) = *else_ {
|
||||
check_collapsible_maybe_if_let(cx, else_);
|
||||
} else {
|
||||
check_collapsible_no_if_let(cx, expr, check, then);
|
||||
}
|
||||
}
|
||||
ast::ExprKind::IfLet(_, _, _, Some(ref else_)) => {
|
||||
check_collapsible_maybe_if_let(cx, else_);
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
fn check_collapsible_maybe_if_let(cx: &EarlyContext, else_: &ast::Expr) {
|
||||
if_let_chain! {[
|
||||
let ast::ExprKind::Block(ref block) = else_.node,
|
||||
block.stmts.is_empty(),
|
||||
let Some(ref else_) = block.expr,
|
||||
], {
|
||||
match else_.node {
|
||||
ast::ExprKind::If(..) | ast::ExprKind::IfLet(..) => {
|
||||
span_lint_and_then(cx,
|
||||
COLLAPSIBLE_IF,
|
||||
block.span,
|
||||
"this `else { if .. }` block can be collapsed", |db| {
|
||||
db.span_suggestion(block.span, "try", snippet_block(cx, else_.span, "..").into_owned());
|
||||
});
|
||||
}}
|
||||
} else if let Some(&ast::Expr { node: ast::ExprKind::If(ref check_inner, ref content, None), span: sp, .. }) =
|
||||
single_stmt_of_block(then) {
|
||||
if e.span.expn_id != sp.expn_id {
|
||||
return;
|
||||
}
|
||||
span_lint_and_then(cx, COLLAPSIBLE_IF, e.span, "this if statement can be collapsed", |db| {
|
||||
db.span_suggestion(e.span,
|
||||
"try",
|
||||
format!("if {} && {} {}",
|
||||
check_to_string(cx, check),
|
||||
check_to_string(cx, check_inner),
|
||||
snippet_block(cx, content.span, "..")));
|
||||
});
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}}
|
||||
}
|
||||
|
||||
fn check_collapsible_no_if_let(
|
||||
cx: &EarlyContext,
|
||||
expr: &ast::Expr,
|
||||
check: &ast::Expr,
|
||||
then: &ast::Block,
|
||||
) {
|
||||
if_let_chain! {[
|
||||
let Some(inner) = single_stmt_of_block(then),
|
||||
let ast::ExprKind::If(ref check_inner, ref content, None) = inner.node,
|
||||
], {
|
||||
if expr.span.expn_id != inner.span.expn_id {
|
||||
return;
|
||||
}
|
||||
span_lint_and_then(cx, COLLAPSIBLE_IF, expr.span, "this if statement can be collapsed", |db| {
|
||||
db.span_suggestion(expr.span,
|
||||
"try",
|
||||
format!("if {} && {} {}",
|
||||
check_to_string(cx, check),
|
||||
check_to_string(cx, check_inner),
|
||||
snippet_block(cx, content.span, "..")));
|
||||
});
|
||||
}}
|
||||
}
|
||||
|
||||
fn requires_brackets(e: &ast::Expr) -> bool {
|
||||
|
@ -26,9 +26,10 @@ fn main() {
|
||||
// Collaspe `else { if .. }` to `else if ..`
|
||||
if x == "hello" {
|
||||
print!("Hello ");
|
||||
} else { //~ERROR: this `else { if .. }`
|
||||
//~| HELP try
|
||||
//~| SUGGESTION } else if y == "world"
|
||||
} else {
|
||||
//~^ ERROR: this `else { if .. }`
|
||||
//~| HELP try
|
||||
//~| SUGGESTION } else if y == "world"
|
||||
if y == "world" {
|
||||
println!("world!")
|
||||
}
|
||||
@ -36,9 +37,21 @@ fn main() {
|
||||
|
||||
if x == "hello" {
|
||||
print!("Hello ");
|
||||
} else { //~ERROR this `else { if .. }`
|
||||
//~| HELP try
|
||||
//~| SUGGESTION } else if y == "world"
|
||||
} else {
|
||||
//~^ ERROR: this `else { if .. }`
|
||||
//~| HELP try
|
||||
//~| SUGGESTION } else if let Some(42)
|
||||
if let Some(42) = Some(42) {
|
||||
println!("world!")
|
||||
}
|
||||
}
|
||||
|
||||
if x == "hello" {
|
||||
print!("Hello ");
|
||||
} else {
|
||||
//~^ ERROR this `else { if .. }`
|
||||
//~| HELP try
|
||||
//~| SUGGESTION } else if y == "world"
|
||||
if y == "world" {
|
||||
println!("world")
|
||||
}
|
||||
@ -47,6 +60,62 @@ fn main() {
|
||||
}
|
||||
}
|
||||
|
||||
if x == "hello" {
|
||||
print!("Hello ");
|
||||
} else {
|
||||
//~^ ERROR this `else { if .. }`
|
||||
//~| HELP try
|
||||
//~| SUGGESTION } else if let Some(42)
|
||||
if let Some(42) = Some(42) {
|
||||
println!("world")
|
||||
}
|
||||
else {
|
||||
println!("!")
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(42) = Some(42) {
|
||||
print!("Hello ");
|
||||
} else {
|
||||
//~^ ERROR this `else { if .. }`
|
||||
//~| HELP try
|
||||
//~| SUGGESTION } else if let Some(42)
|
||||
if let Some(42) = Some(42) {
|
||||
println!("world")
|
||||
}
|
||||
else {
|
||||
println!("!")
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(42) = Some(42) {
|
||||
print!("Hello ");
|
||||
} else {
|
||||
//~^ ERROR this `else { if .. }`
|
||||
//~| HELP try
|
||||
//~| SUGGESTION } else if x == "hello"
|
||||
if x == "hello" {
|
||||
println!("world")
|
||||
}
|
||||
else {
|
||||
println!("!")
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(42) = Some(42) {
|
||||
print!("Hello ");
|
||||
} else {
|
||||
//~^ ERROR this `else { if .. }`
|
||||
//~| HELP try
|
||||
//~| SUGGESTION } else if let Some(42)
|
||||
if let Some(42) = Some(42) {
|
||||
println!("world")
|
||||
}
|
||||
else {
|
||||
println!("!")
|
||||
}
|
||||
}
|
||||
|
||||
// Works because any if with an else statement cannot be collapsed.
|
||||
if x == "hello" {
|
||||
if y == "world" {
|
||||
|
@ -8,6 +8,7 @@
|
||||
#![allow(unused_variables)]
|
||||
#![allow(cyclomatic_complexity)]
|
||||
#![allow(blacklisted_name)]
|
||||
#![allow(collapsible_if)]
|
||||
|
||||
fn bar<T>(_: T) {}
|
||||
fn foo() -> bool { unimplemented!() }
|
||||
|
Loading…
x
Reference in New Issue
Block a user