Skip to content

Commit eb3f37c

Browse files
committed
fix(language_server): on configuration change, send updated diagnostics to the client (#10764)
1 parent 8c499c6 commit eb3f37c

File tree

3 files changed

+91
-3
lines changed

3 files changed

+91
-3
lines changed

crates/oxc_language_server/src/main.rs

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -121,12 +121,21 @@ impl LanguageServer for Backend {
121121

122122
async fn did_change_configuration(&self, params: DidChangeConfigurationParams) {
123123
let workers = self.workspace_workers.lock().await;
124+
let new_diagnostics: papaya::HashMap<String, Vec<Diagnostic>, FxBuildHasher> =
125+
ConcurrentHashMap::default();
124126

125127
// when we have only workspace folder, apply to it
126128
// ToDo: check if this is really safe because the client could still pass an empty settings
127129
if workers.len() == 1 {
128130
let worker = workers.first().unwrap();
129-
worker.did_change_configuration(params.settings).await;
131+
let Some(diagnostics) = worker.did_change_configuration(params.settings).await else {
132+
return;
133+
};
134+
for (uri, reports) in &diagnostics.pin() {
135+
new_diagnostics
136+
.pin()
137+
.insert(uri.clone(), reports.iter().map(|d| d.diagnostic.clone()).collect());
138+
}
130139

131140
// else check if the client support workspace configuration requests so we can only restart only the needed workers
132141
} else if self
@@ -156,16 +165,49 @@ impl LanguageServer for Backend {
156165
// this is a LSP specification and errors should be reported on the client side
157166
for (index, worker) in workers.iter().enumerate() {
158167
let config = &configs[index];
159-
worker.did_change_configuration(config.clone()).await;
168+
let Some(diagnostics) = worker.did_change_configuration(config.clone()).await
169+
else {
170+
continue;
171+
};
172+
173+
for (uri, reports) in &diagnostics.pin() {
174+
new_diagnostics.pin().insert(
175+
uri.clone(),
176+
reports.iter().map(|d| d.diagnostic.clone()).collect(),
177+
);
178+
}
160179
}
161180

162181
// we have multiple workspace folders and the client does not support workspace configuration requests
163182
// we assume that every workspace is under effect
164183
} else {
165184
for worker in workers.iter() {
166-
worker.did_change_configuration(params.settings.clone()).await;
185+
let Some(diagnostics) =
186+
worker.did_change_configuration(params.settings.clone()).await
187+
else {
188+
continue;
189+
};
190+
191+
for (uri, reports) in &diagnostics.pin() {
192+
new_diagnostics.pin().insert(
193+
uri.clone(),
194+
reports.iter().map(|d| d.diagnostic.clone()).collect(),
195+
);
196+
}
167197
}
168198
}
199+
200+
if new_diagnostics.is_empty() {
201+
return;
202+
}
203+
204+
let x = &new_diagnostics
205+
.pin()
206+
.into_iter()
207+
.map(|(key, value)| (key.clone(), value.clone()))
208+
.collect::<Vec<_>>();
209+
210+
self.publish_all_diagnostics(x).await;
169211
}
170212

171213
async fn did_change_watched_files(&self, params: DidChangeWatchedFilesParams) {

editors/vscode/client/extension.spec.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,11 @@ setup(async () => {
2828
await activateExtension();
2929
});
3030

31+
teardown(async () => {
32+
await workspace.getConfiguration('oxc').update('flags', undefined);
33+
await workspace.saveAll();
34+
});
35+
3136
suite('commands', () => {
3237
test('listed commands', async () => {
3338
const oxcCommands = (await commands.getCommands(true)).filter(x => x.startsWith('oxc.'));
@@ -162,6 +167,46 @@ suite('code actions', () => {
162167
await workspace.getConfiguration('editor').update('codeActionsOnSave', undefined);
163168
await workspace.saveAll();
164169
});
170+
171+
test('changing configuration "fix_kind" will reveal more code actions', async () => {
172+
await loadFixture('changing_fix_kind');
173+
const fileUri = Uri.joinPath(WORKSPACE_DIR, 'fixtures', 'for_direction.ts');
174+
await window.showTextDocument(fileUri);
175+
const codeActionsNoFix: ProviderResult<Array<CodeAction>> = await commands.executeCommand(
176+
'vscode.executeCodeActionProvider',
177+
fileUri,
178+
{
179+
start: { line: 0, character: 18 },
180+
end: { line: 0, character: 19 },
181+
},
182+
);
183+
184+
assert(Array.isArray(codeActionsNoFix));
185+
const quickFixesNoFix = codeActionsNoFix.filter(
186+
(action) => action.kind?.value === 'quickfix',
187+
);
188+
strictEqual(quickFixesNoFix.length, 2);
189+
190+
await workspace.getConfiguration('oxc').update('flags', {
191+
'fix_kind': 'dangerous_fix',
192+
});
193+
await workspace.saveAll();
194+
195+
const codeActionsWithFix: ProviderResult<Array<CodeAction>> = await commands.executeCommand(
196+
'vscode.executeCodeActionProvider',
197+
fileUri,
198+
{
199+
start: { line: 0, character: 18 },
200+
end: { line: 0, character: 19 },
201+
},
202+
);
203+
204+
assert(Array.isArray(codeActionsWithFix));
205+
const quickFixesWithFix = codeActionsWithFix.filter(
206+
(action) => action.kind?.value === 'quickfix',
207+
);
208+
strictEqual(quickFixesWithFix.length, 3);
209+
});
165210
});
166211

167212
suite('E2E Diagnostics', () => {
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
for(var i = 0; i < 10; i--){}

0 commit comments

Comments
 (0)