Fix the remove unused source action not removing single unused interfaces

This commit is contained in:
Matt Bierner 2020-05-29 01:14:22 -07:00
parent 5f8e6d0b19
commit dfde221caa
4 changed files with 54 additions and 32 deletions

View file

@ -18,7 +18,7 @@ import FileConfigurationManager from './fileConfigurationManager';
const localize = nls.loadMessageBundle(); const localize = nls.loadMessageBundle();
interface AutoFix { interface AutoFix {
readonly code: number; readonly codes: Set<number>;
readonly fixName: string; readonly fixName: string;
} }
@ -31,12 +31,12 @@ async function buildIndividualFixes(
token: vscode.CancellationToken, token: vscode.CancellationToken,
): Promise<void> { ): Promise<void> {
for (const diagnostic of diagnostics) { for (const diagnostic of diagnostics) {
for (const { code, fixName } of fixes) { for (const { codes, fixName } of fixes) {
if (token.isCancellationRequested) { if (token.isCancellationRequested) {
return; return;
} }
if (diagnostic.code !== code) { if (!codes.has(diagnostic.code as number)) {
continue; continue;
} }
@ -68,12 +68,12 @@ async function buildCombinedFix(
token: vscode.CancellationToken, token: vscode.CancellationToken,
): Promise<void> { ): Promise<void> {
for (const diagnostic of diagnostics) { for (const diagnostic of diagnostics) {
for (const { code, fixName } of fixes) { for (const { codes, fixName } of fixes) {
if (token.isCancellationRequested) { if (token.isCancellationRequested) {
return; return;
} }
if (diagnostic.code !== code) { if (!codes.has(diagnostic.code as number)) {
continue; continue;
} }
@ -139,12 +139,12 @@ class SourceFixAll extends SourceAction {
this.edit = new vscode.WorkspaceEdit(); this.edit = new vscode.WorkspaceEdit();
await buildIndividualFixes([ await buildIndividualFixes([
{ code: errorCodes.incorrectlyImplementsInterface, fixName: fixNames.classIncorrectlyImplementsInterface }, { codes: errorCodes.incorrectlyImplementsInterface, fixName: fixNames.classIncorrectlyImplementsInterface },
{ code: errorCodes.asyncOnlyAllowedInAsyncFunctions, fixName: fixNames.awaitInSyncFunction }, { codes: errorCodes.asyncOnlyAllowedInAsyncFunctions, fixName: fixNames.awaitInSyncFunction },
], this.edit, client, file, diagnostics, token); ], this.edit, client, file, diagnostics, token);
await buildCombinedFix([ await buildCombinedFix([
{ code: errorCodes.unreachableCode, fixName: fixNames.unreachableCode } { codes: errorCodes.unreachableCode, fixName: fixNames.unreachableCode }
], this.edit, client, file, diagnostics, token); ], 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<void> { async build(client: ITypeScriptServiceClient, file: string, diagnostics: readonly vscode.Diagnostic[], token: vscode.CancellationToken): Promise<void> {
this.edit = new vscode.WorkspaceEdit(); this.edit = new vscode.WorkspaceEdit();
await buildCombinedFix([ await buildCombinedFix([
{ code: errorCodes.variableDeclaredButNeverUsed, fixName: fixNames.unusedIdentifier }, { codes: errorCodes.variableDeclaredButNeverUsed, fixName: fixNames.unusedIdentifier },
], this.edit, client, file, diagnostics, token); ], 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<void> { async build(client: ITypeScriptServiceClient, file: string, diagnostics: readonly vscode.Diagnostic[], token: vscode.CancellationToken): Promise<void> {
this.edit = new vscode.WorkspaceEdit(); this.edit = new vscode.WorkspaceEdit();
await buildCombinedFix( await buildCombinedFix([
errorCodes.cannotFindName.map(code => ({ code, fixName: fixNames.fixImport })), { codes: errorCodes.cannotFindName, fixName: fixNames.fixImport }
],
this.edit, client, file, diagnostics, token); this.edit, client, file, diagnostics, token);
} }
} }

View file

@ -115,4 +115,25 @@ suite('TypeScript Fix All', () => {
`used();` `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.CodeAction[]>('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;`,
``
));
});
}); });

View file

@ -27,15 +27,15 @@ import TypingsStatus, { AtaProgressReporter } from './utils/typingsStatus';
import VersionStatus from './utils/versionStatus'; import VersionStatus from './utils/versionStatus';
// Style check diagnostics that can be reported as warnings // Style check diagnostics that can be reported as warnings
const styleCheckDiagnostics = [ const styleCheckDiagnostics = new Set([
errorCodes.variableDeclaredButNeverUsed, ...errorCodes.variableDeclaredButNeverUsed,
errorCodes.propertyDeclaretedButNeverUsed, ...errorCodes.propertyDeclaretedButNeverUsed,
errorCodes.allImportsAreUnused, ...errorCodes.allImportsAreUnused,
errorCodes.unreachableCode, ...errorCodes.unreachableCode,
errorCodes.unusedLabel, ...errorCodes.unusedLabel,
errorCodes.fallThroughCaseInSwitch, ...errorCodes.fallThroughCaseInSwitch,
errorCodes.notAllCodePathsReturnAValue, ...errorCodes.notAllCodePathsReturnAValue,
]; ]);
export default class TypeScriptServiceClientHost extends Disposable { export default class TypeScriptServiceClientHost extends Disposable {
@ -286,6 +286,6 @@ export default class TypeScriptServiceClientHost extends Disposable {
} }
private isStyleCheckDiagnostic(code: number | undefined): boolean { private isStyleCheckDiagnostic(code: number | undefined): boolean {
return code ? styleCheckDiagnostics.indexOf(code) !== -1 : false; return typeof code === 'number' && styleCheckDiagnostics.has(code);
} }
} }

View file

@ -3,14 +3,14 @@
* Licensed under the MIT License. See License.txt in the project root for license information. * Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
export const variableDeclaredButNeverUsed = 6133; export const variableDeclaredButNeverUsed = new Set([6196, 6133]);
export const propertyDeclaretedButNeverUsed = 6138; export const propertyDeclaretedButNeverUsed = new Set([6138]);
export const allImportsAreUnused = 6192; export const allImportsAreUnused = new Set([6192]);
export const unreachableCode = 7027; export const unreachableCode = new Set([7027]);
export const unusedLabel = 7028; export const unusedLabel = new Set([7028]);
export const fallThroughCaseInSwitch = 7029; export const fallThroughCaseInSwitch = new Set([7029]);
export const notAllCodePathsReturnAValue = 7030; export const notAllCodePathsReturnAValue = new Set([7030]);
export const incorrectlyImplementsInterface = 2420; export const incorrectlyImplementsInterface = new Set([2420]);
export const cannotFindName = [2552, 2304]; export const cannotFindName = new Set([2552, 2304]);
export const extendsShouldBeImplements = 2689; export const extendsShouldBeImplements = new Set([2689]);
export const asyncOnlyAllowedInAsyncFunctions = 1308; export const asyncOnlyAllowedInAsyncFunctions = new Set([1308]);