Skip to content

Commit dbbae57

Browse files
authored
Merge pull request #2412 from topecongiro/double-comparison
Add double comparison lint
2 parents 4e46766 + a3c2323 commit dbbae57

File tree

5 files changed

+169
-2
lines changed

5 files changed

+169
-2
lines changed

clippy_lints/src/double_comparison.rs

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
//! Lint on unnecessary double comparisons. Some examples:
2+
3+
use rustc::hir::*;
4+
use rustc::lint::*;
5+
use syntax::codemap::Span;
6+
7+
use utils::{snippet, span_lint_and_sugg, SpanlessEq};
8+
9+
/// **What it does:** Checks for double comparions that could be simpified to a single expression.
10+
///
11+
///
12+
/// **Why is this bad?** Readability.
13+
///
14+
/// **Known problems:** None.
15+
///
16+
/// **Example:**
17+
/// ```rust
18+
/// x == y || x < y
19+
/// ```
20+
///
21+
/// Could be written as:
22+
///
23+
/// ```rust
24+
/// x <= y
25+
/// ```
26+
declare_lint! {
27+
pub DOUBLE_COMPARISONS,
28+
Deny,
29+
"unnecessary double comparisons that can be simplified"
30+
}
31+
32+
pub struct DoubleComparisonPass;
33+
34+
impl LintPass for DoubleComparisonPass {
35+
fn get_lints(&self) -> LintArray {
36+
lint_array!(DOUBLE_COMPARISONS)
37+
}
38+
}
39+
40+
impl<'a, 'tcx> DoubleComparisonPass {
41+
fn check_binop(
42+
&self,
43+
cx: &LateContext<'a, 'tcx>,
44+
op: BinOp_,
45+
lhs: &'tcx Expr,
46+
rhs: &'tcx Expr,
47+
span: Span,
48+
) {
49+
let (lkind, llhs, lrhs, rkind, rlhs, rrhs) = match (lhs.node.clone(), rhs.node.clone()) {
50+
(ExprBinary(lb, llhs, lrhs), ExprBinary(rb, rlhs, rrhs)) => {
51+
(lb.node, llhs, lrhs, rb.node, rlhs, rrhs)
52+
}
53+
_ => return,
54+
};
55+
let 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 lhs_str = snippet(cx, llhs.span, "");
62+
let rhs_str = snippet(cx, lrhs.span, "");
63+
let sugg = format!("{} {} {}", lhs_str, stringify!($op), rhs_str);
64+
span_lint_and_sugg(cx, DOUBLE_COMPARISONS, span,
65+
"This binary expression can be simplified",
66+
"try", sugg);
67+
}}
68+
}
69+
match (op, lkind, rkind) {
70+
(BiOr, BiEq, BiLt) | (BiOr, BiLt, BiEq) => lint_double_comparison!(<=),
71+
(BiOr, BiEq, BiGt) | (BiOr, BiGt, BiEq) => lint_double_comparison!(>=),
72+
(BiOr, BiLt, BiGt) | (BiOr, BiGt, BiLt) => lint_double_comparison!(!=),
73+
(BiAnd, BiLe, BiGe) | (BiAnd, BiGe, BiLe) => lint_double_comparison!(==),
74+
_ => (),
75+
};
76+
}
77+
}
78+
79+
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for DoubleComparisonPass {
80+
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
81+
if let ExprBinary(ref kind, ref lhs, ref rhs) = expr.node {
82+
self.check_binop(cx, kind.node, lhs, rhs, expr.span);
83+
}
84+
}
85+
}

