From 4e24b1b00d889b22bd3f623de603936ea39b6ad2 Mon Sep 17 00:00:00 2001 From: Alexander T Date: Fri, 17 Jul 2020 03:05:33 +0300 Subject: [PATCH] fix(39373): add diagnostic message about using a private name for class declarations without name (#39567) --- src/compiler/diagnosticMessages.json | 4 ++ .../transformers/declarations/diagnostics.ts | 5 ++- ...arationEmitExpressionInExtends6.errors.txt | 15 ++++++++ .../declarationEmitExpressionInExtends6.js | 38 +++++++++++++++++++ ...eclarationEmitExpressionInExtends6.symbols | 12 ++++++ .../declarationEmitExpressionInExtends6.types | 14 +++++++ .../declarationEmitExpressionInExtends6.ts | 14 +++++++ 7 files changed, 100 insertions(+), 2 deletions(-) create mode 100644 tests/baselines/reference/declarationEmitExpressionInExtends6.errors.txt create mode 100644 tests/baselines/reference/declarationEmitExpressionInExtends6.js create mode 100644 tests/baselines/reference/declarationEmitExpressionInExtends6.symbols create mode 100644 tests/baselines/reference/declarationEmitExpressionInExtends6.types create mode 100644 tests/cases/compiler/declarationEmitExpressionInExtends6.ts diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 900e2cd396d..5110ff2be8b 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -3057,6 +3057,10 @@ "category": "Error", "code": 4020 }, + "'extends' clause of exported class has or is using private name '{0}'.": { + "category": "Error", + "code": 4021 + }, "'extends' clause of exported interface '{0}' has or is using private name '{1}'.": { "category": "Error", "code": 4022 diff --git a/src/compiler/transformers/declarations/diagnostics.ts b/src/compiler/transformers/declarations/diagnostics.ts index 1294739ef96..ebb453ee83d 100644 --- a/src/compiler/transformers/declarations/diagnostics.ts +++ b/src/compiler/transformers/declarations/diagnostics.ts @@ -447,11 +447,12 @@ namespace ts { function getHeritageClauseVisibilityError(): SymbolAccessibilityDiagnostic { let diagnosticMessage: DiagnosticMessage; // Heritage clause is written by user so it can always be named - if (node.parent.parent.kind === SyntaxKind.ClassDeclaration) { + if (isClassDeclaration(node.parent.parent)) { // Class or Interface implemented/extended is inaccessible diagnosticMessage = isHeritageClause(node.parent) && node.parent.token === SyntaxKind.ImplementsKeyword ? Diagnostics.Implements_clause_of_exported_class_0_has_or_is_using_private_name_1 : - Diagnostics.extends_clause_of_exported_class_0_has_or_is_using_private_name_1; + node.parent.parent.name ? Diagnostics.extends_clause_of_exported_class_0_has_or_is_using_private_name_1 : + Diagnostics.extends_clause_of_exported_class_has_or_is_using_private_name_0; } else { // interface is inaccessible diff --git a/tests/baselines/reference/declarationEmitExpressionInExtends6.errors.txt b/tests/baselines/reference/declarationEmitExpressionInExtends6.errors.txt new file mode 100644 index 00000000000..9410f5af7f3 --- /dev/null +++ b/tests/baselines/reference/declarationEmitExpressionInExtends6.errors.txt @@ -0,0 +1,15 @@ +/b.ts(2,30): error TS4021: 'extends' clause of exported class has or is using private name 'Foo'. + + +==== /b.ts (1 errors) ==== + const { Foo } = require("./a"); + export default class extends Foo {} + ~~~ +!!! error TS4021: 'extends' clause of exported class has or is using private name 'Foo'. + +==== /node_modules/@types/node/index.d.ts (0 errors) ==== + declare const require: any; + +==== /a.ts (0 errors) ==== + export class Foo {} + \ No newline at end of file diff --git a/tests/baselines/reference/declarationEmitExpressionInExtends6.js b/tests/baselines/reference/declarationEmitExpressionInExtends6.js new file mode 100644 index 00000000000..f7083c8bb8a --- /dev/null +++ b/tests/baselines/reference/declarationEmitExpressionInExtends6.js @@ -0,0 +1,38 @@ +//// [tests/cases/compiler/declarationEmitExpressionInExtends6.ts] //// + +//// [index.d.ts] +declare const require: any; + +//// [a.ts] +export class Foo {} + +//// [b.ts] +const { Foo } = require("./a"); +export default class extends Foo {} + + +//// [b.js] +"use strict"; +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +exports.__esModule = true; +var Foo = require("./a").Foo; +var default_1 = /** @class */ (function (_super) { + __extends(default_1, _super); + function default_1() { + return _super !== null && _super.apply(this, arguments) || this; + } + return default_1; +}(Foo)); +exports["default"] = default_1; diff --git a/tests/baselines/reference/declarationEmitExpressionInExtends6.symbols b/tests/baselines/reference/declarationEmitExpressionInExtends6.symbols new file mode 100644 index 00000000000..32eaa9018c2 --- /dev/null +++ b/tests/baselines/reference/declarationEmitExpressionInExtends6.symbols @@ -0,0 +1,12 @@ +=== /b.ts === +const { Foo } = require("./a"); +>Foo : Symbol(Foo, Decl(b.ts, 0, 7)) +>require : Symbol(require, Decl(index.d.ts, 0, 13)) + +export default class extends Foo {} +>Foo : Symbol(Foo, Decl(b.ts, 0, 7)) + +=== /node_modules/@types/node/index.d.ts === +declare const require: any; +>require : Symbol(require, Decl(index.d.ts, 0, 13)) + diff --git a/tests/baselines/reference/declarationEmitExpressionInExtends6.types b/tests/baselines/reference/declarationEmitExpressionInExtends6.types new file mode 100644 index 00000000000..03ec99ecc4f --- /dev/null +++ b/tests/baselines/reference/declarationEmitExpressionInExtends6.types @@ -0,0 +1,14 @@ +=== /b.ts === +const { Foo } = require("./a"); +>Foo : any +>require("./a") : any +>require : any +>"./a" : "./a" + +export default class extends Foo {} +>Foo : any + +=== /node_modules/@types/node/index.d.ts === +declare const require: any; +>require : any + diff --git a/tests/cases/compiler/declarationEmitExpressionInExtends6.ts b/tests/cases/compiler/declarationEmitExpressionInExtends6.ts new file mode 100644 index 00000000000..057d1cabf02 --- /dev/null +++ b/tests/cases/compiler/declarationEmitExpressionInExtends6.ts @@ -0,0 +1,14 @@ +// @module: commonjs +// @declaration: true +// @types: node +// @currentDirectory: / + +// @Filename: /node_modules/@types/node/index.d.ts +declare const require: any; + +// @Filename: /a.ts +export class Foo {} + +// @Filename: /b.ts +const { Foo } = require("./a"); +export default class extends Foo {}