Skip to content

Commit b638371

Browse files
committed
refactor(language_server): do not check twice for supported extension (#13130)
`should_lint_path` does the same as `Loader::can_load` but with a `OnceLock`
1 parent 34ae2f0 commit b638371

File tree

2 files changed

+63
-76
lines changed

2 files changed

+63
-76
lines changed

crates/oxc_language_server/src/linter/isolated_lint_handler.rs

Lines changed: 46 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use tower_lsp_server::{
1313
use oxc_allocator::Allocator;
1414
use oxc_linter::{
1515
ConfigStore, LINTABLE_EXTENSIONS, LintOptions, LintService, LintServiceOptions, Linter,
16-
MessageWithPosition, loader::Loader, read_to_arena_str,
16+
MessageWithPosition, read_to_arena_str,
1717
};
1818
use oxc_linter::{RuntimeFileSystem, read_to_string};
1919

@@ -93,79 +93,67 @@ impl IsolatedLintHandler {
9393
}
9494

9595
let mut allocator = Allocator::default();
96-
97-
Some(self.lint_path(&mut allocator, &path, content).map_or(vec![], |errors| {
98-
let mut diagnostics: Vec<DiagnosticReport> = errors
99-
.iter()
100-
.map(|e| message_with_position_to_lsp_diagnostic_report(e, uri))
101-
.collect();
102-
103-
// a diagnostics connected from related_info to original diagnostic
104-
let mut inverted_diagnostics = vec![];
105-
for d in &diagnostics {
106-
let Some(related_info) = &d.diagnostic.related_information else {
96+
let source_text = content.or_else(|| read_to_string(&path).ok())?;
97+
let errors = self.lint_path(&mut allocator, &path, source_text);
98+
99+
let mut diagnostics: Vec<DiagnosticReport> =
100+
errors.iter().map(|e| message_with_position_to_lsp_diagnostic_report(e, uri)).collect();
101+
102+
// a diagnostics connected from related_info to original diagnostic
103+
let mut inverted_diagnostics = vec![];
104+
for d in &diagnostics {
105+
let Some(related_info) = &d.diagnostic.related_information else {
106+
continue;
107+
};
108+
let related_information = Some(vec![DiagnosticRelatedInformation {
109+
location: lsp_types::Location { uri: uri.clone(), range: d.diagnostic.range },
110+
message: "original diagnostic".to_string(),
111+
}]);
112+
for r in related_info {
113+
if r.location.range == d.diagnostic.range {
107114
continue;
108-
};
109-
let related_information = Some(vec![DiagnosticRelatedInformation {
110-
location: lsp_types::Location { uri: uri.clone(), range: d.diagnostic.range },
111-
message: "original diagnostic".to_string(),
112-
}]);
113-
for r in related_info {
114-
if r.location.range == d.diagnostic.range {
115-
continue;
116-
}
117-
// If there is no message content for this span, then don't produce an additional diagnostic
118-
// which also has no content. This prevents issues where editors expect diagnostics to have messages.
119-
if r.message.is_empty() {
120-
continue;
121-
}
122-
inverted_diagnostics.push(DiagnosticReport {
123-
diagnostic: lsp_types::Diagnostic {
124-
range: r.location.range,
125-
severity: Some(DiagnosticSeverity::HINT),
126-
code: None,
127-
message: r.message.clone(),
128-
source: d.diagnostic.source.clone(),
129-
code_description: None,
130-
related_information: related_information.clone(),
131-
tags: None,
132-
data: None,
133-
},
134-
fixed_content: PossibleFixContent::None,
135-
rule_name: None,
136-
});
137115
}
116+
// If there is no message content for this span, then don't produce an additional diagnostic
117+
// which also has no content. This prevents issues where editors expect diagnostics to have messages.
118+
if r.message.is_empty() {
119+
continue;
120+
}
121+
inverted_diagnostics.push(DiagnosticReport {
122+
diagnostic: lsp_types::Diagnostic {
123+
range: r.location.range,
124+
severity: Some(DiagnosticSeverity::HINT),
125+
code: None,
126+
message: r.message.clone(),
127+
source: d.diagnostic.source.clone(),
128+
code_description: None,
129+
related_information: related_information.clone(),
130+
tags: None,
131+
data: None,
132+
},
133+
fixed_content: PossibleFixContent::None,
134+
rule_name: None,
135+
});
138136
}
139-
diagnostics.append(&mut inverted_diagnostics);
140-
diagnostics
141-
}))
137+
}
138+
diagnostics.append(&mut inverted_diagnostics);
139+
Some(diagnostics)
142140
}
143141

144142
fn lint_path<'a>(
145143
&mut self,
146144
allocator: &'a mut Allocator,
147145
path: &Path,
148-
source_text: Option<String>,
149-
) -> Option<Vec<MessageWithPosition<'a>>> {
150-
if !Loader::can_load(path) {
151-
debug!("extension not supported yet.");
152-
return None;
153-
}
154-
155-
let source_text = source_text.or_else(|| read_to_string(path).ok())?;
156-
146+
source_text: String,
147+
) -> Vec<MessageWithPosition<'a>> {
157148
debug!("lint {}", path.display());
158149

159-
let result = self
160-
.service
150+
self.service
161151
.with_file_system(Box::new(IsolatedLintHandlerFileSystem::new(
162152
path.to_path_buf(),
163153
source_text,
164154
)))
165155
.with_paths(vec![Arc::from(path.as_os_str())])
166-
.run_source(allocator);
167-
168-
Some(result)
156+
.run_source(allocator)
169157
}
170158

