feat(es/lints): Implement no-compare-neg-zero rule (#4643)

This commit is contained in:
Artur 2022-05-12 23:19:18 +03:00 committed by GitHub
parent 0b35b047bf
commit f45dd72033
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 196 additions and 0 deletions

View File

@ -0,0 +1,9 @@
{
"jsc": {
"lints": {
"no-compare-neg-zero": [
"error"
]
}
}
}

View File

@ -0,0 +1,16 @@
x === -0;
-0 === x;
x == -0;
-0 == x;
x > -0;
-0 > x;
x >= -0;
-0 >= x;
x < -0;
-0 < x;
x <= -0;
-0 <= x;
-0 === -0
x == '-0'
Object.is(x, -0)

View File

@ -0,0 +1,78 @@
x Do not use the '===' to compare against -0
,----
1 | x === -0;
: ^^^^^^^^
`----
x Do not use the '===' to compare against -0
,----
2 | -0 === x;
: ^^^^^^^^
`----
x Do not use the '==' to compare against -0
,----
3 | x == -0;
: ^^^^^^^
`----
x Do not use the '==' to compare against -0
,----
4 | -0 == x;
: ^^^^^^^
`----
x Do not use the '>' to compare against -0
,----
5 | x > -0;
: ^^^^^^
`----
x Do not use the '>' to compare against -0
,----
6 | -0 > x;
: ^^^^^^
`----
x Do not use the '>=' to compare against -0
,----
7 | x >= -0;
: ^^^^^^^
`----
x Do not use the '>=' to compare against -0
,----
8 | -0 >= x;
: ^^^^^^^
`----
x Do not use the '<' to compare against -0
,----
9 | x < -0;
: ^^^^^^
`----
x Do not use the '<' to compare against -0
,----
10 | -0 < x;
: ^^^^^^
`----
x Do not use the '<=' to compare against -0
,----
11 | x <= -0;
: ^^^^^^^
`----
x Do not use the '<=' to compare against -0
,----
12 | -0 <= x;
: ^^^^^^^
`----
x Do not use the '===' to compare against -0
,----
13 | -0 === -0
: ^^^^^^^^^
`----

View File

@ -191,4 +191,8 @@ pub struct LintConfig {
#[cfg(feature = "non_critical_lints")]
#[serde(default, alias = "preferConst")]
pub prefer_const: RuleConfig<()>,
#[cfg(feature = "non_critical_lints")]
#[serde(default, alias = "noCompareNegZero")]
pub no_compare_neg_zero: RuleConfig<()>,
}

View File

@ -20,6 +20,7 @@ pub(crate) mod non_critical_lints {
pub mod eqeqeq;
pub mod no_alert;
pub mod no_bitwise;
pub mod no_compare_neg_zero;
pub mod no_console;
pub mod no_debugger;
pub mod no_empty_function;
@ -166,6 +167,10 @@ pub fn all(lint_params: LintParams) -> Vec<Box<dyn Rule>> {
rules.extend(no_var::no_var(&lint_config.no_var));
rules.extend(prefer_const::prefer_const(&lint_config.prefer_const));
rules.extend(no_compare_neg_zero::no_compare_neg_zero(
&lint_config.no_compare_neg_zero,
));
}
rules

View File

@ -0,0 +1,84 @@
use swc_common::{errors::HANDLER, Span};
use swc_ecma_ast::*;
use swc_ecma_visit::{Visit, VisitWith};
use crate::{
config::{LintRuleReaction, RuleConfig},
rule::{visitor_rule, Rule},
rules::utils::unwrap_seqs_and_parens,
};
pub fn no_compare_neg_zero(config: &RuleConfig<()>) -> Option<Box<dyn Rule>> {
let rule_reaction = config.get_rule_reaction();
match rule_reaction {
LintRuleReaction::Off => None,
_ => Some(visitor_rule(NoCompareNegZero::new(rule_reaction))),
}
}
#[derive(Debug, Default)]
struct NoCompareNegZero {
expected_reaction: LintRuleReaction,
}
impl NoCompareNegZero {
fn new(expected_reaction: LintRuleReaction) -> Self {
Self { expected_reaction }
}
fn emit_report(&self, op: BinaryOp, span: Span) {
let message = format!("Do not use the '{}' to compare against -0", op);
HANDLER.with(|handler| match self.expected_reaction {
LintRuleReaction::Error => {
handler.struct_span_err(span, &message).emit();
}
LintRuleReaction::Warning => {
handler.struct_span_warn(span, &message).emit();
}
_ => {}
});
}
fn is_neg_zero(&self, expr: &Expr) -> bool {
if let Expr::Unary(UnaryExpr {
op: op!(unary, "-"),
arg,
..
}) = unwrap_seqs_and_parens(expr)
{
if let Expr::Lit(Lit::Num(Number { value, .. })) = unwrap_seqs_and_parens(arg.as_ref())
{
return *value == 0f64;
}
}
false
}
fn check(&self, bin_expr: &BinExpr) {
if let op!("===")
| op!("==")
| op!("!==")
| op!("!=")
| op!("<")
| op!("<=")
| op!(">")
| op!(">=") = bin_expr.op
{
if self.is_neg_zero(bin_expr.left.as_ref()) || self.is_neg_zero(bin_expr.right.as_ref())
{
self.emit_report(bin_expr.op, bin_expr.span);
}
}
}
}
impl Visit for NoCompareNegZero {
fn visit_bin_expr(&mut self, bin_expr: &BinExpr) {
self.check(bin_expr);
bin_expr.visit_children_with(self);
}
}