Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add lint for ifs that could be collapsed
"Collapsible" ifs are ones which contain only a then block, and the then block consists of an if that only has a then block.
- Loading branch information
Showing
3 changed files
with
120 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
//! Checks for if expressions that contain only an if expression. | ||
//! | ||
//! For example, the lint would catch: | ||
//! | ||
//! ``` | ||
//! if x { | ||
//! if y { | ||
//! println!("Hello world"); | ||
//! } | ||
//! } | ||
//! ``` | ||
//! | ||
//! This lint is **warn** by default | ||
|
||
use rustc::plugin::Registry; | ||
use rustc::lint::*; | ||
use rustc::middle::def::*; | ||
use syntax::ast::*; | ||
use syntax::ptr::P; | ||
use syntax::codemap::{Span, Spanned}; | ||
use syntax::print::pprust::expr_to_string; | ||
|
||
declare_lint! { | ||
pub COLLAPSIBLE_IF, | ||
Warn, | ||
"Warn on if expressions that can be collapsed" | ||
} | ||
|
||
#[derive(Copy,Clone)] | ||
pub struct CollapsibleIf; | ||
|
||
impl LintPass for CollapsibleIf { | ||
fn get_lints(&self) -> LintArray { | ||
lint_array!(COLLAPSIBLE_IF) | ||
} | ||
|
||
fn check_expr(&mut self, cx: &Context, e: &Expr) { | ||
if let ExprIf(ref check, ref then_block, None) = e.node { | ||
let expr = check_block(then_block); | ||
let expr = match expr { | ||
Some(e) => e, | ||
None => return | ||
}; | ||
if let ExprIf(ref check_inner, _, None) = expr.node { | ||
let (check, check_inner) = (check_to_string(check), check_to_string(check_inner)); | ||
cx.span_lint(COLLAPSIBLE_IF, e.span, | ||
&format!("This if statement can be collapsed. Try: if {} && {}", check, check_inner)); | ||
} | ||
} | ||
} | ||
} | ||
|
||
fn requires_brackets(e: &Expr) -> bool { | ||
match e.node { | ||
ExprBinary(Spanned {node: n, ..}, _, _) if n == BiEq => false, | ||
_ => true | ||
} | ||
} | ||
|
||
fn check_to_string(e: &Expr) -> String { | ||
if requires_brackets(e) { | ||
format!("({})", expr_to_string(e)) | ||
} else { | ||
format!("{}", expr_to_string(e)) | ||
} | ||
} | ||
|
||
fn check_block(b: &Block) -> Option<&P<Expr>> { | ||
if b.stmts.len() == 1 && b.expr.is_none() { | ||
let stmt = &b.stmts[0]; | ||
return match stmt.node { | ||
StmtExpr(ref e, _) => Some(e), | ||
_ => None | ||
}; | ||
} | ||
if let Some(ref e) = b.expr { | ||
return Some(e); | ||
} | ||
None | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
#![feature(plugin)] | ||
#![plugin(clippy)] | ||
|
||
#[deny(collapsible_if)] | ||
fn main() { | ||
let x = "hello"; | ||
let y = "world"; | ||
if x == "hello" { //~ERROR This if statement can be collapsed | ||
if y == "world" { | ||
println!("Hello world!"); | ||
} | ||
} | ||
|
||
if x == "hello" || x == "world" { //~ERROR This if statement can be collapsed | ||
if y == "world" || y == "hello" { | ||
println!("Hello world!"); | ||
} | ||
} | ||
|
||
// Works because any if with an else statement cannot be collapsed. | ||
if x == "hello" { | ||
if y == "world" { | ||
println!("Hello world!"); | ||
} | ||
} else { | ||
println!("Not Hello world"); | ||
} | ||
|
||
if x == "hello" { | ||
if y == "world" { | ||
println!("Hello world!"); | ||
} else { | ||
println!("Hello something else"); | ||
} | ||
} | ||
|
||
} |