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 ::* ;
2015-09-03 20:12:17 +05:30
use rustc_front ::hir ::* ;
2015-08-16 08:54:43 +02:00
2016-02-03 15:39:22 +01:00
use syntax ::ast ::Lit_ ;
2015-09-17 05:31:41 +05:30
2015-08-25 14:41:35 +02:00
use utils ::{ span_lint , snippet } ;
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
}
#[ 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 ) {
2015-08-13 09:44:03 +02:00
if let ExprIf ( ref pred , ref then_block , Some ( ref else_expr ) ) = e . node {
2015-08-11 20:22:20 +02:00
match ( fetch_bool_block ( then_block ) , fetch_bool_expr ( else_expr ) ) {
2015-08-13 09:44:03 +02:00
( Some ( true ) , Some ( 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 " ) ;
}
2015-08-13 09:44:03 +02:00
( Some ( false ) , Some ( 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 " ) ;
}
2015-08-13 09:44:03 +02:00
( Some ( true ) , Some ( false ) ) = > {
let pred_snip = snippet ( cx , pred . span , " .. " ) ;
2016-01-04 09:56:12 +05:30
let hint = if pred_snip = = " .. " {
" its predicate " . into ( )
} else {
2015-08-13 09:44:03 +02:00
format! ( " ` {} ` " , pred_snip )
} ;
2016-01-04 09:56:12 +05:30
span_lint ( cx ,
NEEDLESS_BOOL ,
e . span ,
& format! ( " you can reduce this if-then-else expression to just {} " , hint ) ) ;
2015-11-17 13:39:42 +09:00
}
2015-08-13 09:44:03 +02:00
( Some ( false ) , Some ( true ) ) = > {
let pred_snip = snippet ( cx , pred . span , " .. " ) ;
2016-01-04 09:56:12 +05:30
let hint = if pred_snip = = " .. " {
" `!` and its predicate " . into ( )
} else {
2015-08-13 09:44:03 +02:00
format! ( " `! {} ` " , pred_snip )
} ;
2016-01-04 09:56:12 +05:30
span_lint ( cx ,
NEEDLESS_BOOL ,
e . span ,
& format! ( " you can reduce this if-then-else expression to just {} " , hint ) ) ;
2015-11-17 13:39:42 +09:00
}
2016-01-04 09:56:12 +05:30
_ = > ( ) ,
2015-08-11 20:22:20 +02:00
}
}
2015-05-02 00:35:49 +02:00
}
}
fn fetch_bool_block ( block : & Block ) -> Option < bool > {
2015-08-11 20:22:20 +02:00
if block . stmts . is_empty ( ) {
2015-08-25 14:41:35 +02:00
block . expr . as_ref ( ) . and_then ( | e | fetch_bool_expr ( e ) )
2016-01-04 09:56:12 +05:30
} else {
None
}
2015-05-02 00:35:49 +02:00
}
2015-08-11 20:22:20 +02:00
2015-05-02 00:35:49 +02:00
fn fetch_bool_expr ( expr : & Expr ) -> Option < bool > {
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-03 15:39:22 +01:00
if let Lit_ ::LitBool ( value ) = lit_ptr . node {
2016-01-04 09:56:12 +05:30
Some ( value )
} else {
None
}
}
_ = > None ,
2015-08-11 20:22:20 +02:00
}
2015-05-02 00:35:49 +02:00
}