]> git.lizzy.rs Git - rust.git/blob - clippy_lints/src/double_comparison.rs
Auto merge of #3646 - matthiaskrgr:travis, r=phansch
[rust.git] / clippy_lints / src / double_comparison.rs
1 //! Lint on unnecessary double comparisons. Some examples:
2
3 use rustc::hir::*;
4 use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
5 use rustc::{declare_tool_lint, lint_array};
6 use rustc_errors::Applicability;
7 use syntax::source_map::Span;
8
9 use crate::utils::{snippet_with_applicability, span_lint_and_sugg, SpanlessEq};
10
11 /// **What it does:** Checks for double comparions that could be simplified to a single expression.
12 ///
13 ///
14 /// **Why is this bad?** Readability.
15 ///
16 /// **Known problems:** None.
17 ///
18 /// **Example:**
19 /// ```rust
20 /// x == y || x < y
21 /// ```
22 ///
23 /// Could be written as:
24 ///
25 /// ```rust
26 /// x <= y
27 /// ```
28 declare_clippy_lint! {
29     pub DOUBLE_COMPARISONS,
30     complexity,
31     "unnecessary double comparisons that can be simplified"
32 }
33
34 pub struct Pass;
35
36 impl LintPass for Pass {
37     fn get_lints(&self) -> LintArray {
38         lint_array!(DOUBLE_COMPARISONS)
39     }
40 }
41
42 impl<'a, 'tcx> Pass {
43     #[allow(clippy::similar_names)]
44     fn check_binop(&self, cx: &LateContext<'a, 'tcx>, op: BinOpKind, lhs: &'tcx Expr, rhs: &'tcx Expr, span: Span) {
45         let (lkind, llhs, lrhs, rkind, rlhs, rrhs) = match (lhs.node.clone(), rhs.node.clone()) {
46             (ExprKind::Binary(lb, llhs, lrhs), ExprKind::Binary(rb, rlhs, rrhs)) => {
47                 (lb.node, llhs, lrhs, rb.node, rlhs, rrhs)
48             },
49             _ => return,
50         };
51         let mut spanless_eq = SpanlessEq::new(cx).ignore_fn();
52         if !(spanless_eq.eq_expr(&llhs, &rlhs) && spanless_eq.eq_expr(&lrhs, &rrhs)) {
53             return;
54         }
55         macro_rules! lint_double_comparison {
56             ($op:tt) => {{
57                 let mut applicability = Applicability::MachineApplicable;
58                 let lhs_str = snippet_with_applicability(cx, llhs.span, "", &mut applicability);
59                 let rhs_str = snippet_with_applicability(cx, lrhs.span, "", &mut applicability);
60                 let sugg = format!("{} {} {}", lhs_str, stringify!($op), rhs_str);
61                 span_lint_and_sugg(
62                     cx,
63                     DOUBLE_COMPARISONS,
64                     span,
65                     "This binary expression can be simplified",
66                     "try",
67                     sugg,
68                     applicability,
69                 );
70             }};
71         }
72         match (op, lkind, rkind) {
73             (BinOpKind::Or, BinOpKind::Eq, BinOpKind::Lt) | (BinOpKind::Or, BinOpKind::Lt, BinOpKind::Eq) => {
74                 lint_double_comparison!(<=)
75             },
76             (BinOpKind::Or, BinOpKind::Eq, BinOpKind::Gt) | (BinOpKind::Or, BinOpKind::Gt, BinOpKind::Eq) => {
77                 lint_double_comparison!(>=)
78             },
79             (BinOpKind::Or, BinOpKind::Lt, BinOpKind::Gt) | (BinOpKind::Or, BinOpKind::Gt, BinOpKind::Lt) => {
80                 lint_double_comparison!(!=)
81             },
82             (BinOpKind::And, BinOpKind::Le, BinOpKind::Ge) | (BinOpKind::And, BinOpKind::Ge, BinOpKind::Le) => {
83                 lint_double_comparison!(==)
84             },
85             _ => (),
86         };
87     }
88 }
89
90 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
91     fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
92         if let ExprKind::Binary(ref kind, ref lhs, ref rhs) = expr.node {
93             self.check_binop(cx, kind.node, lhs, rhs, expr.span);
94         }
95     }
96 }