171159
fn should_lint_path(path: &Path) -> bool {

editors/vscode/tests/e2e_server.spec.ts

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,9 @@ import {
1717
getDiagnostics,
1818
loadFixture,
1919
sleep,
20-
testMultiFolderMode,
2120
testSingleFolderMode,
2221
waitForDiagnosticChange,
23-
WORKSPACE_DIR,
24-
WORKSPACE_SECOND_DIR
22+
WORKSPACE_DIR
2523
} from './test-helpers';
2624
import assert = require('assert');
2725

@@ -170,21 +168,22 @@ suite('E2E Diagnostics', () => {
170168
strictEqual(nestedDiagnostics[0].severity, DiagnosticSeverity.Error);
171169
});
172170

173-
testMultiFolderMode('different diagnostic severity', async () => {
174-
await loadFixture('debugger', WORKSPACE_DIR);
175-
await loadFixture('debugger_error', WORKSPACE_SECOND_DIR);
176-
177-
const firstDiagnostics = await getDiagnostics('debugger.js', WORKSPACE_DIR);
178-
const secondDiagnostics = await getDiagnostics('debugger.js', WORKSPACE_SECOND_DIR);
179-
180-
assert(typeof firstDiagnostics[0].code == 'object');
181-
strictEqual(firstDiagnostics[0].code.target.authority, 'oxc.rs');
182-
strictEqual(firstDiagnostics[0].severity, DiagnosticSeverity.Warning);
183-
184-
assert(typeof secondDiagnostics[0].code == 'object');
185-
strictEqual(secondDiagnostics[0].code.target.authority, 'oxc.rs');
186-
strictEqual(secondDiagnostics[0].severity, DiagnosticSeverity.Error);
187-
});
171+
// somehow this test is flaky in CI
172+
// testMultiFolderMode('different diagnostic severity', async () => {
173+
// await loadFixture('debugger', WORKSPACE_DIR);
174+
// await loadFixture('debugger_error', WORKSPACE_SECOND_DIR);
175+
//
176+
// const firstDiagnostics = await getDiagnostics('debugger.js', WORKSPACE_DIR);
177+
// const secondDiagnostics = await getDiagnostics('debugger.js', WORKSPACE_SECOND_DIR);
178+
//
179+
// assert(typeof firstDiagnostics[0].code == 'object');
180+
// strictEqual(firstDiagnostics[0].code.target.authority, 'oxc.rs');
181+
// strictEqual(firstDiagnostics[0].severity, DiagnosticSeverity.Warning);
182+
//
183+
// assert(typeof secondDiagnostics[0].code == 'object');
184+
// strictEqual(secondDiagnostics[0].code.target.authority, 'oxc.rs');
185+
// strictEqual(secondDiagnostics[0].severity, DiagnosticSeverity.Error);
186+
// });
188187

189188
// somehow this test is flaky in CI
190189
test.skip('changing config from `extends` will revalidate the diagnostics', async () => {

0 commit comments

Comments
 (0)