perf(linter/eslint/no-compare-neg-zero): narrow no-compare-neg-zero dispatch (#28352)

Inspect comparisons from unary expressions while preserving TypeScript
wrappers and one diagnostic per comparison. Reduce fixture callbacks
from 20,604 to 9,106.


---

<sub>Stack created with <a
href="https://github.com/github/gh-stack">GitHub Stacks CLI</a> • <a
href="https://gh.io/stacks-feedback">Give Feedback 💬</a></sub>

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
Cam McHenryandCopilot authored and GitHub committed 2026-10-28 22:28:45 -04:00
1 parent 56c99c6fe7
commit 483c4c955a
4 files changed
+45 -9

No files matched your search

+1 -1
View File
@@ -523,7 +523,7 @@ impl RuleRunner for crate::rules::eslint::no_class_assign::NoClassAssign {
impl RuleRunner for crate::rules::eslint::no_compare_neg_zero::NoCompareNegZero {
const NODE_TYPES: Option<&AstTypesBitset> =
Some(&AstTypesBitset::from_types(&[AstType::BinaryExpression]));
Some(&AstTypesBitset::from_types(&[AstType::UnaryExpression]));
const RUN_FUNCTIONS: RuleRunFunctionsImplemented = RuleRunFunctionsImplemented::Run;
}
@@ -4,7 +4,7 @@ use oxc_macros::declare_oxc_lint;
use oxc_span::{GetSpan, Span};
use oxc_syntax::operator::{BinaryOperator, UnaryOperator};
use crate::{AstNode, context::LintContext, rule::Rule};
use crate::{AstNode, ast_util::iter_outer_expressions, context::LintContext, rule::Rule};
fn no_compare_neg_zero_diagnostic(operator: &str, span: Span) -> OxcDiagnostic {
OxcDiagnostic::warn(format!("Do not use the {operator} operator to compare against -0."))
@@ -70,7 +70,15 @@ declare_oxc_lint!(
impl Rule for NoCompareNegZero {
fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) {
let AstKind::BinaryExpression(expr) = node.kind() else {
let AstKind::UnaryExpression(unary) = node.kind() else {
return;
};
if unary.operator != UnaryOperator::UnaryNegation {
return;
}
let Some(AstKind::BinaryExpression(expr)) =
iter_outer_expressions(ctx.nodes(), node.id()).next()
else {
return;
};
if Self::should_check(expr.operator) {
@@ -78,6 +86,15 @@ impl Rule for NoCompareNegZero {
let is_left_neg_zero = is_neg_zero(&expr.left);
let is_right_neg_zero = is_neg_zero(&expr.right);
if is_left_neg_zero || is_right_neg_zero {
let neg_zero = if is_left_neg_zero {
expr.left.get_inner_expression()
} else {
expr.right.get_inner_expression()
};
// When both operands are negative zero, report only from the left operand.
if neg_zero.span() != unary.span {
return;
}
if expr.operator == BinaryOperator::StrictEquality {
ctx.diagnostic_with_suggestion(
no_compare_neg_zero_diagnostic(op, expr.span),
@@ -99,11 +116,6 @@ impl Rule for NoCompareNegZero {
ctx.diagnostic_with_fix(
no_compare_neg_zero_diagnostic(op, expr.span),
|fixer| {
let neg_zero = if is_left_neg_zero {
expr.left.get_inner_expression()
} else {
expr.right.get_inner_expression()
};
let start = neg_zero.span().start;
let span = Span::new(start, start + 1);
fixer.delete(&span)
@@ -167,6 +179,9 @@ fn test() {
("x !== 0", None),
("0 !== x", None),
("Object.is(x, -0)", None),
("x === -(-0)", None),
("x === -(0)", None),
("-0 + x", None),
];
let fail = vec![
@@ -184,6 +199,8 @@ fn test() {
("-0 <= x", None),
// BigInt Literal
("-0n <= x", None),
("-0 === -0", None),
("(-0 as number) < (-0 satisfies number)", None),
];
let fix = vec![
@@ -205,6 +222,11 @@ fn test() {
("x <= (-0n)", "x <= (0n)", None),
("x > (-0 as number)", "x > (0 as number)", None),
("(-0 satisfies number) > x", "(0 satisfies number) > x", None),
("-0 === -0", "Object.is(-0, -0)", None),
("-0 < -0", "0 < -0", None),
("-0n <= -0n", "0n <= -0n", None),
("-1 > -0", "-1 > 0", None),
("(-0 as number) < (-0 satisfies number)", "(0 as number) < (-0 satisfies number)", None),
];
Tester::new(NoCompareNegZero::NAME, NoCompareNegZero::PLUGIN, pass, fail)
@@ -92,3 +92,17 @@ source: crates/oxc_linter/src/tester.rs
· ────────
╰────
help: Use Object.is(x, -0) to test equality with -0 and use 0 for other cases
⚠ eslint(no-compare-neg-zero): Do not use the === operator to compare against -0.
╭─[no_compare_neg_zero.tsx:1:1]
1 │ -0 === -0
· ─────────
╰────
help: Use Object.is(x, -0) to test equality with -0 and use 0 for other cases
⚠ eslint(no-compare-neg-zero): Do not use the < operator to compare against -0.
╭─[no_compare_neg_zero.tsx:1:1]
1 │ (-0 as number) < (-0 satisfies number)
· ──────────────────────────────────────
╰────
help: Use Object.is(x, -0) to test equality with -0 and use 0 for other cases
@@ -39,7 +39,7 @@ eslint/no-bitwise | 42715
eslint/no-caller | 76337
eslint/no-case-declarations | 2320
eslint/no-class-assign | 300
eslint/no-compare-neg-zero | 20604
eslint/no-compare-neg-zero | 9106
eslint/no-cond-assign | 31699
eslint/no-console | 95297
eslint/no-const-assign | 37499