Constant::{Int, F32, F64},
};
use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::{eq_expr_value, get_parent_expr, numeric_literal, sugg};
+use clippy_utils::higher;
+use clippy_utils::{eq_expr_value, get_parent_expr, in_constant, numeric_literal, peel_blocks, sugg};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{BinOpKind, Expr, ExprKind, PathSegment, UnOp};
/// let _ = a.ln_1p();
/// let _ = a.exp_m1();
/// ```
+ #[clippy::version = "1.43.0"]
pub IMPRECISE_FLOPS,
nursery,
"usage of imprecise floating point operations"
/// let _ = a.abs();
/// let _ = -a.abs();
/// ```
+ #[clippy::version = "1.43.0"]
pub SUBOPTIMAL_FLOPS,
nursery,
"usage of sub-optimal floating point operations"
if value == Int(2) {
if let Some(parent) = get_parent_expr(cx, expr) {
if let Some(grandparent) = get_parent_expr(cx, parent) {
- if let ExprKind::MethodCall(PathSegment { ident: method_name, .. }, _, args, _) = grandparent.kind {
+ if let ExprKind::MethodCall(PathSegment { ident: method_name, .. }, args, _) = grandparent.kind {
if method_name.as_str() == "sqrt" && detect_hypot(cx, args).is_some() {
return;
}
),
Applicability::MachineApplicable,
);
-
- return;
}
}
}
if eq_expr_value(cx, lmul_lhs, lmul_rhs);
if eq_expr_value(cx, rmul_lhs, rmul_rhs);
then {
- return Some(format!("{}.hypot({})", Sugg::hir(cx, lmul_lhs, ".."), Sugg::hir(cx, rmul_lhs, "..")));
+ return Some(format!("{}.hypot({})", Sugg::hir(cx, lmul_lhs, "..").maybe_par(), Sugg::hir(cx, rmul_lhs, "..")));
}
}
if_chain! {
if let ExprKind::MethodCall(
PathSegment { ident: lmethod_name, .. },
- ref _lspan,
- largs,
+ [largs_0, largs_1, ..],
_
- ) = add_lhs.kind;
+ ) = &add_lhs.kind;
if let ExprKind::MethodCall(
PathSegment { ident: rmethod_name, .. },
- ref _rspan,
- rargs,
+ [rargs_0, rargs_1, ..],
_
- ) = add_rhs.kind;
+ ) = &add_rhs.kind;
if lmethod_name.as_str() == "powi" && rmethod_name.as_str() == "powi";
- if let Some((lvalue, _)) = constant(cx, cx.typeck_results(), &largs[1]);
- if let Some((rvalue, _)) = constant(cx, cx.typeck_results(), &rargs[1]);
+ if let Some((lvalue, _)) = constant(cx, cx.typeck_results(), largs_1);
+ if let Some((rvalue, _)) = constant(cx, cx.typeck_results(), rargs_1);
if Int(2) == lvalue && Int(2) == rvalue;
then {
- return Some(format!("{}.hypot({})", Sugg::hir(cx, &largs[0], ".."), Sugg::hir(cx, &rargs[0], "..")));
+ return Some(format!("{}.hypot({})", Sugg::hir(cx, largs_0, "..").maybe_par(), Sugg::hir(cx, rargs_0, "..")));
}
}
}
if cx.typeck_results().expr_ty(lhs).is_floating_point();
if let Some((value, _)) = constant(cx, cx.typeck_results(), rhs);
if F32(1.0) == value || F64(1.0) == value;
- if let ExprKind::MethodCall(path, _, method_args, _) = lhs.kind;
- if cx.typeck_results().expr_ty(&method_args[0]).is_floating_point();
+ if let ExprKind::MethodCall(path, [self_arg, ..], _) = &lhs.kind;
+ if cx.typeck_results().expr_ty(self_arg).is_floating_point();
if path.ident.name.as_str() == "exp";
then {
span_lint_and_sugg(
"consider using",
format!(
"{}.exp_m1()",
- Sugg::hir(cx, &method_args[0], "..")
+ Sugg::hir(cx, self_arg, "..")
),
Applicability::MachineApplicable,
);
) = &expr.kind
{
if let Some(parent) = get_parent_expr(cx, expr) {
- if let ExprKind::MethodCall(PathSegment { ident: method_name, .. }, _, args, _) = parent.kind {
+ if let ExprKind::MethodCall(PathSegment { ident: method_name, .. }, args, _) = parent.kind {
if method_name.as_str() == "sqrt" && detect_hypot(cx, args).is_some() {
return;
}
fn check_custom_abs(cx: &LateContext<'_>, expr: &Expr<'_>) {
if_chain! {
- if let ExprKind::If(cond, body, else_body) = expr.kind;
- if let ExprKind::Block(block, _) = body.kind;
- if block.stmts.is_empty();
- if let Some(if_body_expr) = block.expr;
- if let Some(ExprKind::Block(else_block, _)) = else_body.map(|el| &el.kind);
- if else_block.stmts.is_empty();
- if let Some(else_body_expr) = else_block.expr;
+ if let Some(higher::If { cond, then, r#else: Some(r#else) }) = higher::If::hir(expr);
+ let if_body_expr = peel_blocks(then);
+ let else_body_expr = peel_blocks(r#else);
if let Some((if_expr_positive, body)) = are_negated(cx, if_body_expr, else_body_expr);
then {
let positive_abs_sugg = (
fn are_same_base_logs(cx: &LateContext<'_>, expr_a: &Expr<'_>, expr_b: &Expr<'_>) -> bool {
if_chain! {
- if let ExprKind::MethodCall(PathSegment { ident: method_name_a, .. }, _, args_a, _) = expr_a.kind;
- if let ExprKind::MethodCall(PathSegment { ident: method_name_b, .. }, _, args_b, _) = expr_b.kind;
+ if let ExprKind::MethodCall(PathSegment { ident: method_name_a, .. }, args_a, _) = expr_a.kind;
+ if let ExprKind::MethodCall(PathSegment { ident: method_name_b, .. }, args_b, _) = expr_b.kind;
then {
return method_name_a.as_str() == method_name_b.as_str() &&
args_a.len() == args_b.len() &&
(
- ["ln", "log2", "log10"].contains(&&*method_name_a.as_str()) ||
+ ["ln", "log2", "log10"].contains(&method_name_a.as_str()) ||
method_name_a.as_str() == "log" && args_a.len() == 2 && eq_expr_value(cx, &args_a[1], &args_b[1])
);
}
rhs,
) = &expr.kind;
if are_same_base_logs(cx, lhs, rhs);
- if let ExprKind::MethodCall(_, _, largs, _) = lhs.kind;
- if let ExprKind::MethodCall(_, _, rargs, _) = rhs.kind;
+ if let ExprKind::MethodCall(_, [largs_self, ..], _) = &lhs.kind;
+ if let ExprKind::MethodCall(_, [rargs_self, ..], _) = &rhs.kind;
then {
span_lint_and_sugg(
cx,
expr.span,
"log base can be expressed more clearly",
"consider using",
- format!("{}.log({})", Sugg::hir(cx, &largs[0], ".."), Sugg::hir(cx, &rargs[0], ".."),),
+ format!("{}.log({})", Sugg::hir(cx, largs_self, ".."), Sugg::hir(cx, rargs_self, ".."),),
Applicability::MachineApplicable,
);
}
if (F32(f32_consts::PI) == rvalue || F64(f64_consts::PI) == rvalue) &&
(F32(180_f32) == lvalue || F64(180_f64) == lvalue)
{
+ let mut proposal = format!("{}.to_degrees()", Sugg::hir(cx, mul_lhs, ".."));
+ if_chain! {
+ if let ExprKind::Lit(ref literal) = mul_lhs.kind;
+ if let ast::LitKind::Float(ref value, float_type) = literal.node;
+ if float_type == ast::LitFloatType::Unsuffixed;
+ then {
+ if value.as_str().ends_with('.') {
+ proposal = format!("{}0_f64.to_degrees()", Sugg::hir(cx, mul_lhs, ".."));
+ } else {
+ proposal = format!("{}_f64.to_degrees()", Sugg::hir(cx, mul_lhs, ".."));
+ }
+ }
+ }
span_lint_and_sugg(
cx,
SUBOPTIMAL_FLOPS,
expr.span,
"conversion to degrees can be done more accurately",
"consider using",
- format!("{}.to_degrees()", Sugg::hir(cx, mul_lhs, "..")),
+ proposal,
Applicability::MachineApplicable,
);
} else if
(F32(180_f32) == rvalue || F64(180_f64) == rvalue) &&
(F32(f32_consts::PI) == lvalue || F64(f64_consts::PI) == lvalue)
{
+ let mut proposal = format!("{}.to_radians()", Sugg::hir(cx, mul_lhs, ".."));
+ if_chain! {
+ if let ExprKind::Lit(ref literal) = mul_lhs.kind;
+ if let ast::LitKind::Float(ref value, float_type) = literal.node;
+ if float_type == ast::LitFloatType::Unsuffixed;
+ then {
+ if value.as_str().ends_with('.') {
+ proposal = format!("{}0_f64.to_radians()", Sugg::hir(cx, mul_lhs, ".."));
+ } else {
+ proposal = format!("{}_f64.to_radians()", Sugg::hir(cx, mul_lhs, ".."));
+ }
+ }
+ }
span_lint_and_sugg(
cx,
SUBOPTIMAL_FLOPS,
expr.span,
"conversion to radians can be done more accurately",
"consider using",
- format!("{}.to_radians()", Sugg::hir(cx, mul_lhs, "..")),
+ proposal,
Applicability::MachineApplicable,
);
}
impl<'tcx> LateLintPass<'tcx> for FloatingPointArithmetic {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
- if let ExprKind::MethodCall(path, _, args, _) = &expr.kind {
+ // All of these operations are currently not const.
+ if in_constant(cx, expr.hir_id) {
+ return;
+ }
+
+ if let ExprKind::MethodCall(path, args, _) = &expr.kind {
let recv_ty = cx.typeck_results().expr_ty(&args[0]);
if recv_ty.is_floating_point() {
- match &*path.ident.name.as_str() {
+ match path.ident.name.as_str() {
"ln" => check_ln1p(cx, expr, args),
"log" => check_log_base(cx, expr, args),
"powf" => check_powf(cx, expr, args),