mirror of
https://github.com/oxc-project/oxc.git
synced 2026-09-14 19:36:11 +08:00
fix(parser): reject accessor modifiers on methods (#26617)
`class C { accessor x() {} }` was accepted as an ordinary method, silently dropping the `accessor` modifier. Reject it with TypeScript diagnostic TS1275 on methods, getters, setters, and constructors, while preserving valid auto-accessor fields and members named `accessor`.
This commit is contained in:
@@ -895,6 +895,12 @@ parser_diagnostics! {
|
||||
.with_allowed_modifier_help(allowed)
|
||||
};
|
||||
|
||||
accessor_only_on_property_declaration(modifier: Modifier, allowed: Option<ModifierKinds>) => {
|
||||
ts_error("1275", "'accessor' modifier can only appear on a property declaration.")
|
||||
.with_label(modifier.span())
|
||||
.with_allowed_modifier_help(allowed)
|
||||
};
|
||||
|
||||
modifier_only_on_property_declaration_or_index_signature(modifier: Modifier, allowed: Option<ModifierKinds>) => {
|
||||
ts_error(
|
||||
"1024",
|
||||
|
||||
@@ -507,9 +507,19 @@ impl<'a, C: Config> ParserImpl<'a, C> {
|
||||
self.check_method_definition_accessor(&method_definition);
|
||||
self.verify_modifiers(
|
||||
modifiers,
|
||||
ModifierKinds::all_except([ModifierKind::Async, ModifierKind::Declare]),
|
||||
ModifierKinds::all_except([
|
||||
ModifierKind::Async,
|
||||
ModifierKind::Declare,
|
||||
ModifierKind::Accessor,
|
||||
]),
|
||||
false,
|
||||
diagnostics::modifier_cannot_be_used_here,
|
||||
|modifier, allowed| {
|
||||
if modifier.kind == ModifierKind::Accessor {
|
||||
diagnostics::accessor_only_on_property_declaration(modifier, allowed)
|
||||
} else {
|
||||
diagnostics::modifier_cannot_be_used_here(modifier, allowed)
|
||||
}
|
||||
},
|
||||
);
|
||||
ClassElement::MethodDefinition(method_definition)
|
||||
}
|
||||
@@ -522,14 +532,26 @@ impl<'a, C: Config> ParserImpl<'a, C> {
|
||||
modifiers: &Modifiers,
|
||||
decorators: ArenaVec<'a, Decorator<'a>>,
|
||||
) -> ClassElement<'a> {
|
||||
if let Some(modifier) = modifiers.get(ModifierKind::Declare) {
|
||||
self.error(diagnostics::declare_constructor(modifier.span()));
|
||||
}
|
||||
self.verify_modifiers(
|
||||
modifiers,
|
||||
ModifierKinds::all_except([ModifierKind::Readonly]),
|
||||
ModifierKinds::all_except([
|
||||
ModifierKind::Declare,
|
||||
ModifierKind::Readonly,
|
||||
ModifierKind::Accessor,
|
||||
]),
|
||||
false,
|
||||
diagnostics::modifier_only_on_property_declaration_or_index_signature,
|
||||
|modifier, _| match modifier.kind {
|
||||
ModifierKind::Declare => diagnostics::declare_constructor(modifier.span()),
|
||||
ModifierKind::Readonly => {
|
||||
diagnostics::modifier_only_on_property_declaration_or_index_signature(
|
||||
modifier, None,
|
||||
)
|
||||
}
|
||||
ModifierKind::Accessor => {
|
||||
diagnostics::accessor_only_on_property_declaration(modifier, None)
|
||||
}
|
||||
_ => unreachable!(),
|
||||
},
|
||||
);
|
||||
|
||||
let value = self.parse_method(
|
||||
@@ -592,7 +614,11 @@ impl<'a, C: Config> ParserImpl<'a, C> {
|
||||
if generator.is_some() || matches!(self.cur_kind(), Kind::LParen | Kind::LAngle) {
|
||||
self.verify_modifiers(
|
||||
modifiers,
|
||||
ModifierKinds::all_except([ModifierKind::Declare, ModifierKind::Readonly]),
|
||||
ModifierKinds::all_except([
|
||||
ModifierKind::Declare,
|
||||
ModifierKind::Readonly,
|
||||
ModifierKind::Accessor,
|
||||
]),
|
||||
false,
|
||||
|modifier, _| {
|
||||
const ALLOWED: ModifierKinds = ModifierKinds::new([
|
||||
@@ -615,6 +641,12 @@ impl<'a, C: Config> ParserImpl<'a, C> {
|
||||
Some(ALLOWED),
|
||||
)
|
||||
}
|
||||
ModifierKind::Accessor => {
|
||||
diagnostics::accessor_only_on_property_declaration(
|
||||
modifier,
|
||||
Some(ALLOWED),
|
||||
)
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
},
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
abstract class C { abstract accessor x(): void; }
|
||||
@@ -0,0 +1 @@
|
||||
class C { accessor async x() {} }
|
||||
@@ -0,0 +1 @@
|
||||
class C { static accessor get x() { return 0; } }
|
||||
@@ -0,0 +1 @@
|
||||
class C { static accessor x() {} }
|
||||
@@ -0,0 +1 @@
|
||||
class C { static accessor set x(value: number) {} }
|
||||
@@ -0,0 +1,16 @@
|
||||
class C {
|
||||
accessor value = 0;
|
||||
static accessor count = 0;
|
||||
accessor() {}
|
||||
static accessor() {}
|
||||
}
|
||||
|
||||
class Fields {
|
||||
accessor = 0;
|
||||
static accessor = 0;
|
||||
}
|
||||
|
||||
class Newline {
|
||||
accessor
|
||||
x() {}
|
||||
}
|
||||
@@ -1,3 +1,3 @@
|
||||
codegen_misc Summary:
|
||||
AST Parsed : 109/109 (100.00%)
|
||||
Positive Passed: 109/109 (100.00%)
|
||||
AST Parsed : 110/110 (100.00%)
|
||||
Positive Passed: 110/110 (100.00%)
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
formatter_misc Summary:
|
||||
AST Parsed : 109/109 (100.00%)
|
||||
Positive Passed: 109/109 (100.00%)
|
||||
AST Parsed : 110/110 (100.00%)
|
||||
Positive Passed: 110/110 (100.00%)
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
lexer_misc Summary:
|
||||
AST Parsed : 331/331 (100.00%)
|
||||
Positive Passed: 331/331 (100.00%)
|
||||
AST Parsed : 337/337 (100.00%)
|
||||
Positive Passed: 337/337 (100.00%)
|
||||
|
||||
@@ -1,7 +1,40 @@
|
||||
parser_misc Summary:
|
||||
AST Parsed : 109/109 (100.00%)
|
||||
Positive Passed: 109/109 (100.00%)
|
||||
Negative Passed: 222/222 (100.00%)
|
||||
AST Parsed : 110/110 (100.00%)
|
||||
Positive Passed: 110/110 (100.00%)
|
||||
Negative Passed: 227/227 (100.00%)
|
||||
|
||||
× TS(1275): 'accessor' modifier can only appear on a property declaration.
|
||||
╭─[misc/fail/accessor-modifier-abstract-method.ts:1:29]
|
||||
1 │ abstract class C { abstract accessor x(): void; }
|
||||
· ────────
|
||||
╰────
|
||||
help: Allowed modifiers are: private, protected, public, static, abstract, override, async
|
||||
|
||||
× TS(1275): 'accessor' modifier can only appear on a property declaration.
|
||||
╭─[misc/fail/accessor-modifier-async-method.ts:1:11]
|
||||
1 │ class C { accessor async x() {} }
|
||||
· ────────
|
||||
╰────
|
||||
help: Allowed modifiers are: private, protected, public, static, abstract, override, async
|
||||
|
||||
× TS(1275): 'accessor' modifier can only appear on a property declaration.
|
||||
╭─[misc/fail/accessor-modifier-static-getter.ts:1:18]
|
||||
1 │ class C { static accessor get x() { return 0; } }
|
||||
· ────────
|
||||
╰────
|
||||
|
||||
× TS(1275): 'accessor' modifier can only appear on a property declaration.
|
||||
╭─[misc/fail/accessor-modifier-static-method.ts:1:18]
|
||||
1 │ class C { static accessor x() {} }
|
||||
· ────────
|
||||
╰────
|
||||
help: Allowed modifiers are: private, protected, public, static, abstract, override, async
|
||||
|
||||
× TS(1275): 'accessor' modifier can only appear on a property declaration.
|
||||
╭─[misc/fail/accessor-modifier-static-setter.ts:1:18]
|
||||
1 │ class C { static accessor set x(value: number) {} }
|
||||
· ────────
|
||||
╰────
|
||||
|
||||
× Cannot assign to 'arguments' in strict mode
|
||||
╭─[misc/fail/arguments-eval-ambient.ts:2:13]
|
||||
|
||||
@@ -17612,6 +17612,39 @@ Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/types/wit
|
||||
10 │ accessor i() {}
|
||||
╰────
|
||||
|
||||
× TS(1275): 'accessor' modifier can only appear on a property declaration.
|
||||
╭─[typescript/tests/cases/conformance/classes/propertyMemberDeclarations/autoAccessorDisallowedModifiers.ts:10:5]
|
||||
9 │ accessor static h: any;
|
||||
10 │ accessor i() {}
|
||||
· ────────
|
||||
11 │ accessor get j() { return false; }
|
||||
╰────
|
||||
help: Allowed modifiers are: private, protected, public, static, abstract, override, async
|
||||
|
||||
× TS(1275): 'accessor' modifier can only appear on a property declaration.
|
||||
╭─[typescript/tests/cases/conformance/classes/propertyMemberDeclarations/autoAccessorDisallowedModifiers.ts:11:5]
|
||||
10 │ accessor i() {}
|
||||
11 │ accessor get j() { return false; }
|
||||
· ────────
|
||||
12 │ accessor set k(v: any) {}
|
||||
╰────
|
||||
|
||||
× TS(1275): 'accessor' modifier can only appear on a property declaration.
|
||||
╭─[typescript/tests/cases/conformance/classes/propertyMemberDeclarations/autoAccessorDisallowedModifiers.ts:12:5]
|
||||
11 │ accessor get j() { return false; }
|
||||
12 │ accessor set k(v: any) {}
|
||||
· ────────
|
||||
13 │ accessor constructor() {}
|
||||
╰────
|
||||
|
||||
× TS(1275): 'accessor' modifier can only appear on a property declaration.
|
||||
╭─[typescript/tests/cases/conformance/classes/propertyMemberDeclarations/autoAccessorDisallowedModifiers.ts:13:5]
|
||||
12 │ accessor set k(v: any) {}
|
||||
13 │ accessor constructor() {}
|
||||
· ────────
|
||||
14 │ accessor l?: any;
|
||||
╰────
|
||||
|
||||
× TS(1276): An 'accessor' property cannot be declared optional.
|
||||
╭─[typescript/tests/cases/conformance/classes/propertyMemberDeclarations/autoAccessorDisallowedModifiers.ts:14:15]
|
||||
13 │ accessor constructor() {}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
semantic_misc Summary:
|
||||
AST Parsed : 109/109 (100.00%)
|
||||
Positive Passed: 104/109 (95.41%)
|
||||
AST Parsed : 110/110 (100.00%)
|
||||
Positive Passed: 105/110 (95.45%)
|
||||
semantic Error: tasks/coverage/misc/pass/declare-let-private.ts
|
||||
Bindings mismatch:
|
||||
after transform: ScopeId(0): ["private"]
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
transformer_misc Summary:
|
||||
AST Parsed : 109/109 (100.00%)
|
||||
Positive Passed: 109/109 (100.00%)
|
||||
AST Parsed : 110/110 (100.00%)
|
||||
Positive Passed: 110/110 (100.00%)
|
||||
|
||||
Reference in New Issue
Block a user