mirror of
https://github.com/danbulant/oxc
synced 2026-05-24 20:32:10 +00:00
feat(semantic): report parameter related errors for setter/getter (#2316)
This commit is contained in:
parent
9ca13d040d
commit
a3570d41f0
7 changed files with 88 additions and 32 deletions
|
|
@ -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)]
|
||||||
|
|
|
||||||
|
|
@ -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()]
|
||||||
|
|
|
||||||
|
|
@ -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) {} }
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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)]
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue