mirror of
https://github.com/swc-project/swc.git
synced 2024-12-25 14:43:33 +03:00
feat(es/lints): Add constructor-super
rule (#4912)
This commit is contained in:
parent
61d7d881c9
commit
6daeeb0652
@ -0,0 +1,9 @@
|
||||
{
|
||||
"jsc": {
|
||||
"lints": {
|
||||
"constructor-super": [
|
||||
"error"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
@ -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(); } } }
|
@ -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() } } }
|
||||
: ^^^^^
|
||||
`----
|
@ -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<()>,
|
||||
|
332
crates/swc_ecma_lints/src/rules/constructor_super.rs
Normal file
332
crates/swc_ecma_lints/src/rules/constructor_super.rs
Normal file
@ -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<Box<dyn Rule>> {
|
||||
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<Span>,
|
||||
}
|
||||
|
||||
#[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<CodePath> = 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;
|
||||
}
|
||||
}
|
@ -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<Box<dyn Rule>> {
|
||||
&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,
|
||||
));
|
||||
|
Loading…
Reference in New Issue
Block a user