Skip to content

Commit b677376

Browse files
committed
fix(language_server): include the diagnostic of the other linter (#13490)
Not the `ServerLinter` and `WorkspaceWorker` are holding the diagnostics of a file. The next PR will refactor it, so `WorkspaceWorker` will no longer hold a copy of it. Wanted to be ready for a possible patch release closes #13480
1 parent 1b425d6 commit b677376

File tree

5 files changed

+68
-9
lines changed

5 files changed

+68
-9
lines changed

crates/oxc_language_server/src/linter/server_linter.rs

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,29 @@ pub struct ServerLinter {
3737
ignore_matcher: LintIgnoreMatcher,
3838
gitignore_glob: Vec<Gitignore>,
3939
lint_on_run: Run,
40+
diagnostics: Arc<ServerLinterDiagnostics>,
4041
pub extended_paths: Vec<PathBuf>,
4142
}
4243

44+
#[derive(Debug, Default)]
45+
struct ServerLinterDiagnostics {
46+
isolated_linter: Arc<ConcurrentHashMap<String, Vec<DiagnosticReport>>>,
47+
tsgo_linter: Arc<ConcurrentHashMap<String, Vec<DiagnosticReport>>>,
48+
}
49+
50+
impl ServerLinterDiagnostics {
51+
pub fn all_diagnostics(&self, path: &str) -> Vec<DiagnosticReport> {
52+
let mut diagnostics = Vec::new();
53+
if let Some(reports) = self.isolated_linter.pin().get(path) {
54+
diagnostics.extend_from_slice(reports);
55+
}
56+
if let Some(reports) = self.tsgo_linter.pin().get(path) {
57+
diagnostics.extend_from_slice(reports);
58+
}
59+
diagnostics
60+
}
61+
}
62+
4363
impl ServerLinter {
4464
pub fn new(root_uri: &Uri, options: &Options) -> Self {
4565
let root_path = root_uri.to_file_path().unwrap();
@@ -134,6 +154,7 @@ impl ServerLinter {
134154
gitignore_glob: Self::create_ignore_glob(&root_path),
135155
extended_paths,
136156
lint_on_run: options.run,
157+
diagnostics: Arc::new(ServerLinterDiagnostics::default()),
137158
tsgo_linter: if options.type_aware {
138159
Arc::new(Some(TsgoLinter::new(&root_path, config_store)))
139160
} else {
@@ -276,28 +297,26 @@ impl ServerLinter {
276297
return None;
277298
}
278299

279-
let mut reports = Vec::with_capacity(0);
280-
281300
if oxlint
282301
&& let Some(oxlint_reports) =
283302
self.isolated_linter.lock().await.run_single(uri, content.clone())
284303
{
285-
reports.extend(oxlint_reports);
304+
self.diagnostics.isolated_linter.pin().insert(uri.to_string(), oxlint_reports);
286305
}
287306

288307
if !tsgolint {
289-
return Some(reports);
308+
return Some(self.diagnostics.all_diagnostics(&uri.to_string()));
290309
}
291310

292311
let Some(tsgo_linter) = &*self.tsgo_linter else {
293-
return Some(reports);
312+
return Some(self.diagnostics.all_diagnostics(&uri.to_string()));
294313
};
295314

296315
if let Some(tsgo_reports) = tsgo_linter.lint_file(uri, content) {
297-
reports.extend(tsgo_reports);
316+
self.diagnostics.tsgo_linter.pin().insert(uri.to_string(), tsgo_reports);
298317
}
299318

300-
Some(reports)
319+
Some(self.diagnostics.all_diagnostics(&uri.to_string()))
301320
}
302321
}
303322

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"rules": {
3+
"unicorn/no-empty-file": "off"
4+
}
5+
}

editors/vscode/fixtures/lint_on_run/onType.ts

Whitespace-only changes.

editors/vscode/tests/e2e_server.spec.ts

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,13 @@ import {
1515
createOxlintConfiguration,
1616
fixturesWorkspaceUri,
1717
getDiagnostics,
18+
getDiagnosticsWithoutClose,
1819
loadFixture,
1920
sleep,
2021
testSingleFolderMode,
2122
waitForDiagnosticChange,
22-
WORKSPACE_DIR
23+
WORKSPACE_DIR,
24+
writeToFixtureFile
2325
} from './test-helpers';
2426
import assert = require('assert');
2527

@@ -66,6 +68,24 @@ suite('E2E Diagnostics', () => {
6668
});
6769
}
6870

71+
testSingleFolderMode('detects diagnostics on run', async () =>
72+
{
73+
await loadFixture('lint_on_run');
74+
const diagnostics = await getDiagnosticsWithoutClose(`onType.ts`);
75+
strictEqual(diagnostics.length, 0);
76+
77+
await writeToFixtureFile('onType.ts', 'debugger;');
78+
await waitForDiagnosticChange();
79+
const updatedDiagnostics = await getDiagnosticsWithoutClose(`onType.ts`);
80+
strictEqual(updatedDiagnostics.length, 1);
81+
82+
await workspace.saveAll();
83+
await sleep(500);
84+
85+
const sameDiagnostics = await getDiagnosticsWithoutClose(`onType.ts`);
86+
strictEqual(updatedDiagnostics.length, sameDiagnostics.length);
87+
});
88+
6989
test('empty oxlint configuration behaves like default configuration', async () => {
7090
await loadFixture('debugger_empty_config');
7191
const diagnostics = await getDiagnostics('debugger.js');

editors/vscode/tests/test-helpers.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,14 +101,29 @@ export async function loadFixture(fixture: string, workspaceDir: Uri = fixturesW
101101
}
102102

103103
export async function getDiagnostics(file: string, workspaceDir: Uri = fixturesWorkspaceUri()): Promise<Diagnostic[]> {
104+
const diagnostics = await getDiagnosticsWithoutClose(file, workspaceDir);
105+
await commands.executeCommand('workbench.action.closeActiveEditor');
106+
return diagnostics;
107+
}
108+
109+
export async function getDiagnosticsWithoutClose(file: string, workspaceDir: Uri = fixturesWorkspaceUri()): Promise<Diagnostic[]> {
104110
const fileUri = Uri.joinPath(workspaceDir, 'fixtures', file);
105111
await window.showTextDocument(fileUri);
106112
await sleep(500);
107113
const diagnostics = languages.getDiagnostics(fileUri);
108-
await commands.executeCommand('workbench.action.closeActiveEditor');
109114
return diagnostics;
110115
}
111116

117+
export async function writeToFixtureFile(file: string, content: string, workspaceDir: Uri = fixturesWorkspaceUri()): Promise<void> {
118+
const fileUri = Uri.joinPath(workspaceDir, 'fixtures', file);
119+
await window.showTextDocument(fileUri);
120+
121+
for (const char of content) {
122+
await commands.executeCommand('type', { text: char });
123+
await sleep(50);
124+
}
125+
}
126+
112127
export async function waitForDiagnosticChange(): Promise<void> {
113128
return new Promise<void>((resolve) =>
114129
languages.onDidChangeDiagnostics(() => {

0 commit comments

Comments
 (0)