From da2ffdf7a04c28e36ecf8b417f0c9db033491e18 Mon Sep 17 00:00:00 2001 From: Dunqing Date: Fri, 2 Feb 2024 15:58:32 +0800 Subject: [PATCH] feat(semantic): check parameters property (#2264) --- crates/oxc_semantic/src/checker/typescript.rs | 11 ++ tasks/coverage/parser_babel.snap | 80 ++++++++ tasks/coverage/parser_typescript.snap | 178 ++++++++++++++++-- 3 files changed, 258 insertions(+), 11 deletions(-) diff --git a/crates/oxc_semantic/src/checker/typescript.rs b/crates/oxc_semantic/src/checker/typescript.rs index cf45cc2f7..4d4a1001a 100644 --- a/crates/oxc_semantic/src/checker/typescript.rs +++ b/crates/oxc_semantic/src/checker/typescript.rs @@ -44,12 +44,18 @@ fn check_formal_parameters(params: &FormalParameters, ctx: &SemanticBuilder<'_>) #[error("A required parameter cannot follow an optional parameter.")] #[diagnostic()] struct RequiredParameterAfterOptionalParameter(#[label] Span); + #[derive(Debug, Error, Diagnostic)] + #[error("A parameter property is only allowed in a constructor implementation.")] + #[diagnostic()] + struct ParameterPropertyOutsideConstructor(#[label] Span); if !params.is_empty() && params.kind == FormalParameterKind::Signature { check_duplicate_bound_names(params, ctx); } + let is_inside_constructor = ctx.current_scope_flags().is_constructor(); let mut has_optional = false; + for item in ¶ms.items { // function a(optional?: number, required: number) { } if has_optional && !item.pattern.optional && !item.pattern.kind.is_assignment_pattern() { @@ -58,6 +64,11 @@ fn check_formal_parameters(params: &FormalParameters, ctx: &SemanticBuilder<'_>) if item.pattern.optional { has_optional = true; } + + // function a(public x: number) { } + if !is_inside_constructor && item.accessibility.is_some() { + ctx.error(ParameterPropertyOutsideConstructor(item.span)); + } } } diff --git a/tasks/coverage/parser_babel.snap b/tasks/coverage/parser_babel.snap index 921aa5ecf..633bdc1da 100644 --- a/tasks/coverage/parser_babel.snap +++ b/tasks/coverage/parser_babel.snap @@ -9787,6 +9787,30 @@ Expect to Parse: "typescript/types/const-type-parameters-babel-7/input.ts" ╰──── help: Try insert a semicolon here + × A parameter property is only allowed in a constructor implementation. + ╭─[typescript/class/parameter-properties-not-constructor/input.ts:3:1] + 3 │ readonly r, + 4 │ public pu: number, + · ───────────────── + 5 │ protected po?, + ╰──── + + × A parameter property is only allowed in a constructor implementation. + ╭─[typescript/class/parameter-properties-not-constructor/input.ts:4:1] + 4 │ public pu: number, + 5 │ protected po?, + · ───────────── + 6 │ private pi?: number, + ╰──── + + × A parameter property is only allowed in a constructor implementation. + ╭─[typescript/class/parameter-properties-not-constructor/input.ts:5:1] + 5 │ protected po?, + 6 │ private pi?: number, + · ─────────────────── + 7 │ public readonly pur, + ╰──── + × A required parameter cannot follow an optional parameter. ╭─[typescript/class/parameter-properties-not-constructor/input.ts:6:1] 6 │ private pi?: number, @@ -9795,6 +9819,22 @@ Expect to Parse: "typescript/types/const-type-parameters-babel-7/input.ts" 8 │ // Also works on AssignmentPattern ╰──── + × A parameter property is only allowed in a constructor implementation. + ╭─[typescript/class/parameter-properties-not-constructor/input.ts:6:1] + 6 │ private pi?: number, + 7 │ public readonly pur, + · ─────────────────── + 8 │ // Also works on AssignmentPattern + ╰──── + + × A parameter property is only allowed in a constructor implementation. + ╭─[typescript/class/parameter-properties-not-constructor/input.ts:9:1] + 9 │ readonly x = 0, + 10 │ public y?: number = 0) {} + · ───────────────────── + 11 │ } + ╰──── + × Unexpected token ╭─[typescript/const/invalid-initializer-ambient-context/input.ts:1:1] 1 │ declare module N { @@ -9842,6 +9882,30 @@ Expect to Parse: "typescript/types/const-type-parameters-babel-7/input.ts" · ─── ╰──── + × A parameter property is only allowed in a constructor implementation. + ╭─[typescript/function/parameter-properties/input.ts:2:1] + 2 │ readonly r, + 3 │ public pu: number, + · ───────────────── + 4 │ protected po?, + ╰──── + + × A parameter property is only allowed in a constructor implementation. + ╭─[typescript/function/parameter-properties/input.ts:3:1] + 3 │ public pu: number, + 4 │ protected po?, + · ───────────── + 5 │ private pi?: number, + ╰──── + + × A parameter property is only allowed in a constructor implementation. + ╭─[typescript/function/parameter-properties/input.ts:4:1] + 4 │ protected po?, + 5 │ private pi?: number, + · ─────────────────── + 6 │ public readonly pur, + ╰──── + × A required parameter cannot follow an optional parameter. ╭─[typescript/function/parameter-properties/input.ts:5:1] 5 │ private pi?: number, @@ -9850,6 +9914,22 @@ Expect to Parse: "typescript/types/const-type-parameters-babel-7/input.ts" 7 │ readonly x = 0, ╰──── + × A parameter property is only allowed in a constructor implementation. + ╭─[typescript/function/parameter-properties/input.ts:5:1] + 5 │ private pi?: number, + 6 │ public readonly pur, + · ─────────────────── + 7 │ readonly x = 0, + ╰──── + + × A parameter property is only allowed in a constructor implementation. + ╭─[typescript/function/parameter-properties/input.ts:7:1] + 7 │ readonly x = 0, + 8 │ public y?: number = 0 + · ───────────────────── + 9 │ ) {} + ╰──── + × A required parameter cannot follow an optional parameter. ╭─[typescript/function/pattern-optional-parameters/input.ts:1:1] 1 │ function f([]?, {}) {} diff --git a/tasks/coverage/parser_typescript.snap b/tasks/coverage/parser_typescript.snap index 66952b913..91222e3a3 100644 --- a/tasks/coverage/parser_typescript.snap +++ b/tasks/coverage/parser_typescript.snap @@ -1,7 +1,7 @@ parser_typescript Summary: AST Parsed : 5239/5243 (99.92%) Positive Passed: 5232/5243 (99.79%) -Negative Passed: 1025/4879 (21.01%) +Negative Passed: 1035/4879 (21.21%) Expect Syntax Error: "compiler/ClassDeclaration10.ts" Expect Syntax Error: "compiler/ClassDeclaration11.ts" Expect Syntax Error: "compiler/ClassDeclaration13.ts" @@ -21,9 +21,6 @@ Expect Syntax Error: "compiler/FunctionDeclaration4.ts" Expect Syntax Error: "compiler/FunctionDeclaration6.ts" Expect Syntax Error: "compiler/FunctionDeclaration7.ts" Expect Syntax Error: "compiler/InterfaceDeclaration8.ts" -Expect Syntax Error: "compiler/MemberAccessorDeclaration15.ts" -Expect Syntax Error: "compiler/ParameterList13.ts" -Expect Syntax Error: "compiler/ParameterList4.ts" Expect Syntax Error: "compiler/ParameterList7.ts" Expect Syntax Error: "compiler/ParameterList8.ts" Expect Syntax Error: "compiler/abstractClassInLocalScopeIsAbstract.ts" @@ -35,7 +32,6 @@ Expect Syntax Error: "compiler/accessStaticMemberFromInstanceMethod01.ts" Expect Syntax Error: "compiler/accessorAccidentalCallDiagnostic.ts" Expect Syntax Error: "compiler/accessorDeclarationEmitVisibilityErrors.ts" Expect Syntax Error: "compiler/accessorInferredReturnTypeErrorInReturnStatement.ts" -Expect Syntax Error: "compiler/accessorParameterAccessibilityModifier.ts" Expect Syntax Error: "compiler/accessorWithInitializer.ts" Expect Syntax Error: "compiler/accessorWithRestParam.ts" Expect Syntax Error: "compiler/accessorWithoutBody1.ts" @@ -1404,7 +1400,6 @@ Expect Syntax Error: "compiler/parameterNamesInTypeParameterList.ts" Expect Syntax Error: "compiler/parameterPropertyInConstructor1.ts" Expect Syntax Error: "compiler/parameterPropertyInConstructor2.ts" Expect Syntax Error: "compiler/parameterPropertyInConstructor3.ts" -Expect Syntax Error: "compiler/parameterPropertyOutsideConstructor.ts" Expect Syntax Error: "compiler/paramsOnlyHaveLiteralTypesWhenAppropriatelyContextualized.ts" Expect Syntax Error: "compiler/paramterDestrcuturingDeclaration.ts" Expect Syntax Error: "compiler/parenthesizedJSDocCastDoesNotNarrow.ts" @@ -3179,7 +3174,6 @@ Expect Syntax Error: "conformance/parser/ecmascript5/InterfaceDeclarations/parse Expect Syntax Error: "conformance/parser/ecmascript5/MemberAccessorDeclarations/parserMemberAccessor1.ts" Expect Syntax Error: "conformance/parser/ecmascript5/MemberAccessorDeclarations/parserMemberAccessorDeclaration1.ts" Expect Syntax Error: "conformance/parser/ecmascript5/MemberAccessorDeclarations/parserMemberAccessorDeclaration11.ts" -Expect Syntax Error: "conformance/parser/ecmascript5/MemberAccessorDeclarations/parserMemberAccessorDeclaration15.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/parserMemberAccessorDeclaration18.ts" @@ -3204,13 +3198,11 @@ Expect Syntax Error: "conformance/parser/ecmascript5/ModuleDeclarations/parserMo Expect Syntax Error: "conformance/parser/ecmascript5/ModuleDeclarations/parserModuleDeclaration4.d.ts" Expect Syntax Error: "conformance/parser/ecmascript5/ModuleDeclarations/parserModuleDeclaration5.ts" Expect Syntax Error: "conformance/parser/ecmascript5/ParameterLists/parserParameterList11.ts" -Expect Syntax Error: "conformance/parser/ecmascript5/ParameterLists/parserParameterList13.ts" Expect Syntax Error: "conformance/parser/ecmascript5/ParameterLists/parserParameterList14.ts" Expect Syntax Error: "conformance/parser/ecmascript5/ParameterLists/parserParameterList15.ts" Expect Syntax Error: "conformance/parser/ecmascript5/ParameterLists/parserParameterList16.ts" Expect Syntax Error: "conformance/parser/ecmascript5/ParameterLists/parserParameterList17.ts" Expect Syntax Error: "conformance/parser/ecmascript5/ParameterLists/parserParameterList2.ts" -Expect Syntax Error: "conformance/parser/ecmascript5/ParameterLists/parserParameterList4.ts" Expect Syntax Error: "conformance/parser/ecmascript5/ParameterLists/parserParameterList7.ts" Expect Syntax Error: "conformance/parser/ecmascript5/ParameterLists/parserParameterList8.ts" Expect Syntax Error: "conformance/parser/ecmascript5/ParameterLists/parserParameterList9.ts" @@ -3585,8 +3577,6 @@ Expect Syntax Error: "conformance/types/nonPrimitive/nonPrimitiveUnionIntersecti Expect Syntax Error: "conformance/types/objectTypeLiteral/callSignatures/callSignatureWithOptionalParameterAndInitializer.ts" Expect Syntax Error: "conformance/types/objectTypeLiteral/callSignatures/callSignaturesThatDifferOnlyByReturnType2.ts" Expect Syntax Error: "conformance/types/objectTypeLiteral/callSignatures/callSignaturesWithParameterInitializers.ts" -Expect Syntax Error: "conformance/types/objectTypeLiteral/callSignatures/constructSignatureWithAccessibilityModifiersOnParameters.ts" -Expect Syntax Error: "conformance/types/objectTypeLiteral/callSignatures/constructSignatureWithAccessibilityModifiersOnParameters2.ts" Expect Syntax Error: "conformance/types/objectTypeLiteral/callSignatures/specializedSignatureIsNotSubtypeOfNonSpecializedSignature.ts" Expect Syntax Error: "conformance/types/objectTypeLiteral/callSignatures/stringLiteralTypesInImplementationSignatures2.ts" Expect Syntax Error: "conformance/types/objectTypeLiteral/callSignatures/typeParameterUsedAsTypeParameterConstraint4.ts" @@ -4034,6 +4024,29 @@ Expect to Parse: "conformance/salsa/plainJSRedeclare3.ts" ╰──── help: Try insert a semicolon here + × A parameter property is only allowed in a constructor implementation. + ╭─[compiler/MemberAccessorDeclaration15.ts:1:1] + 1 │ class C { + 2 │ set Foo(public a: number) { } + · ──────────────── + 3 │ } + ╰──── + + × A parameter property is only allowed in a constructor implementation. + ╭─[compiler/ParameterList13.ts:1:1] + 1 │ interface I { + 2 │ new (public x); + · ──────── + 3 │ } + ╰──── + + × A parameter property is only allowed in a constructor implementation. + ╭─[compiler/ParameterList4.ts:1:1] + 1 │ function F(public A) { + · ──────── + 2 │ } + ╰──── + × Expected `)` but found `Identifier` ╭─[compiler/ParameterList5.ts:1:1] 1 │ function A(): (public B) => C { @@ -4072,6 +4085,22 @@ Expect to Parse: "conformance/salsa/plainJSRedeclare3.ts" 3 │ }; ╰──── + × A parameter property is only allowed in a constructor implementation. + ╭─[compiler/accessorParameterAccessibilityModifier.ts:3:1] + 3 │ class C { + 4 │ set X(public v) { } + · ──────── + 5 │ static set X(public v2) { } + ╰──── + + × A parameter property is only allowed in a constructor implementation. + ╭─[compiler/accessorParameterAccessibilityModifier.ts:4:1] + 4 │ set X(public v) { } + 5 │ static set X(public v2) { } + · ───────── + 6 │ } + ╰──── + × Unexpected token ╭─[compiler/aliasErrors.ts:12:1] 12 │ import m2 = no.mod; @@ -7969,6 +7998,14 @@ Expect to Parse: "conformance/salsa/plainJSRedeclare3.ts" 3 │ static test() ╰──── + × A parameter property is only allowed in a constructor implementation. + ╭─[compiler/parameterPropertyOutsideConstructor.ts:1:1] + 1 │ class C { + 2 │ foo(public x) { + · ──────── + 3 │ } + ╰──── + × Unexpected token ╭─[compiler/parse1.ts:3:1] 3 │ bar. @@ -17021,6 +17058,14 @@ Expect to Parse: "conformance/salsa/plainJSRedeclare3.ts" 4 │ } ╰──── + × A parameter property is only allowed in a constructor implementation. + ╭─[conformance/parser/ecmascript5/MemberAccessorDeclarations/parserMemberAccessorDeclaration15.ts:2:1] + 2 │ class C { + 3 │ set Foo(public a: number) { } + · ──────────────── + 4 │ } + ╰──── + × Expected a semicolon or an implicit semicolon after a statement, but found none ╭─[conformance/parser/ecmascript5/MemberFunctionDeclarations/parserMemberFunctionDeclaration4.ts:1:1] 1 │ class C { @@ -17084,6 +17129,14 @@ Expect to Parse: "conformance/salsa/plainJSRedeclare3.ts" 3 │ } ╰──── + × A parameter property is only allowed in a constructor implementation. + ╭─[conformance/parser/ecmascript5/ParameterLists/parserParameterList13.ts:1:1] + 1 │ interface I { + 2 │ new (public x); + · ──────── + 3 │ } + ╰──── + × A required parameter cannot follow an optional parameter. ╭─[conformance/parser/ecmascript5/ParameterLists/parserParameterList3.ts:1:1] 1 │ class C { @@ -17092,6 +17145,13 @@ Expect to Parse: "conformance/salsa/plainJSRedeclare3.ts" 3 │ } ╰──── + × A parameter property is only allowed in a constructor implementation. + ╭─[conformance/parser/ecmascript5/ParameterLists/parserParameterList4.ts:1:1] + 1 │ function F(public A) { + · ──────── + 2 │ } + ╰──── + × Expected `)` but found `Identifier` ╭─[conformance/parser/ecmascript5/ParameterLists/parserParameterList5.ts:1:1] 1 │ function A(): (public B) => C { @@ -19286,6 +19346,102 @@ Expect to Parse: "conformance/salsa/plainJSRedeclare3.ts" ╰──── help: Try insert a semicolon here + × A parameter property is only allowed in a constructor implementation. + ╭─[conformance/types/objectTypeLiteral/callSignatures/constructSignatureWithAccessibilityModifiersOnParameters.ts:15:1] + 15 │ interface I { + 16 │ new (public x); + · ──────── + 17 │ } + ╰──── + + × A parameter property is only allowed in a constructor implementation. + ╭─[conformance/types/objectTypeLiteral/callSignatures/constructSignatureWithAccessibilityModifiersOnParameters.ts:19:1] + 19 │ interface I2 { + 20 │ new (private x); + · ───────── + 21 │ } + ╰──── + + × A parameter property is only allowed in a constructor implementation. + ╭─[conformance/types/objectTypeLiteral/callSignatures/constructSignatureWithAccessibilityModifiersOnParameters.ts:23:1] + 23 │ var a: { + 24 │ new (public x); + · ──────── + 25 │ } + ╰──── + + × A parameter property is only allowed in a constructor implementation. + ╭─[conformance/types/objectTypeLiteral/callSignatures/constructSignatureWithAccessibilityModifiersOnParameters.ts:27:1] + 27 │ var b: { + 28 │ new (private x); + · ───────── + 29 │ } + ╰──── + + × A parameter property is only allowed in a constructor implementation. + ╭─[conformance/types/objectTypeLiteral/callSignatures/constructSignatureWithAccessibilityModifiersOnParameters2.ts:18:1] + 18 │ interface I { + 19 │ new (public x); + · ──────── + 20 │ new (public x); + ╰──── + + × A parameter property is only allowed in a constructor implementation. + ╭─[conformance/types/objectTypeLiteral/callSignatures/constructSignatureWithAccessibilityModifiersOnParameters2.ts:19:1] + 19 │ new (public x); + 20 │ new (public x); + · ──────── + 21 │ } + ╰──── + + × A parameter property is only allowed in a constructor implementation. + ╭─[conformance/types/objectTypeLiteral/callSignatures/constructSignatureWithAccessibilityModifiersOnParameters2.ts:23:1] + 23 │ interface I2 { + 24 │ new (private x); + · ───────── + 25 │ new (private x); + ╰──── + + × A parameter property is only allowed in a constructor implementation. + ╭─[conformance/types/objectTypeLiteral/callSignatures/constructSignatureWithAccessibilityModifiersOnParameters2.ts:24:1] + 24 │ new (private x); + 25 │ new (private x); + · ───────── + 26 │ } + ╰──── + + × A parameter property is only allowed in a constructor implementation. + ╭─[conformance/types/objectTypeLiteral/callSignatures/constructSignatureWithAccessibilityModifiersOnParameters2.ts:28:1] + 28 │ var a: { + 29 │ new (public x); + · ──────── + 30 │ new (public y); + ╰──── + + × A parameter property is only allowed in a constructor implementation. + ╭─[conformance/types/objectTypeLiteral/callSignatures/constructSignatureWithAccessibilityModifiersOnParameters2.ts:29:1] + 29 │ new (public x); + 30 │ new (public y); + · ──────── + 31 │ } + ╰──── + + × A parameter property is only allowed in a constructor implementation. + ╭─[conformance/types/objectTypeLiteral/callSignatures/constructSignatureWithAccessibilityModifiersOnParameters2.ts:33:1] + 33 │ var b: { + 34 │ new (private x); + · ───────── + 35 │ new (private y); + ╰──── + + × A parameter property is only allowed in a constructor implementation. + ╭─[conformance/types/objectTypeLiteral/callSignatures/constructSignatureWithAccessibilityModifiersOnParameters2.ts:34:1] + 34 │ new (private x); + 35 │ new (private y); + · ───────── + 36 │ } + ╰──── + × A rest element must be last in a destructuring pattern ╭─[conformance/types/objectTypeLiteral/callSignatures/restParameterWithoutAnnotationIsAnyArray.ts:4:1] 4 │ var f = function foo(...x) { }