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:
camc314
2026-09-14 06:03:38 +00:00
parent a5bba6dd84
commit 8ca76da714
15 changed files with 146 additions and 21 deletions
+6
View File
@@ -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",
+40 -8
View File
@@ -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() {}
}
+2 -2
View File
@@ -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%)
+2 -2
View File
@@ -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%)
+2 -2
View File
@@ -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%)
+36 -3
View File
@@ -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() {}
+2 -2
View File
@@ -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%)