Skip to content

Commit 42c36dc

Browse files
committed
Auto merge of #5365 - mgr-inz-rafal:issue4983_bool_updates, r=yaahc
Issue4983 bool updates changelog: Check for bool inequality comparison that might be written more concisely Fixes #4983
2 parents 3e1dd20 + c8f3241 commit 42c36dc

File tree

4 files changed

+110
-4
lines changed

4 files changed

+110
-4
lines changed

clippy_lints/src/needless_bool.rs

+53-3
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,15 @@
33
//! This lint is **warn** by default
44
55
use crate::utils::sugg::Sugg;
6-
use crate::utils::{higher, parent_node_is_if_expr, span_lint, span_lint_and_sugg};
6+
use crate::utils::{higher, parent_node_is_if_expr, snippet_with_applicability, span_lint, span_lint_and_sugg};
7+
use if_chain::if_chain;
78
use rustc_ast::ast::LitKind;
89
use rustc_errors::Applicability;
9-
use rustc_hir::{BinOpKind, Block, Expr, ExprKind, StmtKind};
10+
use rustc_hir::{BinOpKind, Block, Expr, ExprKind, StmtKind, UnOp};
1011
use rustc_lint::{LateContext, LateLintPass};
1112
use rustc_session::{declare_lint_pass, declare_tool_lint};
1213
use rustc_span::source_map::Spanned;
14+
use rustc_span::Span;
1315

1416
declare_clippy_lint! {
1517
/// **What it does:** Checks for expressions of the form `if c { true } else {
@@ -188,6 +190,34 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BoolComparison {
188190
}
189191
}
190192

193+
struct ExpressionInfoWithSpan {
194+
one_side_is_unary_not: bool,
195+
left_span: Span,
196+
right_span: Span,
197+
}
198+
199+
fn is_unary_not(e: &Expr<'_>) -> (bool, Span) {
200+
if_chain! {
201+
if let ExprKind::Unary(unop, operand) = e.kind;
202+
if let UnOp::UnNot = unop;
203+
then {
204+
return (true, operand.span);
205+
}
206+
};
207+
(false, e.span)
208+
}
209+
210+
fn one_side_is_unary_not<'tcx>(left_side: &'tcx Expr<'_>, right_side: &'tcx Expr<'_>) -> ExpressionInfoWithSpan {
211+
let left = is_unary_not(left_side);
212+
let right = is_unary_not(right_side);
213+
214+
ExpressionInfoWithSpan {
215+
one_side_is_unary_not: left.0 != right.0,
216+
left_span: left.1,
217+
right_span: right.1,
218+
}
219+
}
220+
191221
fn check_comparison<'a, 'tcx>(
192222
cx: &LateContext<'a, 'tcx>,
193223
e: &'tcx Expr<'_>,
@@ -199,10 +229,30 @@ fn check_comparison<'a, 'tcx>(
199229
) {
200230
use self::Expression::{Bool, Other};
201231

202-
if let ExprKind::Binary(_, ref left_side, ref right_side) = e.kind {
232+
if let ExprKind::Binary(op, ref left_side, ref right_side) = e.kind {
203233
let (l_ty, r_ty) = (cx.tables.expr_ty(left_side), cx.tables.expr_ty(right_side));
204234
if l_ty.is_bool() && r_ty.is_bool() {
205235
let mut applicability = Applicability::MachineApplicable;
236+
237+
if let BinOpKind::Eq = op.node {
238+
let expression_info = one_side_is_unary_not(&left_side, &right_side);
239+
if expression_info.one_side_is_unary_not {
240+
span_lint_and_sugg(
241+
cx,
242+
BOOL_COMPARISON,
243+
e.span,
244+
"This comparison might be written more concisely",
245+
"try simplifying it as shown",
246+
format!(
247+
"{} != {}",
248+
snippet_with_applicability(cx, expression_info.left_span, "..", &mut applicability),
249+
snippet_with_applicability(cx, expression_info.right_span, "..", &mut applicability)
250+
),
251+
applicability,
252+
)
253+
}
254+
}
255+
206256
match (fetch_bool_expr(left_side), fetch_bool_expr(right_side)) {
207257
(Bool(true), Other) => left_true.map_or((), |(h, m)| {
208258
suggest_bool_comparison(cx, e, right_side, applicability, m, h)

tests/ui/bool_comparison.fixed

+16
Original file line numberDiff line numberDiff line change
@@ -111,3 +111,19 @@ fn issue3703() {
111111
if Foo < false {}
112112
if false < Foo {}
113113
}
114+
115+
#[allow(dead_code)]
116+
fn issue4983() {
117+
let a = true;
118+
let b = false;
119+
120+
if a != b {};
121+
if a != b {};
122+
if a == b {};
123+
if !a == !b {};
124+
125+
if b != a {};
126+
if b != a {};
127+
if b == a {};
128+
if !b == !a {};
129+
}

tests/ui/bool_comparison.rs

+16
Original file line numberDiff line numberDiff line change
@@ -111,3 +111,19 @@ fn issue3703() {
111111
if Foo < false {}
112112
if false < Foo {}
113113
}
114+
115+
#[allow(dead_code)]
116+
fn issue4983() {
117+
let a = true;
118+
let b = false;
119+
120+
if a == !b {};
121+
if !a == b {};
122+
if a == b {};
123+
if !a == !b {};
124+
125+
if b == !a {};
126+
if !b == a {};
127+
if b == a {};
128+
if !b == !a {};
129+
}

tests/ui/bool_comparison.stderr

+25-1
Original file line numberDiff line numberDiff line change
@@ -84,5 +84,29 @@ error: order comparisons between booleans can be simplified
8484
LL | if x > y {
8585
| ^^^^^ help: try simplifying it as shown: `x & !y`
8686

87-
error: aborting due to 14 previous errors
87+
error: This comparison might be written more concisely
88+
--> $DIR/bool_comparison.rs:120:8
89+
|
90+
LL | if a == !b {};
91+
| ^^^^^^^ help: try simplifying it as shown: `a != b`
92+
93+
error: This comparison might be written more concisely
94+
--> $DIR/bool_comparison.rs:121:8
95+
|
96+
LL | if !a == b {};
97+
| ^^^^^^^ help: try simplifying it as shown: `a != b`
98+
99+
error: This comparison might be written more concisely
100+
--> $DIR/bool_comparison.rs:125:8
101+
|
102+
LL | if b == !a {};
103+
| ^^^^^^^ help: try simplifying it as shown: `b != a`
104+
105+
error: This comparison might be written more concisely
106+
--> $DIR/bool_comparison.rs:126:8
107+
|
108+
LL | if !b == a {};
109+
| ^^^^^^^ help: try simplifying it as shown: `b != a`
110+
111+
error: aborting due to 18 previous errors
88112

0 commit comments

Comments
 (0)