clippy_lints/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ pub mod copies;
8686
pub mod cyclomatic_complexity;
8787
pub mod derive;
8888
pub mod doc;
89+
pub mod double_comparison;
8990
pub mod double_parens;
9091
pub mod drop_forget_ref;
9192
pub mod else_if_without_else;
@@ -369,6 +370,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) {
369370
reg.register_late_lint_pass(box fallible_impl_from::FallibleImplFrom);
370371
reg.register_late_lint_pass(box replace_consts::ReplaceConsts);
371372
reg.register_late_lint_pass(box types::UnitArg);
373+
reg.register_late_lint_pass(box double_comparison::DoubleComparisonPass);
372374

373375
reg.register_lint_group("clippy_restrictions", vec![
374376
arithmetic::FLOAT_ARITHMETIC,

clippy_lints/src/misc.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -545,11 +545,11 @@ fn check_to_owned(cx: &LateContext, expr: &Expr, other: &Expr) {
545545

546546
// *arg impls PartialEq<other>
547547
if !arg_ty
548-
.builtin_deref(true, ty::LvaluePreference::NoPreference)
548+
.builtin_deref(true)
549549
.map_or(false, |tam| implements_trait(cx, tam.ty, partial_eq_trait_id, &[other_ty]))
550550
// arg impls PartialEq<*other>
551551
&& !other_ty
552-
.builtin_deref(true, ty::LvaluePreference::NoPreference)
552+
.builtin_deref(true)
553553
.map_or(false, |tam| implements_trait(cx, arg_ty, partial_eq_trait_id, &[tam.ty]))
554554
// arg impls PartialEq<other>
555555
&& !implements_trait(cx, arg_ty, partial_eq_trait_id, &[other_ty])

tests/ui/double_comparison.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
fn main() {
2+
let x = 1;
3+
let y = 2;
4+
if x == y || x < y {
5+
// do something
6+
}
7+
if x < y || x == y {
8+
// do something
9+
}
10+
if x == y || x > y {
11+
// do something
12+
}
13+
if x > y || x == y {
14+
// do something
15+
}
16+
if x < y || x > y {
17+
// do something
18+
}
19+
if x > y || x < y {
20+
// do something
21+
}
22+
if x <= y && x >= y {
23+
// do something
24+
}
25+
if x >= y && x <= y {
26+
// do something
27+
}
28+
}

tests/ui/double_comparison.stderr

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
error: This binary expression can be simplified
2+
--> $DIR/double_comparison.rs:4:8
3+
|
4+
4 | if x == y || x < y {
5+
| ^^^^^^^^^^^^^^^ help: try: `x <= y`
6+
|
7+
= note: #[deny(double_comparisons)] on by default
8+
9+
error: This binary expression can be simplified
10+
--> $DIR/double_comparison.rs:7:8
11+
|
12+
7 | if x < y || x == y {
13+
| ^^^^^^^^^^^^^^^ help: try: `x <= y`
14+
15+
error: This binary expression can be simplified
16+
--> $DIR/double_comparison.rs:10:8
17+
|
18+
10 | if x == y || x > y {
19+
| ^^^^^^^^^^^^^^^ help: try: `x >= y`
20+
21+
error: This binary expression can be simplified
22+
--> $DIR/double_comparison.rs:13:8
23+
|
24+
13 | if x > y || x == y {
25+
| ^^^^^^^^^^^^^^^ help: try: `x >= y`
26+
27+
error: This binary expression can be simplified
28+
--> $DIR/double_comparison.rs:16:8
29+
|
30+
16 | if x < y || x > y {
31+
| ^^^^^^^^^^^^^^ help: try: `x != y`
32+
33+
error: This binary expression can be simplified
34+
--> $DIR/double_comparison.rs:19:8
35+
|
36+
19 | if x > y || x < y {
37+
| ^^^^^^^^^^^^^^ help: try: `x != y`
38+
39+
error: This binary expression can be simplified
40+
--> $DIR/double_comparison.rs:22:8
41+
|
42+
22 | if x <= y && x >= y {
43+
| ^^^^^^^^^^^^^^^^ help: try: `x == y`
44+
45+
error: This binary expression can be simplified
46+
--> $DIR/double_comparison.rs:25:8
47+
|
48+
25 | if x >= y && x <= y {
49+
| ^^^^^^^^^^^^^^^^ help: try: `x == y`
50+
51+
error: aborting due to 8 previous errors
52+

0 commit comments

Comments
 (0)