diff --git a/src/services/codefixes/helpers.ts b/src/services/codefixes/helpers.ts index 7e4cf36f1f0..ef0ca1a9a57 100644 --- a/src/services/codefixes/helpers.ts +++ b/src/services/codefixes/helpers.ts @@ -20,15 +20,17 @@ namespace ts.codefix { } function getInsertionForMemberSymbol(symbol: Symbol, enclosingDeclaration: ClassLikeDeclaration, checker: TypeChecker, newlineChar: string): string { - const name = symbol.getName(); + // const name = symbol.getName(); const type = checker.getTypeOfSymbolAtLocation(symbol, enclosingDeclaration); const declarations = symbol.getDeclarations(); if (!(declarations && declarations.length)) { return ""; } - const node = declarations[0]; - const visibility = getVisibilityPrefix(getModifierFlags(node)); - switch (node.kind) { + + const declaration = declarations[0] as Declaration; + const name = declaration.name.getText(); + const visibility = getVisibilityPrefix(getModifierFlags(declaration)); + switch (declaration.kind) { case SyntaxKind.GetAccessor: case SyntaxKind.SetAccessor: case SyntaxKind.PropertySignature: @@ -68,14 +70,15 @@ namespace ts.codefix { bodySig = checker.getSignatureFromDeclaration(declarations[declarations.length - 1] as SignatureDeclaration); } else { - bodySig = createBodyDeclarationSignatureWithAnyTypes(declarations as SignatureDeclaration[], signatures, enclosingDeclaration, checker); + Debug.assert(declarations.length === signatures.length); + bodySig = createBodySignatureWithAnyTypes(signatures, enclosingDeclaration, checker); } const sigString = checker.signatureToString(bodySig, enclosingDeclaration, TypeFormatFlags.SuppressAnyReturnType, SignatureKind.Call); result += `${visibility}${name}${sigString}${getMethodBodyStub(newlineChar)}`; return result; case SyntaxKind.ComputedPropertyName: - if (hasDynamicName(node)) { + if (hasDynamicName(declaration)) { return ""; } throw new Error("Not implemented, computed property name."); @@ -87,22 +90,25 @@ namespace ts.codefix { } } - function createBodyDeclarationSignatureWithAnyTypes(signatureDecls: SignatureDeclaration[], signatures: Signature[], enclosingDeclaration: ClassLikeDeclaration, checker: TypeChecker): Signature { - Debug.assert(signatureDecls.length === signatures.length); + function createBodySignatureWithAnyTypes(signatures: Signature[], enclosingDeclaration: ClassLikeDeclaration, checker: TypeChecker): Signature { const newSignatureDeclaration = createNode(SyntaxKind.CallSignature) as SignatureDeclaration; newSignatureDeclaration.parent = enclosingDeclaration; - newSignatureDeclaration.name = signatureDecls[0].name; + newSignatureDeclaration.name = signatures[0].getDeclaration().name; - let maxArgs = -1, maxArgsIndex = 0; + let maxArgs = -1; let minArgumentCount = signatures[0].minArgumentCount; let hasRestParameter = false; + let allMaxArgsAreRest = true; for (let i = 0; i < signatures.length; i++) { const sig = signatures[i]; minArgumentCount = Math.min(sig.minArgumentCount, minArgumentCount); if (sig.parameters.length > maxArgs) { maxArgs = sig.parameters.length; - maxArgsIndex = i; + allMaxArgsAreRest = sig.hasRestParameter; + } + else if (sig.parameters.length === maxArgs) { + allMaxArgsAreRest = allMaxArgsAreRest && sig.hasRestParameter; } hasRestParameter = hasRestParameter || sig.hasRestParameter; } @@ -120,10 +126,6 @@ namespace ts.codefix { if (hasRestParameter) { lastParameter.dotDotDotToken = createToken(SyntaxKind.DotDotDotToken); - let allMaxArgsAreRest = true; - for (const sig of signatures) { - allMaxArgsAreRest = allMaxArgsAreRest && sig.parameters[maxArgs - 1] && sig.hasRestParameter; - } if (!allMaxArgsAreRest) { const newParameter = createParameterDeclaration(maxArgs - 1, minArgumentCount, newSignatureDeclaration); newSignatureDeclaration.parameters.push(newParameter); @@ -137,13 +139,13 @@ namespace ts.codefix { return checker.getSignatureFromDeclaration(newSignatureDeclaration); - function createParameterDeclaration(index: number, minArgCount: number, enclosingSignature: SignatureDeclaration): ParameterDeclaration { + function createParameterDeclaration(index: number, minArgCount: number, enclosingSignatureDeclaration: SignatureDeclaration): ParameterDeclaration { const newParameter = createNode(SyntaxKind.Parameter) as ParameterDeclaration; newParameter.symbol = checker.createSymbol(SymbolFlags.FunctionScopedVariable, "arg" + index); newParameter.symbol.valueDeclaration = newParameter; newParameter.symbol.declarations = [newParameter]; newParameter.type = anyTypeNode; - newParameter.parent = enclosingSignature; + newParameter.parent = enclosingSignatureDeclaration; if (index >= minArgCount) { newParameter.questionToken = optionalToken; } diff --git a/tests/cases/fourslash/codeFixClassExtendsAbstractMethod.ts b/tests/cases/fourslash/codeFixClassExtendsAbstractMethod.ts index bf9eba11c8e..587b5d9b2b7 100644 --- a/tests/cases/fourslash/codeFixClassExtendsAbstractMethod.ts +++ b/tests/cases/fourslash/codeFixClassExtendsAbstractMethod.ts @@ -12,7 +12,7 @@ verify.rangeAfterCodeFix(` f(a: number, b: string): boolean; f(a: string, b: number): Function; f(a: string): Function; - f(arg0: any, arg1? any) { - throw new Error("Method not implemented"); + f(arg0: any, arg1?: any) { + throw new Error('Method not implemented.'); } `); diff --git a/tests/cases/fourslash/codeFixUnImplementedInterface39 - Copy (3).ts b/tests/cases/fourslash/codeFixUnImplementedInterface39 - Copy (3).ts deleted file mode 100644 index f81dea49782..00000000000 --- a/tests/cases/fourslash/codeFixUnImplementedInterface39 - Copy (3).ts +++ /dev/null @@ -1,18 +0,0 @@ -/// - -//// namespace N1 { -//// export interface I1 { -//// f1():string; -//// } -//// } -//// interface I1 { -//// f1(); -//// } -//// -//// class C1 implements N1.I1 {[| -//// |]} - -verify.rangeAfterCodeFix(`f1(): string{ - throw new Error('Method not implemented.'); -} -`); diff --git a/tests/cases/fourslash/codeFixUnImplementedInterface39 - Copy (4).ts b/tests/cases/fourslash/codeFixUnImplementedInterface39 - Copy (4).ts deleted file mode 100644 index f81dea49782..00000000000 --- a/tests/cases/fourslash/codeFixUnImplementedInterface39 - Copy (4).ts +++ /dev/null @@ -1,18 +0,0 @@ -/// - -//// namespace N1 { -//// export interface I1 { -//// f1():string; -//// } -//// } -//// interface I1 { -//// f1(); -//// } -//// -//// class C1 implements N1.I1 {[| -//// |]} - -verify.rangeAfterCodeFix(`f1(): string{ - throw new Error('Method not implemented.'); -} -`); diff --git a/tests/cases/fourslash/codeFixUnImplementedInterface39 - Copy (5).ts b/tests/cases/fourslash/codeFixUnImplementedInterface39 - Copy (5).ts deleted file mode 100644 index f81dea49782..00000000000 --- a/tests/cases/fourslash/codeFixUnImplementedInterface39 - Copy (5).ts +++ /dev/null @@ -1,18 +0,0 @@ -/// - -//// namespace N1 { -//// export interface I1 { -//// f1():string; -//// } -//// } -//// interface I1 { -//// f1(); -//// } -//// -//// class C1 implements N1.I1 {[| -//// |]} - -verify.rangeAfterCodeFix(`f1(): string{ - throw new Error('Method not implemented.'); -} -`); diff --git a/tests/cases/fourslash/codeFixUnImplementedInterface39 - Copy (6).ts b/tests/cases/fourslash/codeFixUnImplementedInterface39 - Copy (6).ts deleted file mode 100644 index f81dea49782..00000000000 --- a/tests/cases/fourslash/codeFixUnImplementedInterface39 - Copy (6).ts +++ /dev/null @@ -1,18 +0,0 @@ -/// - -//// namespace N1 { -//// export interface I1 { -//// f1():string; -//// } -//// } -//// interface I1 { -//// f1(); -//// } -//// -//// class C1 implements N1.I1 {[| -//// |]} - -verify.rangeAfterCodeFix(`f1(): string{ - throw new Error('Method not implemented.'); -} -`); diff --git a/tests/cases/fourslash/codeFixUnImplementedInterfaceComputedPropertyNameWellKnownSymbols.ts b/tests/cases/fourslash/codeFixUnImplementedInterfaceComputedPropertyNameWellKnownSymbols.ts new file mode 100644 index 00000000000..ffad13e74de --- /dev/null +++ b/tests/cases/fourslash/codeFixUnImplementedInterfaceComputedPropertyNameWellKnownSymbols.ts @@ -0,0 +1,53 @@ +/// + +// @lib: es2017 + +//// interface I { +//// [Symbol.hasInstance](o: any): boolean; +//// [Symbol.isConcatSpreadable]: boolean; +//// [Symbol.iterator](): Iterator; +//// [Symbol.match]: boolean; +//// [Symbol.replace](...args); +//// [Symbol.search](str: string): number; +//// [Symbol.species](): Species; +//// [Symbol.split](str: string, limit?: number): string[]; +//// [Symbol.toPrimitive](hint: "number"): number; +//// [Symbol.toPrimitive](hint: "default"): number; +//// [Symbol.toPrimitive](hint: "string"): string; +//// [Symbol.toStringTag]: string; +//// [Symbol.unscopables]: any; +//// } +//// +//// class C implements I {[| |]} + + +verify.rangeAfterCodeFix(` + [Symbol.hasInstance](o: any): boolean { + throw new Error('Method not implemented.'); + } + [Symbol.isConcatSpreadable]: boolean; + [Symbol.iterator]() { + throw new Error('Method not implemented.'); + } + [Symbol.match]: boolean; + [Symbol.replace](...args: {}) { + throw new Error('Method not implemented.'); + } + [Symbol.search](str: string): number { + throw new Error('Method not implemented.'); + } + [Symbol.species](): number { + throw new Error('Method not implemented.'); + } + [Symbol.split](str: string, limit?: number): {} { + throw new Error('Method not implemented.'); + } + [Symbol.toPrimitive](hint: "number"): number; + [Symbol.toPrimitive](hint: "default"): number; + [Symbol.toPrimitive](hint: "string"): string; + [Symbol.toPrimitive](arg0: any) { + throw new Error('Method not implemented.'); + } + [Symbol.toStringTag]: string; + [Symbol.unscopables]: any; +`);