]> git.lizzy.rs Git - rust.git/blob - src/needless_bool.rs
Remove * dep
[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::lint::*;
6 use rustc_front::hir::*;
7
8 use syntax::ast::Lit_::*;
9
10 use utils::{span_lint, snippet};
11
12 /// **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. It is `Warn` by default.
13 ///
14 /// **Why is this bad?** Redundant code.
15 ///
16 /// **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.
17 ///
18 /// **Example:** `if x { false } else { true }`
19 declare_lint! {
20     pub NEEDLESS_BOOL,
21     Warn,
22     "if-statements with plain booleans in the then- and else-clause, e.g. \
23      `if p { true } else { false }`"
24 }
25
26 #[derive(Copy,Clone)]
27 pub struct NeedlessBool;
28
29 impl LintPass for NeedlessBool {
30     fn get_lints(&self) -> LintArray {
31         lint_array!(NEEDLESS_BOOL)
32     }
33 }
34
35 impl LateLintPass for NeedlessBool {
36     fn check_expr(&mut self, cx: &LateContext, e: &Expr) {
37         if let ExprIf(ref pred, ref then_block, Some(ref else_expr)) = e.node {
38             match (fetch_bool_block(then_block), fetch_bool_expr(else_expr)) {
39                 (Some(true), Some(true)) => {
40                     span_lint(cx, NEEDLESS_BOOL, e.span,
41                               "this if-then-else expression will always return true");
42                 }
43                 (Some(false), Some(false)) => {
44                     span_lint(cx, NEEDLESS_BOOL, e.span,
45                               "this if-then-else expression will always return false");
46                 }
47                 (Some(true), Some(false)) => {
48                     let pred_snip = snippet(cx, pred.span, "..");
49                     let hint = if pred_snip == ".." { "its predicate".into() } else {
50                         format!("`{}`", pred_snip)
51                     };
52                     span_lint(cx, NEEDLESS_BOOL, e.span, &format!(
53                         "you can reduce this if-then-else expression to just {}", hint));
54                 }
55                 (Some(false), Some(true)) => {
56                     let pred_snip = snippet(cx, pred.span, "..");
57                     let hint = if pred_snip == ".." { "`!` and its predicate".into() } else {
58                         format!("`!{}`", pred_snip)
59                     };
60                     span_lint(cx, NEEDLESS_BOOL, e.span, &format!(
61                         "you can reduce this if-then-else expression to just {}", hint));
62                 }
63                 _ => ()
64             }
65         }
66     }
67 }
68
69 fn fetch_bool_block(block: &Block) -> Option<bool> {
70     if block.stmts.is_empty() {
71         block.expr.as_ref().and_then(|e| fetch_bool_expr(e))
72     } else { None }
73 }
74
75 fn fetch_bool_expr(expr: &Expr) -> Option<bool> {
76     match expr.node {
77         ExprBlock(ref block) => fetch_bool_block(block),
78         ExprLit(ref lit_ptr) => if let LitBool(value) = lit_ptr.node {
79             Some(value) } else { None },
80         _ => None
81     }
82 }