| use clippy_utils::consts::{ConstEvalCtxt, Constant}; |
| use clippy_utils::diagnostics::span_lint; |
| use clippy_utils::ty::same_type_modulo_regions; |
| |
| 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_modulo_regions(input_ty, output_ty) |
| } |
| |
| fn check_op<'tcx>( |
| cx: &LateContext<'tcx>, |
| tck: &'tcx TypeckResults<'tcx>, |
| op: &Expr<'tcx>, |
| other: &Expr<'tcx>, |
| parent: &Expr<'tcx>, |
| ) { |
| if ConstEvalCtxt::with_env(cx.tcx, cx.typing_env(), tck).eval_local(op, parent.span.ctxt()) |
| == 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", |
| ); |
| } |
| } |