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 } ;
45use clippy_utils:: diagnostics:: span_lint_and_help;
56use clippy_utils:: is_else_clause;
67use rustc_hir:: { BinOpKind , Expr , ExprKind , UnOp } ;
@@ -47,6 +48,13 @@ declare_clippy_lint! {
4748
4849declare_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+
5058impl 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 ,
0 commit comments