feat(linter): check Super in javascript

This commit is contained in:
Boshen 2023-03-11 18:48:34 +08:00
parent 6c28948faf
commit 82ef1f2944
No known key found for this signature in database
GPG key ID: 6AC90C77AAAA6ABC
4 changed files with 1628 additions and 150 deletions

View file

@ -33,6 +33,7 @@ impl Rule for EarlyErrorJavaScript {
AstKind::ContinueStatement(stmt) => check_continue_statement(stmt, node, ctx),
AstKind::LabeledStatement(stmt) => check_labeled_statement(stmt, node, ctx),
AstKind::Class(class) => check_class(class, ctx),
AstKind::Super(sup) => check_super(sup, node, ctx),
_ => {}
}
}
@ -475,3 +476,99 @@ fn check_class(class: &Class, ctx: &LintContext) {
prev_constructor = Some(new_span);
}
}
fn check_super<'a>(sup: &Super, node: &AstNode<'a>, ctx: &LintContext<'a>) {
#[derive(Debug, Error, Diagnostic)]
#[error("'super' can only be referenced in a derived class.")]
#[diagnostic(help("either remove this super, or extend the class"))]
struct SuperWithoutDerivedClass(#[label] Span, #[label("class does not have `extends`")] Span);
#[derive(Debug, Error, Diagnostic)]
#[error("Super calls are not permitted outside constructors or in nested functions inside constructors.
")]
#[diagnostic()]
struct UnexpectedSuperCall(#[label] Span);
#[derive(Debug, Error, Diagnostic)]
#[error("'super' can only be referenced in members of derived classes or object literal expressions.
")]
#[diagnostic()]
struct UnexpectedSuperReference(#[label] Span);
let super_call_span = match ctx.parent_kind(node) {
AstKind::CallExpression(expr) => Some(expr.span),
AstKind::NewExpression(expr) => Some(expr.span),
_ => None,
};
// skip(1) is the self `Super`
// skip(2) is the parent `CallExpression` or `NewExpression`
for node_id in ctx.ancestors(node).skip(2) {
match ctx.kind(node_id) {
AstKind::Class(class) => {
// ClassTail : ClassHeritageopt { ClassBody }
// It is a Syntax Error if ClassHeritage is not present and the following algorithm returns true:
// 1. Let constructor be ConstructorMethod of ClassBody.
// 2. If constructor is empty, return false.
// 3. Return HasDirectSuper of constructor.
if class.super_class.is_none() {
return ctx.diagnostic(SuperWithoutDerivedClass(sup.span, class.span));
}
break;
}
AstKind::MethodDefinition(def) => {
// ClassElement : MethodDefinition
// It is a Syntax Error if PropName of MethodDefinition is not "constructor" and HasDirectSuper of MethodDefinition is true.
if let Some(super_call_span) = super_call_span {
if def.kind == MethodDefinitionKind::Constructor {
// pass through and let AstKind::Class check ClassHeritage
} else {
return ctx.diagnostic(UnexpectedSuperCall(super_call_span));
}
} else {
// super references are allowed in method
break;
}
}
// FieldDefinition : ClassElementName Initializer opt
// * It is a Syntax Error if Initializer is present and Initializer Contains SuperCall is true.
// PropertyDefinition : MethodDefinition
// * It is a Syntax Error if HasDirectSuper of MethodDefinition is true.
AstKind::PropertyDefinition(_) => {
if let Some(super_call_span) = super_call_span {
return ctx.diagnostic(UnexpectedSuperCall(super_call_span));
}
break;
}
AstKind::PropertyValue(value) => {
if let PropertyValue::Expression(
Expression::FunctionExpression(_) | Expression::ArrowFunctionExpression(_),
) = value
{
if let Some(super_call_span) = super_call_span {
return ctx.diagnostic(UnexpectedSuperCall(super_call_span));
}
break;
}
}
// ClassStaticBlockBody : ClassStaticBlockStatementList
// * It is a Syntax Error if ClassStaticBlockStatementList Contains SuperCall is true.
AstKind::StaticBlock(_) => {
if let Some(super_call_span) = super_call_span {
return ctx.diagnostic(UnexpectedSuperCall(super_call_span));
}
}
// ModuleBody : ModuleItemList
// * It is a Syntax Error if ModuleItemList Contains super.
// ScriptBody : StatementList
// * It is a Syntax Error if StatementList Contains super
AstKind::Program(_) => {
return super_call_span.map_or_else(
|| ctx.diagnostic(UnexpectedSuperReference(sup.span)),
|super_call_span| ctx.diagnostic(UnexpectedSuperCall(super_call_span)),
);
}
_ => {}
}
}
}

View file

@ -1,7 +1,7 @@
Babel Summary:
AST Parsed : 2053/2069 (99.23%)
Positive Passed: 2053/2069 (99.23%)
Negative Passed: 989/1502 (65.85%)
Negative Passed: 992/1502 (66.05%)
Expect Syntax Error: "annex-b/disabled/1.1-html-comments-close/input.js"
Expect Syntax Error: "annex-b/disabled/3.1-sloppy-labeled-functions-if-body/input.js"
Expect Syntax Error: "annex-b/disabled/3.1-sloppy-labeled-functions-multiple-labels/input.js"
@ -92,7 +92,6 @@ Expect Syntax Error: "core/uncategorised/544/input.js"
Expect Syntax Error: "core/uncategorised/550/input.js"
Expect Syntax Error: "core/uncategorised/552/input.js"
Expect Syntax Error: "es2015/class-methods/direct-super-in-object-method/input.js"
Expect Syntax Error: "es2015/class-methods/direct-super-outside-constructor/input.js"
Expect Syntax Error: "es2015/class-methods/disallow-duplicate-method-params/input.js"
Expect Syntax Error: "es2015/destructuring/binding-arguments-module/input.js"
Expect Syntax Error: "es2015/destructuring/binding-arguments-strict/input.js"
@ -130,7 +129,6 @@ Expect Syntax Error: "es2015/uncategorised/.260/input.js"
Expect Syntax Error: "es2015/uncategorised/.335/input.js"
Expect Syntax Error: "es2015/uncategorised/.343/input.js"
Expect Syntax Error: "es2015/uncategorised/109/input.js"
Expect Syntax Error: "es2015/uncategorised/123/input.js"
Expect Syntax Error: "es2015/uncategorised/166/input.js"
Expect Syntax Error: "es2015/uncategorised/220/input.js"
Expect Syntax Error: "es2015/uncategorised/227/input.js"
@ -265,7 +263,6 @@ Expect Syntax Error: "esprima/es2015-object-initialiser/invalid-proto-identifier
Expect Syntax Error: "esprima/es2015-object-initialiser/invalid-proto-literal-identifier/input.js"
Expect Syntax Error: "esprima/es2015-object-initialiser/invalid-proto-literals/input.js"
Expect Syntax Error: "esprima/es2015-object-initialiser/invalid-proto-setter-literal-identifier/input.js"
Expect Syntax Error: "esprima/es2015-super-property/invalid_super_not_inside_function/input.js"
Expect Syntax Error: "esprima/es2015-yield/invalid-yield-binding-property/input.js"
Expect Syntax Error: "esprima/es2015-yield/invalid-yield-expression/input.js"
Expect Syntax Error: "esprima/es2015-yield/invalid-yield-generator-arrow-default/input.js"
@ -2184,6 +2181,15 @@ Expect to Parse: "typescript/types/const-type-parameters/input.ts"
╰────
help: Try insert a semicolon here
× Super calls are not permitted outside constructors or in nested functions inside constructors.
╭─[es2015/class-methods/direct-super-outside-constructor/input.js:1:1]
1 │ class A {
2 │ x () {super()}
· ───────
3 │ }
╰────
× Automatic Semicolon Insertion
╭─[es2015/class-methods/disallow-computed-async-identifier/input.js:1:1]
1 │ class A {
@ -2871,6 +2877,14 @@ Expect to Parse: "typescript/types/const-type-parameters/input.ts"
· ╰── A 'set' accessor must have exactly one parameter.
╰────
× 'super' can only be referenced in a derived class.
╭─[es2015/uncategorised/123/input.js:1:1]
1 │ "use strict"; (class A {constructor() { super() }})
· ─────────────────┬──────────────────
· ╰── class does not have `extends`
╰────
help: either remove this super, or extend the class
× Multiple constructor implementations are not allowed.
╭─[es2015/uncategorised/125/input.js:1:1]
1 │ class A { constructor() {} 'constructor'() {} }
@ -3394,6 +3408,13 @@ Expect to Parse: "typescript/types/const-type-parameters/input.ts"
· ─
╰────
× 'super' can only be referenced in members of derived classes or object literal expressions.
╭─[es2015/uncategorised/344/input.js:1:1]
1 │ super
· ─────
╰────
× 'super' can only be used with function calls or in property accesses
╭─[es2015/uncategorised/344/input.js:1:1]
1 │ super
@ -6145,6 +6166,15 @@ Expect to Parse: "typescript/types/const-type-parameters/input.ts"
╰────
help: replace with `super()` or `super.prop` or `super[prop]`
× Super calls are not permitted outside constructors or in nested functions inside constructors.
╭─[esprima/es2015-super-property/.invalid_super_id/input.js:1:1]
1 │ class A {
2 │ foo() { new super + 3 }
· ─────────
3 │ }
╰────
× 'super' can only be used with function calls or in property accesses
╭─[esprima/es2015-super-property/.invalid_super_id/input.js:1:1]
1 │ class A {
@ -6155,6 +6185,13 @@ Expect to Parse: "typescript/types/const-type-parameters/input.ts"
╰────
help: replace with `super()` or `super.prop` or `super[prop]`
× Super calls are not permitted outside constructors or in nested functions inside constructors.
╭─[esprima/es2015-super-property/invalid_super_not_inside_function/input.js:1:1]
1 │ var x = super();
· ───────
╰────
× Bad escape sequence in untagged template literal
╭─[esprima/es2015-template-literals/.octal-literal/input.js:1:1]
1 │ `\00`;

File diff suppressed because it is too large Load diff

View file

@ -1,7 +1,7 @@
TypeScript Summary:
AST Parsed : 2305/2338 (98.59%)
Positive Passed: 2305/2338 (98.59%)
Negative Passed: 591/2532 (23.34%)
Negative Passed: 597/2532 (23.58%)
Expect Syntax Error: "Symbols/ES5SymbolProperty2.ts"
Expect Syntax Error: "Symbols/ES5SymbolProperty6.ts"
Expect Syntax Error: "additionalChecks/noPropertyAccessFromIndexSignature1.ts"
@ -137,7 +137,6 @@ Expect Syntax Error: "classes/constructorDeclarations/superCalls/derivedClassPar
Expect Syntax Error: "classes/constructorDeclarations/superCalls/derivedClassSuperCallsWithThisArg.ts"
Expect Syntax Error: "classes/constructorDeclarations/superCalls/derivedClassSuperProperties.ts"
Expect Syntax Error: "classes/constructorDeclarations/superCalls/derivedClassSuperStatementPosition.ts"
Expect Syntax Error: "classes/constructorDeclarations/superCalls/superCallInConstructorWithNoBaseType.ts"
Expect Syntax Error: "classes/constructorDeclarations/superCalls/superPropertyInConstructorBeforeSuperCall.ts"
Expect Syntax Error: "classes/indexMemberDeclarations/privateIndexer.ts"
Expect Syntax Error: "classes/indexMemberDeclarations/publicIndexer.ts"
@ -181,7 +180,6 @@ Expect Syntax Error: "classes/members/instanceAndStaticMembers/typeOfThisInStati
Expect Syntax Error: "classes/members/instanceAndStaticMembers/typeOfThisInStaticMembers11.ts"
Expect Syntax Error: "classes/members/instanceAndStaticMembers/typeOfThisInStaticMembers12.ts"
Expect Syntax Error: "classes/members/instanceAndStaticMembers/typeOfThisInStaticMembers13.ts"
Expect Syntax Error: "classes/members/instanceAndStaticMembers/typeOfThisInStaticMembers6.ts"
Expect Syntax Error: "classes/members/instanceAndStaticMembers/typeOfThisInStaticMembers8.ts"
Expect Syntax Error: "classes/members/instanceAndStaticMembers/typeOfThisInStaticMembers9.ts"
Expect Syntax Error: "classes/members/instanceAndStaticMembers/typeOfThisInstanceMemberNarrowedWithLoopAntecedent.ts"
@ -409,7 +407,6 @@ Expect Syntax Error: "es6/classDeclaration/superCallBeforeThisAccessing3.ts"
Expect Syntax Error: "es6/classDeclaration/superCallBeforeThisAccessing4.ts"
Expect Syntax Error: "es6/classDeclaration/superCallBeforeThisAccessing6.ts"
Expect Syntax Error: "es6/classDeclaration/superCallBeforeThisAccessing7.ts"
Expect Syntax Error: "es6/classDeclaration/superCallFromClassThatHasNoBaseTypeButWithSameSymbolInterface.ts"
Expect Syntax Error: "es6/classExpressions/typeArgumentInferenceWithClassExpression2.ts"
Expect Syntax Error: "es6/computedProperties/computedPropertyNames12_ES5.ts"
Expect Syntax Error: "es6/computedProperties/computedPropertyNames12_ES6.ts"
@ -429,8 +426,6 @@ Expect Syntax Error: "es6/computedProperties/computedPropertyNames24_ES5.ts"
Expect Syntax Error: "es6/computedProperties/computedPropertyNames24_ES6.ts"
Expect Syntax Error: "es6/computedProperties/computedPropertyNames26_ES5.ts"
Expect Syntax Error: "es6/computedProperties/computedPropertyNames26_ES6.ts"
Expect Syntax Error: "es6/computedProperties/computedPropertyNames27_ES5.ts"
Expect Syntax Error: "es6/computedProperties/computedPropertyNames27_ES6.ts"
Expect Syntax Error: "es6/computedProperties/computedPropertyNames2_ES5.ts"
Expect Syntax Error: "es6/computedProperties/computedPropertyNames2_ES6.ts"
Expect Syntax Error: "es6/computedProperties/computedPropertyNames30_ES5.ts"
@ -798,7 +793,6 @@ Expect Syntax Error: "expressions/propertyAccess/propertyAccessNumericLiterals.t
Expect Syntax Error: "expressions/propertyAccess/propertyAccessStringIndexSignature.ts"
Expect Syntax Error: "expressions/propertyAccess/propertyAccessStringIndexSignatureNoImplicitAny.ts"
Expect Syntax Error: "expressions/propertyAccess/propertyAccessWidening.ts"
Expect Syntax Error: "expressions/superPropertyAccess/errorSuperPropertyAccess.ts"
Expect Syntax Error: "expressions/superPropertyAccess/superSymbolIndexedAccess3.ts"
Expect Syntax Error: "expressions/superPropertyAccess/superSymbolIndexedAccess4.ts"
Expect Syntax Error: "expressions/thisKeyword/thisInInvalidContexts.ts"
@ -2760,6 +2754,32 @@ Expect to Parse: "salsa/privateIdentifierExpando.ts"
╰────
help: Try insert a semicolon here
× 'super' can only be referenced in a derived class.
╭─[classes/constructorDeclarations/superCalls/superCallInConstructorWithNoBaseType.ts:1:1]
1 │ ╭─▶ class C {
2 │ │ constructor() {
3 │ │╭▶ super(); // error
· ││ ─────
4 │ │ }
5 │ ├─▶ }
· ╰──── class does not have `extends`
6 │
╰────
help: either remove this super, or extend the class
× 'super' can only be referenced in a derived class.
╭─[classes/constructorDeclarations/superCalls/superCallInConstructorWithNoBaseType.ts:6:1]
6 │
7 │ ╭─▶ class D<T> {
8 │ │ public constructor(public x: T) {
9 │ │╭▶ super(); // error
· ││ ─────
10 │ │ }
11 │ ├─▶ }
· ╰──── class does not have `extends`
╰────
help: either remove this super, or extend the class
× Expect token
╭─[classes/indexMemberDeclarations/privateIndexer2.ts:3:1]
3 │ var x = {
@ -2779,6 +2799,15 @@ Expect to Parse: "salsa/privateIdentifierExpando.ts"
╰────
help: Try insert a semicolon here
× Super calls are not permitted outside constructors or in nested functions inside constructors.
╭─[classes/members/instanceAndStaticMembers/typeOfThisInStaticMembers6.ts:5:1]
5 │ class D extends C {
6 │ static c = super();
· ───────
7 │ }
╰────
× Private identifier '#prop' is not allowed outside class bodies
╭─[classes/members/privateNames/privateNameAccessorsAccess.ts:15:1]
15 │ }
@ -4447,6 +4476,37 @@ Expect to Parse: "salsa/privateIdentifierExpando.ts"
8 │ }
╰────
× 'super' can only be referenced in a derived class.
╭─[es6/classDeclaration/superCallFromClassThatHasNoBaseTypeButWithSameSymbolInterface.ts:2:1]
2 │
3 │ ╭─▶ class Foo {
4 │ │ constructor() {
5 │ │╭▶ super(); // error
· ││ ─────
6 │ │ }
7 │ ├─▶ }
· ╰──── class does not have `extends`
╰────
help: either remove this super, or extend the class
× Super calls are not permitted outside constructors or in nested functions inside constructors.
╭─[es6/computedProperties/computedPropertyNames27_ES5.ts:4:1]
4 │ class C extends Base {
5 │ [(super(), "prop")]() { }
· ───────
6 │ }
╰────
× Super calls are not permitted outside constructors or in nested functions inside constructors.
╭─[es6/computedProperties/computedPropertyNames27_ES6.ts:4:1]
4 │ class C extends Base {
5 │ [(super(), "prop")]() { }
· ───────
6 │ }
╰────
× A 'set' accessor must have exactly one parameter.
╭─[es6/computedProperties/computedPropertyNames49_ES5.ts:9:1]
9 │ },
@ -5662,6 +5722,162 @@ Expect to Parse: "salsa/privateIdentifierExpando.ts"
· ╰── Tagged template expressions are not permitted in an optional chain
╰────
× 'super' can only be referenced in a derived class.
╭─[expressions/superCalls/errorSuperCalls.ts:1:1]
1 │ //super call in class constructor with no base type
2 │ ╭─▶ class NoBase {
3 │ │ constructor() {
4 │ │╭▶ super();
· ││ ─────
5 │ │ }
6 │ │
7 │ │ //super call in class member function with no base type
8 │ │ fn() {
9 │ │ super();
10 │ │ }
11 │ │
12 │ │ //super call in class accessor (get and set) with no base type
13 │ │ get foo() {
14 │ │ super();
15 │ │ return null;
16 │ │ }
17 │ │ set foo(v) {
18 │ │ super();
19 │ │ }
20 │ │
21 │ │ //super call in class member initializer with no base type
22 │ │ p = super();
23 │ │
24 │ │ //super call in static class member function with no base type
25 │ │ static fn() {
26 │ │ super();
27 │ │ }
28 │ │
29 │ │ //super call in static class member initializer with no base type
30 │ │ static k = super();
31 │ │
32 │ │ //super call in static class accessor (get and set) with no base type
33 │ │ static get q() {
34 │ │ super();
35 │ │ return null;
36 │ │ }
37 │ │ static set q(n) {
38 │ │ super();
39 │ │ }
40 │ ├─▶ }
· ╰──── class does not have `extends`
41 │
╰────
help: either remove this super, or extend the class
× Super calls are not permitted outside constructors or in nested functions inside constructors.
╭─[expressions/superCalls/errorSuperCalls.ts:8:1]
8 │ fn() {
9 │ super();
· ───────
10 │ }
╰────
× Super calls are not permitted outside constructors or in nested functions inside constructors.
╭─[expressions/superCalls/errorSuperCalls.ts:13:1]
13 │ get foo() {
14 │ super();
· ───────
15 │ return null;
╰────
× Super calls are not permitted outside constructors or in nested functions inside constructors.
╭─[expressions/superCalls/errorSuperCalls.ts:17:1]
17 │ set foo(v) {
18 │ super();
· ───────
19 │ }
╰────
× Super calls are not permitted outside constructors or in nested functions inside constructors.
╭─[expressions/superCalls/errorSuperCalls.ts:21:1]
21 │ //super call in class member initializer with no base type
22 │ p = super();
· ───────
23 │
╰────
× Super calls are not permitted outside constructors or in nested functions inside constructors.
╭─[expressions/superCalls/errorSuperCalls.ts:25:1]
25 │ static fn() {
26 │ super();
· ───────
27 │ }
╰────
× Super calls are not permitted outside constructors or in nested functions inside constructors.
╭─[expressions/superCalls/errorSuperCalls.ts:29:1]
29 │ //super call in static class member initializer with no base type
30 │ static k = super();
· ───────
31 │
╰────
× Super calls are not permitted outside constructors or in nested functions inside constructors.
╭─[expressions/superCalls/errorSuperCalls.ts:33:1]
33 │ static get q() {
34 │ super();
· ───────
35 │ return null;
╰────
× Super calls are not permitted outside constructors or in nested functions inside constructors.
╭─[expressions/superCalls/errorSuperCalls.ts:37:1]
37 │ static set q(n) {
38 │ super();
· ───────
39 │ }
╰────
× Super calls are not permitted outside constructors or in nested functions inside constructors.
╭─[expressions/superCalls/errorSuperCalls.ts:57:1]
57 │ //super call in class member initializer of derived type
58 │ t = super();
· ───────
59 │
╰────
× Super calls are not permitted outside constructors or in nested functions inside constructors.
╭─[expressions/superCalls/errorSuperCalls.ts:61:1]
61 │ //super call in class member function of derived type
62 │ super();
· ───────
63 │ }
╰────
× Super calls are not permitted outside constructors or in nested functions inside constructors.
╭─[expressions/superCalls/errorSuperCalls.ts:66:1]
66 │ get foo() {
67 │ super();
· ───────
68 │ return null;
╰────
× Super calls are not permitted outside constructors or in nested functions inside constructors.
╭─[expressions/superCalls/errorSuperCalls.ts:70:1]
70 │ set foo(n) {
71 │ super();
· ───────
72 │ }
╰────
× 'super' can only be used with function calls or in property accesses
╭─[expressions/superCalls/errorSuperCalls.ts:45:1]
45 │ constructor() {
@ -5672,6 +5888,22 @@ Expect to Parse: "salsa/privateIdentifierExpando.ts"
╰────
help: replace with `super()` or `super.prop` or `super[prop]`
× 'super' can only be referenced in members of derived classes or object literal expressions.
╭─[expressions/superPropertyAccess/errorSuperPropertyAccess.ts:126:1]
126 │ // In object literal
127 │ var obj = { n: super.wat, p: super.foo() };
· ─────
╰────
× 'super' can only be referenced in members of derived classes or object literal expressions.
╭─[expressions/superPropertyAccess/errorSuperPropertyAccess.ts:126:1]
126 │ // In object literal
127 │ var obj = { n: super.wat, p: super.foo() };
· ─────
╰────
× Expect token
╭─[expressions/typeAssertions/typeAssertions.ts:43:1]
43 │ var str: string;
@ -7962,6 +8194,15 @@ Expect to Parse: "salsa/privateIdentifierExpando.ts"
3 │ }
╰────
× Super calls are not permitted outside constructors or in nested functions inside constructors.
╭─[parser/ecmascript5/SuperExpressions/parserSuperExpression2.ts:2:1]
2 │ M() {
3 │ super<T>(0);
· ───────────
4 │ }
╰────
× 'super' can only be used with function calls or in property accesses
╭─[parser/ecmascript5/SuperExpressions/parserSuperExpression2.ts:2:1]
2 │ M() {