use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; use crate::consts::{constant_simple, Constant}; use crate::utils::span_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 /// /// **Known problems:** None. /// /// **Example:** /// ```rust /// let x = 1; /// 0 / x; /// 0 * x; /// x & 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, ref left, ref right) = e.kind { match cmp.node { BinOpKind::Mul | BinOpKind::BitAnd => { check(cx, left, e.span); check(cx, right, e.span); }, BinOpKind::Div => check(cx, left, e.span), _ => (), } } } } fn check(cx: &LateContext<'_>, e: &Expr<'_>, span: Span) { if let Some(Constant::Int(0)) = constant_simple(cx, cx.typeck_results(), e) { span_lint( cx, ERASING_OP, span, "this operation will always return zero. This is likely not the intended outcome", ); } }