Move NeedlessBitwiseBool
into Operators
lint pass
This commit is contained in:
parent
71c2daa60a
commit
fc5eac5894
@ -387,7 +387,6 @@
|
||||
mutex_atomic::MUTEX_ATOMIC,
|
||||
mutex_atomic::MUTEX_INTEGER,
|
||||
needless_arbitrary_self_type::NEEDLESS_ARBITRARY_SELF_TYPE,
|
||||
needless_bitwise_bool::NEEDLESS_BITWISE_BOOL,
|
||||
needless_bool::BOOL_COMPARISON,
|
||||
needless_bool::NEEDLESS_BOOL,
|
||||
needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE,
|
||||
@ -435,6 +434,7 @@
|
||||
operators::MISREFACTORED_ASSIGN_OP,
|
||||
operators::MODULO_ARITHMETIC,
|
||||
operators::MODULO_ONE,
|
||||
operators::NEEDLESS_BITWISE_BOOL,
|
||||
operators::OP_REF,
|
||||
operators::VERBOSE_BIT_MASK,
|
||||
option_env_unwrap::OPTION_ENV_UNWRAP,
|
||||
|
@ -67,7 +67,6 @@
|
||||
LintId::of(misc::USED_UNDERSCORE_BINDING),
|
||||
LintId::of(mismatching_type_param_order::MISMATCHING_TYPE_PARAM_ORDER),
|
||||
LintId::of(mut_mut::MUT_MUT),
|
||||
LintId::of(needless_bitwise_bool::NEEDLESS_BITWISE_BOOL),
|
||||
LintId::of(needless_continue::NEEDLESS_CONTINUE),
|
||||
LintId::of(needless_for_each::NEEDLESS_FOR_EACH),
|
||||
LintId::of(needless_pass_by_value::NEEDLESS_PASS_BY_VALUE),
|
||||
@ -75,6 +74,7 @@
|
||||
LintId::of(non_expressive_names::MANY_SINGLE_CHAR_NAMES),
|
||||
LintId::of(non_expressive_names::SIMILAR_NAMES),
|
||||
LintId::of(operators::FLOAT_CMP),
|
||||
LintId::of(operators::NEEDLESS_BITWISE_BOOL),
|
||||
LintId::of(operators::VERBOSE_BIT_MASK),
|
||||
LintId::of(pass_by_ref_or_value::LARGE_TYPES_PASSED_BY_VALUE),
|
||||
LintId::of(pass_by_ref_or_value::TRIVIALLY_COPY_PASS_BY_REF),
|
||||
|
@ -302,7 +302,6 @@ macro_rules! declare_clippy_lint {
|
||||
mod mutable_debug_assertion;
|
||||
mod mutex_atomic;
|
||||
mod needless_arbitrary_self_type;
|
||||
mod needless_bitwise_bool;
|
||||
mod needless_bool;
|
||||
mod needless_borrowed_ref;
|
||||
mod needless_continue;
|
||||
@ -569,7 +568,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
||||
))
|
||||
});
|
||||
store.register_late_pass(|| Box::new(booleans::NonminimalBool));
|
||||
store.register_late_pass(|| Box::new(needless_bitwise_bool::NeedlessBitwiseBool));
|
||||
store.register_late_pass(|| Box::new(enum_clike::UnportableVariant));
|
||||
store.register_late_pass(|| Box::new(float_literal::FloatLiteral));
|
||||
store.register_late_pass(|| Box::new(ptr::Ptr));
|
||||
|
@ -1,85 +0,0 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::source::snippet_opt;
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{BinOpKind, Expr, ExprKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::ty;
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Checks for uses of bitwise and/or operators between booleans, where performance may be improved by using
|
||||
/// a lazy and.
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// The bitwise operators do not support short-circuiting, so it may hinder code performance.
|
||||
/// Additionally, boolean logic "masked" as bitwise logic is not caught by lints like `unnecessary_fold`
|
||||
///
|
||||
/// ### Known problems
|
||||
/// This lint evaluates only when the right side is determined to have no side effects. At this time, that
|
||||
/// determination is quite conservative.
|
||||
///
|
||||
/// ### Example
|
||||
/// ```rust
|
||||
/// let (x,y) = (true, false);
|
||||
/// if x & !y {} // where both x and y are booleans
|
||||
/// ```
|
||||
/// Use instead:
|
||||
/// ```rust
|
||||
/// let (x,y) = (true, false);
|
||||
/// if x && !y {}
|
||||
/// ```
|
||||
#[clippy::version = "1.54.0"]
|
||||
pub NEEDLESS_BITWISE_BOOL,
|
||||
pedantic,
|
||||
"Boolean expressions that use bitwise rather than lazy operators"
|
||||
}
|
||||
|
||||
declare_lint_pass!(NeedlessBitwiseBool => [NEEDLESS_BITWISE_BOOL]);
|
||||
|
||||
fn is_bitwise_operation(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
|
||||
let ty = cx.typeck_results().expr_ty(expr);
|
||||
if_chain! {
|
||||
if !expr.span.from_expansion();
|
||||
if let (&ExprKind::Binary(ref op, _, right), &ty::Bool) = (&expr.kind, &ty.kind());
|
||||
if op.node == BinOpKind::BitAnd || op.node == BinOpKind::BitOr;
|
||||
if let ExprKind::Call(..) | ExprKind::MethodCall(..) | ExprKind::Binary(..) | ExprKind::Unary(..) = right.kind;
|
||||
if !right.can_have_side_effects();
|
||||
then {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
fn suggestion_snippet(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<String> {
|
||||
if let ExprKind::Binary(ref op, left, right) = expr.kind {
|
||||
if let (Some(l_snippet), Some(r_snippet)) = (snippet_opt(cx, left.span), snippet_opt(cx, right.span)) {
|
||||
let op_snippet = match op.node {
|
||||
BinOpKind::BitAnd => "&&",
|
||||
_ => "||",
|
||||
};
|
||||
return Some(format!("{} {} {}", l_snippet, op_snippet, r_snippet));
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
impl LateLintPass<'_> for NeedlessBitwiseBool {
|
||||
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
|
||||
if is_bitwise_operation(cx, expr) {
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
NEEDLESS_BITWISE_BOOL,
|
||||
expr.span,
|
||||
"use of bitwise operator instead of lazy operator between booleans",
|
||||
|diag| {
|
||||
if let Some(sugg) = suggestion_snippet(cx, expr) {
|
||||
diag.span_suggestion(expr.span, "try", sugg, Applicability::MachineApplicable);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
@ -18,6 +18,7 @@
|
||||
mod misrefactored_assign_op;
|
||||
mod modulo_arithmetic;
|
||||
mod modulo_one;
|
||||
mod needless_bitwise_bool;
|
||||
mod numeric_arithmetic;
|
||||
mod op_ref;
|
||||
mod verbose_bit_mask;
|
||||
@ -641,6 +642,35 @@
|
||||
"any modulo arithmetic statement"
|
||||
}
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Checks for uses of bitwise and/or operators between booleans, where performance may be improved by using
|
||||
/// a lazy and.
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// The bitwise operators do not support short-circuiting, so it may hinder code performance.
|
||||
/// Additionally, boolean logic "masked" as bitwise logic is not caught by lints like `unnecessary_fold`
|
||||
///
|
||||
/// ### Known problems
|
||||
/// This lint evaluates only when the right side is determined to have no side effects. At this time, that
|
||||
/// determination is quite conservative.
|
||||
///
|
||||
/// ### Example
|
||||
/// ```rust
|
||||
/// let (x,y) = (true, false);
|
||||
/// if x & !y {} // where both x and y are booleans
|
||||
/// ```
|
||||
/// Use instead:
|
||||
/// ```rust
|
||||
/// let (x,y) = (true, false);
|
||||
/// if x && !y {}
|
||||
/// ```
|
||||
#[clippy::version = "1.54.0"]
|
||||
pub NEEDLESS_BITWISE_BOOL,
|
||||
pedantic,
|
||||
"Boolean expressions that use bitwise rather than lazy operators"
|
||||
}
|
||||
|
||||
pub struct Operators {
|
||||
arithmetic_context: numeric_arithmetic::Context,
|
||||
verbose_bit_mask_threshold: u64,
|
||||
@ -668,6 +698,7 @@ pub struct Operators {
|
||||
FLOAT_CMP_CONST,
|
||||
MODULO_ONE,
|
||||
MODULO_ARITHMETIC,
|
||||
NEEDLESS_BITWISE_BOOL,
|
||||
]);
|
||||
impl Operators {
|
||||
pub fn new(verbose_bit_mask_threshold: u64) -> Self {
|
||||
@ -690,6 +721,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
|
||||
}
|
||||
erasing_op::check(cx, e, op.node, lhs, rhs);
|
||||
identity_op::check(cx, e, op.node, lhs, rhs);
|
||||
needless_bitwise_bool::check(cx, e, op.node, lhs, rhs);
|
||||
}
|
||||
self.arithmetic_context.check_binary(cx, e, op.node, lhs, rhs);
|
||||
bit_mask::check(cx, e, op.node, lhs, rhs);
|
||||
|
36
clippy_lints/src/operators/needless_bitwise_bool.rs
Normal file
36
clippy_lints/src/operators/needless_bitwise_bool.rs
Normal file
@ -0,0 +1,36 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::source::snippet_opt;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{BinOpKind, Expr, ExprKind};
|
||||
use rustc_lint::LateContext;
|
||||
|
||||
use super::NEEDLESS_BITWISE_BOOL;
|
||||
|
||||
pub(super) fn check(cx: &LateContext<'_>, e: &Expr<'_>, op: BinOpKind, lhs: &Expr<'_>, rhs: &Expr<'_>) {
|
||||
let op_str = match op {
|
||||
BinOpKind::BitAnd => "&&",
|
||||
BinOpKind::BitOr => "||",
|
||||
_ => return,
|
||||
};
|
||||
if matches!(
|
||||
rhs.kind,
|
||||
ExprKind::Call(..) | ExprKind::MethodCall(..) | ExprKind::Binary(..) | ExprKind::Unary(..)
|
||||
) && cx.typeck_results().expr_ty(e).is_bool()
|
||||
&& !rhs.can_have_side_effects()
|
||||
{
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
NEEDLESS_BITWISE_BOOL,
|
||||
e.span,
|
||||
"use of bitwise operator instead of lazy operator between booleans",
|
||||
|diag| {
|
||||
if let Some(lhs_snip) = snippet_opt(cx, lhs.span)
|
||||
&& let Some(rhs_snip) = snippet_opt(cx, rhs.span)
|
||||
{
|
||||
let sugg = format!("{} {} {}", lhs_snip, op_str, rhs_snip);
|
||||
diag.span_suggestion(e.span, "try", sugg, Applicability::MachineApplicable);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user