1 use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
2 use clippy_utils::macros::{find_assert_eq_args, first_node_macro_backtrace};
3 use clippy_utils::{ast_utils::is_useless_with_eq_exprs, eq_expr_value, is_in_test_function};
4 use rustc_hir::{BinOpKind, Expr};
5 use rustc_lint::LateContext;
6
7 use super::EQ_OP;
8
check_assert<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>)9 pub(crate) fn check_assert<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
10 if let Some((macro_call, macro_name))
11 = first_node_macro_backtrace(cx, e).find_map(|macro_call| {
12 let name = cx.tcx.item_name(macro_call.def_id);
13 matches!(name.as_str(), "assert_eq" | "assert_ne" | "debug_assert_eq" | "debug_assert_ne")
14 .then(|| (macro_call, name))
15 })
16 && let Some((lhs, rhs, _)) = find_assert_eq_args(cx, e, macro_call.expn)
17 && eq_expr_value(cx, lhs, rhs)
18 && macro_call.is_local()
19 && !is_in_test_function(cx.tcx, e.hir_id)
20 {
21 span_lint(
22 cx,
23 EQ_OP,
24 lhs.span.to(rhs.span),
25 &format!("identical args used in this `{macro_name}!` macro call"),
26 );
27 }
28 }
29
check<'tcx>( cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, op: BinOpKind, left: &'tcx Expr<'_>, right: &'tcx Expr<'_>, )30 pub(crate) fn check<'tcx>(
31 cx: &LateContext<'tcx>,
32 e: &'tcx Expr<'_>,
33 op: BinOpKind,
34 left: &'tcx Expr<'_>,
35 right: &'tcx Expr<'_>,
36 ) {
37 if is_useless_with_eq_exprs(op.into()) && eq_expr_value(cx, left, right) && !is_in_test_function(cx.tcx, e.hir_id) {
38 span_lint_and_then(
39 cx,
40 EQ_OP,
41 e.span,
42 &format!("equal expressions as operands to `{}`", op.as_str()),
43 |diag| {
44 if let BinOpKind::Ne = op && cx.typeck_results().expr_ty(left).is_floating_point() {
45 diag.note("if you intended to check if the operand is NaN, use `.is_nan()` instead");
46 }
47 },
48 );
49 }
50 }
51