diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index c82e0ece07473..f0382b0a6ee3a 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -14217,14 +14217,14 @@ namespace ts { function checkPropertyDeclaration(node: PropertyDeclaration) { // Grammar checking - checkGrammarDecorators(node) || checkGrammarModifiers(node) || checkGrammarProperty(node) || checkGrammarComputedPropertyName(node.name); + checkGrammarDecorators(node) || checkGrammarModifiers(node) || checkGrammarProperty(node) || checkGrammarComputedPropertyName(node.name) || checkGrammarStaticPropertyOrMethodName(node); checkVariableLikeDeclaration(node); } function checkMethodDeclaration(node: MethodDeclaration) { // Grammar checking - checkGrammarMethod(node) || checkGrammarComputedPropertyName(node.name); + checkGrammarMethod(node) || checkGrammarComputedPropertyName(node.name) || checkGrammarStaticPropertyOrMethodName(node); // Grammar checking for modifiers is done inside the function checkGrammarFunctionLikeDeclaration checkFunctionOrMethodDeclaration(node); @@ -14236,6 +14236,35 @@ namespace ts { } } + function checkGrammarStaticPropertyOrMethodName(node: ClassElement) { + if (node.flags & NodeFlags.Static) { + if (node.kind === SyntaxKind.PropertyDeclaration) { + return checkGrammarStaticMemberName(node, ((node as ClassElement).name as Identifier).text); + } + else if (node.kind === SyntaxKind.MethodDeclaration) { + if (languageVersion < ScriptTarget.ES6) { + return checkGrammarStaticMemberName(node, ((node as ClassElement).name as Identifier).text); + } + } + } + + return false; + } + + function checkGrammarStaticMemberName(node: Node, name: string) { + // see: https://github.com/Microsoft/TypeScript/issues/442 + const forbiddenNames = ["length", "name", "arguments", "caller"]; + if (forbiddenNames.indexOf(name) !== -1) { + if (languageVersion < ScriptTarget.ES6) { + return grammarErrorOnNode(node, Diagnostics._0_is_not_allowed_to_be_used_as_a_name_of_a_static_property_or_method_in_a_class_for_target_es5_2696, name); + } else { + return grammarErrorOnNode(node, Diagnostics._0_is_not_allowed_to_be_used_as_a_name_of_a_static_property_in_a_class_for_target_es6_and_higher_2697, name); + } + } + + return false; + } + function checkConstructorDeclaration(node: ConstructorDeclaration) { // Grammar check on signature of constructor and modifier of the constructor is done in checkSignatureDeclaration function. checkSignatureDeclaration(node); @@ -19714,6 +19743,13 @@ namespace ts { if (computedPropertyName.expression.kind === SyntaxKind.BinaryExpression && (computedPropertyName.expression).operatorToken.kind === SyntaxKind.CommaToken) { return grammarErrorOnNode(computedPropertyName.expression, Diagnostics.A_comma_expression_is_not_allowed_in_a_computed_property_name); } + + if (computedPropertyName.expression.kind === SyntaxKind.StringLiteral) { + const member = computedPropertyName.parent.parent.parent; + if (member.flags & NodeFlags.Static && member.kind === SyntaxKind.PropertyDeclaration) { + return checkGrammarStaticMemberName(computedPropertyName, (computedPropertyName.expression as StringLiteral).text); + } + } } function checkGrammarForGenerator(node: FunctionLikeDeclaration) { diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 0f3e90405a6f6..f6b2ae15ba8cd 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -1959,6 +1959,14 @@ "category": "Error", "code": 2695 }, + "'{0}' is not allowed to be used as a name of a static property or method in a class for target ES5.": { + "category": "Error", + "code": 2696 + }, + "'{0}' is not allowed to be used as a name of a static property in a class for target ES6 and higher.": { + "category": "Error", + "code": 2697 + }, "Import declaration '{0}' is using private name '{1}'.": { "category": "Error", diff --git a/tests/baselines/reference/checkGrammarStaticMemberName_es5.errors.txt b/tests/baselines/reference/checkGrammarStaticMemberName_es5.errors.txt new file mode 100644 index 0000000000000..ec2d9292600c5 --- /dev/null +++ b/tests/baselines/reference/checkGrammarStaticMemberName_es5.errors.txt @@ -0,0 +1,60 @@ +tests/cases/compiler/checkGrammarStaticMemberName_es5.ts(3,5): error TS2696: 'length' is not allowed to be used as a name of a static property or method in a class for target ES5. +tests/cases/compiler/checkGrammarStaticMemberName_es5.ts(4,5): error TS2696: 'name' is not allowed to be used as a name of a static property or method in a class for target ES5. +tests/cases/compiler/checkGrammarStaticMemberName_es5.ts(5,5): error TS2696: 'arguments' is not allowed to be used as a name of a static property or method in a class for target ES5. +tests/cases/compiler/checkGrammarStaticMemberName_es5.ts(6,5): error TS2696: 'caller' is not allowed to be used as a name of a static property or method in a class for target ES5. +tests/cases/compiler/checkGrammarStaticMemberName_es5.ts(8,9): error TS2696: 'length' is not allowed to be used as a name of a static property or method in a class for target ES5. +tests/cases/compiler/checkGrammarStaticMemberName_es5.ts(9,9): error TS2696: 'name' is not allowed to be used as a name of a static property or method in a class for target ES5. +tests/cases/compiler/checkGrammarStaticMemberName_es5.ts(10,9): error TS2696: 'arguments' is not allowed to be used as a name of a static property or method in a class for target ES5. +tests/cases/compiler/checkGrammarStaticMemberName_es5.ts(11,9): error TS2696: 'caller' is not allowed to be used as a name of a static property or method in a class for target ES5. +tests/cases/compiler/checkGrammarStaticMemberName_es5.ts(16,12): error TS2696: 'length' is not allowed to be used as a name of a static property or method in a class for target ES5. +tests/cases/compiler/checkGrammarStaticMemberName_es5.ts(17,12): error TS2696: 'name' is not allowed to be used as a name of a static property or method in a class for target ES5. +tests/cases/compiler/checkGrammarStaticMemberName_es5.ts(18,12): error TS2696: 'arguments' is not allowed to be used as a name of a static property or method in a class for target ES5. +tests/cases/compiler/checkGrammarStaticMemberName_es5.ts(19,12): error TS2696: 'caller' is not allowed to be used as a name of a static property or method in a class for target ES5. + + +==== tests/cases/compiler/checkGrammarStaticMemberName_es5.ts (12 errors) ==== + + class static_property { + static length = 1; + ~~~~~~~~~~~~~~~~~~ +!!! error TS2696: 'length' is not allowed to be used as a name of a static property or method in a class for target ES5. + static name = 1; + ~~~~~~~~~~~~~~~~ +!!! error TS2696: 'name' is not allowed to be used as a name of a static property or method in a class for target ES5. + static arguments = 1; + ~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2696: 'arguments' is not allowed to be used as a name of a static property or method in a class for target ES5. + static caller = 1; + ~~~~~~~~~~~~~~~~~~ +!!! error TS2696: 'caller' is not allowed to be used as a name of a static property or method in a class for target ES5. + static foo = { + ["length"]: 1, + ~~~~~~~~~~ +!!! error TS2696: 'length' is not allowed to be used as a name of a static property or method in a class for target ES5. + ["name"]: 1, + ~~~~~~~~ +!!! error TS2696: 'name' is not allowed to be used as a name of a static property or method in a class for target ES5. + ["arguments"]: 1, + ~~~~~~~~~~~~~ +!!! error TS2696: 'arguments' is not allowed to be used as a name of a static property or method in a class for target ES5. + ["caller"]: 1, + ~~~~~~~~~~ +!!! error TS2696: 'caller' is not allowed to be used as a name of a static property or method in a class for target ES5. + }; + } + + class static_method { + static length() { return 1; } + ~~~~~~ +!!! error TS2696: 'length' is not allowed to be used as a name of a static property or method in a class for target ES5. + static name() { return 1; } + ~~~~ +!!! error TS2696: 'name' is not allowed to be used as a name of a static property or method in a class for target ES5. + static arguments() { return 1; } + ~~~~~~~~~ +!!! error TS2696: 'arguments' is not allowed to be used as a name of a static property or method in a class for target ES5. + static caller() { return 1; } + ~~~~~~ +!!! error TS2696: 'caller' is not allowed to be used as a name of a static property or method in a class for target ES5. + } + \ No newline at end of file diff --git a/tests/baselines/reference/checkGrammarStaticMemberName_es5.js b/tests/baselines/reference/checkGrammarStaticMemberName_es5.js new file mode 100644 index 0000000000000..5735f94995869 --- /dev/null +++ b/tests/baselines/reference/checkGrammarStaticMemberName_es5.js @@ -0,0 +1,50 @@ +//// [checkGrammarStaticMemberName_es5.ts] + +class static_property { + static length = 1; + static name = 1; + static arguments = 1; + static caller = 1; + static foo = { + ["length"]: 1, + ["name"]: 1, + ["arguments"]: 1, + ["caller"]: 1, + }; +} + +class static_method { + static length() { return 1; } + static name() { return 1; } + static arguments() { return 1; } + static caller() { return 1; } +} + + +//// [checkGrammarStaticMemberName_es5.js] +var static_property = (function () { + function static_property() { + } + static_property.length = 1; + static_property.name = 1; + static_property.arguments = 1; + static_property.caller = 1; + static_property.foo = (_a = {}, + _a["length"] = 1, + _a["name"] = 1, + _a["arguments"] = 1, + _a["caller"] = 1, + _a + ); + return static_property; + var _a; +}()); +var static_method = (function () { + function static_method() { + } + static_method.length = function () { return 1; }; + static_method.name = function () { return 1; }; + static_method.arguments = function () { return 1; }; + static_method.caller = function () { return 1; }; + return static_method; +}()); diff --git a/tests/baselines/reference/checkGrammarStaticMemberName_es6.errors.txt b/tests/baselines/reference/checkGrammarStaticMemberName_es6.errors.txt new file mode 100644 index 0000000000000..0b07dbecee7db --- /dev/null +++ b/tests/baselines/reference/checkGrammarStaticMemberName_es6.errors.txt @@ -0,0 +1,48 @@ +tests/cases/compiler/checkGrammarStaticMemberName_es6.ts(3,5): error TS2697: 'length' is not allowed to be used as a name of a static property in a class for target ES6 and higher. +tests/cases/compiler/checkGrammarStaticMemberName_es6.ts(4,5): error TS2697: 'name' is not allowed to be used as a name of a static property in a class for target ES6 and higher. +tests/cases/compiler/checkGrammarStaticMemberName_es6.ts(5,5): error TS2697: 'arguments' is not allowed to be used as a name of a static property in a class for target ES6 and higher. +tests/cases/compiler/checkGrammarStaticMemberName_es6.ts(6,5): error TS2697: 'caller' is not allowed to be used as a name of a static property in a class for target ES6 and higher. +tests/cases/compiler/checkGrammarStaticMemberName_es6.ts(8,9): error TS2697: 'length' is not allowed to be used as a name of a static property in a class for target ES6 and higher. +tests/cases/compiler/checkGrammarStaticMemberName_es6.ts(9,9): error TS2697: 'name' is not allowed to be used as a name of a static property in a class for target ES6 and higher. +tests/cases/compiler/checkGrammarStaticMemberName_es6.ts(10,9): error TS2697: 'arguments' is not allowed to be used as a name of a static property in a class for target ES6 and higher. +tests/cases/compiler/checkGrammarStaticMemberName_es6.ts(11,9): error TS2697: 'caller' is not allowed to be used as a name of a static property in a class for target ES6 and higher. + + +==== tests/cases/compiler/checkGrammarStaticMemberName_es6.ts (8 errors) ==== + + class static_property { + static length = 1; + ~~~~~~~~~~~~~~~~~~ +!!! error TS2697: 'length' is not allowed to be used as a name of a static property in a class for target ES6 and higher. + static name = 1; + ~~~~~~~~~~~~~~~~ +!!! error TS2697: 'name' is not allowed to be used as a name of a static property in a class for target ES6 and higher. + static arguments = 1; + ~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2697: 'arguments' is not allowed to be used as a name of a static property in a class for target ES6 and higher. + static caller = 1; + ~~~~~~~~~~~~~~~~~~ +!!! error TS2697: 'caller' is not allowed to be used as a name of a static property in a class for target ES6 and higher. + static foo = { + ["length"]: 1, + ~~~~~~~~~~ +!!! error TS2697: 'length' is not allowed to be used as a name of a static property in a class for target ES6 and higher. + ["name"]: 1, + ~~~~~~~~ +!!! error TS2697: 'name' is not allowed to be used as a name of a static property in a class for target ES6 and higher. + ["arguments"]: 1, + ~~~~~~~~~~~~~ +!!! error TS2697: 'arguments' is not allowed to be used as a name of a static property in a class for target ES6 and higher. + ["caller"]: 1, + ~~~~~~~~~~ +!!! error TS2697: 'caller' is not allowed to be used as a name of a static property in a class for target ES6 and higher. + }; + } + + class static_method { + static length() { return 1; } + static name() { return 1; } + static arguments() { return 1; } + static caller() { return 1; } + } + \ No newline at end of file diff --git a/tests/baselines/reference/checkGrammarStaticMemberName_es6.js b/tests/baselines/reference/checkGrammarStaticMemberName_es6.js new file mode 100644 index 0000000000000..5dc0854c8b4e7 --- /dev/null +++ b/tests/baselines/reference/checkGrammarStaticMemberName_es6.js @@ -0,0 +1,42 @@ +//// [checkGrammarStaticMemberName_es6.ts] + +class static_property { + static length = 1; + static name = 1; + static arguments = 1; + static caller = 1; + static foo = { + ["length"]: 1, + ["name"]: 1, + ["arguments"]: 1, + ["caller"]: 1, + }; +} + +class static_method { + static length() { return 1; } + static name() { return 1; } + static arguments() { return 1; } + static caller() { return 1; } +} + + +//// [checkGrammarStaticMemberName_es6.js] +class static_property { +} +static_property.length = 1; +static_property.name = 1; +static_property.arguments = 1; +static_property.caller = 1; +static_property.foo = { + ["length"]: 1, + ["name"]: 1, + ["arguments"]: 1, + ["caller"]: 1, +}; +class static_method { + static length() { return 1; } + static name() { return 1; } + static arguments() { return 1; } + static caller() { return 1; } +} diff --git a/tests/baselines/reference/staticMemberOfClassAndPublicMemberOfAnotherClassAssignment.errors.txt b/tests/baselines/reference/staticMemberOfClassAndPublicMemberOfAnotherClassAssignment.errors.txt index 5962654080621..494eaef6f0820 100644 --- a/tests/baselines/reference/staticMemberOfClassAndPublicMemberOfAnotherClassAssignment.errors.txt +++ b/tests/baselines/reference/staticMemberOfClassAndPublicMemberOfAnotherClassAssignment.errors.txt @@ -1,3 +1,4 @@ +tests/cases/compiler/staticMemberOfClassAndPublicMemberOfAnotherClassAssignment.ts(8,19): error TS2696: 'name' is not allowed to be used as a name of a static property or method in a class for target ES5. tests/cases/compiler/staticMemberOfClassAndPublicMemberOfAnotherClassAssignment.ts(12,1): error TS2322: Type 'C' is not assignable to type 'A'. Property 'name' is missing in type 'C'. tests/cases/compiler/staticMemberOfClassAndPublicMemberOfAnotherClassAssignment.ts(13,1): error TS2322: Type 'typeof B' is not assignable to type 'A'. @@ -8,7 +9,7 @@ tests/cases/compiler/staticMemberOfClassAndPublicMemberOfAnotherClassAssignment. Property 'name' is missing in type 'typeof B'. -==== tests/cases/compiler/staticMemberOfClassAndPublicMemberOfAnotherClassAssignment.ts (4 errors) ==== +==== tests/cases/compiler/staticMemberOfClassAndPublicMemberOfAnotherClassAssignment.ts (5 errors) ==== interface A { name(); } @@ -17,6 +18,8 @@ tests/cases/compiler/staticMemberOfClassAndPublicMemberOfAnotherClassAssignment. } class C { public static name() { } + ~~~~ +!!! error TS2696: 'name' is not allowed to be used as a name of a static property or method in a class for target ES5. } var a: A = new B(); diff --git a/tests/cases/compiler/checkGrammarStaticMemberName_es5.ts b/tests/cases/compiler/checkGrammarStaticMemberName_es5.ts new file mode 100644 index 0000000000000..4103154b4d904 --- /dev/null +++ b/tests/cases/compiler/checkGrammarStaticMemberName_es5.ts @@ -0,0 +1,21 @@ +// @target: es5 + +class static_property { + static length = 1; + static name = 1; + static arguments = 1; + static caller = 1; + static foo = { + ["length"]: 1, + ["name"]: 1, + ["arguments"]: 1, + ["caller"]: 1, + }; +} + +class static_method { + static length() { return 1; } + static name() { return 1; } + static arguments() { return 1; } + static caller() { return 1; } +} diff --git a/tests/cases/compiler/checkGrammarStaticMemberName_es6.ts b/tests/cases/compiler/checkGrammarStaticMemberName_es6.ts new file mode 100644 index 0000000000000..0bb98ecd945b7 --- /dev/null +++ b/tests/cases/compiler/checkGrammarStaticMemberName_es6.ts @@ -0,0 +1,21 @@ +// @target: es6 + +class static_property { + static length = 1; + static name = 1; + static arguments = 1; + static caller = 1; + static foo = { + ["length"]: 1, + ["name"]: 1, + ["arguments"]: 1, + ["caller"]: 1, + }; +} + +class static_method { + static length() { return 1; } + static name() { return 1; } + static arguments() { return 1; } + static caller() { return 1; } +}