Skip to content

Commit f942470

Browse files
committed
Auto merge of #11028 - BenWiederhake:dev-ifnotelse_neqzero, r=llogiq
Skip if_not_else lint for '!= 0'-style checks Currently, clippy makes unhelpful suggestions such as this: ``` warning: unnecessary `!=` operation --> src/vm.rs:598:36 | 598 | *destination = if source & 0x8000 != 0 { 0xFFFF } else { 0 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: change to `==` and swap the blocks of the `if`/`else` = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#if_not_else = note: `-W clippy::if-not-else` implied by `-W clippy::pedantic` ``` Bit tests often take on the form `if foo & 0x1234 != 0 { … } else { … }`, and the `!= 0` part reads as "has any bits set". Therefore, this code already has the "correct" order, and shouldn't be changed. This PR disables the lint for these cases, and in fact all cases where the condition is "foo is non-zero". I did my homework: - \[X] Followed [lint naming conventions][lint_naming] → Not applicable, this PR fixes an existing lint - \[X] Added passing UI tests (including committed `.stderr` file) → Yes, `tests/ui/if_not_else_bittest.rs` - \[X] `cargo test` passes locally - \[X] Executed `cargo dev update_lints` - \[X] Added lint documentation → Not applicable, this PR fixes an existing lint - \[X] Run `cargo dev fmt` changelog: Fix [`if_not_else`] false positive when something like `bitflags != 0` is used
2 parents 56c8235 + 5e17f9f commit f942470

File tree

2 files changed

+22
-1
lines changed

2 files changed

+22
-1
lines changed

clippy_lints/src/if_not_else.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
//! lint on if branches that could be swapped so no `!` operation is necessary
22
//! on the condition
33
4+
use clippy_utils::consts::{constant_simple, Constant};
45
use clippy_utils::diagnostics::span_lint_and_help;
56
use clippy_utils::is_else_clause;
67
use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp};
@@ -47,6 +48,13 @@ declare_clippy_lint! {
4748

4849
declare_lint_pass!(IfNotElse => [IF_NOT_ELSE]);
4950

51+
fn is_zero_const(expr: &Expr<'_>, cx: &LateContext<'_>) -> bool {
52+
if let Some(value) = constant_simple(cx, cx.typeck_results(), expr) {
53+
return Constant::Int(0) == value;
54+
}
55+
false
56+
}
57+
5058
impl LateLintPass<'_> for IfNotElse {
5159
fn check_expr(&mut self, cx: &LateContext<'_>, item: &Expr<'_>) {
5260
// While loops will be desugared to ExprKind::If. This will cause the lint to fire.
@@ -72,7 +80,9 @@ impl LateLintPass<'_> for IfNotElse {
7280
"remove the `!` and swap the blocks of the `if`/`else`",
7381
);
7482
},
75-
ExprKind::Binary(ref kind, _, _) if kind.node == BinOpKind::Ne => {
83+
ExprKind::Binary(ref kind, _, lhs) if kind.node == BinOpKind::Ne && !is_zero_const(lhs, cx) => {
84+
// Disable firing the lint on `… != 0`, as these are likely to be bit tests.
85+
// For example, `if foo & 0x0F00 != 0 { … } else { … }` already is in the "proper" order.
7686
span_lint_and_help(
7787
cx,
7888
IF_NOT_ELSE,

tests/ui/if_not_else_bittest.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#![deny(clippy::if_not_else)]
2+
3+
fn show_permissions(flags: u32) {
4+
if flags & 0x0F00 != 0 {
5+
println!("Has the 0x0F00 permission.");
6+
} else {
7+
println!("The 0x0F00 permission is missing.");
8+
}
9+
}
10+
11+
fn main() {}

0 commit comments

Comments
 (0)