From dfde221caad8b5cccce0dc76d388704c7337d109 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Fri, 29 May 2020 01:14:22 -0700 Subject: [PATCH] Fix the remove unused source action not removing single unused interfaces --- .../src/features/fixAll.ts | 23 ++++++++++--------- .../src/test/fixAll.test.ts | 21 +++++++++++++++++ .../src/typeScriptServiceClientHost.ts | 20 ++++++++-------- .../src/utils/errorCodes.ts | 22 +++++++++--------- 4 files changed, 54 insertions(+), 32 deletions(-) diff --git a/extensions/typescript-language-features/src/features/fixAll.ts b/extensions/typescript-language-features/src/features/fixAll.ts index afa694e6d7b..8d85618ae98 100644 --- a/extensions/typescript-language-features/src/features/fixAll.ts +++ b/extensions/typescript-language-features/src/features/fixAll.ts @@ -18,7 +18,7 @@ import FileConfigurationManager from './fileConfigurationManager'; const localize = nls.loadMessageBundle(); interface AutoFix { - readonly code: number; + readonly codes: Set; readonly fixName: string; } @@ -31,12 +31,12 @@ async function buildIndividualFixes( token: vscode.CancellationToken, ): Promise { for (const diagnostic of diagnostics) { - for (const { code, fixName } of fixes) { + for (const { codes, fixName } of fixes) { if (token.isCancellationRequested) { return; } - if (diagnostic.code !== code) { + if (!codes.has(diagnostic.code as number)) { continue; } @@ -68,12 +68,12 @@ async function buildCombinedFix( token: vscode.CancellationToken, ): Promise { for (const diagnostic of diagnostics) { - for (const { code, fixName } of fixes) { + for (const { codes, fixName } of fixes) { if (token.isCancellationRequested) { return; } - if (diagnostic.code !== code) { + if (!codes.has(diagnostic.code as number)) { continue; } @@ -139,12 +139,12 @@ class SourceFixAll extends SourceAction { this.edit = new vscode.WorkspaceEdit(); await buildIndividualFixes([ - { code: errorCodes.incorrectlyImplementsInterface, fixName: fixNames.classIncorrectlyImplementsInterface }, - { code: errorCodes.asyncOnlyAllowedInAsyncFunctions, fixName: fixNames.awaitInSyncFunction }, + { codes: errorCodes.incorrectlyImplementsInterface, fixName: fixNames.classIncorrectlyImplementsInterface }, + { codes: errorCodes.asyncOnlyAllowedInAsyncFunctions, fixName: fixNames.awaitInSyncFunction }, ], this.edit, client, file, diagnostics, token); await buildCombinedFix([ - { code: errorCodes.unreachableCode, fixName: fixNames.unreachableCode } + { codes: errorCodes.unreachableCode, fixName: fixNames.unreachableCode } ], this.edit, client, file, diagnostics, token); } } @@ -160,7 +160,7 @@ class SourceRemoveUnused extends SourceAction { async build(client: ITypeScriptServiceClient, file: string, diagnostics: readonly vscode.Diagnostic[], token: vscode.CancellationToken): Promise { this.edit = new vscode.WorkspaceEdit(); await buildCombinedFix([ - { code: errorCodes.variableDeclaredButNeverUsed, fixName: fixNames.unusedIdentifier }, + { codes: errorCodes.variableDeclaredButNeverUsed, fixName: fixNames.unusedIdentifier }, ], this.edit, client, file, diagnostics, token); } } @@ -175,8 +175,9 @@ class SourceAddMissingImports extends SourceAction { async build(client: ITypeScriptServiceClient, file: string, diagnostics: readonly vscode.Diagnostic[], token: vscode.CancellationToken): Promise { this.edit = new vscode.WorkspaceEdit(); - await buildCombinedFix( - errorCodes.cannotFindName.map(code => ({ code, fixName: fixNames.fixImport })), + await buildCombinedFix([ + { codes: errorCodes.cannotFindName, fixName: fixNames.fixImport } + ], this.edit, client, file, diagnostics, token); } } diff --git a/extensions/typescript-language-features/src/test/fixAll.test.ts b/extensions/typescript-language-features/src/test/fixAll.test.ts index 0675c2f16cf..37fae0bcfc8 100644 --- a/extensions/typescript-language-features/src/test/fixAll.test.ts +++ b/extensions/typescript-language-features/src/test/fixAll.test.ts @@ -115,4 +115,25 @@ suite('TypeScript Fix All', () => { `used();` )); }); + + test('Remove unused should remove unused interfaces', async () => { + const editor = await createTestEditor(testDocumentUri, + `export const _ = 1;`, + `interface Foo {}` + ); + + await wait(2000); + + const fixes = await vscode.commands.executeCommand('vscode.executeCodeActionProvider', + testDocumentUri, + emptyRange, + vscode.CodeActionKind.Source.append('removeUnused') + ); + + await vscode.workspace.applyEdit(fixes![0].edit!); + assert.strictEqual(editor.document.getText(), joinLines( + `export const _ = 1;`, + `` + )); + }); }); diff --git a/extensions/typescript-language-features/src/typeScriptServiceClientHost.ts b/extensions/typescript-language-features/src/typeScriptServiceClientHost.ts index 0be49c3113b..32f0e47609a 100644 --- a/extensions/typescript-language-features/src/typeScriptServiceClientHost.ts +++ b/extensions/typescript-language-features/src/typeScriptServiceClientHost.ts @@ -27,15 +27,15 @@ import TypingsStatus, { AtaProgressReporter } from './utils/typingsStatus'; import VersionStatus from './utils/versionStatus'; // Style check diagnostics that can be reported as warnings -const styleCheckDiagnostics = [ - errorCodes.variableDeclaredButNeverUsed, - errorCodes.propertyDeclaretedButNeverUsed, - errorCodes.allImportsAreUnused, - errorCodes.unreachableCode, - errorCodes.unusedLabel, - errorCodes.fallThroughCaseInSwitch, - errorCodes.notAllCodePathsReturnAValue, -]; +const styleCheckDiagnostics = new Set([ + ...errorCodes.variableDeclaredButNeverUsed, + ...errorCodes.propertyDeclaretedButNeverUsed, + ...errorCodes.allImportsAreUnused, + ...errorCodes.unreachableCode, + ...errorCodes.unusedLabel, + ...errorCodes.fallThroughCaseInSwitch, + ...errorCodes.notAllCodePathsReturnAValue, +]); export default class TypeScriptServiceClientHost extends Disposable { @@ -286,6 +286,6 @@ export default class TypeScriptServiceClientHost extends Disposable { } private isStyleCheckDiagnostic(code: number | undefined): boolean { - return code ? styleCheckDiagnostics.indexOf(code) !== -1 : false; + return typeof code === 'number' && styleCheckDiagnostics.has(code); } } diff --git a/extensions/typescript-language-features/src/utils/errorCodes.ts b/extensions/typescript-language-features/src/utils/errorCodes.ts index 1d066d9d196..2f554e96584 100644 --- a/extensions/typescript-language-features/src/utils/errorCodes.ts +++ b/extensions/typescript-language-features/src/utils/errorCodes.ts @@ -3,14 +3,14 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -export const variableDeclaredButNeverUsed = 6133; -export const propertyDeclaretedButNeverUsed = 6138; -export const allImportsAreUnused = 6192; -export const unreachableCode = 7027; -export const unusedLabel = 7028; -export const fallThroughCaseInSwitch = 7029; -export const notAllCodePathsReturnAValue = 7030; -export const incorrectlyImplementsInterface = 2420; -export const cannotFindName = [2552, 2304]; -export const extendsShouldBeImplements = 2689; -export const asyncOnlyAllowedInAsyncFunctions = 1308; +export const variableDeclaredButNeverUsed = new Set([6196, 6133]); +export const propertyDeclaretedButNeverUsed = new Set([6138]); +export const allImportsAreUnused = new Set([6192]); +export const unreachableCode = new Set([7027]); +export const unusedLabel = new Set([7028]); +export const fallThroughCaseInSwitch = new Set([7029]); +export const notAllCodePathsReturnAValue = new Set([7030]); +export const incorrectlyImplementsInterface = new Set([2420]); +export const cannotFindName = new Set([2552, 2304]); +export const extendsShouldBeImplements = new Set([2689]); +export const asyncOnlyAllowedInAsyncFunctions = new Set([1308]);