oxc-project/oxc · warning · OxcDiagnostic

Both sides of this comparison are exactly the same

Error message

Both sides of this comparison are exactly the same

What it means

oxlint's port of ESLint `no-self-compare`. It flags comparisons whose left and right operands are structurally identical (`x === x`), checked with AST content equality (ContentEq). The only result of `x === x` is `true` — or `false` when x is NaN — so the help text points at `Number.isNaN()` as the intended check.

Source

Thrown at crates/oxc_linter/src/rules/eslint/no_self_compare.rs:9

use oxc_ast::AstKind;
use oxc_diagnostics::OxcDiagnostic;
use oxc_macros::declare_oxc_lint;
use oxc_span::{ContentEq, GetSpan, Span};

use crate::{AstNode, context::LintContext, rule::Rule};

fn no_self_compare_diagnostic(left_span: Span, right_span: Span) -> OxcDiagnostic {
    OxcDiagnostic::warn("Both sides of this comparison are exactly the same")
        .with_help("If you are testing for NaN, you can use the `Number.isNaN()` function.")
        .with_labels([left_span, right_span])
}

#[derive(Debug, Default, Clone)]
pub struct NoSelfCompare;

declare_oxc_lint!(
    /// ### What it does
    ///
    /// Disallow comparisons where both sides are exactly the same.
    ///
    /// ### Why is this bad?
    ///
    /// Comparing a variable against itself is usually an error, either a typo or refactoring error.
    /// It is confusing to the reader and may potentially introduce a runtime error.
    ///
    /// ### Examples

View on GitHub (pinned to e1e7af627c)

Solutions

  1. For NaN detection use `Number.isNaN(x)`.
  2. Otherwise correct the operand that should differ (`x === y`).
  3. Remove the comparison if it is dead logic that always evaluates to true.

Example fix

// before
if (value === value) { /* skip NaN */ }

// after
if (!Number.isNaN(value)) { /* skip NaN */ }
Defensive patterns

Strategy: type-guard

Validate before calling

// Reject self-comparisons before they ship (simple identifier form)
function hasSelfCompare(src) {
  return /([A-Za-z_$][\w$.]*)\s*(?:===|!==|==|!=)\s*\1(?![\w$])/.test(src);
}

Type guard

// Correct way to express the intent this rule guesses at:
function isNotNaN(value) {
  return typeof value === 'number' && !Number.isNaN(value);
}
// use: if (isNotNaN(x)) { ... } instead of if (x === x)

Prevention

When it happens

Trigger: `if (x === x)`, `a !== a` (NaN test), `obj.value === obj.value`; both labels are attached, one per operand span.

Common situations: Hand-rolled NaN checks predating `Number.isNaN`; template/copy-paste comparisons where both sides were meant to differ; refactors that replaced one identifier with the wrong twin.

Related errors


AI-assisted analysis of oxc-project/oxc@e1e7af627c (2026-08-20). Data as JSON: /api/errors/5f522c9a2bba228a. Report an issue: GitHub.