From c529526fad497ce42ed5192798bc79b8a41ec4c2 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Fri, 3 Nov 2017 00:26:59 -0700 Subject: [PATCH 1/4] Added tests. --- .../codeFixAmbientClassImplementInterface01.ts | 11 +++++++++++ .../codeFixAmbientClassImplementInterface02.ts | 13 +++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 tests/cases/fourslash/codeFixAmbientClassImplementInterface01.ts create mode 100644 tests/cases/fourslash/codeFixAmbientClassImplementInterface02.ts diff --git a/tests/cases/fourslash/codeFixAmbientClassImplementInterface01.ts b/tests/cases/fourslash/codeFixAmbientClassImplementInterface01.ts new file mode 100644 index 0000000000000..c84267d2928ca --- /dev/null +++ b/tests/cases/fourslash/codeFixAmbientClassImplementInterface01.ts @@ -0,0 +1,11 @@ +/// + +////interface Hook { +//// tap(): void +////} +//// +////declare class SyncHook implements Hook {[| |]} + +verify.rangeAfterCodeFix(` +tap(): void; +`); diff --git a/tests/cases/fourslash/codeFixAmbientClassImplementInterface02.ts b/tests/cases/fourslash/codeFixAmbientClassImplementInterface02.ts new file mode 100644 index 0000000000000..6347e7bc80fc8 --- /dev/null +++ b/tests/cases/fourslash/codeFixAmbientClassImplementInterface02.ts @@ -0,0 +1,13 @@ +/// + +////interface Hook { +//// tap(): void; +//// tap(x: number): string; +////} +//// +////declare class SyncHook implements Hook {[| |] + +verify.rangeAfterCodeFix(` +tap(): void; +tap(x: number): string; +`); \ No newline at end of file From 1a522fd1c86129a1ac64625ed069dfaaaab8895d Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Fri, 3 Nov 2017 00:30:30 -0700 Subject: [PATCH 2/4] Improve signature for 'format.setOption' in fourslash. --- tests/cases/fourslash/fourslash.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/cases/fourslash/fourslash.ts b/tests/cases/fourslash/fourslash.ts index 9eca1d6456556..ed33dd4b5e81a 100644 --- a/tests/cases/fourslash/fourslash.ts +++ b/tests/cases/fourslash/fourslash.ts @@ -97,7 +97,6 @@ declare namespace FourSlashInterface { InsertSpaceAfterTypeAssertion: boolean; PlaceOpenBraceOnNewLineForFunctions: boolean; PlaceOpenBraceOnNewLineForControlBlocks: boolean; - [s: string]: boolean | number | string | undefined; } interface Range { fileName: string; @@ -375,7 +374,7 @@ declare namespace FourSlashInterface { setFormatOptions(options: FormatCodeOptions): any; selection(startMarker: string, endMarker: string): void; onType(posMarker: string, key: string): void; - setOption(name: keyof FormatCodeOptions, value: number | string | boolean): void; + setOption(name: K, value: FormatCodeOptions[K]): void; } class cancellation { resetCancelled(): void; From 3f20f001d937a3f16c3863aeeb79407de394495c Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Fri, 3 Nov 2017 00:32:12 -0700 Subject: [PATCH 3/4] Avoid generating implementation signatures in ambient contexts. --- src/services/codefixes/helpers.ts | 29 ++++++++--------------------- 1 file changed, 8 insertions(+), 21 deletions(-) diff --git a/src/services/codefixes/helpers.ts b/src/services/codefixes/helpers.ts index 685c6832f13df..b217f03a9f6d8 100644 --- a/src/services/codefixes/helpers.ts +++ b/src/services/codefixes/helpers.ts @@ -93,6 +93,7 @@ namespace ts.codefix { // (eg: an abstract method or interface declaration), there is a 1-1 // correspondence of declarations and signatures. const signatures = checker.getSignaturesOfType(type, SignatureKind.Call); + const needsImplementation = !isInAmbientContext(enclosingDeclaration); if (!some(signatures)) { return undefined; } @@ -100,7 +101,8 @@ namespace ts.codefix { if (declarations.length === 1) { Debug.assert(signatures.length === 1); const signature = signatures[0]; - return signatureToMethodDeclaration(signature, enclosingDeclaration, createStubbedMethodBody()); + const body = needsImplementation ? createStubbedMethodBody() : undefined; + return signatureToMethodDeclaration(signature, enclosingDeclaration, body); } const signatureDeclarations: MethodDeclaration[] = []; @@ -119,7 +121,7 @@ namespace ts.codefix { signatureDeclarations.push(methodDeclaration); } } - else { + else if (needsImplementation) { Debug.assert(declarations.length === signatures.length); const methodImplementingSignatures = createMethodImplementingSignatures(signatures, name, optional, modifiers); signatureDeclarations.push(methodImplementingSignatures); @@ -222,32 +224,17 @@ namespace ts.codefix { parameters.push(restParameter); } - return createStubbedMethod( - modifiers, - name, - optional, - /*typeParameters*/ undefined, - parameters, - /*returnType*/ undefined); - } - - export function createStubbedMethod( - modifiers: ReadonlyArray, - name: PropertyName, - optional: boolean, - typeParameters: ReadonlyArray | undefined, - parameters: ReadonlyArray, - returnType: TypeNode | undefined) { return createMethod( /*decorators*/ undefined, modifiers, /*asteriskToken*/ undefined, name, optional ? createToken(SyntaxKind.QuestionToken) : undefined, - typeParameters, + /*typeParameters*/ undefined, parameters, - returnType, - createStubbedMethodBody()); + /*returnType*/ undefined, + createStubbedMethodBody(), + ); } function createStubbedMethodBody() { From 8a211aec2bce2749f6f3c16518903b7ab9fdc748 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Fri, 3 Nov 2017 15:04:18 -0700 Subject: [PATCH 4/4] Use `NodeFlags.Ambient`. Make return type explicit for `signatureToSignatureDeclaration`. --- src/compiler/checker.ts | 2 +- src/compiler/types.ts | 2 +- src/services/codefixes/helpers.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index b540f92b52579..0eb11696687cd 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2457,7 +2457,7 @@ namespace ts { const result = context.encounteredError ? undefined : resultingNode; return result; }, - signatureToSignatureDeclaration: (signature: Signature, kind: SyntaxKind, enclosingDeclaration?: Node, flags?: NodeBuilderFlags) => { + signatureToSignatureDeclaration: (signature: Signature, kind: SyntaxKind, enclosingDeclaration?: Node, flags?: NodeBuilderFlags): SignatureDeclaration | undefined => { Debug.assert(enclosingDeclaration === undefined || (enclosingDeclaration.flags & NodeFlags.Synthesized) === 0); const context = createNodeBuilderContext(enclosingDeclaration, flags); const resultingNode = signatureToSignatureDeclarationHelper(signature, kind, context); diff --git a/src/compiler/types.ts b/src/compiler/types.ts index b4e84ae6a759a..db37dc3747005 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2657,7 +2657,7 @@ namespace ts { /** Note that the resulting nodes cannot be checked. */ typeToTypeNode(type: Type, enclosingDeclaration?: Node, flags?: NodeBuilderFlags): TypeNode; /** Note that the resulting nodes cannot be checked. */ - signatureToSignatureDeclaration(signature: Signature, kind: SyntaxKind, enclosingDeclaration?: Node, flags?: NodeBuilderFlags): SignatureDeclaration; + signatureToSignatureDeclaration(signature: Signature, kind: SyntaxKind, enclosingDeclaration?: Node, flags?: NodeBuilderFlags): SignatureDeclaration | undefined; /** Note that the resulting nodes cannot be checked. */ indexInfoToIndexSignatureDeclaration(indexInfo: IndexInfo, kind: IndexKind, enclosingDeclaration?: Node, flags?: NodeBuilderFlags): IndexSignatureDeclaration; diff --git a/src/services/codefixes/helpers.ts b/src/services/codefixes/helpers.ts index b217f03a9f6d8..bf3eb98ceb690 100644 --- a/src/services/codefixes/helpers.ts +++ b/src/services/codefixes/helpers.ts @@ -93,7 +93,7 @@ namespace ts.codefix { // (eg: an abstract method or interface declaration), there is a 1-1 // correspondence of declarations and signatures. const signatures = checker.getSignaturesOfType(type, SignatureKind.Call); - const needsImplementation = !isInAmbientContext(enclosingDeclaration); + const needsImplementation = !(enclosingDeclaration.flags & NodeFlags.Ambient); if (!some(signatures)) { return undefined; }