Mark add missing imports as preferred fixes

Allow auto fixing add missing imports if:

- There is only one possible import
- And there are no better fixes (such as spelling changes)
This commit is contained in:
Matt Bierner 2020-05-14 22:28:20 -07:00
parent 541b9eb7a6
commit 39fb3b1065
8 changed files with 92 additions and 21 deletions

2
.vscode/launch.json vendored
View file

@ -310,7 +310,7 @@
"name": "TypeScript Extension Tests",
"runtimeExecutable": "${execPath}",
"args": [
"${workspaceFolder}/extensions/typescript-language-features/test-fixtures",
"${workspaceFolder}/extensions/typescript-language-features/test-workspace",
"--extensionDevelopmentPath=${workspaceFolder}/extensions/typescript-language-features",
"--extensionTestsPath=${workspaceFolder}/extensions/typescript-language-features/out/test"
],

View file

@ -59,6 +59,7 @@ const indentationFilter = [
// except specific folders
'!test/automation/out/**',
'!test/smoke/out/**',
'!extensions/typescript-language-features/test-workspace/**',
'!extensions/vscode-api-tests/testWorkspace/**',
'!extensions/vscode-api-tests/testWorkspace2/**',
'!build/monaco/**',

View file

@ -333,17 +333,18 @@ const fixAllErrorCodes = new Map<number, number>([
[2345, 2339],
]);
const preferredFixes = new Map<string, /* priorty */number>([
[fixNames.annotateWithTypeFromJSDoc, 0],
[fixNames.constructorForDerivedNeedSuperCall, 0],
[fixNames.extendsInterfaceBecomesImplements, 0],
[fixNames.awaitInSyncFunction, 0],
[fixNames.classIncorrectlyImplementsInterface, 1],
[fixNames.unreachableCode, 0],
[fixNames.unusedIdentifier, 0],
[fixNames.forgottenThisPropertyAccess, 0],
[fixNames.spelling, 1],
[fixNames.addMissingAwait, 0],
const preferredFixes = new Map<string, { readonly value: number, readonly thereCanOnlyBeOne?: boolean }>([
[fixNames.annotateWithTypeFromJSDoc, { value: 1 }],
[fixNames.constructorForDerivedNeedSuperCall, { value: 1 }],
[fixNames.extendsInterfaceBecomesImplements, { value: 1 }],
[fixNames.awaitInSyncFunction, { value: 1 }],
[fixNames.classIncorrectlyImplementsInterface, { value: 1 }],
[fixNames.unreachableCode, { value: 1 }],
[fixNames.unusedIdentifier, { value: 1 }],
[fixNames.forgottenThisPropertyAccess, { value: 1 }],
[fixNames.spelling, { value: 2 }],
[fixNames.addMissingAwait, { value: 1 }],
[fixNames.fixImport, { value: 0, thereCanOnlyBeOne: true }],
]);
function isPreferredFix(
@ -354,20 +355,30 @@ function isPreferredFix(
return false;
}
const priority = preferredFixes.get(action.tsAction.fixName);
if (typeof priority === 'undefined') {
const fixPriority = preferredFixes.get(action.tsAction.fixName);
if (!fixPriority) {
return false;
}
return allActions.every(otherAction => {
if (otherAction.tsAction === action.tsAction) {
if (otherAction === action) {
return true;
}
const otherPriority = preferredFixes.get(otherAction.tsAction.fixName);
if (typeof otherPriority === 'undefined') {
if (otherAction.isFixAll) {
return true;
}
return priority >= otherPriority;
const otherFixPriority = preferredFixes.get(otherAction.tsAction.fixName);
if (!otherFixPriority || otherFixPriority.value < fixPriority.value) {
return true;
}
if (fixPriority.thereCanOnlyBeOne && action.tsAction.fixName === otherAction.tsAction.fixName) {
return false;
}
return true;
});
}

View file

@ -5,13 +5,11 @@
import * as assert from 'assert';
import 'mocha';
import { join } from 'path';
import * as vscode from 'vscode';
import { disposeAll } from '../utils/dispose';
import { createTestEditor, joinLines, wait } from './testUtils';
const testDocumentUri = vscode.Uri.parse('untitled:test.ts');
suite('TypeScript Quick Fix', () => {
const _disposables: vscode.Disposable[] = [];
@ -23,6 +21,8 @@ suite('TypeScript Quick Fix', () => {
});
test('Fix all should not be marked as preferred #97866', async () => {
const testDocumentUri = vscode.Uri.parse('untitled:test.ts');
const editor = await createTestEditor(testDocumentUri,
`export const _ = 1;`,
`const a$0 = 1;`,
@ -40,4 +40,57 @@ suite('TypeScript Quick Fix', () => {
`const b = 2;`,
));
});
test('Add import should be a preferred fix if there is only one possible import', async () => {
await createTestEditor(workspaceFile('foo.ts'),
`export const foo = 1;`);
const editor = await createTestEditor(workspaceFile('index.ts'),
`export const _ = 1;`,
`foo$0;`
);
await wait(3000);
await vscode.commands.executeCommand('editor.action.autoFix');
await wait(500);
assert.strictEqual(editor.document.getText(), joinLines(
`import { foo } from "./foo";`,
``,
`export const _ = 1;`,
`foo;`
));
});
test('Add import should not be a preferred fix if are multiple possible imports', async () => {
await createTestEditor(workspaceFile('foo.ts'),
`export const foo = 1;`);
await createTestEditor(workspaceFile('bar.ts'),
`export const foo = 1;`);
const editor = await createTestEditor(workspaceFile('index.ts'),
`export const _ = 1;`,
`foo$0;`
);
await wait(3000);
await vscode.commands.executeCommand('editor.action.autoFix');
await wait(500);
assert.strictEqual(editor.document.getText(), joinLines(
`export const _ = 1;`,
`foo;`
));
});
});
function workspaceFile(fileName: string) {
return vscode.Uri.file(join(vscode.workspace.rootPath!, fileName));
}

View file

@ -0,0 +1 @@
// export const foo = 1;

View file

@ -0,0 +1,5 @@
{
"compilerOptions": {
"target": "es2018"
}
}