-
-
Notifications
You must be signed in to change notification settings - Fork 472
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(linter): implement unicorn/no-negation-in-equality-check (#4034)
Fixes #3869 Hey there, thought I'd give this a try as it's tagged "good first issue" :) Let me know if there's anything that needs to change, I wasn't sure about the rule category so left as TODO.
- Loading branch information
Showing
3 changed files
with
230 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
135 changes: 135 additions & 0 deletions
135
crates/oxc_linter/src/rules/unicorn/no_negation_in_equality_check.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,135 @@ | ||
use oxc_ast::{ast::Expression, AstKind}; | ||
use oxc_diagnostics::OxcDiagnostic; | ||
use oxc_macros::declare_oxc_lint; | ||
use oxc_span::Span; | ||
use oxc_syntax::operator::{BinaryOperator, UnaryOperator}; | ||
|
||
use crate::{context::LintContext, rule::Rule, AstNode}; | ||
|
||
fn no_negation_in_equality_check_diagnostic( | ||
span0: Span, | ||
current_operator: BinaryOperator, | ||
suggested_operator: BinaryOperator, | ||
) -> OxcDiagnostic { | ||
OxcDiagnostic::warn( | ||
"eslint-plugin-unicorn(no-negation-in-equality-check): Negated expression is not allowed in equality check.", | ||
) | ||
.with_help(format!("Remove the negation operator and use '{}' instead of '{}'.", suggested_operator.as_str(), current_operator.as_str())) | ||
.with_label(span0) | ||
} | ||
|
||
#[derive(Debug, Default, Clone)] | ||
pub struct NoNegationInEqualityCheck; | ||
|
||
declare_oxc_lint!( | ||
/// ### What it does | ||
/// | ||
/// Disallow negated expressions on the left of (in)equality checks. | ||
/// | ||
/// ### Why is this bad? | ||
/// | ||
/// A negated expression on the left of an (in)equality check is likely a mistake from trying to negate the whole condition. | ||
/// | ||
/// ### Example | ||
/// ```javascript | ||
/// // Bad | ||
/// | ||
/// if (!foo === bar) {} | ||
/// | ||
/// if (!foo !== bar) {} | ||
/// | ||
/// // Good | ||
/// | ||
/// if (foo !== bar) {} | ||
/// | ||
/// if (!(foo === bar)) {} | ||
/// ``` | ||
NoNegationInEqualityCheck, | ||
correctness, | ||
); | ||
|
||
impl Rule for NoNegationInEqualityCheck { | ||
fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) { | ||
if let AstKind::BinaryExpression(binary_expr) = node.kind() { | ||
let Expression::UnaryExpression(left_unary_expr) = &binary_expr.left else { | ||
return; | ||
}; | ||
|
||
if left_unary_expr.operator != UnaryOperator::LogicalNot { | ||
return; | ||
} | ||
|
||
if let Expression::UnaryExpression(left_nested_unary_expr) = &left_unary_expr.argument { | ||
if left_nested_unary_expr.operator == UnaryOperator::LogicalNot { | ||
return; | ||
} | ||
} | ||
|
||
if !binary_expr.operator.is_equality() { | ||
return; | ||
} | ||
|
||
let Some(suggested_operator) = binary_expr.operator.equality_inverse_operator() else { | ||
return; | ||
}; | ||
|
||
ctx.diagnostic(no_negation_in_equality_check_diagnostic( | ||
left_unary_expr.span, | ||
binary_expr.operator, | ||
suggested_operator, | ||
)); | ||
} | ||
} | ||
} | ||
|
||
#[test] | ||
fn test() { | ||
use crate::tester::Tester; | ||
|
||
let pass = vec![ | ||
"!foo instanceof bar", | ||
"+foo === bar", | ||
"!(foo === bar)", | ||
"!!foo === bar", | ||
"!!!foo === bar", | ||
"foo === !bar", | ||
]; | ||
|
||
let fail = vec![ | ||
"!foo === bar", | ||
"!foo !== bar", | ||
"!foo == bar", | ||
"!foo != bar", | ||
" | ||
function x() { | ||
return!foo === bar; | ||
} | ||
", | ||
" | ||
function x() { | ||
return! | ||
foo === bar; | ||
throw! | ||
foo === bar; | ||
} | ||
", | ||
" | ||
foo | ||
!(a) === b | ||
", | ||
" | ||
foo | ||
![a, b].join('') === c | ||
", | ||
" | ||
foo | ||
! [a, b].join('') === c | ||
", | ||
" | ||
foo | ||
!/* comment */[a, b].join('') === c | ||
", | ||
]; | ||
|
||
Tester::new(NoNegationInEqualityCheck::NAME, pass, fail).test_and_snapshot(); | ||
} |
93 changes: 93 additions & 0 deletions
93
crates/oxc_linter/src/snapshots/no_negation_in_equality_check.snap
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
--- | ||
source: crates/oxc_linter/src/tester.rs | ||
--- | ||
⚠ eslint-plugin-unicorn(no-negation-in-equality-check): Negated expression is not allowed in equality check. | ||
╭─[no_negation_in_equality_check.tsx:1:1] | ||
1 │ !foo === bar | ||
· ──── | ||
╰──── | ||
help: Remove the negation operator and use '!==' instead of '==='. | ||
|
||
⚠ eslint-plugin-unicorn(no-negation-in-equality-check): Negated expression is not allowed in equality check. | ||
╭─[no_negation_in_equality_check.tsx:1:1] | ||
1 │ !foo !== bar | ||
· ──── | ||
╰──── | ||
help: Remove the negation operator and use '===' instead of '!=='. | ||
|
||
⚠ eslint-plugin-unicorn(no-negation-in-equality-check): Negated expression is not allowed in equality check. | ||
╭─[no_negation_in_equality_check.tsx:1:1] | ||
1 │ !foo == bar | ||
· ──── | ||
╰──── | ||
help: Remove the negation operator and use '!=' instead of '=='. | ||
|
||
⚠ eslint-plugin-unicorn(no-negation-in-equality-check): Negated expression is not allowed in equality check. | ||
╭─[no_negation_in_equality_check.tsx:1:1] | ||
1 │ !foo != bar | ||
· ──── | ||
╰──── | ||
help: Remove the negation operator and use '==' instead of '!='. | ||
|
||
⚠ eslint-plugin-unicorn(no-negation-in-equality-check): Negated expression is not allowed in equality check. | ||
╭─[no_negation_in_equality_check.tsx:3:14] | ||
2 │ function x() { | ||
3 │ return!foo === bar; | ||
· ──── | ||
4 │ } | ||
╰──── | ||
help: Remove the negation operator and use '!==' instead of '==='. | ||
|
||
⚠ eslint-plugin-unicorn(no-negation-in-equality-check): Negated expression is not allowed in equality check. | ||
╭─[no_negation_in_equality_check.tsx:3:14] | ||
2 │ function x() { | ||
3 │ ╭─▶ return! | ||
4 │ ╰─▶ foo === bar; | ||
5 │ throw! | ||
╰──── | ||
help: Remove the negation operator and use '!==' instead of '==='. | ||
|
||
⚠ eslint-plugin-unicorn(no-negation-in-equality-check): Negated expression is not allowed in equality check. | ||
╭─[no_negation_in_equality_check.tsx:5:13] | ||
4 │ foo === bar; | ||
5 │ ╭─▶ throw! | ||
6 │ ╰─▶ foo === bar; | ||
7 │ } | ||
╰──── | ||
help: Remove the negation operator and use '!==' instead of '==='. | ||
|
||
⚠ eslint-plugin-unicorn(no-negation-in-equality-check): Negated expression is not allowed in equality check. | ||
╭─[no_negation_in_equality_check.tsx:3:7] | ||
2 │ foo | ||
3 │ !(a) === b | ||
· ──── | ||
4 │ | ||
╰──── | ||
help: Remove the negation operator and use '!==' instead of '==='. | ||
|
||
⚠ eslint-plugin-unicorn(no-negation-in-equality-check): Negated expression is not allowed in equality check. | ||
╭─[no_negation_in_equality_check.tsx:3:7] | ||
2 │ foo | ||
3 │ ![a, b].join('') === c | ||
· ──────────────── | ||
4 │ | ||
╰──── | ||
help: Remove the negation operator and use '!==' instead of '==='. | ||
|
||
⚠ eslint-plugin-unicorn(no-negation-in-equality-check): Negated expression is not allowed in equality check. | ||
╭─[no_negation_in_equality_check.tsx:3:7] | ||
2 │ foo | ||
3 │ ! [a, b].join('') === c | ||
· ───────────────── | ||
4 │ | ||
╰──── | ||
help: Remove the negation operator and use '!==' instead of '==='. | ||
|
||
⚠ eslint-plugin-unicorn(no-negation-in-equality-check): Negated expression is not allowed in equality check. | ||
╭─[no_negation_in_equality_check.tsx:3:7] | ||
2 │ foo | ||
3 │ !/* comment */[a, b].join('') === c | ||
· ───────────────────────────── | ||
4 │ | ||
╰──── | ||
help: Remove the negation operator and use '!==' instead of '==='. |