]> git.lizzy.rs Git - rust.git/blob - clippy_lints/src/needless_bool.rs
Fix deploy.sh III
[rust.git] / clippy_lints / 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::hir::*;
7 use syntax::ast::LitKind;
8 use syntax::codemap::Spanned;
9 use utils::{span_lint, span_lint_and_then, snippet};
10 use utils::sugg::Sugg;
11
12 /// **What it does:** This lint checks for expressions of the form `if c { true } else { false }`
13 /// (or vice versa) and suggest using the condition directly.
14 ///
15 /// **Why is this bad?** Redundant code.
16 ///
17 /// **Known problems:** Maybe false positives: Sometimes, the two branches are painstakingly
18 /// documented (which we of course do not detect), so they *may* have some value. Even then, the
19 /// documentation can be rewritten to match the shorter code.
20 ///
21 /// **Example:**
22 /// ```rust
23 /// if x { false } else { true }
24 /// ```
25 declare_lint! {
26     pub NEEDLESS_BOOL,
27     Warn,
28     "if-statements with plain booleans in the then- and else-clause, e.g. \
29      `if p { true } else { false }`"
30 }
31
32 /// **What it does:** This lint checks for expressions of the form `x == true` (or vice versa) and
33 /// suggest using the variable directly.
34 ///
35 /// **Why is this bad?** Unnecessary code.
36 ///
37 /// **Known problems:** None.
38 ///
39 /// **Example:** `if x == true { }` could be `if x { }`
40 declare_lint! {
41     pub BOOL_COMPARISON,
42     Warn,
43     "comparing a variable to a boolean, e.g. \
44      `if x == true`"
45 }
46
47 #[derive(Copy,Clone)]
48 pub struct NeedlessBool;
49
50 impl LintPass for NeedlessBool {
51     fn get_lints(&self) -> LintArray {
52         lint_array!(NEEDLESS_BOOL)
53     }
54 }
55
56 impl LateLintPass for NeedlessBool {
57     fn check_expr(&mut self, cx: &LateContext, e: &Expr) {
58         use self::Expression::*;
59         if let ExprIf(ref pred, ref then_block, Some(ref else_expr)) = e.node {
60             let reduce = |ret, not| {
61                 let snip = Sugg::hir(cx, pred, "<predicate>");
62                 let snip = if not {
63                     !snip
64                 } else {
65                     snip
66                 };
67
68                 let hint = if ret {
69                     format!("return {}", snip)
70                 } else {
71                     snip.to_string()
72                 };
73
74                 span_lint_and_then(cx,
75                                    NEEDLESS_BOOL,
76                                    e.span,
77                                    "this if-then-else expression returns a bool literal",
78                                    |db| {
79                                        db.span_suggestion(e.span, "you can reduce it to", hint);
80                                    });
81             };
82             match (fetch_bool_block(then_block), fetch_bool_expr(else_expr)) {
83                 (RetBool(true), RetBool(true)) |
84                 (Bool(true), Bool(true)) => {
85                     span_lint(cx,
86                               NEEDLESS_BOOL,
87                               e.span,
88                               "this if-then-else expression will always return true");
89                 }
90                 (RetBool(false), RetBool(false)) |
91                 (Bool(false), Bool(false)) => {
92                     span_lint(cx,
93                               NEEDLESS_BOOL,
94                               e.span,
95                               "this if-then-else expression will always return false");
96                 }
97                 (RetBool(true), RetBool(false)) => reduce(true, false),
98                 (Bool(true), Bool(false)) => reduce(false, false),
99                 (RetBool(false), RetBool(true)) => reduce(true, true),
100                 (Bool(false), Bool(true)) => reduce(false, true),
101                 _ => (),
102             }
103         }
104     }
105 }
106
107 #[derive(Copy,Clone)]
108 pub struct BoolComparison;
109
110 impl LintPass for BoolComparison {
111     fn get_lints(&self) -> LintArray {
112         lint_array!(BOOL_COMPARISON)
113     }
114 }
115
116 impl LateLintPass for BoolComparison {
117     fn check_expr(&mut self, cx: &LateContext, e: &Expr) {
118         use self::Expression::*;
119         if let ExprBinary(Spanned { node: BiEq, .. }, ref left_side, ref right_side) = e.node {
120             match (fetch_bool_expr(left_side), fetch_bool_expr(right_side)) {
121                 (Bool(true), Other) => {
122                     let hint = snippet(cx, right_side.span, "..").into_owned();
123                     span_lint_and_then(cx,
124                                        BOOL_COMPARISON,
125                                        e.span,
126                                        "equality checks against true are unnecessary",
127                                        |db| {
128                                            db.span_suggestion(e.span, "try simplifying it as shown:", hint);
129                                        });
130                 }
131                 (Other, Bool(true)) => {
132                     let hint = snippet(cx, left_side.span, "..").into_owned();
133                     span_lint_and_then(cx,
134                                        BOOL_COMPARISON,
135                                        e.span,
136                                        "equality checks against true are unnecessary",
137                                        |db| {
138                                            db.span_suggestion(e.span, "try simplifying it as shown:", hint);
139                                        });
140                 }
141                 (Bool(false), Other) => {
142                     let hint = Sugg::hir(cx, right_side, "..");
143                     span_lint_and_then(cx,
144                                        BOOL_COMPARISON,
145                                        e.span,
146                                        "equality checks against false can be replaced by a negation",
147                                        |db| {
148                                            db.span_suggestion(e.span, "try simplifying it as shown:", (!hint).to_string());
149                                        });
150                 }
151                 (Other, Bool(false)) => {
152                     let hint = Sugg::hir(cx, left_side, "..");
153                     span_lint_and_then(cx,
154                                        BOOL_COMPARISON,
155                                        e.span,
156                                        "equality checks against false can be replaced by a negation",
157                                        |db| {
158                                            db.span_suggestion(e.span, "try simplifying it as shown:", (!hint).to_string());
159                                        });
160                 }
161                 _ => (),
162             }
163         }
164     }
165 }
166
167 enum Expression {
168     Bool(bool),
169     RetBool(bool),
170     Other,
171 }
172
173 fn fetch_bool_block(block: &Block) -> Expression {
174     match (&*block.stmts, block.expr.as_ref()) {
175         (&[], Some(e)) => fetch_bool_expr(&**e),
176         (&[ref e], None) => {
177             if let StmtSemi(ref e, _) = e.node {
178                 if let ExprRet(_) = e.node {
179                     fetch_bool_expr(&**e)
180                 } else {
181                     Expression::Other
182                 }
183             } else {
184                 Expression::Other
185             }
186         }
187         _ => Expression::Other,
188     }
189 }
190
191 fn fetch_bool_expr(expr: &Expr) -> Expression {
192     match expr.node {
193         ExprBlock(ref block) => fetch_bool_block(block),
194         ExprLit(ref lit_ptr) => {
195             if let LitKind::Bool(value) = lit_ptr.node {
196                 Expression::Bool(value)
197             } else {
198                 Expression::Other
199             }
200         }
201         ExprRet(Some(ref expr)) => {
202             match fetch_bool_expr(expr) {
203                 Expression::Bool(value) => Expression::RetBool(value),
204                 _ => Expression::Other,
205             }
206         }
207         _ => Expression::Other,
208     }
209 }