]> git.lizzy.rs Git - rust.git/blob - clippy_lints/src/double_comparison.rs
Auto merge of #3919 - matthiaskrgr:readme_3, r=flip1995
[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_lint_pass, declare_tool_lint};
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 comparisons 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 declare_lint_pass!(DoubleComparisons => [DOUBLE_COMPARISONS]);
35
36 impl<'a, 'tcx> DoubleComparisons {
37     #[allow(clippy::similar_names)]
38     fn check_binop(self, cx: &LateContext<'a, 'tcx>, op: BinOpKind, lhs: &'tcx Expr, rhs: &'tcx Expr, span: Span) {
39         let (lkind, llhs, lrhs, rkind, rlhs, rrhs) = match (&lhs.node, &rhs.node) {
40             (ExprKind::Binary(lb, llhs, lrhs), ExprKind::Binary(rb, rlhs, rrhs)) => {
41                 (lb.node, llhs, lrhs, rb.node, rlhs, rrhs)
42             },
43             _ => return,
44         };
45         let mut spanless_eq = SpanlessEq::new(cx).ignore_fn();
46         if !(spanless_eq.eq_expr(&llhs, &rlhs) && spanless_eq.eq_expr(&lrhs, &rrhs)) {
47             return;
48         }
49         macro_rules! lint_double_comparison {
50             ($op:tt) => {{
51                 let mut applicability = Applicability::MachineApplicable;
52                 let lhs_str = snippet_with_applicability(cx, llhs.span, "", &mut applicability);
53                 let rhs_str = snippet_with_applicability(cx, lrhs.span, "", &mut applicability);
54                 let sugg = format!("{} {} {}", lhs_str, stringify!($op), rhs_str);
55                 span_lint_and_sugg(
56                     cx,
57                     DOUBLE_COMPARISONS,
58                     span,
59                     "This binary expression can be simplified",
60                     "try",
61                     sugg,
62                     applicability,
63                 );
64             }};
65         }
66         match (op, lkind, rkind) {
67             (BinOpKind::Or, BinOpKind::Eq, BinOpKind::Lt) | (BinOpKind::Or, BinOpKind::Lt, BinOpKind::Eq) => {
68                 lint_double_comparison!(<=)
69             },
70             (BinOpKind::Or, BinOpKind::Eq, BinOpKind::Gt) | (BinOpKind::Or, BinOpKind::Gt, BinOpKind::Eq) => {
71                 lint_double_comparison!(>=)
72             },
73             (BinOpKind::Or, BinOpKind::Lt, BinOpKind::Gt) | (BinOpKind::Or, BinOpKind::Gt, BinOpKind::Lt) => {
74                 lint_double_comparison!(!=)
75             },
76             (BinOpKind::And, BinOpKind::Le, BinOpKind::Ge) | (BinOpKind::And, BinOpKind::Ge, BinOpKind::Le) => {
77                 lint_double_comparison!(==)
78             },
79             _ => (),
80         };
81     }
82 }
83
84 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for DoubleComparisons {
85     fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
86         if let ExprKind::Binary(ref kind, ref lhs, ref rhs) = expr.node {
87             self.check_binop(cx, kind.node, lhs, rhs, expr.span);
88         }
89     }
90 }