From 02bf011a7debf0c9e7385d3d6105ffce16e96fc8 Mon Sep 17 00:00:00 2001 From: klensy Date: Sat, 14 Dec 2024 18:45:03 +0300 Subject: [PATCH 1/2] eq_op: allow optionally check for call fn --- clippy_config/src/conf.rs | 3 +++ clippy_lints/src/operators/eq_op.rs | 20 ++++++++++++++++---- clippy_lints/src/operators/mod.rs | 6 ++++-- clippy_utils/src/hir_utils.rs | 5 +++++ clippy_utils/src/lib.rs | 3 ++- 5 files changed, 30 insertions(+), 7 deletions(-) diff --git a/clippy_config/src/conf.rs b/clippy_config/src/conf.rs index 41b56b45d9ae..ee4727cb77ac 100644 --- a/clippy_config/src/conf.rs +++ b/clippy_config/src/conf.rs @@ -454,6 +454,9 @@ define_Conf! { /// For internal testing only, ignores the current `publish` settings in the Cargo manifest. #[lints(cargo_common_metadata)] cargo_ignore_publish: bool = false, + /// Check fn calls in eq_op lint + #[lints(expect_used)] + check_fn_call_in_eq_op: bool = false, /// Whether to also run the listed lints on private items. #[lints(missing_errors_doc, missing_panics_doc, missing_safety_doc, unnecessary_safety_doc)] check_private_items: bool = false, diff --git a/clippy_lints/src/operators/eq_op.rs b/clippy_lints/src/operators/eq_op.rs index 1421893274f5..6985aa0f27d6 100644 --- a/clippy_lints/src/operators/eq_op.rs +++ b/clippy_lints/src/operators/eq_op.rs @@ -1,13 +1,13 @@ use clippy_utils::ast_utils::is_useless_with_eq_exprs; use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; use clippy_utils::macros::{find_assert_eq_args, first_node_macro_backtrace}; -use clippy_utils::{eq_expr_value, is_in_test_function}; +use clippy_utils::{eq_expr_value, eq_expr_value_with_sideffects, is_in_test_function}; use rustc_hir::{BinOpKind, Expr}; use rustc_lint::LateContext; use super::EQ_OP; -pub(crate) fn check_assert<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { +pub(crate) fn check_assert<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, with_sideffects: bool) { if let Some((macro_call, macro_name)) = first_node_macro_backtrace(cx, e).find_map(|macro_call| { let name = cx.tcx.item_name(macro_call.def_id); matches!( @@ -16,7 +16,11 @@ pub(crate) fn check_assert<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { ) .then(|| (macro_call, name)) }) && let Some((lhs, rhs, _)) = find_assert_eq_args(cx, e, macro_call.expn) - && eq_expr_value(cx, lhs, rhs) + && if with_sideffects { + eq_expr_value_with_sideffects(cx, lhs, rhs) + } else { + eq_expr_value(cx, lhs, rhs) + } && macro_call.is_local() && !is_in_test_function(cx.tcx, e.hir_id) { @@ -35,8 +39,16 @@ pub(crate) fn check<'tcx>( op: BinOpKind, left: &'tcx Expr<'_>, right: &'tcx Expr<'_>, + with_sideffects: bool, ) { - if is_useless_with_eq_exprs(op) && eq_expr_value(cx, left, right) && !is_in_test_function(cx.tcx, e.hir_id) { + if is_useless_with_eq_exprs(op) + && if with_sideffects { + eq_expr_value_with_sideffects(cx, left, right) + } else { + eq_expr_value(cx, left, right) + } + && !is_in_test_function(cx.tcx, e.hir_id) + { span_lint_and_then( cx, EQ_OP, diff --git a/clippy_lints/src/operators/mod.rs b/clippy_lints/src/operators/mod.rs index 9e8a821c3f4e..f1091558dc75 100644 --- a/clippy_lints/src/operators/mod.rs +++ b/clippy_lints/src/operators/mod.rs @@ -841,6 +841,7 @@ pub struct Operators { arithmetic_context: numeric_arithmetic::Context, verbose_bit_mask_threshold: u64, modulo_arithmetic_allow_comparison_to_zero: bool, + check_fn_call_in_eq_op: bool, } impl Operators { pub fn new(conf: &'static Conf) -> Self { @@ -848,6 +849,7 @@ impl Operators { arithmetic_context: numeric_arithmetic::Context::default(), verbose_bit_mask_threshold: conf.verbose_bit_mask_threshold, modulo_arithmetic_allow_comparison_to_zero: conf.allow_comparison_to_zero, + check_fn_call_in_eq_op: conf.check_fn_call_in_eq_op, } } } @@ -883,13 +885,13 @@ impl_lint_pass!(Operators => [ impl<'tcx> LateLintPass<'tcx> for Operators { fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { - eq_op::check_assert(cx, e); + eq_op::check_assert(cx, e, self.check_fn_call_in_eq_op); match e.kind { ExprKind::Binary(op, lhs, rhs) => { if !e.span.from_expansion() { absurd_extreme_comparisons::check(cx, e, op.node, lhs, rhs); if !(macro_with_not_op(lhs) || macro_with_not_op(rhs)) { - eq_op::check(cx, e, op.node, lhs, rhs); + eq_op::check(cx, e, op.node, lhs, rhs, self.check_fn_call_in_eq_op); op_ref::check(cx, e, op.node, lhs, rhs); } erasing_op::check(cx, e, op.node, lhs, rhs); diff --git a/clippy_utils/src/hir_utils.rs b/clippy_utils/src/hir_utils.rs index 8a88a24e924c..204584278278 100644 --- a/clippy_utils/src/hir_utils.rs +++ b/clippy_utils/src/hir_utils.rs @@ -752,6 +752,11 @@ pub fn eq_expr_value(cx: &LateContext<'_>, left: &Expr<'_>, right: &Expr<'_>) -> SpanlessEq::new(cx).deny_side_effects().eq_expr(left, right) } +/// Checks if two expressions evaluate to the same value, ignoring side effects. +pub fn eq_expr_value_with_sideffects(cx: &LateContext<'_>, left: &Expr<'_>, right: &Expr<'_>) -> bool { + SpanlessEq::new(cx).eq_expr(left, right) +} + /// Returns the segments of a path that might have generic parameters. /// Usually just the last segment for free items, except for when the path resolves to an associated /// item, in which case it is the last two diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 434c26d687d7..76715a40abfd 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -81,7 +81,8 @@ pub mod visitors; pub use self::attrs::*; pub use self::check_proc_macro::{is_from_proc_macro, is_span_if, is_span_match}; pub use self::hir_utils::{ - HirEqInterExpr, SpanlessEq, SpanlessHash, both, count_eq, eq_expr_value, hash_expr, hash_stmt, is_bool, over, + HirEqInterExpr, SpanlessEq, SpanlessHash, both, count_eq, eq_expr_value, eq_expr_value_with_sideffects, hash_expr, + hash_stmt, is_bool, over, }; use core::mem; From fb2489678099d97dc6e26460a3d76e11267f6791 Mon Sep 17 00:00:00 2001 From: klensy Date: Sat, 14 Dec 2024 18:45:37 +0300 Subject: [PATCH 2/2] [dont merge] turn on --- clippy_config/src/conf.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_config/src/conf.rs b/clippy_config/src/conf.rs index ee4727cb77ac..fafb0f8f8820 100644 --- a/clippy_config/src/conf.rs +++ b/clippy_config/src/conf.rs @@ -456,7 +456,7 @@ define_Conf! { cargo_ignore_publish: bool = false, /// Check fn calls in eq_op lint #[lints(expect_used)] - check_fn_call_in_eq_op: bool = false, + check_fn_call_in_eq_op: bool = true, /// Whether to also run the listed lints on private items. #[lints(missing_errors_doc, missing_panics_doc, missing_safety_doc, unnecessary_safety_doc)] check_private_items: bool = false,