]> git.lizzy.rs Git - rust.git/blob - src/copies.rs
Lint about consecutive ifs with same condition
[rust.git] / src / copies.rs
1 use rustc::lint::*;
2 use rustc_front::hir::*;
3 use utils::{get_parent_expr, is_exp_equal, span_lint};
4
5 /// **What it does:** This lint checks for consecutive `ifs` with the same condition. This lint is
6 /// `Warn` by default.
7 ///
8 /// **Why is this bad?** This is probably a copy & paste error.
9 ///
10 /// **Known problems:** Hopefully none.
11 ///
12 /// **Example:** `if a == b { .. } else if a == b { .. }`
13 declare_lint! {
14     pub IFS_SAME_COND,
15     Warn,
16     "consecutive `ifs` with the same condition"
17 }
18
19 #[derive(Copy, Clone, Debug)]
20 pub struct CopyAndPaste;
21
22 impl LintPass for CopyAndPaste {
23     fn get_lints(&self) -> LintArray {
24         lint_array![
25             IFS_SAME_COND
26         ]
27     }
28 }
29
30 impl LateLintPass for CopyAndPaste {
31     fn check_expr(&mut self, cx: &LateContext, expr: &Expr) {
32         // skip ifs directly in else, it will be checked in the parent if
33         if let Some(&Expr{node: ExprIf(_, _, Some(ref else_expr)), ..}) = get_parent_expr(cx, expr) {
34             if else_expr.id == expr.id {
35                 return;
36             }
37         }
38
39         let conds = condition_sequence(expr);
40
41         for (n, i) in conds.iter().enumerate() {
42             for j in conds.iter().skip(n+1) {
43                 if is_exp_equal(cx, i, j) {
44                     span_lint(cx, IFS_SAME_COND, j.span, "this if as the same condition as a previous if");
45                 }
46             }
47         }
48     }
49 }
50
51 /// Return the list of conditions expression in a sequence of `if/else`.
52 /// Eg. would return `[a, b]` for the expression `if a {..} else if b {..}`.
53 fn condition_sequence(mut expr: &Expr) -> Vec<&Expr> {
54     let mut result = vec![];
55
56     while let ExprIf(ref cond, _, ref else_expr) = expr.node {
57         result.push(&**cond);
58
59         if let Some(ref else_expr) = *else_expr {
60             expr = else_expr;
61         }
62         else {
63             break;
64         }
65     }
66
67     result
68 }