| use clippy_utils::consts::ConstEvalCtxt; | |
| use clippy_utils::consts::Constant::Int; | |
| use clippy_utils::diagnostics::span_lint_and_sugg; | |
| use clippy_utils::sugg::Sugg; | |
| use clippy_utils::{eq_expr_value, sym}; | |
| use rustc_errors::Applicability; | |
| use rustc_hir::{BinOpKind, Expr, ExprKind, PathSegment}; | |
| use rustc_lint::LateContext; | |
| use rustc_span::Spanned; | |
| use super::IMPRECISE_FLOPS; | |
| pub(super) fn detect(cx: &LateContext<'_>, receiver: &Expr<'_>, app: &mut Applicability) -> Option<String> { | |
| if let ExprKind::Binary( | |
| Spanned { | |
| node: BinOpKind::Add, .. | |
| }, | |
| add_lhs, | |
| add_rhs, | |
| ) = receiver.kind | |
| { | |
| // check if expression of the form x * x + y * y | |
| if let ExprKind::Binary( | |
| Spanned { | |
| node: BinOpKind::Mul, .. | |
| }, | |
| lmul_lhs, | |
| lmul_rhs, | |
| ) = add_lhs.kind | |
| && let ExprKind::Binary( | |
| Spanned { | |
| node: BinOpKind::Mul, .. | |
| }, | |
| rmul_lhs, | |
| rmul_rhs, | |
| ) = add_rhs.kind | |
| && eq_expr_value(cx, lmul_lhs, lmul_rhs) | |
| && eq_expr_value(cx, rmul_lhs, rmul_rhs) | |
| { | |
| return Some(format!( | |
| "{}.hypot({})", | |
| Sugg::hir_with_applicability(cx, lmul_lhs, "_", app).maybe_paren(), | |
| Sugg::hir_with_applicability(cx, rmul_lhs, "_", app) | |
| )); | |
| } | |
| // check if expression of the form x.powi(2) + y.powi(2) | |
| if let ExprKind::MethodCall(PathSegment { ident: lmethod, .. }, largs_0, [largs_1, ..], _) = add_lhs.kind | |
| && let ExprKind::MethodCall(PathSegment { ident: rmethod, .. }, rargs_0, [rargs_1, ..], _) = add_rhs.kind | |
| && lmethod.name == sym::powi | |
| && rmethod.name == sym::powi | |
| && let ecx = ConstEvalCtxt::new(cx) | |
| && let Some(lvalue) = ecx.eval(largs_1) | |
| && let Some(rvalue) = ecx.eval(rargs_1) | |
| && Int(2) == lvalue | |
| && Int(2) == rvalue | |
| { | |
| return Some(format!( | |
| "{}.hypot({})", | |
| Sugg::hir_with_applicability(cx, largs_0, "_", app).maybe_paren(), | |
| Sugg::hir_with_applicability(cx, rargs_0, "_", app) | |
| )); | |
| } | |
| } | |
| None | |
| } | |
| pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>) { | |
| let mut app = Applicability::MachineApplicable; | |
| if let Some(message) = detect(cx, receiver, &mut app) { | |
| span_lint_and_sugg( | |
| cx, | |
| IMPRECISE_FLOPS, | |
| expr.span, | |
| "hypotenuse can be computed more accurately", | |
| "consider using", | |
| message, | |
| app, | |
| ); | |
| } | |
| } |