diff --git a/clippy_lints/src/erasing_op.rs b/clippy_lints/src/erasing_op.rs deleted file mode 100644 index c1a84973c421..000000000000 --- a/clippy_lints/src/erasing_op.rs +++ /dev/null @@ -1,77 +0,0 @@ -use clippy_utils::consts::{constant_simple, Constant}; -use clippy_utils::diagnostics::span_lint; -use clippy_utils::ty::same_type_and_consts; - -use rustc_hir::{BinOpKind, Expr, ExprKind}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty::TypeckResults; -use rustc_session::{declare_lint_pass, declare_tool_lint}; - -declare_clippy_lint! { - /// ### What it does - /// Checks for erasing operations, e.g., `x * 0`. - /// - /// ### Why is this bad? - /// The whole expression can be replaced by zero. - /// This is most likely not the intended outcome and should probably be - /// corrected - /// - /// ### Example - /// ```rust - /// let x = 1; - /// 0 / x; - /// 0 * x; - /// x & 0; - /// ``` - #[clippy::version = "pre 1.29.0"] - pub ERASING_OP, - correctness, - "using erasing operations, e.g., `x * 0` or `y & 0`" -} - -declare_lint_pass!(ErasingOp => [ERASING_OP]); - -impl<'tcx> LateLintPass<'tcx> for ErasingOp { - fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { - if e.span.from_expansion() { - return; - } - if let ExprKind::Binary(ref cmp, left, right) = e.kind { - let tck = cx.typeck_results(); - match cmp.node { - BinOpKind::Mul | BinOpKind::BitAnd => { - check(cx, tck, left, right, e); - check(cx, tck, right, left, e); - }, - BinOpKind::Div => check(cx, tck, left, right, e), - _ => (), - } - } - } -} - -fn different_types(tck: &TypeckResults<'_>, input: &Expr<'_>, output: &Expr<'_>) -> bool { - let input_ty = tck.expr_ty(input).peel_refs(); - let output_ty = tck.expr_ty(output).peel_refs(); - !same_type_and_consts(input_ty, output_ty) -} - -fn check<'tcx>( - cx: &LateContext<'tcx>, - tck: &TypeckResults<'tcx>, - op: &Expr<'tcx>, - other: &Expr<'tcx>, - parent: &Expr<'tcx>, -) { - if constant_simple(cx, tck, op) == Some(Constant::Int(0)) { - if different_types(tck, other, parent) { - return; - } - span_lint( - cx, - ERASING_OP, - parent.span, - "this operation will always return zero. This is likely not the intended outcome", - ); - } -} diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs index 634d7f1f69fc..533e6294925f 100644 --- a/clippy_lints/src/lib.register_all.rs +++ b/clippy_lints/src/lib.register_all.rs @@ -61,7 +61,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(enum_clike::ENUM_CLIKE_UNPORTABLE_VARIANT), LintId::of(enum_variants::ENUM_VARIANT_NAMES), LintId::of(enum_variants::MODULE_INCEPTION), - LintId::of(erasing_op::ERASING_OP), LintId::of(escape::BOXED_LOCAL), LintId::of(eta_reduction::REDUNDANT_CLOSURE), LintId::of(explicit_write::EXPLICIT_WRITE), @@ -257,6 +256,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(operators::DOUBLE_COMPARISONS), LintId::of(operators::DURATION_SUBSEC), LintId::of(operators::EQ_OP), + LintId::of(operators::ERASING_OP), LintId::of(operators::INEFFECTIVE_BIT_MASK), LintId::of(operators::MISREFACTORED_ASSIGN_OP), LintId::of(operators::OP_REF), diff --git a/clippy_lints/src/lib.register_correctness.rs b/clippy_lints/src/lib.register_correctness.rs index 2b81eee13266..b8362d5a72df 100644 --- a/clippy_lints/src/lib.register_correctness.rs +++ b/clippy_lints/src/lib.register_correctness.rs @@ -21,7 +21,6 @@ store.register_group(true, "clippy::correctness", Some("clippy_correctness"), ve LintId::of(drop_forget_ref::FORGET_REF), LintId::of(drop_forget_ref::UNDROPPED_MANUALLY_DROPS), LintId::of(enum_clike::ENUM_CLIKE_UNPORTABLE_VARIANT), - LintId::of(erasing_op::ERASING_OP), LintId::of(format_impl::RECURSIVE_FORMAT_IMPL), LintId::of(formatting::POSSIBLE_MISSING_COMMA), LintId::of(functions::NOT_UNSAFE_PTR_ARG_DEREF), @@ -50,6 +49,7 @@ store.register_group(true, "clippy::correctness", Some("clippy_correctness"), ve LintId::of(operators::ABSURD_EXTREME_COMPARISONS), LintId::of(operators::BAD_BIT_MASK), LintId::of(operators::EQ_OP), + LintId::of(operators::ERASING_OP), LintId::of(operators::INEFFECTIVE_BIT_MASK), LintId::of(option_env_unwrap::OPTION_ENV_UNWRAP), LintId::of(ptr::INVALID_NULL_PTR_USAGE), diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index 8b1bb440f084..7ebf2880d2c0 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -141,7 +141,6 @@ store.register_lints(&[ enum_variants::MODULE_INCEPTION, enum_variants::MODULE_NAME_REPETITIONS, equatable_if_let::EQUATABLE_IF_LET, - erasing_op::ERASING_OP, escape::BOXED_LOCAL, eta_reduction::REDUNDANT_CLOSURE, eta_reduction::REDUNDANT_CLOSURE_FOR_METHOD_CALLS, @@ -431,6 +430,7 @@ store.register_lints(&[ operators::DOUBLE_COMPARISONS, operators::DURATION_SUBSEC, operators::EQ_OP, + operators::ERASING_OP, operators::FLOAT_ARITHMETIC, operators::INEFFECTIVE_BIT_MASK, operators::INTEGER_ARITHMETIC, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index f042d7547c26..3ded4a843757 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -220,7 +220,6 @@ mod entry; mod enum_clike; mod enum_variants; mod equatable_if_let; -mod erasing_op; mod escape; mod eta_reduction; mod excessive_bools; @@ -585,7 +584,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| Box::new(misc::MiscLints)); store.register_late_pass(|| Box::new(eta_reduction::EtaReduction)); store.register_late_pass(|| Box::new(identity_op::IdentityOp)); - store.register_late_pass(|| Box::new(erasing_op::ErasingOp)); store.register_late_pass(|| Box::new(mut_mut::MutMut)); store.register_late_pass(|| Box::new(mut_reference::UnnecessaryMutPassed)); store.register_late_pass(|| Box::new(len_zero::LenZero)); diff --git a/clippy_lints/src/operators/erasing_op.rs b/clippy_lints/src/operators/erasing_op.rs new file mode 100644 index 000000000000..066e08f3bd4c --- /dev/null +++ b/clippy_lints/src/operators/erasing_op.rs @@ -0,0 +1,53 @@ +use clippy_utils::consts::{constant_simple, Constant}; +use clippy_utils::diagnostics::span_lint; +use clippy_utils::ty::same_type_and_consts; + +use rustc_hir::{BinOpKind, Expr}; +use rustc_lint::LateContext; +use rustc_middle::ty::TypeckResults; + +use super::ERASING_OP; + +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + e: &'tcx Expr<'_>, + op: BinOpKind, + left: &'tcx Expr<'_>, + right: &'tcx Expr<'_>, +) { + let tck = cx.typeck_results(); + match op { + BinOpKind::Mul | BinOpKind::BitAnd => { + check_op(cx, tck, left, right, e); + check_op(cx, tck, right, left, e); + }, + BinOpKind::Div => check_op(cx, tck, left, right, e), + _ => (), + } +} + +fn different_types(tck: &TypeckResults<'_>, input: &Expr<'_>, output: &Expr<'_>) -> bool { + let input_ty = tck.expr_ty(input).peel_refs(); + let output_ty = tck.expr_ty(output).peel_refs(); + !same_type_and_consts(input_ty, output_ty) +} + +fn check_op<'tcx>( + cx: &LateContext<'tcx>, + tck: &TypeckResults<'tcx>, + op: &Expr<'tcx>, + other: &Expr<'tcx>, + parent: &Expr<'tcx>, +) { + if constant_simple(cx, tck, op) == Some(Constant::Int(0)) { + if different_types(tck, other, parent) { + return; + } + span_lint( + cx, + ERASING_OP, + parent.span, + "this operation will always return zero. This is likely not the intended outcome", + ); + } +} diff --git a/clippy_lints/src/operators/mod.rs b/clippy_lints/src/operators/mod.rs index fd8b55beaed4..01a23f0e3224 100644 --- a/clippy_lints/src/operators/mod.rs +++ b/clippy_lints/src/operators/mod.rs @@ -8,6 +8,7 @@ mod bit_mask; mod double_comparison; mod duration_subsec; mod eq_op; +mod erasing_op; mod misrefactored_assign_op; mod numeric_arithmetic; mod op_ref; @@ -360,6 +361,28 @@ declare_clippy_lint! { "taking a reference to satisfy the type constraints on `==`" } +declare_clippy_lint! { + /// ### What it does + /// Checks for erasing operations, e.g., `x * 0`. + /// + /// ### Why is this bad? + /// The whole expression can be replaced by zero. + /// This is most likely not the intended outcome and should probably be + /// corrected + /// + /// ### Example + /// ```rust + /// let x = 1; + /// 0 / x; + /// 0 * x; + /// x & 0; + /// ``` + #[clippy::version = "pre 1.29.0"] + pub ERASING_OP, + correctness, + "using erasing operations, e.g., `x * 0` or `y & 0`" +} + pub struct Operators { arithmetic_context: numeric_arithmetic::Context, verbose_bit_mask_threshold: u64, @@ -377,6 +400,7 @@ impl_lint_pass!(Operators => [ DURATION_SUBSEC, EQ_OP, OP_REF, + ERASING_OP, ]); impl Operators { pub fn new(verbose_bit_mask_threshold: u64) -> Self { @@ -397,6 +421,7 @@ impl<'tcx> LateLintPass<'tcx> for Operators { eq_op::check(cx, e, op.node, lhs, rhs); op_ref::check(cx, e, op.node, lhs, rhs); } + erasing_op::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);