Skip to content

Commit 35730f2

Browse files
committed
Improve error span:duplicate symbols cross-js/ts
when the JS symbol is a JS initializer
1 parent 04ceb3d commit 35730f2

File tree

3 files changed

+21
-6
lines changed

3 files changed

+21
-6
lines changed

src/compiler/checker.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -911,10 +911,12 @@ namespace ts {
911911
? Diagnostics.Cannot_redeclare_block_scoped_variable_0
912912
: Diagnostics.Duplicate_identifier_0;
913913
forEach(source.declarations, node => {
914-
error(getNameOfDeclaration(node) || node, message, symbolToString(source));
914+
const errorNode = (getJavascriptInitializer(node, /*isPrototypeAssignment*/ false) ? getOuterNameOfJsInitializer(node) : getNameOfDeclaration(node)) || node;
915+
error(errorNode, message, symbolToString(source));
915916
});
916917
forEach(target.declarations, node => {
917-
error(getNameOfDeclaration(node) || node, message, symbolToString(source));
918+
const errorNode = (getJavascriptInitializer(node, /*isPrototypeAssignment*/ false) ? getOuterNameOfJsInitializer(node) : getNameOfDeclaration(node)) || node;
919+
error(errorNode, message, symbolToString(source));
918920
});
919921
}
920922
}

src/compiler/utilities.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1522,13 +1522,13 @@ namespace ts {
15221522
*
15231523
* This function returns the provided initializer, or undefined if it is not valid.
15241524
*/
1525-
export function getJavascriptInitializer(initializer: Expression, isPrototypeAssignment: boolean) {
1525+
export function getJavascriptInitializer(initializer: Node, isPrototypeAssignment: boolean): Expression {
15261526
if (isCallExpression(initializer)) {
15271527
const e = skipParentheses(initializer.expression);
15281528
return e.kind === SyntaxKind.FunctionExpression || e.kind === SyntaxKind.ArrowFunction ? initializer : undefined;
15291529
}
15301530
if (initializer.kind === SyntaxKind.FunctionExpression || initializer.kind === SyntaxKind.ClassExpression) {
1531-
return initializer;
1531+
return initializer as Expression;
15321532
}
15331533
if (isObjectLiteralExpression(initializer) && (initializer.properties.length === 0 || isPrototypeAssignment)) {
15341534
return initializer;
@@ -1550,6 +1550,19 @@ namespace ts {
15501550
}
15511551
}
15521552

1553+
/** Given a Javascript initializer, return the outer name. That is, the lhs of the assignment or the declaration name. */
1554+
export function getOuterNameOfJsInitializer(node: Declaration): DeclarationName | undefined {
1555+
if (isBinaryExpression(node.parent)) {
1556+
const parent = (node.parent.operatorToken.kind === SyntaxKind.BarBarToken && isBinaryExpression(node.parent.parent)) ? node.parent.parent : node.parent;
1557+
if (parent.operatorToken.kind === SyntaxKind.EqualsToken && isIdentifier(parent.left)) {
1558+
return parent.left;
1559+
}
1560+
}
1561+
else if (isVariableDeclaration(node.parent)) {
1562+
return node.parent.name;
1563+
}
1564+
}
1565+
15531566
/**
15541567
* Is the 'declared' name the same as the one in the initializer?
15551568
* @return true for identical entity names, as well as ones where the initializer is prefixed with

tests/baselines/reference/jsContainerMergeTsDeclaration.errors.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
error TS5055: Cannot write file 'tests/cases/conformance/salsa/a.js' because it would overwrite input file.
22
Adding a tsconfig.json file will help organize projects that contain both TypeScript and JavaScript files. Learn more at https://aka.ms/tsconfig.
3-
tests/cases/conformance/salsa/a.js(1,23): error TS2300: Duplicate identifier 'x'.
3+
tests/cases/conformance/salsa/a.js(1,10): error TS2300: Duplicate identifier 'x'.
44
tests/cases/conformance/salsa/b.ts(1,5): error TS2300: Duplicate identifier 'x'.
55

66

77
!!! error TS5055: Cannot write file 'tests/cases/conformance/salsa/a.js' because it would overwrite input file.
88
!!! 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.
99
==== tests/cases/conformance/salsa/a.js (1 errors) ====
1010
var /*1*/x = function foo() {
11-
~~~
11+
~
1212
!!! error TS2300: Duplicate identifier 'x'.
1313
}
1414
x.a = function bar() {

0 commit comments

Comments
 (0)