From 25306f9f7e26777010f28f610a72173bcf70825f Mon Sep 17 00:00:00 2001 From: Oleksandr T Date: Sat, 25 Sep 2021 10:15:37 +0300 Subject: [PATCH] feat(36080): forbid to use JSDoc visibility modifiers in private fields --- src/compiler/checker.ts | 11 ++ ...ateNamesIncompatibleModifiersJs.errors.txt | 110 ++++++++++++++++++ .../privateNamesIncompatibleModifiersJs.js | 82 +++++++++++++ ...rivateNamesIncompatibleModifiersJs.symbols | 80 +++++++++++++ .../privateNamesIncompatibleModifiersJs.types | 89 ++++++++++++++ .../privateNamesIncompatibleModifiersJs.ts | 65 +++++++++++ 6 files changed, 437 insertions(+) create mode 100644 tests/baselines/reference/privateNamesIncompatibleModifiersJs.errors.txt create mode 100644 tests/baselines/reference/privateNamesIncompatibleModifiersJs.js create mode 100644 tests/baselines/reference/privateNamesIncompatibleModifiersJs.symbols create mode 100644 tests/baselines/reference/privateNamesIncompatibleModifiersJs.types create mode 100644 tests/cases/conformance/classes/members/privateNames/privateNamesIncompatibleModifiersJs.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index dab50b7c9f380..f1489b47ddab7 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -35689,6 +35689,13 @@ namespace ts { } } + function checkJSDocAccessibilityModifiers(node: JSDocPublicTag | JSDocProtectedTag | JSDocPrivateTag): void { + const host = getJSDocHost(node); + if (host && isPrivateIdentifierClassElementDeclaration(host)) { + error(node, Diagnostics.An_accessibility_modifier_cannot_be_used_with_a_private_identifier); + } + } + function getIdentifierFromEntityNameExpression(node: Identifier | PropertyAccessExpression): Identifier | PrivateIdentifier; function getIdentifierFromEntityNameExpression(node: Expression): Identifier | PrivateIdentifier | undefined; function getIdentifierFromEntityNameExpression(node: Expression): Identifier | PrivateIdentifier | undefined { @@ -39678,6 +39685,10 @@ namespace ts { return; case SyntaxKind.JSDocTypeExpression: return checkSourceElement((node as JSDocTypeExpression).type); + case SyntaxKind.JSDocPublicTag: + case SyntaxKind.JSDocProtectedTag: + case SyntaxKind.JSDocPrivateTag: + return checkJSDocAccessibilityModifiers(node as JSDocPublicTag | JSDocProtectedTag | JSDocPrivateTag); case SyntaxKind.IndexedAccessType: return checkIndexedAccessType(node as IndexedAccessTypeNode); case SyntaxKind.MappedType: diff --git a/tests/baselines/reference/privateNamesIncompatibleModifiersJs.errors.txt b/tests/baselines/reference/privateNamesIncompatibleModifiersJs.errors.txt new file mode 100644 index 0000000000000..64f1646385f86 --- /dev/null +++ b/tests/baselines/reference/privateNamesIncompatibleModifiersJs.errors.txt @@ -0,0 +1,110 @@ +tests/cases/conformance/classes/members/privateNames/privateNamesIncompatibleModifiersJs.js(3,8): error TS18010: An accessibility modifier cannot be used with a private identifier. +tests/cases/conformance/classes/members/privateNames/privateNamesIncompatibleModifiersJs.js(8,8): error TS18010: An accessibility modifier cannot be used with a private identifier. +tests/cases/conformance/classes/members/privateNames/privateNamesIncompatibleModifiersJs.js(13,8): error TS18010: An accessibility modifier cannot be used with a private identifier. +tests/cases/conformance/classes/members/privateNames/privateNamesIncompatibleModifiersJs.js(18,8): error TS18010: An accessibility modifier cannot be used with a private identifier. +tests/cases/conformance/classes/members/privateNames/privateNamesIncompatibleModifiersJs.js(23,8): error TS18010: An accessibility modifier cannot be used with a private identifier. +tests/cases/conformance/classes/members/privateNames/privateNamesIncompatibleModifiersJs.js(28,8): error TS18010: An accessibility modifier cannot be used with a private identifier. +tests/cases/conformance/classes/members/privateNames/privateNamesIncompatibleModifiersJs.js(33,8): error TS18010: An accessibility modifier cannot be used with a private identifier. +tests/cases/conformance/classes/members/privateNames/privateNamesIncompatibleModifiersJs.js(37,8): error TS18010: An accessibility modifier cannot be used with a private identifier. +tests/cases/conformance/classes/members/privateNames/privateNamesIncompatibleModifiersJs.js(42,8): error TS18010: An accessibility modifier cannot be used with a private identifier. +tests/cases/conformance/classes/members/privateNames/privateNamesIncompatibleModifiersJs.js(46,8): error TS18010: An accessibility modifier cannot be used with a private identifier. +tests/cases/conformance/classes/members/privateNames/privateNamesIncompatibleModifiersJs.js(51,7): error TS18010: An accessibility modifier cannot be used with a private identifier. +tests/cases/conformance/classes/members/privateNames/privateNamesIncompatibleModifiersJs.js(55,8): error TS18010: An accessibility modifier cannot be used with a private identifier. + + +==== tests/cases/conformance/classes/members/privateNames/privateNamesIncompatibleModifiersJs.js (12 errors) ==== + class A { + /** + * @public + ~~~~~~~ + */ + ~~~~~ +!!! error TS18010: An accessibility modifier cannot be used with a private identifier. + #a = 1; + + /** + * @private + ~~~~~~~~ + */ + ~~~~~ +!!! error TS18010: An accessibility modifier cannot be used with a private identifier. + #b = 1; + + /** + * @protected + ~~~~~~~~~~ + */ + ~~~~~ +!!! error TS18010: An accessibility modifier cannot be used with a private identifier. + #c = 1; + + /** + * @public + ~~~~~~~ + */ + ~~~~~ +!!! error TS18010: An accessibility modifier cannot be used with a private identifier. + #aMethod() { return 1; } + + /** + * @private + ~~~~~~~~ + */ + ~~~~~ +!!! error TS18010: An accessibility modifier cannot be used with a private identifier. + #bMethod() { return 1; } + + /** + * @protected + ~~~~~~~~~~ + */ + ~~~~~ +!!! error TS18010: An accessibility modifier cannot be used with a private identifier. + #cMethod() { return 1; } + + /** + * @public + ~~~~~~~ + */ + ~~~~~ +!!! error TS18010: An accessibility modifier cannot be used with a private identifier. + get #aProp() { return 1; } + /** + * @public + ~~~~~~~ + */ + ~~~~~ +!!! error TS18010: An accessibility modifier cannot be used with a private identifier. + set #aProp(value) { } + + /** + * @private + ~~~~~~~~ + */ + ~~~~~ +!!! error TS18010: An accessibility modifier cannot be used with a private identifier. + get #bProp() { return 1; } + /** + * @private + ~~~~~~~~ + */ + ~~~~~ +!!! error TS18010: An accessibility modifier cannot be used with a private identifier. + set #bProp(value) { } + + /** + * @protected + ~~~~~~~~~~ + */ + ~~~~ +!!! error TS18010: An accessibility modifier cannot be used with a private identifier. + get #cProp() { return 1; } + /** + * @protected + ~~~~~~~~~~ + */ + ~~~~~ +!!! error TS18010: An accessibility modifier cannot be used with a private identifier. + set #cProp(value) { } + } + \ No newline at end of file diff --git a/tests/baselines/reference/privateNamesIncompatibleModifiersJs.js b/tests/baselines/reference/privateNamesIncompatibleModifiersJs.js new file mode 100644 index 0000000000000..e667cf6899cac --- /dev/null +++ b/tests/baselines/reference/privateNamesIncompatibleModifiersJs.js @@ -0,0 +1,82 @@ +//// [privateNamesIncompatibleModifiersJs.js] +class A { + /** + * @public + */ + #a = 1; + + /** + * @private + */ + #b = 1; + + /** + * @protected + */ + #c = 1; + + /** + * @public + */ + #aMethod() { return 1; } + + /** + * @private + */ + #bMethod() { return 1; } + + /** + * @protected + */ + #cMethod() { return 1; } + + /** + * @public + */ + get #aProp() { return 1; } + /** + * @public + */ + set #aProp(value) { } + + /** + * @private + */ + get #bProp() { return 1; } + /** + * @private + */ + set #bProp(value) { } + + /** + * @protected + */ + get #cProp() { return 1; } + /** + * @protected + */ + set #cProp(value) { } +} + + +//// [privateNamesIncompatibleModifiersJs.js] +"use strict"; +var _A_instances, _A_a, _A_b, _A_c, _A_aMethod, _A_bMethod, _A_cMethod, _A_aProp_get, _A_aProp_set, _A_bProp_get, _A_bProp_set, _A_cProp_get, _A_cProp_set; +class A { + constructor() { + _A_instances.add(this); + /** + * @public + */ + _A_a.set(this, 1); + /** + * @private + */ + _A_b.set(this, 1); + /** + * @protected + */ + _A_c.set(this, 1); + } +} +_A_a = new WeakMap(), _A_b = new WeakMap(), _A_c = new WeakMap(), _A_instances = new WeakSet(), _A_aMethod = function _A_aMethod() { return 1; }, _A_bMethod = function _A_bMethod() { return 1; }, _A_cMethod = function _A_cMethod() { return 1; }, _A_aProp_get = function _A_aProp_get() { return 1; }, _A_aProp_set = function _A_aProp_set(value) { }, _A_bProp_get = function _A_bProp_get() { return 1; }, _A_bProp_set = function _A_bProp_set(value) { }, _A_cProp_get = function _A_cProp_get() { return 1; }, _A_cProp_set = function _A_cProp_set(value) { }; diff --git a/tests/baselines/reference/privateNamesIncompatibleModifiersJs.symbols b/tests/baselines/reference/privateNamesIncompatibleModifiersJs.symbols new file mode 100644 index 0000000000000..a03ba72c66b4d --- /dev/null +++ b/tests/baselines/reference/privateNamesIncompatibleModifiersJs.symbols @@ -0,0 +1,80 @@ +=== tests/cases/conformance/classes/members/privateNames/privateNamesIncompatibleModifiersJs.js === +class A { +>A : Symbol(A, Decl(privateNamesIncompatibleModifiersJs.js, 0, 0)) + + /** + * @public + */ + #a = 1; +>#a : Symbol(A.#a, Decl(privateNamesIncompatibleModifiersJs.js, 0, 9)) + + /** + * @private + */ + #b = 1; +>#b : Symbol(A.#b, Decl(privateNamesIncompatibleModifiersJs.js, 4, 11)) + + /** + * @protected + */ + #c = 1; +>#c : Symbol(A.#c, Decl(privateNamesIncompatibleModifiersJs.js, 9, 11)) + + /** + * @public + */ + #aMethod() { return 1; } +>#aMethod : Symbol(A.#aMethod, Decl(privateNamesIncompatibleModifiersJs.js, 14, 11)) + + /** + * @private + */ + #bMethod() { return 1; } +>#bMethod : Symbol(A.#bMethod, Decl(privateNamesIncompatibleModifiersJs.js, 19, 28)) + + /** + * @protected + */ + #cMethod() { return 1; } +>#cMethod : Symbol(A.#cMethod, Decl(privateNamesIncompatibleModifiersJs.js, 24, 28)) + + /** + * @public + */ + get #aProp() { return 1; } +>#aProp : Symbol(A.#aProp, Decl(privateNamesIncompatibleModifiersJs.js, 29, 28), Decl(privateNamesIncompatibleModifiersJs.js, 34, 30)) + + /** + * @public + */ + set #aProp(value) { } +>#aProp : Symbol(A.#aProp, Decl(privateNamesIncompatibleModifiersJs.js, 29, 28), Decl(privateNamesIncompatibleModifiersJs.js, 34, 30)) +>value : Symbol(value, Decl(privateNamesIncompatibleModifiersJs.js, 38, 15)) + + /** + * @private + */ + get #bProp() { return 1; } +>#bProp : Symbol(A.#bProp, Decl(privateNamesIncompatibleModifiersJs.js, 38, 25), Decl(privateNamesIncompatibleModifiersJs.js, 43, 30)) + + /** + * @private + */ + set #bProp(value) { } +>#bProp : Symbol(A.#bProp, Decl(privateNamesIncompatibleModifiersJs.js, 38, 25), Decl(privateNamesIncompatibleModifiersJs.js, 43, 30)) +>value : Symbol(value, Decl(privateNamesIncompatibleModifiersJs.js, 47, 15)) + + /** + * @protected + */ + get #cProp() { return 1; } +>#cProp : Symbol(A.#cProp, Decl(privateNamesIncompatibleModifiersJs.js, 47, 25), Decl(privateNamesIncompatibleModifiersJs.js, 52, 30)) + + /** + * @protected + */ + set #cProp(value) { } +>#cProp : Symbol(A.#cProp, Decl(privateNamesIncompatibleModifiersJs.js, 47, 25), Decl(privateNamesIncompatibleModifiersJs.js, 52, 30)) +>value : Symbol(value, Decl(privateNamesIncompatibleModifiersJs.js, 56, 15)) +} + diff --git a/tests/baselines/reference/privateNamesIncompatibleModifiersJs.types b/tests/baselines/reference/privateNamesIncompatibleModifiersJs.types new file mode 100644 index 0000000000000..f7e6ed4f15474 --- /dev/null +++ b/tests/baselines/reference/privateNamesIncompatibleModifiersJs.types @@ -0,0 +1,89 @@ +=== tests/cases/conformance/classes/members/privateNames/privateNamesIncompatibleModifiersJs.js === +class A { +>A : A + + /** + * @public + */ + #a = 1; +>#a : number +>1 : 1 + + /** + * @private + */ + #b = 1; +>#b : number +>1 : 1 + + /** + * @protected + */ + #c = 1; +>#c : number +>1 : 1 + + /** + * @public + */ + #aMethod() { return 1; } +>#aMethod : () => number +>1 : 1 + + /** + * @private + */ + #bMethod() { return 1; } +>#bMethod : () => number +>1 : 1 + + /** + * @protected + */ + #cMethod() { return 1; } +>#cMethod : () => number +>1 : 1 + + /** + * @public + */ + get #aProp() { return 1; } +>#aProp : number +>1 : 1 + + /** + * @public + */ + set #aProp(value) { } +>#aProp : number +>value : number + + /** + * @private + */ + get #bProp() { return 1; } +>#bProp : number +>1 : 1 + + /** + * @private + */ + set #bProp(value) { } +>#bProp : number +>value : number + + /** + * @protected + */ + get #cProp() { return 1; } +>#cProp : number +>1 : 1 + + /** + * @protected + */ + set #cProp(value) { } +>#cProp : number +>value : number +} + diff --git a/tests/cases/conformance/classes/members/privateNames/privateNamesIncompatibleModifiersJs.ts b/tests/cases/conformance/classes/members/privateNames/privateNamesIncompatibleModifiersJs.ts new file mode 100644 index 0000000000000..5154b5e4395ad --- /dev/null +++ b/tests/cases/conformance/classes/members/privateNames/privateNamesIncompatibleModifiersJs.ts @@ -0,0 +1,65 @@ +// @allowJs: true +// @checkJs: true +// @strict: true +// @target: es6 +// @outDir: ./out +// @filename: privateNamesIncompatibleModifiersJs.js + +class A { + /** + * @public + */ + #a = 1; + + /** + * @private + */ + #b = 1; + + /** + * @protected + */ + #c = 1; + + /** + * @public + */ + #aMethod() { return 1; } + + /** + * @private + */ + #bMethod() { return 1; } + + /** + * @protected + */ + #cMethod() { return 1; } + + /** + * @public + */ + get #aProp() { return 1; } + /** + * @public + */ + set #aProp(value) { } + + /** + * @private + */ + get #bProp() { return 1; } + /** + * @private + */ + set #bProp(value) { } + + /** + * @protected + */ + get #cProp() { return 1; } + /** + * @protected + */ + set #cProp(value) { } +}