2015-05-02 00:35:49 +02:00
//! Checks for needless boolean results of if-else expressions
//!
2015-05-04 07:17:15 +02:00
//! This lint is **warn** by default
2015-05-02 00:35:49 +02:00
use rustc ::lint ::* ;
2016-04-07 17:46:48 +02:00
use rustc ::hir ::* ;
2016-02-12 18:35:44 +01:00
use syntax ::ast ::LitKind ;
2016-02-09 14:10:22 -05:00
use syntax ::codemap ::Spanned ;
2016-03-14 17:13:10 +01:00
use utils ::{ span_lint , span_lint_and_then , snippet , snippet_opt } ;
2015-05-02 00:35:49 +02:00
2016-02-06 00:41:54 +01:00
/// **What it does:** This lint checks for expressions of the form `if c { true } else { false }` (or vice versa) and suggest using the condition directly.
2015-12-11 01:22:27 +01:00
///
/// **Why is this bad?** Redundant code.
///
/// **Known problems:** Maybe false positives: Sometimes, the two branches are painstakingly documented (which we of course do not detect), so they *may* have some value. Even then, the documentation can be rewritten to match the shorter code.
///
/// **Example:** `if x { false } else { true }`
2015-05-02 00:35:49 +02:00
declare_lint! {
pub NEEDLESS_BOOL ,
Warn ,
2015-08-13 10:32:35 +02:00
" if-statements with plain booleans in the then- and else-clause, e.g. \
` if p { true } else { false } ` "
2015-05-02 00:35:49 +02:00
}
2016-02-09 14:10:22 -05:00
/// **What it does:** This lint checks for expressions of the form `x == true` (or vice versa) and suggest using the variable directly.
///
/// **Why is this bad?** Unnecessary code.
///
/// **Known problems:** None.
///
/// **Example:** `if x == true { }` could be `if x { }`
declare_lint! {
pub BOOL_COMPARISON ,
Warn ,
" comparing a variable to a boolean, e.g. \
` if x = = true ` "
}
2015-05-02 00:35:49 +02:00
#[ derive(Copy,Clone) ]
pub struct NeedlessBool ;
impl LintPass for NeedlessBool {
fn get_lints ( & self ) -> LintArray {
lint_array! ( NEEDLESS_BOOL )
}
2015-09-19 08:23:04 +05:30
}
2015-08-11 20:22:20 +02:00
2015-09-19 08:23:04 +05:30
impl LateLintPass for NeedlessBool {
fn check_expr ( & mut self , cx : & LateContext , e : & Expr ) {
2016-03-14 16:41:41 +01:00
use self ::Expression ::* ;
2015-08-13 09:44:03 +02:00
if let ExprIf ( ref pred , ref then_block , Some ( ref else_expr ) ) = e . node {
2016-03-14 16:41:41 +01:00
let reduce = | hint : & str , not | {
2016-03-14 17:13:10 +01:00
let hint = match snippet_opt ( cx , pred . span ) {
Some ( pred_snip ) = > format! ( " ` {} {} ` " , not , pred_snip ) ,
None = > hint . into ( ) ,
2016-03-14 16:41:41 +01:00
} ;
2016-03-14 17:13:10 +01:00
span_lint_and_then ( cx ,
NEEDLESS_BOOL ,
e . span ,
2016-04-14 20:14:03 +02:00
" this if-then-else expression returns a bool literal " ,
| db | {
db . span_suggestion ( e . span , " you can reduce it to " , hint ) ;
} ) ;
2016-03-14 16:41:41 +01:00
} ;
2015-08-11 20:22:20 +02:00
match ( fetch_bool_block ( then_block ) , fetch_bool_expr ( else_expr ) ) {
2016-03-14 16:41:41 +01:00
( RetBool ( true ) , RetBool ( true ) ) |
( Bool ( true ) , Bool ( true ) ) = > {
2016-01-04 09:56:12 +05:30
span_lint ( cx ,
NEEDLESS_BOOL ,
e . span ,
2015-11-17 14:22:57 +09:00
" this if-then-else expression will always return true " ) ;
}
2016-03-14 16:41:41 +01:00
( RetBool ( false ) , RetBool ( false ) ) |
( Bool ( false ) , Bool ( false ) ) = > {
2016-01-04 09:56:12 +05:30
span_lint ( cx ,
NEEDLESS_BOOL ,
e . span ,
2015-11-17 14:22:57 +09:00
" this if-then-else expression will always return false " ) ;
}
2016-03-14 16:41:41 +01:00
( RetBool ( true ) , RetBool ( false ) ) = > reduce ( " its predicate " , " return " ) ,
( Bool ( true ) , Bool ( false ) ) = > reduce ( " its predicate " , " " ) ,
( RetBool ( false ) , RetBool ( true ) ) = > reduce ( " `!` and its predicate " , " return ! " ) ,
( Bool ( false ) , Bool ( true ) ) = > reduce ( " `!` and its predicate " , " ! " ) ,
2016-01-04 09:56:12 +05:30
_ = > ( ) ,
2015-08-11 20:22:20 +02:00
}
}
2015-05-02 00:35:49 +02:00
}
}
2016-02-09 14:10:22 -05:00
#[ derive(Copy,Clone) ]
pub struct BoolComparison ;
impl LintPass for BoolComparison {
fn get_lints ( & self ) -> LintArray {
lint_array! ( BOOL_COMPARISON )
}
}
impl LateLintPass for BoolComparison {
fn check_expr ( & mut self , cx : & LateContext , e : & Expr ) {
2016-03-14 16:41:41 +01:00
use self ::Expression ::* ;
2016-04-14 20:14:03 +02:00
if let ExprBinary ( Spanned { node : BiEq , .. } , ref left_side , ref right_side ) = e . node {
2016-02-09 14:10:22 -05:00
match ( fetch_bool_expr ( left_side ) , fetch_bool_expr ( right_side ) ) {
2016-03-14 16:41:41 +01:00
( Bool ( true ) , Other ) = > {
2016-02-10 10:20:23 +05:30
let hint = snippet ( cx , right_side . span , " .. " ) . into_owned ( ) ;
2016-02-09 14:44:42 -05:00
span_lint_and_then ( cx ,
BOOL_COMPARISON ,
e . span ,
2016-03-19 15:06:56 +01:00
" equality checks against true are unnecessary " ,
2016-02-09 14:44:42 -05:00
| db | {
2016-02-09 15:44:07 -05:00
db . span_suggestion ( e . span , " try simplifying it as shown: " , hint ) ;
2016-02-09 14:44:42 -05:00
} ) ;
2016-02-09 14:10:22 -05:00
}
2016-03-14 16:41:41 +01:00
( Other , Bool ( true ) ) = > {
2016-02-10 10:20:23 +05:30
let hint = snippet ( cx , left_side . span , " .. " ) . into_owned ( ) ;
2016-02-09 14:44:42 -05:00
span_lint_and_then ( cx ,
BOOL_COMPARISON ,
e . span ,
2016-03-19 15:06:56 +01:00
" equality checks against true are unnecessary " ,
2016-02-09 14:44:42 -05:00
| db | {
2016-02-09 15:44:07 -05:00
db . span_suggestion ( e . span , " try simplifying it as shown: " , hint ) ;
2016-02-09 14:44:42 -05:00
} ) ;
2016-02-09 14:10:22 -05:00
}
2016-03-14 16:41:41 +01:00
( Bool ( false ) , Other ) = > {
2016-02-09 15:44:07 -05:00
let hint = format! ( " ! {} " , snippet ( cx , right_side . span , " .. " ) ) ;
2016-02-09 14:44:42 -05:00
span_lint_and_then ( cx ,
BOOL_COMPARISON ,
e . span ,
2016-02-09 15:44:07 -05:00
" equality checks against false can be replaced by a negation " ,
2016-02-09 14:44:42 -05:00
| db | {
2016-02-09 15:44:07 -05:00
db . span_suggestion ( e . span , " try simplifying it as shown: " , hint ) ;
2016-02-09 14:44:42 -05:00
} ) ;
2016-02-09 14:10:22 -05:00
}
2016-03-14 16:41:41 +01:00
( Other , Bool ( false ) ) = > {
2016-02-09 15:44:07 -05:00
let hint = format! ( " ! {} " , snippet ( cx , left_side . span , " .. " ) ) ;
2016-02-09 14:44:42 -05:00
span_lint_and_then ( cx ,
BOOL_COMPARISON ,
e . span ,
2016-02-09 15:44:07 -05:00
" equality checks against false can be replaced by a negation " ,
2016-02-09 14:44:42 -05:00
| db | {
2016-02-09 15:44:07 -05:00
db . span_suggestion ( e . span , " try simplifying it as shown: " , hint ) ;
2016-02-09 14:44:42 -05:00
} ) ;
2016-02-09 14:10:22 -05:00
}
_ = > ( ) ,
}
}
}
}
2016-03-14 16:41:41 +01:00
enum Expression {
Bool ( bool ) ,
RetBool ( bool ) ,
Other ,
}
fn fetch_bool_block ( block : & Block ) -> Expression {
match ( & * block . stmts , block . expr . as_ref ( ) ) {
2016-06-10 19:47:10 +02:00
( & [ ] , Some ( e ) ) = > fetch_bool_expr ( & * * e ) ,
( & [ ref e ] , None ) = > {
2016-04-14 20:14:03 +02:00
if let StmtSemi ( ref e , _ ) = e . node {
if let ExprRet ( _ ) = e . node {
fetch_bool_expr ( & * * e )
} else {
Expression ::Other
}
2016-03-14 16:41:41 +01:00
} else {
Expression ::Other
}
2016-04-14 20:14:03 +02:00
}
2016-03-14 16:41:41 +01:00
_ = > Expression ::Other ,
2016-01-04 09:56:12 +05:30
}
2015-05-02 00:35:49 +02:00
}
2015-08-11 20:22:20 +02:00
2016-03-14 16:41:41 +01:00
fn fetch_bool_expr ( expr : & Expr ) -> Expression {
2015-08-21 20:44:48 +02:00
match expr . node {
ExprBlock ( ref block ) = > fetch_bool_block ( block ) ,
2016-01-04 09:56:12 +05:30
ExprLit ( ref lit_ptr ) = > {
2016-02-12 18:35:44 +01:00
if let LitKind ::Bool ( value ) = lit_ptr . node {
2016-03-14 16:41:41 +01:00
Expression ::Bool ( value )
2016-01-04 09:56:12 +05:30
} else {
2016-03-14 16:41:41 +01:00
Expression ::Other
2016-01-04 09:56:12 +05:30
}
2016-04-14 20:14:03 +02:00
}
ExprRet ( Some ( ref expr ) ) = > {
match fetch_bool_expr ( expr ) {
Expression ::Bool ( value ) = > Expression ::RetBool ( value ) ,
_ = > Expression ::Other ,
}
}
2016-03-14 16:41:41 +01:00
_ = > Expression ::Other ,
2015-08-11 20:22:20 +02:00
}
2015-05-02 00:35:49 +02:00
}