From 35730f2879700ac828c8f9c6753f53effd7796cd Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Thu, 8 Mar 2018 10:33:38 -0800 Subject: [PATCH] Improve error span:duplicate symbols cross-js/ts when the JS symbol is a JS initializer --- src/compiler/checker.ts | 6 ++++-- src/compiler/utilities.ts | 17 +++++++++++++++-- .../jsContainerMergeTsDeclaration.errors.txt | 4 ++-- 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 50b04b71bee..f8b08464677 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -911,10 +911,12 @@ namespace ts { ? Diagnostics.Cannot_redeclare_block_scoped_variable_0 : Diagnostics.Duplicate_identifier_0; forEach(source.declarations, node => { - error(getNameOfDeclaration(node) || node, message, symbolToString(source)); + const errorNode = (getJavascriptInitializer(node, /*isPrototypeAssignment*/ false) ? getOuterNameOfJsInitializer(node) : getNameOfDeclaration(node)) || node; + error(errorNode, message, symbolToString(source)); }); forEach(target.declarations, node => { - error(getNameOfDeclaration(node) || node, message, symbolToString(source)); + const errorNode = (getJavascriptInitializer(node, /*isPrototypeAssignment*/ false) ? getOuterNameOfJsInitializer(node) : getNameOfDeclaration(node)) || node; + error(errorNode, message, symbolToString(source)); }); } } diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index d1c4de29059..ff28dc62919 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -1522,13 +1522,13 @@ namespace ts { * * This function returns the provided initializer, or undefined if it is not valid. */ - export function getJavascriptInitializer(initializer: Expression, isPrototypeAssignment: boolean) { + export function getJavascriptInitializer(initializer: Node, isPrototypeAssignment: boolean): Expression { if (isCallExpression(initializer)) { const e = skipParentheses(initializer.expression); return e.kind === SyntaxKind.FunctionExpression || e.kind === SyntaxKind.ArrowFunction ? initializer : undefined; } if (initializer.kind === SyntaxKind.FunctionExpression || initializer.kind === SyntaxKind.ClassExpression) { - return initializer; + return initializer as Expression; } if (isObjectLiteralExpression(initializer) && (initializer.properties.length === 0 || isPrototypeAssignment)) { return initializer; @@ -1550,6 +1550,19 @@ namespace ts { } } + /** Given a Javascript initializer, return the outer name. That is, the lhs of the assignment or the declaration name. */ + export function getOuterNameOfJsInitializer(node: Declaration): DeclarationName | undefined { + if (isBinaryExpression(node.parent)) { + const parent = (node.parent.operatorToken.kind === SyntaxKind.BarBarToken && isBinaryExpression(node.parent.parent)) ? node.parent.parent : node.parent; + if (parent.operatorToken.kind === SyntaxKind.EqualsToken && isIdentifier(parent.left)) { + return parent.left; + } + } + else if (isVariableDeclaration(node.parent)) { + return node.parent.name; + } + } + /** * Is the 'declared' name the same as the one in the initializer? * @return true for identical entity names, as well as ones where the initializer is prefixed with diff --git a/tests/baselines/reference/jsContainerMergeTsDeclaration.errors.txt b/tests/baselines/reference/jsContainerMergeTsDeclaration.errors.txt index d5e6c331e77..eb9ea6e9f53 100644 --- a/tests/baselines/reference/jsContainerMergeTsDeclaration.errors.txt +++ b/tests/baselines/reference/jsContainerMergeTsDeclaration.errors.txt @@ -1,6 +1,6 @@ error TS5055: Cannot write file 'tests/cases/conformance/salsa/a.js' because it would overwrite input file. Adding a tsconfig.json file will help organize projects that contain both TypeScript and JavaScript files. Learn more at https://aka.ms/tsconfig. -tests/cases/conformance/salsa/a.js(1,23): error TS2300: Duplicate identifier 'x'. +tests/cases/conformance/salsa/a.js(1,10): error TS2300: Duplicate identifier 'x'. tests/cases/conformance/salsa/b.ts(1,5): error TS2300: Duplicate identifier 'x'. @@ -8,7 +8,7 @@ tests/cases/conformance/salsa/b.ts(1,5): error TS2300: Duplicate identifier 'x'. !!! error TS5055: Adding a tsconfig.json file will help organize projects that contain both TypeScript and JavaScript files. Learn more at https://aka.ms/tsconfig. ==== tests/cases/conformance/salsa/a.js (1 errors) ==== var /*1*/x = function foo() { - ~~~ + ~ !!! error TS2300: Duplicate identifier 'x'. } x.a = function bar() {