diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index c82e0ece07473..27d75eb2797cc 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,36 @@ namespace ts { } } + function checkGrammarStaticPropertyOrMethodName(node: ClassElement) { + if (node.flags & ModifierFlags.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, 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, 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 +19744,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 & ModifierFlags.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.js b/tests/baselines/reference/checkGrammarStaticMemberName_es5.js new file mode 100644 index 0000000000000..5469d2e6ed035 --- /dev/null +++ b/tests/baselines/reference/checkGrammarStaticMemberName_es5.js @@ -0,0 +1,49 @@ +//// [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() { + } + return 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); +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; +}()); +var _a; diff --git a/tests/baselines/reference/checkGrammarStaticMemberName_es5.symbols b/tests/baselines/reference/checkGrammarStaticMemberName_es5.symbols new file mode 100644 index 0000000000000..33574365958de --- /dev/null +++ b/tests/baselines/reference/checkGrammarStaticMemberName_es5.symbols @@ -0,0 +1,51 @@ +=== tests/cases/compiler/checkGrammarStaticMemberName_es5.ts === + +class static_property { +>static_property : Symbol(static_property, Decl(checkGrammarStaticMemberName_es5.ts, 0, 0)) + + static length = 1; +>length : Symbol(static_property.length, Decl(checkGrammarStaticMemberName_es5.ts, 1, 23)) + + static name = 1; +>name : Symbol(static_property.name, Decl(checkGrammarStaticMemberName_es5.ts, 2, 22)) + + static arguments = 1; +>arguments : Symbol(static_property.arguments, Decl(checkGrammarStaticMemberName_es5.ts, 3, 20)) + + static caller = 1; +>caller : Symbol(static_property.caller, Decl(checkGrammarStaticMemberName_es5.ts, 4, 25)) + + static foo = { +>foo : Symbol(static_property.foo, Decl(checkGrammarStaticMemberName_es5.ts, 5, 22)) + + ["length"]: 1, +>"length" : Symbol(["length"], Decl(checkGrammarStaticMemberName_es5.ts, 6, 18)) + + ["name"]: 1, +>"name" : Symbol(["name"], Decl(checkGrammarStaticMemberName_es5.ts, 7, 22)) + + ["arguments"]: 1, +>"arguments" : Symbol(["arguments"], Decl(checkGrammarStaticMemberName_es5.ts, 8, 20)) + + ["caller"]: 1, +>"caller" : Symbol(["caller"], Decl(checkGrammarStaticMemberName_es5.ts, 9, 25)) + + }; +} + +class static_method { +>static_method : Symbol(static_method, Decl(checkGrammarStaticMemberName_es5.ts, 12, 1)) + + static length() { return 1; } +>length : Symbol(static_method.length, Decl(checkGrammarStaticMemberName_es5.ts, 14, 21)) + + static name() { return 1; } +>name : Symbol(static_method.name, Decl(checkGrammarStaticMemberName_es5.ts, 15, 33)) + + static arguments() { return 1; } +>arguments : Symbol(static_method.arguments, Decl(checkGrammarStaticMemberName_es5.ts, 16, 31)) + + static caller() { return 1; } +>caller : Symbol(static_method.caller, Decl(checkGrammarStaticMemberName_es5.ts, 17, 36)) +} + diff --git a/tests/baselines/reference/checkGrammarStaticMemberName_es5.types b/tests/baselines/reference/checkGrammarStaticMemberName_es5.types new file mode 100644 index 0000000000000..c8478a5467753 --- /dev/null +++ b/tests/baselines/reference/checkGrammarStaticMemberName_es5.types @@ -0,0 +1,64 @@ +=== tests/cases/compiler/checkGrammarStaticMemberName_es5.ts === + +class static_property { +>static_property : static_property + + static length = 1; +>length : number +>1 : 1 + + static name = 1; +>name : number +>1 : 1 + + static arguments = 1; +>arguments : number +>1 : 1 + + static caller = 1; +>caller : number +>1 : 1 + + static foo = { +>foo : { ["length"]: number; ["name"]: number; ["arguments"]: number; ["caller"]: number; } +>{ ["length"]: 1, ["name"]: 1, ["arguments"]: 1, ["caller"]: 1, } : { ["length"]: number; ["name"]: number; ["arguments"]: number; ["caller"]: number; } + + ["length"]: 1, +>"length" : "length" +>1 : 1 + + ["name"]: 1, +>"name" : "name" +>1 : 1 + + ["arguments"]: 1, +>"arguments" : "arguments" +>1 : 1 + + ["caller"]: 1, +>"caller" : "caller" +>1 : 1 + + }; +} + +class static_method { +>static_method : static_method + + static length() { return 1; } +>length : () => number +>1 : 1 + + static name() { return 1; } +>name : () => number +>1 : 1 + + static arguments() { return 1; } +>arguments : () => number +>1 : 1 + + static caller() { return 1; } +>caller : () => number +>1 : 1 +} + 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/checkGrammarStaticMemberName_es6.symbols b/tests/baselines/reference/checkGrammarStaticMemberName_es6.symbols new file mode 100644 index 0000000000000..5f877e054ee7a --- /dev/null +++ b/tests/baselines/reference/checkGrammarStaticMemberName_es6.symbols @@ -0,0 +1,51 @@ +=== tests/cases/compiler/checkGrammarStaticMemberName_es6.ts === + +class static_property { +>static_property : Symbol(static_property, Decl(checkGrammarStaticMemberName_es6.ts, 0, 0)) + + static length = 1; +>length : Symbol(static_property.length, Decl(checkGrammarStaticMemberName_es6.ts, 1, 23)) + + static name = 1; +>name : Symbol(static_property.name, Decl(checkGrammarStaticMemberName_es6.ts, 2, 22)) + + static arguments = 1; +>arguments : Symbol(static_property.arguments, Decl(checkGrammarStaticMemberName_es6.ts, 3, 20)) + + static caller = 1; +>caller : Symbol(static_property.caller, Decl(checkGrammarStaticMemberName_es6.ts, 4, 25)) + + static foo = { +>foo : Symbol(static_property.foo, Decl(checkGrammarStaticMemberName_es6.ts, 5, 22)) + + ["length"]: 1, +>"length" : Symbol(["length"], Decl(checkGrammarStaticMemberName_es6.ts, 6, 18)) + + ["name"]: 1, +>"name" : Symbol(["name"], Decl(checkGrammarStaticMemberName_es6.ts, 7, 22)) + + ["arguments"]: 1, +>"arguments" : Symbol(["arguments"], Decl(checkGrammarStaticMemberName_es6.ts, 8, 20)) + + ["caller"]: 1, +>"caller" : Symbol(["caller"], Decl(checkGrammarStaticMemberName_es6.ts, 9, 25)) + + }; +} + +class static_method { +>static_method : Symbol(static_method, Decl(checkGrammarStaticMemberName_es6.ts, 12, 1)) + + static length() { return 1; } +>length : Symbol(static_method.length, Decl(checkGrammarStaticMemberName_es6.ts, 14, 21)) + + static name() { return 1; } +>name : Symbol(static_method.name, Decl(checkGrammarStaticMemberName_es6.ts, 15, 33)) + + static arguments() { return 1; } +>arguments : Symbol(static_method.arguments, Decl(checkGrammarStaticMemberName_es6.ts, 16, 31)) + + static caller() { return 1; } +>caller : Symbol(static_method.caller, Decl(checkGrammarStaticMemberName_es6.ts, 17, 36)) +} + diff --git a/tests/baselines/reference/checkGrammarStaticMemberName_es6.types b/tests/baselines/reference/checkGrammarStaticMemberName_es6.types new file mode 100644 index 0000000000000..b78ca9c96578f --- /dev/null +++ b/tests/baselines/reference/checkGrammarStaticMemberName_es6.types @@ -0,0 +1,64 @@ +=== tests/cases/compiler/checkGrammarStaticMemberName_es6.ts === + +class static_property { +>static_property : static_property + + static length = 1; +>length : number +>1 : 1 + + static name = 1; +>name : number +>1 : 1 + + static arguments = 1; +>arguments : number +>1 : 1 + + static caller = 1; +>caller : number +>1 : 1 + + static foo = { +>foo : { ["length"]: number; ["name"]: number; ["arguments"]: number; ["caller"]: number; } +>{ ["length"]: 1, ["name"]: 1, ["arguments"]: 1, ["caller"]: 1, } : { ["length"]: number; ["name"]: number; ["arguments"]: number; ["caller"]: number; } + + ["length"]: 1, +>"length" : "length" +>1 : 1 + + ["name"]: 1, +>"name" : "name" +>1 : 1 + + ["arguments"]: 1, +>"arguments" : "arguments" +>1 : 1 + + ["caller"]: 1, +>"caller" : "caller" +>1 : 1 + + }; +} + +class static_method { +>static_method : static_method + + static length() { return 1; } +>length : () => number +>1 : 1 + + static name() { return 1; } +>name : () => number +>1 : 1 + + static arguments() { return 1; } +>arguments : () => number +>1 : 1 + + static caller() { return 1; } +>caller : () => number +>1 : 1 +} + 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; } +}