feat(semantic): report parameter related errors for setter/getter (#2316)

This commit is contained in:
Dunqing 2024-02-05 17:38:43 +08:00 committed by GitHub
parent 9ca13d040d
commit a3570d41f0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 88 additions and 32 deletions

View file

@ -2084,6 +2084,9 @@ impl MethodDefinitionKind {
pub fn is_method(&self) -> bool { pub fn is_method(&self) -> bool {
matches!(self, Self::Method) matches!(self, Self::Method)
} }
pub fn is_set(&self) -> bool {
matches!(self, Self::Set)
}
} }
#[derive(Debug, Clone, Hash)] #[derive(Debug, Clone, Hash)]

View file

@ -252,16 +252,6 @@ pub struct IllegalNewline(
#[diagnostic()] #[diagnostic()]
pub struct OptionalChainTaggedTemplate(#[label] pub Span); pub struct OptionalChainTaggedTemplate(#[label] pub Span);
#[derive(Debug, Error, Diagnostic)]
#[error("A 'get' accessor must not have any formal parameters.")]
#[diagnostic()]
pub struct GetterParameters(#[label] pub Span);
#[derive(Debug, Error, Diagnostic)]
#[error("A 'set' accessor must have exactly one parameter.")]
#[diagnostic()]
pub struct SetterParameters(#[label] pub Span);
#[derive(Debug, Error, Diagnostic)] #[derive(Debug, Error, Diagnostic)]
#[error("TS2681: A constructor cannot have a `this` parameter.")] #[error("TS2681: A constructor cannot have a `this` parameter.")]
#[diagnostic()] #[diagnostic()]

View file

@ -361,14 +361,6 @@ impl<'a> Parser<'a> {
let value = self.parse_method(r#async, generator)?; let value = self.parse_method(r#async, generator)?;
if kind == MethodDefinitionKind::Get && value.params.parameters_count() != 0 {
self.error(diagnostics::GetterParameters(value.params.span));
}
if kind == MethodDefinitionKind::Set && value.params.parameters_count() != 1 {
self.error(diagnostics::SetterParameters(value.params.span));
}
if kind == MethodDefinitionKind::Constructor { if kind == MethodDefinitionKind::Constructor {
if let Some(this_param) = &value.this_param { if let Some(this_param) = &value.this_param {
// class Foo { constructor(this: number) {} } // class Foo { constructor(this: number) {} }

View file

@ -5,7 +5,7 @@ use oxc_span::Span;
use oxc_syntax::operator::AssignmentOperator; use oxc_syntax::operator::AssignmentOperator;
use super::list::ObjectExpressionProperties; use super::list::ObjectExpressionProperties;
use crate::{diagnostics, lexer::Kind, list::SeparatedList, Parser}; use crate::{lexer::Kind, list::SeparatedList, Parser};
impl<'a> Parser<'a> { impl<'a> Parser<'a> {
/// [Object Expression](https://tc39.es/ecma262/#sec-object-initializer) /// [Object Expression](https://tc39.es/ecma262/#sec-object-initializer)
@ -217,9 +217,6 @@ impl<'a> Parser<'a> {
self.expect(Kind::Get)?; self.expect(Kind::Get)?;
let (key, computed) = self.parse_property_name()?; let (key, computed) = self.parse_property_name()?;
let method = self.parse_method(false, false)?; let method = self.parse_method(false, false)?;
if method.params.parameters_count() != 0 {
self.error(diagnostics::GetterParameters(method.params.span));
}
let value = self.ast.function_expression(method); let value = self.ast.function_expression(method);
Ok(self.ast.object_property( Ok(self.ast.object_property(
self.end_span(span), self.end_span(span),
@ -241,10 +238,6 @@ impl<'a> Parser<'a> {
let (key, computed) = self.parse_property_name()?; let (key, computed) = self.parse_property_name()?;
let method = self.parse_method(false, false)?; let method = self.parse_method(false, false)?;
if method.params.parameters_count() != 1 {
self.error(diagnostics::SetterParameters(method.params.span));
}
Ok(self.ast.object_property( Ok(self.ast.object_property(
self.end_span(span), self.end_span(span),
PropertyKind::Set, PropertyKind::Set,

View file

@ -78,8 +78,9 @@ impl EarlyErrorJavaScript {
} }
AstKind::Class(class) => check_class(class, node, ctx), AstKind::Class(class) => check_class(class, node, ctx),
AstKind::Super(sup) => check_super(sup, node, ctx), AstKind::MethodDefinition(method) => check_method_definition(method, ctx),
AstKind::ObjectProperty(prop) => check_object_property(prop, ctx), AstKind::ObjectProperty(prop) => check_object_property(prop, ctx),
AstKind::Super(sup) => check_super(sup, node, ctx),
AstKind::FormalParameters(params) => check_formal_parameters(params, node, ctx), AstKind::FormalParameters(params) => check_formal_parameters(params, node, ctx),
AstKind::ArrayPattern(pat) => check_array_pattern(pat, ctx), AstKind::ArrayPattern(pat) => check_array_pattern(pat, ctx),
@ -791,6 +792,48 @@ fn check_class(class: &Class, node: &AstNode<'_>, ctx: &SemanticBuilder<'_>) {
} }
} }
fn check_setter(function: &Function<'_>, ctx: &SemanticBuilder<'_>) {
#[derive(Debug, Error, Diagnostic)]
#[error("A 'set' accessor must have exactly one parameter.")]
#[diagnostic()]
struct SetterWithParameters(#[label] Span);
#[derive(Debug, Error, Diagnostic)]
#[error("A 'set' accessor cannot have rest parameter.")]
#[diagnostic()]
struct SetterWithRestParameter(#[label] Span);
function.params.rest.as_ref().map_or_else(
|| {
if function.params.parameters_count() != 1 {
ctx.error(SetterWithParameters(function.params.span));
}
},
|rest| {
ctx.error(SetterWithRestParameter(rest.span));
},
);
}
fn check_getter(function: &Function<'_>, ctx: &SemanticBuilder<'_>) {
#[derive(Debug, Error, Diagnostic)]
#[error("A 'get' accessor must not have any formal parameters.")]
#[diagnostic()]
pub struct GetterParameters(#[label] pub Span);
if !function.params.items.is_empty() {
ctx.error(GetterParameters(function.params.span));
}
}
fn check_method_definition(method: &MethodDefinition<'_>, ctx: &SemanticBuilder<'_>) {
match method.kind {
MethodDefinitionKind::Set => check_setter(&method.value, ctx),
MethodDefinitionKind::Get => check_getter(&method.value, ctx),
_ => {}
}
}
fn check_super<'a>(sup: &Super, node: &AstNode<'a>, ctx: &SemanticBuilder<'a>) { fn check_super<'a>(sup: &Super, node: &AstNode<'a>, ctx: &SemanticBuilder<'a>) {
#[derive(Debug, Error, Diagnostic)] #[derive(Debug, Error, Diagnostic)]
#[error("'super' can only be referenced in a derived class.")] #[error("'super' can only be referenced in a derived class.")]
@ -906,6 +949,14 @@ fn check_object_property(prop: &ObjectProperty, ctx: &SemanticBuilder<'_>) {
if let Some(expr) = &prop.init { if let Some(expr) = &prop.init {
ctx.error(CoverInitializedName(expr.span())); ctx.error(CoverInitializedName(expr.span()));
} }
if let Expression::FunctionExpression(function) = &prop.value {
match prop.kind {
PropertyKind::Set => check_setter(function, ctx),
PropertyKind::Get => check_getter(function, ctx),
PropertyKind::Init => {}
}
}
} }
#[derive(Debug, Error, Diagnostic)] #[derive(Debug, Error, Diagnostic)]

View file

@ -1,7 +1,7 @@
parser_babel Summary: parser_babel Summary:
AST Parsed : 2090/2096 (99.71%) AST Parsed : 2090/2096 (99.71%)
Positive Passed: 2086/2096 (99.52%) Positive Passed: 2086/2096 (99.52%)
Negative Passed: 1360/1500 (90.67%) Negative Passed: 1361/1500 (90.73%)
Expect Syntax Error: "annex-b/disabled/1.1-html-comments-close/input.js" 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/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-if-body/input.js"
@ -36,7 +36,6 @@ Expect Syntax Error: "es2020/dynamic-import-createImportExpression-false/invalid
Expect Syntax Error: "esprima/es2015-arrow-function/invalid-param-strict-mode/input.js" Expect Syntax Error: "esprima/es2015-arrow-function/invalid-param-strict-mode/input.js"
Expect Syntax Error: "esprima/es2015-generator/generator-parameter-binding-property-reserved/input.js" Expect Syntax Error: "esprima/es2015-generator/generator-parameter-binding-property-reserved/input.js"
Expect Syntax Error: "esprima/invalid-syntax/migrated_0101/input.js" Expect Syntax Error: "esprima/invalid-syntax/migrated_0101/input.js"
Expect Syntax Error: "esprima/rest-parameter/invalid-setter-rest/input.js"
Expect Syntax Error: "typescript/arrow-function/async-rest-optional-parameter/input.ts" Expect Syntax Error: "typescript/arrow-function/async-rest-optional-parameter/input.ts"
Expect Syntax Error: "typescript/cast/satisfies-const-error/input.ts" 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-assert-and-assign/input.ts"
@ -9461,6 +9460,12 @@ Expect to Parse: "typescript/types/const-type-parameters-babel-7/input.ts"
· ────── · ──────
╰──── ╰────
× A 'set' accessor cannot have rest parameter.
╭─[esprima/rest-parameter/invalid-setter-rest/input.js:1:13]
1 │ x = { set f(...y) {} }
· ────
╰────
× Invalid Unicode escape sequence × Invalid Unicode escape sequence
╭─[esprima/statement-expression/migrated_0002/input.js:1:2] ╭─[esprima/statement-expression/migrated_0002/input.js:1:2]
1 │ \\u0061 1 │ \\u0061

View file

@ -1,7 +1,7 @@
parser_typescript Summary: parser_typescript Summary:
AST Parsed : 5239/5243 (99.92%) AST Parsed : 5239/5243 (99.92%)
Positive Passed: 5232/5243 (99.79%) Positive Passed: 5232/5243 (99.79%)
Negative Passed: 1038/4879 (21.27%) Negative Passed: 1040/4879 (21.32%)
Expect Syntax Error: "compiler/ClassDeclaration10.ts" Expect Syntax Error: "compiler/ClassDeclaration10.ts"
Expect Syntax Error: "compiler/ClassDeclaration11.ts" Expect Syntax Error: "compiler/ClassDeclaration11.ts"
Expect Syntax Error: "compiler/ClassDeclaration13.ts" Expect Syntax Error: "compiler/ClassDeclaration13.ts"
@ -33,7 +33,6 @@ Expect Syntax Error: "compiler/accessorAccidentalCallDiagnostic.ts"
Expect Syntax Error: "compiler/accessorDeclarationEmitVisibilityErrors.ts" Expect Syntax Error: "compiler/accessorDeclarationEmitVisibilityErrors.ts"
Expect Syntax Error: "compiler/accessorInferredReturnTypeErrorInReturnStatement.ts" Expect Syntax Error: "compiler/accessorInferredReturnTypeErrorInReturnStatement.ts"
Expect Syntax Error: "compiler/accessorWithInitializer.ts" Expect Syntax Error: "compiler/accessorWithInitializer.ts"
Expect Syntax Error: "compiler/accessorWithRestParam.ts"
Expect Syntax Error: "compiler/accessorWithoutBody1.ts" Expect Syntax Error: "compiler/accessorWithoutBody1.ts"
Expect Syntax Error: "compiler/accessorWithoutBody2.ts" Expect Syntax Error: "compiler/accessorWithoutBody2.ts"
Expect Syntax Error: "compiler/accessorsInAmbientContext.ts" Expect Syntax Error: "compiler/accessorsInAmbientContext.ts"
@ -3173,7 +3172,6 @@ Expect Syntax Error: "conformance/parser/ecmascript5/MemberAccessorDeclarations/
Expect Syntax Error: "conformance/parser/ecmascript5/MemberAccessorDeclarations/parserMemberAccessorDeclaration11.ts" Expect Syntax Error: "conformance/parser/ecmascript5/MemberAccessorDeclarations/parserMemberAccessorDeclaration11.ts"
Expect Syntax Error: "conformance/parser/ecmascript5/MemberAccessorDeclarations/parserMemberAccessorDeclaration16.ts" Expect Syntax Error: "conformance/parser/ecmascript5/MemberAccessorDeclarations/parserMemberAccessorDeclaration16.ts"
Expect Syntax Error: "conformance/parser/ecmascript5/MemberAccessorDeclarations/parserMemberAccessorDeclaration17.ts" Expect Syntax Error: "conformance/parser/ecmascript5/MemberAccessorDeclarations/parserMemberAccessorDeclaration17.ts"
Expect Syntax Error: "conformance/parser/ecmascript5/MemberAccessorDeclarations/parserMemberAccessorDeclaration18.ts"
Expect Syntax Error: "conformance/parser/ecmascript5/MemberAccessorDeclarations/parserMemberAccessorDeclaration2.ts" Expect Syntax Error: "conformance/parser/ecmascript5/MemberAccessorDeclarations/parserMemberAccessorDeclaration2.ts"
Expect Syntax Error: "conformance/parser/ecmascript5/MemberAccessorDeclarations/parserMemberAccessorDeclaration3.ts" Expect Syntax Error: "conformance/parser/ecmascript5/MemberAccessorDeclarations/parserMemberAccessorDeclaration3.ts"
Expect Syntax Error: "conformance/parser/ecmascript5/MemberAccessorDeclarations/parserMemberAccessorDeclaration7.ts" Expect Syntax Error: "conformance/parser/ecmascript5/MemberAccessorDeclarations/parserMemberAccessorDeclaration7.ts"
@ -4099,6 +4097,22 @@ Expect to Parse: "conformance/salsa/plainJSRedeclare3.ts"
6 │ } 6 │ }
╰──── ╰────
× A 'set' accessor cannot have rest parameter.
╭─[compiler/accessorWithRestParam.ts:4:11]
3 │ class C {
4 │ set X(...v) { }
· ────
5 │ static set X(...v2) { }
╰────
× A 'set' accessor cannot have rest parameter.
╭─[compiler/accessorWithRestParam.ts:5:18]
4 │ set X(...v) { }
5 │ static set X(...v2) { }
· ─────
6 │ }
╰────
× Unexpected token × Unexpected token
╭─[compiler/aliasErrors.ts:13:12] ╭─[compiler/aliasErrors.ts:13:12]
12 │ import m2 = no.mod; 12 │ import m2 = no.mod;
@ -17151,6 +17165,14 @@ Expect to Parse: "conformance/salsa/plainJSRedeclare3.ts"
4 │ } 4 │ }
╰──── ╰────
× A 'set' accessor cannot have rest parameter.
╭─[conformance/parser/ecmascript5/MemberAccessorDeclarations/parserMemberAccessorDeclaration18.ts:3:12]
2 │ class C {
3 │ set Foo(...a) { }
· ────
4 │ }
╰────
× Expected a semicolon or an implicit semicolon after a statement, but found none × Expected a semicolon or an implicit semicolon after a statement, but found none
╭─[conformance/parser/ecmascript5/MemberFunctionDeclarations/parserMemberFunctionDeclaration4.ts:2:11] ╭─[conformance/parser/ecmascript5/MemberFunctionDeclarations/parserMemberFunctionDeclaration4.ts:2:11]
1 │ class C { 1 │ class C {