From 6daeeb0652513af7435c2197d74734c89965d66e Mon Sep 17 00:00:00 2001 From: Artur Date: Mon, 13 Jun 2022 22:24:38 +0300 Subject: [PATCH] feat(es/lints): Add `constructor-super` rule (#4912) --- .../lints/constructor-super/default/.swcrc | 9 + .../lints/constructor-super/default/input.js | 43 +++ .../default/output.swc-stderr | 240 +++++++++++++ crates/swc_ecma_lints/src/config.rs | 4 + .../src/rules/constructor_super.rs | 332 ++++++++++++++++++ crates/swc_ecma_lints/src/rules/mod.rs | 5 + 6 files changed, 633 insertions(+) create mode 100644 crates/swc/tests/errors/lints/constructor-super/default/.swcrc create mode 100644 crates/swc/tests/errors/lints/constructor-super/default/input.js create mode 100644 crates/swc/tests/errors/lints/constructor-super/default/output.swc-stderr create mode 100644 crates/swc_ecma_lints/src/rules/constructor_super.rs diff --git a/crates/swc/tests/errors/lints/constructor-super/default/.swcrc b/crates/swc/tests/errors/lints/constructor-super/default/.swcrc new file mode 100644 index 00000000000..a5e7bc95b53 --- /dev/null +++ b/crates/swc/tests/errors/lints/constructor-super/default/.swcrc @@ -0,0 +1,9 @@ +{ + "jsc": { + "lints": { + "constructor-super": [ + "error" + ] + } + } +} \ No newline at end of file diff --git a/crates/swc/tests/errors/lints/constructor-super/default/input.js b/crates/swc/tests/errors/lints/constructor-super/default/input.js new file mode 100644 index 00000000000..15a416c2185 --- /dev/null +++ b/crates/swc/tests/errors/lints/constructor-super/default/input.js @@ -0,0 +1,43 @@ +class A1 extends null { constructor() { super(); } } +class A2 extends null { constructor() { } } +class A3 extends 100 { constructor() { super(); } } +class A4 extends 'test' { constructor() { super(); } } +class A5 extends (B = 5) { constructor() { super(); } } +class A6 extends (B && 5) { constructor() { super(); } } +class A7 extends (B &&= 5) { constructor() { super(); } } +class A8 extends (B += C) { constructor() { super(); } } +class A9 extends (B -= C) { constructor() { super(); } } +class A10 extends (B **= C) { constructor() { super(); } } +class A11 extends (B |= C) { constructor() { super(); } } +class A12 extends (B &= C) { constructor() { super(); } } +class A13 extends B { constructor() { } } +class A14 extends B { constructor() { for (var a of b) super.foo(); } } +class A15 extends B { constructor() { class C extends D { constructor() { super(); } } } } +class A16 extends B { constructor() { var c = class extends D { constructor() { super(); } } } } +class A17 extends B { constructor() { var c = () => super(); } } +class A18 extends B { constructor() { class C extends D { constructor() { super(); } } } } +class A19 extends B { constructor() { var C = class extends D { constructor() { super(); } } } } +class A20 extends B { constructor() { super(); class C extends D { constructor() { } } } } +class A21 extends B { constructor() { super(); var C = class extends D { constructor() { } } } } +class A23 extends B { constructor() { if (a) super(); } } +class A24 extends B { constructor() { x ? super() : null; } } +class A25 extends B { constructor() { switch (x) { case 'a': super(); } } } +class A26 { constructor() { for (let i = 0; i < a.length; i++) { super(); } } } +class A27 { constructor() { for (let i = 0; i < a.length; i++) { super(); } super(); } } +class A28 extends B { constructor() { return; super(); } } +class A29 extends B { constructor() { try { super(); } catch (e) { } } } +class A30 extends B { constructor() { try { } catch (e) { super(); } } } +class A31 extends B { constructor() { try { } catch (e) { super(); } super(); } } +class A30 extends B { constructor() { try { super(); } catch (e) { } finally { super() } } } + + +// valid +class V1 extends (B, C) { constructor() { super(); } } +class V2 extends (class B { }) { constructor() { super(); } } +class V3 { constructor() { class B extends C { constructor() { super(); } } } } +class V4 extends Object { constructor() { super(); for (let i = 0; i < 0; i++); } } +class V5 { } +class V6 { constructor() { } } +class V7 extends null { } +class V8 { constructor() { } } +class A9 extends B { constructor() { try { } finally { super(); } } } diff --git a/crates/swc/tests/errors/lints/constructor-super/default/output.swc-stderr b/crates/swc/tests/errors/lints/constructor-super/default/output.swc-stderr new file mode 100644 index 00000000000..bda8eaa7427 --- /dev/null +++ b/crates/swc/tests/errors/lints/constructor-super/default/output.swc-stderr @@ -0,0 +1,240 @@ + + x the name `A30` is defined multiple times + ,-[29:1] + 29 | class A30 extends B { constructor() { try { } catch (e) { super(); } } } + : ^|^ + : `-- previous definition of `A30` here + 30 | class A31 extends B { constructor() { try { } catch (e) { super(); } super(); } } + 31 | class A30 extends B { constructor() { try { super(); } catch (e) { } finally { super() } } } + : ^|^ + : `-- `A30` redefined here + `---- + + x the name `A9` is defined multiple times + ,-[9:1] + 9 | class A9 extends (B -= C) { constructor() { super(); } } + : ^| + : `-- previous definition of `A9` here + 10 | class A10 extends (B **= C) { constructor() { super(); } } + 11 | class A11 extends (B |= C) { constructor() { super(); } } + 12 | class A12 extends (B &= C) { constructor() { super(); } } + 13 | class A13 extends B { constructor() { } } + 14 | class A14 extends B { constructor() { for (var a of b) super.foo(); } } + 15 | class A15 extends B { constructor() { class C extends D { constructor() { super(); } } } } + 16 | class A16 extends B { constructor() { var c = class extends D { constructor() { super(); } } } } + 17 | class A17 extends B { constructor() { var c = () => super(); } } + 18 | class A18 extends B { constructor() { class C extends D { constructor() { super(); } } } } + 19 | class A19 extends B { constructor() { var C = class extends D { constructor() { super(); } } } } + 20 | class A20 extends B { constructor() { super(); class C extends D { constructor() { } } } } + 21 | class A21 extends B { constructor() { super(); var C = class extends D { constructor() { } } } } + 22 | class A23 extends B { constructor() { if (a) super(); } } + 23 | class A24 extends B { constructor() { x ? super() : null; } } + 24 | class A25 extends B { constructor() { switch (x) { case 'a': super(); } } } + 25 | class A26 { constructor() { for (let i = 0; i < a.length; i++) { super(); } } } + 26 | class A27 { constructor() { for (let i = 0; i < a.length; i++) { super(); } super(); } } + 27 | class A28 extends B { constructor() { return; super(); } } + 28 | class A29 extends B { constructor() { try { super(); } catch (e) { } } } + 29 | class A30 extends B { constructor() { try { } catch (e) { super(); } } } + 30 | class A31 extends B { constructor() { try { } catch (e) { super(); } super(); } } + 31 | class A30 extends B { constructor() { try { super(); } catch (e) { } finally { super() } } } + 32 | + 33 | + 34 | // valid + 35 | class V1 extends (B, C) { constructor() { super(); } } + 36 | class V2 extends (class B { }) { constructor() { super(); } } + 37 | class V3 { constructor() { class B extends C { constructor() { super(); } } } } + 38 | class V4 extends Object { constructor() { super(); for (let i = 0; i < 0; i++); } } + 39 | class V5 { } + 40 | class V6 { constructor() { } } + 41 | class V7 extends null { } + 42 | class V8 { constructor() { } } + 43 | class A9 extends B { constructor() { try { } finally { super(); } } } + : ^| + : `-- `A9` redefined here + `---- + + x Unexpected 'super()' because 'super' is not a constructor + ,---- + 1 | class A1 extends null { constructor() { super(); } } + : ^^^^^ + `---- + + x Expected to call 'super()' + ,---- + 2 | class A2 extends null { constructor() { } } + : ^^^^^^^^^^^^^^^^^ + `---- + + x Unexpected 'super()' because 'super' is not a constructor + ,---- + 3 | class A3 extends 100 { constructor() { super(); } } + : ^^^^^ + `---- + + x Unexpected 'super()' because 'super' is not a constructor + ,---- + 4 | class A4 extends 'test' { constructor() { super(); } } + : ^^^^^ + `---- + + x Unexpected 'super()' because 'super' is not a constructor + ,---- + 5 | class A5 extends (B = 5) { constructor() { super(); } } + : ^^^^^ + `---- + + x Unexpected 'super()' because 'super' is not a constructor + ,---- + 6 | class A6 extends (B && 5) { constructor() { super(); } } + : ^^^^^ + `---- + + x Unexpected 'super()' because 'super' is not a constructor + ,---- + 7 | class A7 extends (B &&= 5) { constructor() { super(); } } + : ^^^^^ + `---- + + x Unexpected 'super()' because 'super' is not a constructor + ,---- + 8 | class A8 extends (B += C) { constructor() { super(); } } + : ^^^^^ + `---- + + x Unexpected 'super()' because 'super' is not a constructor + ,---- + 9 | class A9 extends (B -= C) { constructor() { super(); } } + : ^^^^^ + `---- + + x Unexpected 'super()' because 'super' is not a constructor + ,---- + 10 | class A10 extends (B **= C) { constructor() { super(); } } + : ^^^^^ + `---- + + x Unexpected 'super()' because 'super' is not a constructor + ,---- + 11 | class A11 extends (B |= C) { constructor() { super(); } } + : ^^^^^ + `---- + + x Unexpected 'super()' because 'super' is not a constructor + ,---- + 12 | class A12 extends (B &= C) { constructor() { super(); } } + : ^^^^^ + `---- + + x Expected to call 'super()' + ,---- + 13 | class A13 extends B { constructor() { } } + : ^^^^^^^^^^^^^^^^^ + `---- + + x Expected to call 'super()' + ,---- + 14 | class A14 extends B { constructor() { for (var a of b) super.foo(); } } + : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + `---- + + x Expected to call 'super()' + ,---- + 15 | class A15 extends B { constructor() { class C extends D { constructor() { super(); } } } } + : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + `---- + + x Expected to call 'super()' + ,---- + 16 | class A16 extends B { constructor() { var c = class extends D { constructor() { super(); } } } } + : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + `---- + + x Expected to call 'super()' + ,---- + 17 | class A17 extends B { constructor() { var c = () => super(); } } + : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + `---- + + x Expected to call 'super()' + ,---- + 18 | class A18 extends B { constructor() { class C extends D { constructor() { super(); } } } } + : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + `---- + + x Expected to call 'super()' + ,---- + 19 | class A19 extends B { constructor() { var C = class extends D { constructor() { super(); } } } } + : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + `---- + + x Expected to call 'super()' + ,---- + 20 | class A20 extends B { constructor() { super(); class C extends D { constructor() { } } } } + : ^^^^^^^^^^^^^^^^^ + `---- + + x Expected to call 'super()' + ,---- + 21 | class A21 extends B { constructor() { super(); var C = class extends D { constructor() { } } } } + : ^^^^^^^^^^^^^^^^^ + `---- + + x Lacked a call of 'super()' in some code path + ,---- + 22 | class A23 extends B { constructor() { if (a) super(); } } + : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + `---- + + x Lacked a call of 'super()' in some code path + ,---- + 23 | class A24 extends B { constructor() { x ? super() : null; } } + : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + `---- + + x More than one call 'super()' possible into loop + ,---- + 25 | class A26 { constructor() { for (let i = 0; i < a.length; i++) { super(); } } } + : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + `---- + + x More than one call 'super()' possible into loop + ,---- + 26 | class A27 { constructor() { for (let i = 0; i < a.length; i++) { super(); } super(); } } + : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + `---- + + x Unexpected duplicate 'super()' + ,---- + 26 | class A27 { constructor() { for (let i = 0; i < a.length; i++) { super(); } super(); } } + : ^^^^^ + `---- + + x Expected to call 'super()' + ,---- + 27 | class A28 extends B { constructor() { return; super(); } } + : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + `---- + + x Lacked a call of 'super()' in some code path + ,---- + 28 | class A29 extends B { constructor() { try { super(); } catch (e) { } } } + : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + `---- + + x Lacked a call of 'super()' in some code path + ,---- + 29 | class A30 extends B { constructor() { try { } catch (e) { super(); } } } + : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + `---- + + x Unexpected duplicate 'super()' + ,---- + 30 | class A31 extends B { constructor() { try { } catch (e) { super(); } super(); } } + : ^^^^^ + `---- + + x Unexpected duplicate 'super()' + ,---- + 31 | class A30 extends B { constructor() { try { super(); } catch (e) { } finally { super() } } } + : ^^^^^ + `---- diff --git a/crates/swc_ecma_lints/src/config.rs b/crates/swc_ecma_lints/src/config.rs index 966ee726df1..1f0e826d894 100644 --- a/crates/swc_ecma_lints/src/config.rs +++ b/crates/swc_ecma_lints/src/config.rs @@ -196,6 +196,10 @@ pub struct LintConfig { #[serde(default, alias = "noCompareNegZero")] pub no_compare_neg_zero: RuleConfig<()>, + #[cfg(feature = "non_critical_lints")] + #[serde(default, alias = "constructorSuper")] + pub constructor_super: RuleConfig<()>, + #[cfg(feature = "non_critical_lints")] #[serde(default, alias = "noSparseArrays")] pub no_sparse_arrays: RuleConfig<()>, diff --git a/crates/swc_ecma_lints/src/rules/constructor_super.rs b/crates/swc_ecma_lints/src/rules/constructor_super.rs new file mode 100644 index 00000000000..19b37c521b6 --- /dev/null +++ b/crates/swc_ecma_lints/src/rules/constructor_super.rs @@ -0,0 +1,332 @@ +use std::mem; + +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, +}; + +const BAD_SUPER_MESSAGE: &str = "Unexpected 'super()' because 'super' is not a constructor"; +const CALL_SUPER_EXCPECTED_MESSAGE: &str = "Expected to call 'super()'"; +const UNEXPECTED_DUPLICATE_SUPER_CALL_MESSAGE: &str = "Unexpected duplicate 'super()'"; +const LACKED_CALL_SUPER_MESSAGE: &str = "Lacked a call of 'super()' in some code path"; +const MORE_THAN_ONE_CALL_POSSIBLE_MESSAGE: &str = "More than one call 'super()' possible into loop"; + +pub fn constructor_super(config: &RuleConfig<()>) -> Option> { + let rule_reaction = config.get_rule_reaction(); + + match rule_reaction { + LintRuleReaction::Off => None, + _ => Some(visitor_rule(ConstructorSuper::new(rule_reaction))), + } +} + +#[derive(Debug, Clone, Copy)] +enum SuperClass { + Valid, + Invalid, + NotSetted, +} + +impl Default for SuperClass { + fn default() -> Self { + SuperClass::NotSetted + } +} + +#[derive(Debug, Default)] +struct ClassMeta { + super_class: SuperClass, + constructor_scope: usize, + code_path: CodePath, + loop_span: Option, +} + +#[derive(Debug, Default, Clone)] +struct CodePath { + super_calls_count: usize, + possibly_returned: bool, + super_call_missed: bool, + + // only for switch-case + break_exists: bool, +} + +#[derive(Debug, Default)] +struct ConstructorSuper { + expected_reaction: LintRuleReaction, + class_meta: ClassMeta, + scope: usize, +} + +impl ConstructorSuper { + fn new(expected_reaction: LintRuleReaction) -> Self { + Self { + expected_reaction, + scope: 0, + class_meta: Default::default(), + } + } + + fn emit_report(&self, span: Span, message: &str) { + 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 collect_class(&mut self, class: &Class) { + self.class_meta.super_class = match &class.super_class { + Some(super_class) => match unwrap_seqs_and_parens(super_class.as_ref()) { + Expr::Ident(_) | Expr::Class(_) => SuperClass::Valid, + _ => SuperClass::Invalid, + }, + None => SuperClass::NotSetted, + }; + } + + fn check_on_super_call(&mut self, span: Span) { + match self.class_meta.super_class { + SuperClass::Invalid => { + self.emit_report(span, BAD_SUPER_MESSAGE); + } + SuperClass::NotSetted => { + if let Some(span) = self.class_meta.loop_span { + self.emit_report(span, MORE_THAN_ONE_CALL_POSSIBLE_MESSAGE); + } else if self.class_meta.code_path.super_calls_count > 1 { + self.emit_report(span, UNEXPECTED_DUPLICATE_SUPER_CALL_MESSAGE); + } else { + self.emit_report(span, CALL_SUPER_EXCPECTED_MESSAGE); + } + } + SuperClass::Valid => { + if let Some(span) = self.class_meta.loop_span { + self.emit_report(span, MORE_THAN_ONE_CALL_POSSIBLE_MESSAGE); + } else if self.class_meta.code_path.super_calls_count > 1 { + self.emit_report(span, UNEXPECTED_DUPLICATE_SUPER_CALL_MESSAGE); + } + } + } + } + + fn check_on_constructor(&self, span: Span) { + match self.class_meta.super_class { + SuperClass::Valid => { + if self.class_meta.code_path.super_call_missed { + self.emit_report(span, LACKED_CALL_SUPER_MESSAGE); + } + + if self.class_meta.code_path.super_calls_count == 0 { + self.emit_report(span, CALL_SUPER_EXCPECTED_MESSAGE); + } + } + SuperClass::NotSetted => {} + SuperClass::Invalid => { + if self.class_meta.code_path.super_calls_count == 0 { + self.emit_report(span, CALL_SUPER_EXCPECTED_MESSAGE); + } + } + } + } + + fn update_current_code_path(&mut self, ordered_pathes: &[CodePath]) { + let current_code_path = &mut self.class_meta.code_path; + + for code_path in ordered_pathes.iter() { + current_code_path.possibly_returned = + current_code_path.possibly_returned || code_path.possibly_returned; + + current_code_path.super_calls_count = std::cmp::max( + current_code_path.super_calls_count, + code_path.super_calls_count, + ); + + current_code_path.super_call_missed = current_code_path.super_call_missed + || code_path.super_call_missed + || code_path.super_calls_count == 0; + } + } +} + +impl Visit for ConstructorSuper { + fn visit_class(&mut self, class: &Class) { + let prev_class_markers = mem::take(&mut self.class_meta); + + self.collect_class(class); + + class.visit_children_with(self); + + self.class_meta = prev_class_markers; + } + + fn visit_constructor(&mut self, constructor: &Constructor) { + self.scope += 1; + + self.class_meta.constructor_scope = self.scope; + + constructor.visit_children_with(self); + + self.check_on_constructor(constructor.span); + + self.scope -= 1; + } + + fn visit_call_expr(&mut self, call_expr: &CallExpr) { + if let Callee::Super(super_call) = &call_expr.callee { + if !self.class_meta.code_path.possibly_returned + && self.class_meta.constructor_scope == self.scope + { + self.class_meta.code_path.super_calls_count += 1; + self.class_meta.code_path.super_call_missed = false; + } + + self.check_on_super_call(super_call.span); + } + + call_expr.visit_children_with(self); + } + + fn visit_if_stmt(&mut self, if_stmt: &IfStmt) { + if_stmt.test.visit_children_with(self); + + let parent_code_path = self.class_meta.code_path.clone(); + + if_stmt.cons.visit_children_with(self); + + let cons_code_path = mem::replace(&mut self.class_meta.code_path, parent_code_path.clone()); + + if_stmt.alt.visit_children_with(self); + + let alt_code_path = mem::replace(&mut self.class_meta.code_path, parent_code_path); + + self.update_current_code_path(&[cons_code_path, alt_code_path]); + } + + fn visit_return_stmt(&mut self, n: &ReturnStmt) { + if self.scope == self.class_meta.constructor_scope { + self.class_meta.code_path.possibly_returned = true; + } + + n.visit_children_with(self); + } + + fn visit_cond_expr(&mut self, cond_expr: &CondExpr) { + cond_expr.test.visit_children_with(self); + + let parent_code_path = self.class_meta.code_path.clone(); + + cond_expr.cons.visit_children_with(self); + + let cons_code_path = mem::replace(&mut self.class_meta.code_path, parent_code_path.clone()); + + cond_expr.alt.visit_children_with(self); + + let alt_code_path = mem::replace(&mut self.class_meta.code_path, parent_code_path); + + self.update_current_code_path(&[cons_code_path, alt_code_path]); + } + + fn visit_switch_stmt(&mut self, switch_stmt: &SwitchStmt) { + switch_stmt.discriminant.visit_children_with(self); + + let parent_code_path = self.class_meta.code_path.clone(); + + let mut cases: Vec = Vec::with_capacity(switch_stmt.cases.len()); + + for switch_case in switch_stmt.cases.iter() { + switch_case.visit_children_with(self); + + if self.class_meta.code_path.break_exists { + cases.push(mem::replace( + &mut self.class_meta.code_path, + parent_code_path.clone(), + )); + } + } + + if cases.is_empty() { + cases.push(mem::replace( + &mut self.class_meta.code_path, + parent_code_path, + )); + } + + self.update_current_code_path(cases.as_slice()); + } + + fn visit_try_stmt(&mut self, try_stmt: &TryStmt) { + let parent_code_path = self.class_meta.code_path.clone(); + + try_stmt.block.visit_children_with(self); + + let block_code_path = + mem::replace(&mut self.class_meta.code_path, parent_code_path.clone()); + + if try_stmt.handler.is_some() { + try_stmt.handler.visit_children_with(self); + + let handler_code_path = mem::replace(&mut self.class_meta.code_path, parent_code_path); + + self.update_current_code_path(&[block_code_path, handler_code_path]); + } else { + self.update_current_code_path(&[block_code_path]); + } + + try_stmt.finalizer.visit_children_with(self); + } + + fn visit_break_stmt(&mut self, break_stmt: &BreakStmt) { + self.class_meta.code_path.break_exists = true; + + break_stmt.visit_children_with(self); + } + + fn visit_function(&mut self, function: &Function) { + self.scope += 1; + + function.visit_children_with(self); + + self.scope -= 1; + } + + fn visit_for_in_stmt(&mut self, for_in_stmt: &ForInStmt) { + let prev_loop_span = mem::replace(&mut self.class_meta.loop_span, Some(for_in_stmt.span)); + + for_in_stmt.visit_children_with(self); + + self.class_meta.loop_span = prev_loop_span; + } + + fn visit_for_of_stmt(&mut self, for_of_stmt: &ForOfStmt) { + let prev_loop_span = mem::replace(&mut self.class_meta.loop_span, Some(for_of_stmt.span)); + + for_of_stmt.visit_children_with(self); + + self.class_meta.loop_span = prev_loop_span; + } + + fn visit_for_stmt(&mut self, for_stmt: &ForStmt) { + let prev_loop_span = mem::replace(&mut self.class_meta.loop_span, Some(for_stmt.span)); + + for_stmt.visit_children_with(self); + + self.class_meta.loop_span = prev_loop_span; + } + + fn visit_arrow_expr(&mut self, arrow_expr: &ArrowExpr) { + self.scope += 1; + + arrow_expr.visit_children_with(self); + + self.scope -= 1; + } +} diff --git a/crates/swc_ecma_lints/src/rules/mod.rs b/crates/swc_ecma_lints/src/rules/mod.rs index 3c84214550a..bd4c0b25a8f 100644 --- a/crates/swc_ecma_lints/src/rules/mod.rs +++ b/crates/swc_ecma_lints/src/rules/mod.rs @@ -15,6 +15,7 @@ mod utils; #[cfg(feature = "non_critical_lints")] #[path = ""] pub(crate) mod non_critical_lints { + pub mod constructor_super; pub mod default_case_last; pub mod default_param_last; pub mod dot_notation; @@ -175,6 +176,10 @@ pub fn all(lint_params: LintParams) -> Vec> { &lint_config.no_compare_neg_zero, )); + rules.extend(constructor_super::constructor_super( + &lint_config.constructor_super, + )); + rules.extend(no_sparse_arrays::no_sparse_arrays( &lint_config.no_sparse_arrays, ));