2015-11-19 23:22:52 -06:00
use rustc_front ::hir ::* ;
use rustc ::lint ::{ LateLintPass , LateContext , LintArray , LintPass } ;
use rustc_front ::intravisit ::{ Visitor , walk_expr } ;
use utils ::* ;
2016-01-01 10:48:19 -06:00
/// **What it does:** This lint checks for `if` conditions that use blocks to contain an expression. It is `Warn` by default.
2015-12-14 06:31:28 -06:00
///
/// **Why is this bad?** It isn't really rust style, same as using parentheses to contain expressions.
///
/// **Known problems:** None
///
/// **Example:** `if { true } ..`
2015-11-19 23:22:52 -06:00
declare_lint! {
pub BLOCK_IN_IF_CONDITION_EXPR , Warn ,
" braces can be eliminated in conditions that are expressions, e.g `if { true } ...` "
}
2016-01-01 10:48:19 -06:00
/// **What it does:** This lint checks for `if` conditions that use blocks containing statements, or conditions that use closures with blocks. It is `Warn` by default.
2015-12-14 06:31:28 -06:00
///
/// **Why is this bad?** Using blocks in the condition makes it hard to read.
///
/// **Known problems:** None
///
/// **Example:** `if { let x = somefunc(); x } ..` or `if somefunc(|x| { x == 47 }) ..`
2015-11-19 23:22:52 -06:00
declare_lint! {
pub BLOCK_IN_IF_CONDITION_STMT , Warn ,
" avoid complex blocks in conditions, instead move the block higher and bind it \
with ' let ' ; e . g : ` if { let x = true ; x } .. . ` "
}
#[ derive(Copy,Clone) ]
pub struct BlockInIfCondition ;
impl LintPass for BlockInIfCondition {
fn get_lints ( & self ) -> LintArray {
lint_array! ( BLOCK_IN_IF_CONDITION_EXPR , BLOCK_IN_IF_CONDITION_STMT )
}
}
struct ExVisitor < ' v > {
2016-01-03 22:26:12 -06:00
found_block : Option < & ' v Expr > ,
2015-11-19 23:22:52 -06:00
}
impl < ' v > Visitor < ' v > for ExVisitor < ' v > {
fn visit_expr ( & mut self , expr : & ' v Expr ) {
if let ExprClosure ( _ , _ , ref block ) = expr . node {
let complex = {
if ! block . stmts . is_empty ( ) {
true
} else {
if let Some ( ref ex ) = block . expr {
match ex . node {
ExprBlock ( _ ) = > true ,
2016-01-03 22:26:12 -06:00
_ = > false ,
2015-11-19 23:22:52 -06:00
}
} else {
false
}
}
} ;
if complex {
2016-01-03 22:26:12 -06:00
self . found_block = Some ( & expr ) ;
2015-11-19 23:22:52 -06:00
return ;
}
}
walk_expr ( self , expr ) ;
}
}
2016-01-03 22:26:12 -06:00
const BRACED_EXPR_MESSAGE : & 'static str = " omit braces around single expression condition " ;
const COMPLEX_BLOCK_MESSAGE : & 'static str = " in an 'if' condition, avoid complex blocks or closures with blocks; \
instead , move the block or closure higher and bind it with a ' let ' " ;
2015-11-19 23:22:52 -06:00
impl LateLintPass for BlockInIfCondition {
fn check_expr ( & mut self , cx : & LateContext , expr : & Expr ) {
if let ExprIf ( ref check , ref then , _ ) = expr . node {
if let ExprBlock ( ref block ) = check . node {
2015-12-22 19:12:08 -06:00
if block . rules = = DefaultBlock {
if block . stmts . is_empty ( ) {
if let Some ( ref ex ) = block . expr {
// don't dig into the expression here, just suggest that they remove
// the block
2016-01-08 09:51:12 -06:00
if in_macro ( cx , expr . span ) | | differing_macro_contexts ( expr . span , ex . span ) {
2016-01-02 10:11:48 -06:00
return ;
}
2016-01-03 22:26:12 -06:00
span_help_and_lint ( cx ,
BLOCK_IN_IF_CONDITION_EXPR ,
check . span ,
BRACED_EXPR_MESSAGE ,
& format! ( " try \n if {} {} ... " ,
snippet_block ( cx , ex . span , " .. " ) ,
snippet_block ( cx , then . span , " .. " ) ) ) ;
2015-12-22 19:12:08 -06:00
}
} else {
2016-01-31 16:25:10 -06:00
let span = block . expr . as_ref ( ) . map_or_else ( | | block . stmts [ 0 ] . span ,
| e | e . span ) ;
if in_macro ( cx , span ) | | differing_macro_contexts ( expr . span , span ) {
2016-01-02 10:11:48 -06:00
return ;
}
2015-12-22 19:12:08 -06:00
// move block higher
2016-01-03 22:26:12 -06:00
span_help_and_lint ( cx ,
BLOCK_IN_IF_CONDITION_STMT ,
check . span ,
COMPLEX_BLOCK_MESSAGE ,
& format! ( " try \n let res = {} ; \n if res {} ... " ,
snippet_block ( cx , block . span , " .. " ) ,
snippet_block ( cx , then . span , " .. " ) ) ) ;
2015-11-19 23:22:52 -06:00
}
}
} else {
let mut visitor = ExVisitor { found_block : None } ;
walk_expr ( & mut visitor , check ) ;
if let Some ( ref block ) = visitor . found_block {
2016-01-03 22:26:12 -06:00
span_help_and_lint ( cx , BLOCK_IN_IF_CONDITION_STMT , block . span , COMPLEX_BLOCK_MESSAGE , " " ) ;
2015-11-19 23:22:52 -06:00
}
}
}
}
}