feat(semantic): check for abstract ClassElements in non-abstract classes (#4127)

feat(semantic): check for abstract ClassElements in non-abstract classes

chore: update coverage snapshots
This commit is contained in:
DonIsaac 2024-07-09 03:35:32 +00:00
parent c5b4be021e
commit 2f53bdf72d
5 changed files with 119 additions and 9 deletions

View file

@ -1269,6 +1269,23 @@ impl<'a> ClassElement<'a> {
Self::StaticBlock(_) | Self::TSIndexSignature(_) => false,
}
}
/// Has this property been marked as abstract?
///
/// ```ts
/// abstract class Foo { // <-- not considered
/// foo: string; // <-- false
/// abstract bar: string; // <-- true
/// }
/// ```
pub fn is_abstract(&self) -> bool {
match self {
Self::MethodDefinition(method) => method.r#type.is_abstract(),
Self::AccessorProperty(accessor) => accessor.r#type.is_abstract(),
Self::PropertyDefinition(property) => property.r#type.is_abstract(),
Self::StaticBlock(_) | Self::TSIndexSignature(_) => false,
}
}
}
impl PropertyDefinitionType {

View file

@ -70,6 +70,7 @@ pub fn check<'a>(node: &AstNode<'a>, ctx: &SemanticBuilder<'a>) {
}
AstKind::Class(class) => {
js::check_class(class, node, ctx);
ts::check_class(class, ctx);
}
AstKind::MethodDefinition(method) => {
js::check_method_definition(method, ctx);

View file

@ -185,6 +185,27 @@ pub fn check_ts_import_equals_declaration<'a>(
}
}
/// - Abstract properties can only appear within an abstract class. (1253)
/// - Abstract methods can only appear within an abstract class. (1244)
fn abstract_elem_in_concrete_class(is_property: bool, span: Span) -> OxcDiagnostic {
let (code, elem_kind) = if is_property { (1253, "properties") } else { (1244, "methods") };
OxcDiagnostic::error(format!(
"TS({code}): Abstract {elem_kind} can only appear within an abstract class."
))
.with_label(span)
}
pub fn check_class<'a>(class: &Class<'a>, ctx: &SemanticBuilder<'a>) {
if !class.r#abstract {
for elem in &class.body.body {
if elem.is_abstract() {
let span = elem.property_key().map_or_else(|| elem.span(), GetSpan::span);
ctx.error(abstract_elem_in_concrete_class(elem.is_property(), span));
}
}
}
}
fn abstract_element_cannot_have_initializer(
code: u32,
elem_name: &str,

View file

@ -3,7 +3,7 @@ commit: 12619ffe
parser_babel Summary:
AST Parsed : 2093/2101 (99.62%)
Positive Passed: 2083/2101 (99.14%)
Negative Passed: 1377/1501 (91.74%)
Negative Passed: 1380/1501 (91.94%)
Expect Syntax Error: "annex-b/disabled/1.1-html-comments-close/input.js"
Expect Syntax Error: "annex-b/disabled/3.1-sloppy-labeled-functions/input.js"
Expect Syntax Error: "annex-b/disabled/3.1-sloppy-labeled-functions-if-body/input.js"
@ -42,9 +42,6 @@ Expect Syntax Error: "esprima/invalid-syntax/migrated_0276/input.js"
Expect Syntax Error: "typescript/cast/satisfies-const-error/input.ts"
Expect Syntax Error: "typescript/cast/unparenthesized-assert-and-assign/input.ts"
Expect Syntax Error: "typescript/cast/unparenthesized-type-assertion-and-assign/input.ts"
Expect Syntax Error: "typescript/class/abstract-method-in-non-abstract-class-1/input.ts"
Expect Syntax Error: "typescript/class/abstract-method-in-non-abstract-class-2/input.ts"
Expect Syntax Error: "typescript/class/abstract-method-in-non-abstract-class-3/input.ts"
Expect Syntax Error: "typescript/class/constructor-with-invalid-order-modifiers-1/input.ts"
Expect Syntax Error: "typescript/class/constructor-with-invalid-order-modifiers-2/input.ts"
Expect Syntax Error: "typescript/class/constructor-with-invalid-order-modifiers-3/input.ts"
@ -9971,6 +9968,28 @@ Expect to Parse: "typescript/types/const-type-parameters-babel-7/input.ts"
2 │ func<T>(a: T);
╰────
× TS(1244): Abstract methods can only appear within an abstract class.
╭─[typescript/class/abstract-method-in-non-abstract-class-1/input.ts:2:12]
1 │ class Foo {
2 │ abstract method();
· ──────
3 │ }
╰────
× TS(1244): Abstract methods can only appear within an abstract class.
╭─[typescript/class/abstract-method-in-non-abstract-class-2/input.ts:4:16]
3 │ return class {
4 │ abstract m();
· ─
5 │ }
╰────
× TS(1244): Abstract methods can only appear within an abstract class.
╭─[typescript/class/abstract-method-in-non-abstract-class-3/input.ts:1:41]
1 │ abstract class C { p = class { abstract method() } }
· ──────
╰────
× TS(1245): Method 'method' cannot have an implementation because it is marked abstract.
╭─[typescript/class/abstract-method-with-body/input.ts:2:12]
1 │ abstract class Foo {
@ -10115,6 +10134,14 @@ Expect to Parse: "typescript/types/const-type-parameters-babel-7/input.ts"
× TS(1245): Method 'd' cannot have an implementation because it is marked abstract.
╭─[typescript/class/generator-method-with-modifiers/input.ts:5:13]
4 │ static *c() {}
5 │ abstract *d() {}
· ─
6 │ readonly *e() {}
╰────
× TS(1244): Abstract methods can only appear within an abstract class.
╭─[typescript/class/generator-method-with-modifiers/input.ts:5:13]
4 │ static *c() {}
5 │ abstract *d() {}
· ─
6 │ readonly *e() {}

View file

@ -3,7 +3,7 @@ commit: d8086f14
parser_typescript Summary:
AST Parsed : 5279/5283 (99.92%)
Positive Passed: 5272/5283 (99.79%)
Negative Passed: 1090/4875 (22.36%)
Negative Passed: 1094/4875 (22.44%)
Expect Syntax Error: "compiler/ClassDeclaration10.ts"
Expect Syntax Error: "compiler/ClassDeclaration11.ts"
Expect Syntax Error: "compiler/ClassDeclaration13.ts"
@ -27,7 +27,6 @@ Expect Syntax Error: "compiler/ParameterList8.ts"
Expect Syntax Error: "compiler/abstractClassInLocalScopeIsAbstract.ts"
Expect Syntax Error: "compiler/abstractClassUnionInstantiation.ts"
Expect Syntax Error: "compiler/abstractPropertyInConstructor.ts"
Expect Syntax Error: "compiler/abstractPropertyNegative.ts"
Expect Syntax Error: "compiler/accessInstanceMemberFromStaticMethod01.ts"
Expect Syntax Error: "compiler/accessStaticMemberFromInstanceMethod01.ts"
Expect Syntax Error: "compiler/accessorAccidentalCallDiagnostic.ts"
@ -100,7 +99,6 @@ Expect Syntax Error: "compiler/arrayOfSubtypeIsAssignableToReadonlyArray.ts"
Expect Syntax Error: "compiler/arrayReferenceWithoutTypeArgs.ts"
Expect Syntax Error: "compiler/arrayToLocaleStringES5.ts"
Expect Syntax Error: "compiler/arrowFunctionInConstructorArgument1.ts"
Expect Syntax Error: "compiler/asiAbstract.ts"
Expect Syntax Error: "compiler/asiPublicPrivateProtected.ts"
Expect Syntax Error: "compiler/assignLambdaToNominalSubtypeOfFunction.ts"
Expect Syntax Error: "compiler/assignToEnum.ts"
@ -1964,7 +1962,6 @@ Expect Syntax Error: "conformance/classes/classDeclarations/classAbstractKeyword
Expect Syntax Error: "conformance/classes/classDeclarations/classAbstractKeyword/classAbstractInheritance1.ts"
Expect Syntax Error: "conformance/classes/classDeclarations/classAbstractKeyword/classAbstractInheritance2.ts"
Expect Syntax Error: "conformance/classes/classDeclarations/classAbstractKeyword/classAbstractInstantiations1.ts"
Expect Syntax Error: "conformance/classes/classDeclarations/classAbstractKeyword/classAbstractInstantiations2.ts"
Expect Syntax Error: "conformance/classes/classDeclarations/classAbstractKeyword/classAbstractMixedWithModifiers.ts"
Expect Syntax Error: "conformance/classes/classDeclarations/classAbstractKeyword/classAbstractOverloads.ts"
Expect Syntax Error: "conformance/classes/classDeclarations/classAbstractKeyword/classAbstractOverrideWithAbstract.ts"
@ -1972,7 +1969,6 @@ Expect Syntax Error: "conformance/classes/classDeclarations/classAbstractKeyword
Expect Syntax Error: "conformance/classes/classDeclarations/classAbstractKeyword/classAbstractSingleLineDecl.ts"
Expect Syntax Error: "conformance/classes/classDeclarations/classAbstractKeyword/classAbstractSuperCalls.ts"
Expect Syntax Error: "conformance/classes/classDeclarations/classAbstractKeyword/classAbstractUsingAbstractMethod1.ts"
Expect Syntax Error: "conformance/classes/classDeclarations/classAbstractKeyword/classAbstractUsingAbstractMethods2.ts"
Expect Syntax Error: "conformance/classes/classDeclarations/classAndInterfaceMergeConflictingMembers.ts"
Expect Syntax Error: "conformance/classes/classDeclarations/classExtendingClassLikeType.ts"
Expect Syntax Error: "conformance/classes/classDeclarations/classExtendingNonConstructor.ts"
@ -4019,6 +4015,14 @@ Expect to Parse: "conformance/salsa/plainJSRedeclare3.ts"
╰────
help: Try insert a semicolon here
× TS(1253): Abstract properties can only appear within an abstract class.
╭─[compiler/abstractPropertyNegative.ts:15:14]
14 │ readonly ro = "readonly please";
15 │ abstract notAllowed: string;
· ──────────
16 │ get concreteWithNoBody(): string;
╰────
× Unexpected token
╭─[compiler/accessorBodyInTypeContext.ts:2:15]
1 │ type A = {
@ -4181,6 +4185,14 @@ Expect to Parse: "conformance/salsa/plainJSRedeclare3.ts"
3 │
╰────
× TS(1244): Abstract methods can only appear within an abstract class.
╭─[compiler/asiAbstract.ts:3:12]
2 │ class NonAbstractClass {
3 │ abstract s();
· ─
4 │ }
╰────
× TS1108: A 'return' statement can only be used within a function body
╭─[compiler/asiReturn.ts:2:1]
1 │ // This should be an error for using a return outside a function, but ASI should work properly
@ -11131,6 +11143,14 @@ Expect to Parse: "conformance/salsa/plainJSRedeclare3.ts"
9 │ }
╰────
× TS(1244): Abstract methods can only appear within an abstract class.
╭─[conformance/classes/classDeclarations/classAbstractKeyword/classAbstractInstantiations2.ts:50:14]
49 │ class H { // error -- not declared abstract
50 │ abstract baz() : number;
· ───
51 │ }
╰────
× Unexpected token
╭─[conformance/classes/classDeclarations/classAbstractKeyword/classAbstractManyKeywords.ts:3:1]
2 │ export abstract class B {}
@ -11163,6 +11183,14 @@ Expect to Parse: "conformance/salsa/plainJSRedeclare3.ts"
18 │
╰────
× TS(1244): Abstract methods can only appear within an abstract class.
╭─[conformance/classes/classDeclarations/classAbstractKeyword/classAbstractMethodInNonAbstractClass.ts:2:14]
1 │ class A {
2 │ abstract foo();
· ───
3 │ }
╰────
× TS(1245): Method 'foo' cannot have an implementation because it is marked abstract.
╭─[conformance/classes/classDeclarations/classAbstractKeyword/classAbstractMethodInNonAbstractClass.ts:6:14]
5 │ class B {
@ -11174,6 +11202,14 @@ Expect to Parse: "conformance/salsa/plainJSRedeclare3.ts"
× TS(1245): Method 'foo' cannot have an implementation because it is marked abstract.
╭─[conformance/classes/classDeclarations/classAbstractKeyword/classAbstractMethodInNonAbstractClass.ts:6:14]
5 │ class B {
6 │ abstract foo() {}
· ───
7 │ }
╰────
× TS(1244): Abstract methods can only appear within an abstract class.
╭─[conformance/classes/classDeclarations/classAbstractKeyword/classAbstractMethodInNonAbstractClass.ts:6:14]
5 │ class B {
6 │ abstract foo() {}
· ───
7 │ }
@ -11195,6 +11231,14 @@ Expect to Parse: "conformance/salsa/plainJSRedeclare3.ts"
3 │ }
╰────
× TS(1244): Abstract methods can only appear within an abstract class.
╭─[conformance/classes/classDeclarations/classAbstractKeyword/classAbstractUsingAbstractMethods2.ts:2:14]
1 │ class A {
2 │ abstract foo();
· ───
3 │ }
╰────
× 'abstract' modifier cannot be used here.
╭─[conformance/classes/classDeclarations/classAbstractKeyword/classAbstractWithInterface.ts:1:1]
1 │ abstract interface I {}