]> git.lizzy.rs Git - rust.git/blob - src/needless_bool.rs
3296bdeca8706eab5e508abdf92c8dcc19a65957
[rust.git] / src / needless_bool.rs
1 //! Checks for needless boolean results of if-else expressions
2 //!
3 //! This lint is **warn** by default
4
5 use rustc::plugin::Registry;
6 use rustc::lint::*;
7 use rustc::middle::const_eval::lookup_const_by_id;
8 use rustc::middle::def::*;
9 use syntax::ast::*;
10 use syntax::ast_util::{is_comparison_binop, binop_to_string};
11 use syntax::ptr::P;
12 use syntax::codemap::Span;
13 use utils::{de_p, span_lint};
14
15 declare_lint! {
16     pub NEEDLESS_BOOL,
17     Warn,
18     "Warn on needless use of if x { true } else { false } (or vice versa)"
19 }
20
21 #[derive(Copy,Clone)]
22 pub struct NeedlessBool;
23
24 impl LintPass for NeedlessBool {
25     fn get_lints(&self) -> LintArray {
26         lint_array!(NEEDLESS_BOOL)
27     }
28
29     fn check_expr(&mut self, cx: &Context, e: &Expr) {
30         if let ExprIf(_, ref then_block, Option::Some(ref else_expr)) = e.node {
31             match (fetch_bool_block(then_block), fetch_bool_expr(else_expr)) {
32                 (Option::Some(true), Option::Some(true)) => {
33                     span_lint(cx, NEEDLESS_BOOL, e.span,
34                               "your if-then-else expression will always return true"); },
35                 (Option::Some(true), Option::Some(false)) => {
36                     span_lint(cx, NEEDLESS_BOOL, e.span,
37                               "you can reduce your if-statement to its predicate"); },
38                 (Option::Some(false), Option::Some(true)) => {
39                     span_lint(cx, NEEDLESS_BOOL, e.span,
40                               "you can reduce your if-statement to '!' + your predicate"); },
41                 (Option::Some(false), Option::Some(false)) => {
42                     span_lint(cx, NEEDLESS_BOOL, e.span,
43                               "your if-then-else expression will always return false"); },
44                 _ => ()
45             }
46         }
47     }
48 }
49
50 fn fetch_bool_block(block: &Block) -> Option<bool> {
51     if block.stmts.is_empty() {
52         block.expr.as_ref().map(de_p).and_then(fetch_bool_expr)
53     } else { Option::None }
54 }
55
56 fn fetch_bool_expr(expr: &Expr) -> Option<bool> {
57     match &expr.node {
58         &ExprBlock(ref block) => fetch_bool_block(block),
59         &ExprLit(ref lit_ptr) => if let &LitBool(value) = &lit_ptr.node {
60             Option::Some(value) } else { Option::None },
61         _ => Option::None
62     }
63 }