Ryan Cumming abc0784e57 Fix cargo watch code action filtering
There are two issues with the implementation of `provideCodeActions`
introduced in #1439:

1. We're returning the code action based on the file its diagnostic is
   in; not the file the suggested fix is in. I'm not sure how often
   fixes are suggested cross-file but it's something we should handle.

2. We're not filtering code actions based on the passed range. The means
   if there is any suggestion in a file we'll show an action for every
   line of the file. I naively thought that VS Code would filter for us
   but that was wrong.

Unfortunately the VS Code `CodeAction` object is very complex - it can
handle edits across multiple files, run commands, etc. This makes it
complex to check them for equality or see if any of their edits
intersects with a specified range.

To make it easier to work with suggestions this introduces a
`SuggestedFix` model object and a `SuggestFixCollection` code action
provider. This is a layer between the raw Rust JSON and VS Code's
`CodeAction`s. I was reluctant to introduce another layer of abstraction
here but my attempt to work directly with VS Code's model objects was
worse.
2019-06-29 17:39:36 +10:00

99 lines
2.7 KiB
TypeScript

import * as assert from 'assert';
import * as vscode from 'vscode';
import { areDiagnosticsEqual } from '../../../utils/diagnostics/vscode';
const range1 = new vscode.Range(
new vscode.Position(1, 2),
new vscode.Position(3, 4)
);
const range2 = new vscode.Range(
new vscode.Position(5, 6),
new vscode.Position(7, 8)
);
describe('areDiagnosticsEqual', () => {
it('should treat identical diagnostics as equal', () => {
const diagnostic1 = new vscode.Diagnostic(
range1,
'Hello, world!',
vscode.DiagnosticSeverity.Error
);
const diagnostic2 = new vscode.Diagnostic(
range1,
'Hello, world!',
vscode.DiagnosticSeverity.Error
);
assert(areDiagnosticsEqual(diagnostic1, diagnostic2));
});
it('should treat diagnostics with different sources as inequal', () => {
const diagnostic1 = new vscode.Diagnostic(
range1,
'Hello, world!',
vscode.DiagnosticSeverity.Error
);
diagnostic1.source = 'rustc';
const diagnostic2 = new vscode.Diagnostic(
range1,
'Hello, world!',
vscode.DiagnosticSeverity.Error
);
diagnostic2.source = 'clippy';
assert(!areDiagnosticsEqual(diagnostic1, diagnostic2));
});
it('should treat diagnostics with different ranges as inequal', () => {
const diagnostic1 = new vscode.Diagnostic(
range1,
'Hello, world!',
vscode.DiagnosticSeverity.Error
);
const diagnostic2 = new vscode.Diagnostic(
range2,
'Hello, world!',
vscode.DiagnosticSeverity.Error
);
assert(!areDiagnosticsEqual(diagnostic1, diagnostic2));
});
it('should treat diagnostics with different messages as inequal', () => {
const diagnostic1 = new vscode.Diagnostic(
range1,
'Hello, world!',
vscode.DiagnosticSeverity.Error
);
const diagnostic2 = new vscode.Diagnostic(
range1,
'Goodbye!, world!',
vscode.DiagnosticSeverity.Error
);
assert(!areDiagnosticsEqual(diagnostic1, diagnostic2));
});
it('should treat diagnostics with different severities as inequal', () => {
const diagnostic1 = new vscode.Diagnostic(
range1,
'Hello, world!',
vscode.DiagnosticSeverity.Warning
);
const diagnostic2 = new vscode.Diagnostic(
range1,
'Hello, world!',
vscode.DiagnosticSeverity.Error
);
assert(!areDiagnosticsEqual(diagnostic1, diagnostic2));
});
});