Fix location for duplicate function implementation errors

Use only the relevant declarations (by collecting them in the for loop),
and use `declaration` if `getNameOfDeclaration` didn't work (useful for
`export default` with anonymous functions).

Fixes #39804.

Also, use `nodeIsPresent` once, and a random `?.`.
This commit is contained in:
Eli Barzilay
2020-07-29 15:32:52 -04:00
parent 03b658035d
commit f2d1531768
6 changed files with 56 additions and 6 deletions

View File

@@ -31280,6 +31280,7 @@ namespace ts {
let duplicateFunctionDeclaration = false;
let multipleConstructorImplementation = false;
let hasNonAmbientClass = false;
const functionDeclarations = [] as Declaration[];
for (const current of declarations) {
const node = <SignatureDeclaration | ClassDeclaration | ClassExpression>current;
const inAmbientContext = node.flags & NodeFlags.Ambient;
@@ -31300,13 +31301,15 @@ namespace ts {
}
if (node.kind === SyntaxKind.FunctionDeclaration || node.kind === SyntaxKind.MethodDeclaration || node.kind === SyntaxKind.MethodSignature || node.kind === SyntaxKind.Constructor) {
functionDeclarations.push(node);
const currentNodeFlags = getEffectiveDeclarationFlags(node, flagsToCheck);
someNodeFlags |= currentNodeFlags;
allNodeFlags &= currentNodeFlags;
someHaveQuestionToken = someHaveQuestionToken || hasQuestionToken(node);
allHaveQuestionToken = allHaveQuestionToken && hasQuestionToken(node);
const bodyIsPresent = nodeIsPresent((node as FunctionLikeDeclaration).body);
if (nodeIsPresent((node as FunctionLikeDeclaration).body) && bodyDeclaration) {
if (bodyIsPresent && bodyDeclaration) {
if (isConstructor) {
multipleConstructorImplementation = true;
}
@@ -31314,11 +31317,11 @@ namespace ts {
duplicateFunctionDeclaration = true;
}
}
else if (previousDeclaration && previousDeclaration.parent === node.parent && previousDeclaration.end !== node.pos) {
else if (previousDeclaration?.parent === node.parent && previousDeclaration.end !== node.pos) {
reportImplementationExpectedError(previousDeclaration);
}
if (nodeIsPresent((node as FunctionLikeDeclaration).body)) {
if (bodyIsPresent) {
if (!bodyDeclaration) {
bodyDeclaration = node as FunctionLikeDeclaration;
}
@@ -31336,14 +31339,14 @@ namespace ts {
}
if (multipleConstructorImplementation) {
forEach(declarations, declaration => {
forEach(functionDeclarations, declaration => {
error(declaration, Diagnostics.Multiple_constructor_implementations_are_not_allowed);
});
}
if (duplicateFunctionDeclaration) {
forEach(declarations, declaration => {
error(getNameOfDeclaration(declaration), Diagnostics.Duplicate_function_implementation);
forEach(functionDeclarations, declaration => {
error(getNameOfDeclaration(declaration) || declaration, Diagnostics.Duplicate_function_implementation);
});
}

View File

@@ -0,0 +1,13 @@
tests/cases/compiler/exportDefaultInterfaceAndTwoFunctions.ts(2,1): error TS2393: Duplicate function implementation.
tests/cases/compiler/exportDefaultInterfaceAndTwoFunctions.ts(3,1): error TS2393: Duplicate function implementation.
==== tests/cases/compiler/exportDefaultInterfaceAndTwoFunctions.ts (2 errors) ====
export default interface A { a: string; }
export default function() { return 1; }
~~~~~~
!!! error TS2393: Duplicate function implementation.
export default function() { return 2; }
~~~~~~
!!! error TS2393: Duplicate function implementation.

View File

@@ -0,0 +1,13 @@
//// [exportDefaultInterfaceAndTwoFunctions.ts]
export default interface A { a: string; }
export default function() { return 1; }
export default function() { return 2; }
//// [exportDefaultInterfaceAndTwoFunctions.js]
"use strict";
exports.__esModule = true;
function default_1() { return 1; }
exports["default"] = default_1;
function default_2() { return 2; }
exports["default"] = default_2;

View File

@@ -0,0 +1,8 @@
=== tests/cases/compiler/exportDefaultInterfaceAndTwoFunctions.ts ===
export default interface A { a: string; }
>A : Symbol(A, Decl(exportDefaultInterfaceAndTwoFunctions.ts, 0, 41), Decl(exportDefaultInterfaceAndTwoFunctions.ts, 1, 39), Decl(exportDefaultInterfaceAndTwoFunctions.ts, 0, 0))
>a : Symbol(A.a, Decl(exportDefaultInterfaceAndTwoFunctions.ts, 0, 28))
export default function() { return 1; }
export default function() { return 2; }

View File

@@ -0,0 +1,10 @@
=== tests/cases/compiler/exportDefaultInterfaceAndTwoFunctions.ts ===
export default interface A { a: string; }
>a : string
export default function() { return 1; }
>1 : 1
export default function() { return 2; }
>2 : 2

View File

@@ -0,0 +1,3 @@
export default interface A { a: string; }
export default function() { return 1; }
export default function() { return 2; }