]> git.lizzy.rs Git - rust.git/blob - clippy_lints/src/double_comparison.rs
Auto merge of #3845 - euclio:unused-comments, 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 declare_clippy_lint! {
12     /// **What it does:** Checks for double comparions that could be simplified to a single expression.
13     ///
14     ///
15     /// **Why is this bad?** Readability.
16     ///
17     /// **Known problems:** None.
18     ///
19     /// **Example:**
20     /// ```rust
21     /// x == y || x < y
22     /// ```
23     ///
24     /// Could be written as:
25     ///
26     /// ```rust
27     /// x <= y
28     /// ```
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     fn name(&self) -> &'static str {
42         "DoubleComparisons"
43     }
44 }
45
46 impl<'a, 'tcx> Pass {
47     #[allow(clippy::similar_names)]
48     fn check_binop(&self, cx: &LateContext<'a, 'tcx>, op: BinOpKind, lhs: &'tcx Expr, rhs: &'tcx Expr, span: Span) {
49         let (lkind, llhs, lrhs, rkind, rlhs, rrhs) = match (lhs.node.clone(), rhs.node.clone()) {
50             (ExprKind::Binary(lb, llhs, lrhs), ExprKind::Binary(rb, rlhs, rrhs)) => {
51                 (lb.node, llhs, lrhs, rb.node, rlhs, rrhs)
52             },
53             _ => return,
54         };
55         let mut spanless_eq = SpanlessEq::new(cx).ignore_fn();
56         if !(spanless_eq.eq_expr(&llhs, &rlhs) && spanless_eq.eq_expr(&lrhs, &rrhs)) {
57             return;
58         }
59         macro_rules! lint_double_comparison {
60             ($op:tt) => {{
61                 let mut applicability = Applicability::MachineApplicable;
62                 let lhs_str = snippet_with_applicability(cx, llhs.span, "", &mut applicability);
63                 let rhs_str = snippet_with_applicability(cx, lrhs.span, "", &mut applicability);
64                 let sugg = format!("{} {} {}", lhs_str, stringify!($op), rhs_str);
65                 span_lint_and_sugg(
66                     cx,
67                     DOUBLE_COMPARISONS,
68                     span,
69                     "This binary expression can be simplified",
70                     "try",
71                     sugg,
72                     applicability,
73                 );
74             }};
75         }
76         match (op, lkind, rkind) {
77             (BinOpKind::Or, BinOpKind::Eq, BinOpKind::Lt) | (BinOpKind::Or, BinOpKind::Lt, BinOpKind::Eq) => {
78                 lint_double_comparison!(<=)
79             },
80             (BinOpKind::Or, BinOpKind::Eq, BinOpKind::Gt) | (BinOpKind::Or, BinOpKind::Gt, BinOpKind::Eq) => {
81                 lint_double_comparison!(>=)
82             },
83             (BinOpKind::Or, BinOpKind::Lt, BinOpKind::Gt) | (BinOpKind::Or, BinOpKind::Gt, BinOpKind::Lt) => {
84                 lint_double_comparison!(!=)
85             },
86             (BinOpKind::And, BinOpKind::Le, BinOpKind::Ge) | (BinOpKind::And, BinOpKind::Ge, BinOpKind::Le) => {
87                 lint_double_comparison!(==)
88             },
89             _ => (),
90         };
91     }
92 }
93
94 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
95     fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
96         if let ExprKind::Binary(ref kind, ref lhs, ref rhs) = expr.node {
97             self.check_binop(cx, kind.node, lhs, rhs, expr.span);
98         }
99     }
100 }