diff --git a/clippy_lints/src/floating_point_arithmetic.rs b/clippy_lints/src/floating_point_arithmetic.rs index 46a2396fcd12..8d580c714885 100644 --- a/clippy_lints/src/floating_point_arithmetic.rs +++ b/clippy_lints/src/floating_point_arithmetic.rs @@ -234,6 +234,38 @@ fn check_expm1(cx: &LateContext<'_, '_>, expr: &Expr) { } } +// Expressions are considered equivalent if they are constant and evaluate to the +// same value or if they refer to the same variable. +fn are_exprs_equivalent(cx: &LateContext<'_, '_>, left: &Expr, right: &Expr) -> bool { + // Checks whether the values are constant and equal + if_chain! { + if let Some((left_value, _)) = constant(cx, cx.tables, left); + if let Some((right_value, _)) = constant(cx, cx.tables, right); + if left_value == right_value; + then { + return true; + } + } + + // Checks whether the values are the same variable + if_chain! { + if let ExprKind::Path(ref left_qpath) = left.kind; + if let QPath::Resolved(_, ref left_path) = *left_qpath; + if left_path.segments.len() == 1; + if let def::Res::Local(left_local_id) = qpath_res(cx, left_qpath, left.hir_id); + if let ExprKind::Path(ref right_qpath) = right.kind; + if let QPath::Resolved(_, ref right_path) = *right_qpath; + if right_path.segments.len() == 1; + if let def::Res::Local(right_local_id) = qpath_res(cx, right_qpath, right.hir_id); + if left_local_id == right_local_id; + then { + return true; + } + } + + false +} + fn check_log_division(cx: &LateContext<'_, '_>, expr: &Expr) { let log_methods = ["log", "log2", "log10", "ln"]; @@ -250,32 +282,9 @@ fn check_log_division(cx: &LateContext<'_, '_>, expr: &Expr) { let left_recv = &left_args[0]; let right_recv = &right_args[0]; - if left_method == "log" { - if_chain! { - // Checks whether the bases are constant and equal - if let Some((numerator_base, _)) = constant(cx, cx.tables, &left_args[1]); - if let Some((denominator_base, _)) = constant(cx, cx.tables, &right_args[1]); - if numerator_base == denominator_base; - then { } - else { - if_chain! { - // Checks whether the bases are the same variable - if let ExprKind::Path(ref left_base_qpath) = &left_args[1].kind; - if let QPath::Resolved(_, ref left_base_path) = *left_base_qpath; - if left_base_path.segments.len() == 1; - if let def::Res::Local(left_local_id) = qpath_res(cx, left_base_qpath, expr.hir_id); - if let ExprKind::Path(ref right_base_qpath) = &right_args[1].kind; - if let QPath::Resolved(_, ref right_base_path) = *right_base_qpath; - if right_base_path.segments.len() == 1; - if let def::Res::Local(right_local_id) = qpath_res(cx, right_base_qpath, expr.hir_id); - if left_local_id == right_local_id; - then { } - else { - return; - } - } - } - } + // Return early when bases are not equal + if left_method == "log" && !are_exprs_equivalent(cx, &left_args[1], &right_args[1]) { + return; } // Reduce the expression further for bases 2, 10 and e @@ -293,7 +302,7 @@ fn check_log_division(cx: &LateContext<'_, '_>, expr: &Expr) { cx, FLOATING_POINT_IMPROVEMENTS, expr.span, - "x.log(b) / y.log(b) can be expressed more succinctly", + "x.log(b) / y.log(b) can be reduced to x.log(y)", "consider using", suggestion, Applicability::MachineApplicable, diff --git a/tests/ui/floating_point_arithmetic.stderr b/tests/ui/floating_point_arithmetic.stderr index 249bd559be63..076b8d4fefe6 100644 --- a/tests/ui/floating_point_arithmetic.stderr +++ b/tests/ui/floating_point_arithmetic.stderr @@ -192,73 +192,73 @@ error: (e.pow(x) - 1) can be computed more accurately LL | let _ = x.exp() - 1.0 + 2.0; | ^^^^^^^^^^^^^ help: consider using: `x.exp_m1()` -error: x.log(b) / y.log(b) can be expressed more succinctly +error: x.log(b) / y.log(b) can be reduced to x.log(y) --> $DIR/floating_point_arithmetic.rs:90:13 | LL | let _ = x.log2() / y.log2(); | ^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log(y)` -error: x.log(b) / y.log(b) can be expressed more succinctly +error: x.log(b) / y.log(b) can be reduced to x.log(y) --> $DIR/floating_point_arithmetic.rs:91:13 | LL | let _ = x.log10() / y.log10(); | ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log(y)` -error: x.log(b) / y.log(b) can be expressed more succinctly +error: x.log(b) / y.log(b) can be reduced to x.log(y) --> $DIR/floating_point_arithmetic.rs:92:13 | LL | let _ = x.ln() / y.ln(); | ^^^^^^^^^^^^^^^ help: consider using: `x.log(y)` -error: x.log(b) / y.log(b) can be expressed more succinctly +error: x.log(b) / y.log(b) can be reduced to x.log(y) --> $DIR/floating_point_arithmetic.rs:93:13 | LL | let _ = x.log(4.0) / y.log(4.0); | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log(y)` -error: x.log(b) / y.log(b) can be expressed more succinctly +error: x.log(b) / y.log(b) can be reduced to x.log(y) --> $DIR/floating_point_arithmetic.rs:94:13 | LL | let _ = x.log(b) / y.log(b); | ^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log(y)` -error: x.log(b) / y.log(b) can be expressed more succinctly +error: x.log(b) / y.log(b) can be reduced to x.log(y) --> $DIR/floating_point_arithmetic.rs:96:13 | LL | let _ = x.log(b) / 2f32.log(b); | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log2()` -error: x.log(b) / y.log(b) can be expressed more succinctly +error: x.log(b) / y.log(b) can be reduced to x.log(y) --> $DIR/floating_point_arithmetic.rs:102:13 | LL | let _ = x.log2() / y.log2(); | ^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log(y)` -error: x.log(b) / y.log(b) can be expressed more succinctly +error: x.log(b) / y.log(b) can be reduced to x.log(y) --> $DIR/floating_point_arithmetic.rs:103:13 | LL | let _ = x.log10() / y.log10(); | ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log(y)` -error: x.log(b) / y.log(b) can be expressed more succinctly +error: x.log(b) / y.log(b) can be reduced to x.log(y) --> $DIR/floating_point_arithmetic.rs:104:13 | LL | let _ = x.ln() / y.ln(); | ^^^^^^^^^^^^^^^ help: consider using: `x.log(y)` -error: x.log(b) / y.log(b) can be expressed more succinctly +error: x.log(b) / y.log(b) can be reduced to x.log(y) --> $DIR/floating_point_arithmetic.rs:105:13 | LL | let _ = x.log(4.0) / y.log(4.0); | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log(y)` -error: x.log(b) / y.log(b) can be expressed more succinctly +error: x.log(b) / y.log(b) can be reduced to x.log(y) --> $DIR/floating_point_arithmetic.rs:106:13 | LL | let _ = x.log(b) / y.log(b); | ^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log(y)` -error: x.log(b) / y.log(b) can be expressed more succinctly +error: x.log(b) / y.log(b) can be reduced to x.log(y) --> $DIR/floating_point_arithmetic.rs:108:13 | LL | let _ = x.log(b) / 2f64.log(b);