1 //! Checks for if expressions that contain only an if expression.
3 //! For example, the lint would catch:
8 //! println!("Hello world");
13 //! This lint is **warn** by default
15 use rustc::plugin::Registry;
17 use rustc::middle::def::*;
20 use syntax::codemap::{Span, Spanned, ExpnInfo};
21 use syntax::print::pprust::expr_to_string;
27 "Warn on if expressions that can be collapsed"
31 pub struct CollapsibleIf;
33 impl LintPass for CollapsibleIf {
34 fn get_lints(&self) -> LintArray {
35 lint_array!(COLLAPSIBLE_IF)
38 fn check_expr(&mut self, cx: &Context, expr: &Expr) {
39 cx.sess().codemap().with_expn_info(expr.span.expn_id,
40 |info| check_expr_expd(cx, expr, info))
44 fn check_expr_expd(cx: &Context, e: &Expr, info: Option<&ExpnInfo>) {
45 if in_macro(cx, info) { return; }
47 if let ExprIf(ref check, ref then, None) = e.node {
48 if let Some(&Expr{ node: ExprIf(ref check_inner, _, None), ..}) =
49 single_stmt_of_block(then) {
50 cx.span_lint(COLLAPSIBLE_IF, e.span, &format!(
51 "This if statement can be collapsed. Try: if {} && {}\n{:?}",
52 check_to_string(check), check_to_string(check_inner), e));
57 fn requires_brackets(e: &Expr) -> bool {
59 ExprBinary(Spanned {node: n, ..}, _, _) if n == BiEq => false,
64 fn check_to_string(e: &Expr) -> String {
65 if requires_brackets(e) {
66 format!("({})", expr_to_string(e))
68 format!("{}", expr_to_string(e))
72 fn single_stmt_of_block(block: &Block) -> Option<&Expr> {
73 if block.stmts.len() == 1 && block.expr.is_none() {
74 if let StmtExpr(ref expr, _) = block.stmts[0].node {
75 single_stmt_of_expr(expr)
78 if block.stmts.is_empty() {
79 if let Some(ref p) = block.expr { Some(&*p) } else { None }
84 fn single_stmt_of_expr(expr: &Expr) -> Option<&Expr> {
85 if let ExprBlock(ref block) = expr.node {
86 single_stmt_of_block(block)