Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use oxc_diagnostics::Severity;

use crate::LSP_MAX_INT;

#[derive(Debug, Clone)]
#[derive(Debug, Clone, Default)]
pub struct DiagnosticReport {
pub diagnostic: lsp_types::Diagnostic,
pub fixed_content: PossibleFixContent,
Expand All @@ -23,8 +23,9 @@ pub struct FixedContent {
pub range: Range,
}

#[derive(Debug, Clone)]
#[derive(Debug, Clone, Default)]
pub enum PossibleFixContent {
#[default]
None,
Single(FixedContent),
Multiple(Vec<FixedContent>),
Expand Down
58 changes: 52 additions & 6 deletions crates/oxc_language_server/src/linter/server_linter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,17 @@ impl ServerLinterDiagnostics {
pub fn get_diagnostics(&self, path: &str) -> Option<Vec<DiagnosticReport>> {
let mut reports = Vec::new();
let mut found = false;
if let Some(Some(diagnostics)) = self.isolated_linter.pin().get(path) {
reports.extend(diagnostics.clone());
if let Some(entry) = self.isolated_linter.pin().get(path) {
found = true;
if let Some(diagnostics) = entry {
reports.extend(diagnostics.clone());
}
}
if let Some(Some(diagnostics)) = self.tsgo_linter.pin().get(path) {
reports.extend(diagnostics.clone());
if let Some(entry) = self.tsgo_linter.pin().get(path) {
found = true;
if let Some(diagnostics) = entry {
reports.extend(diagnostics.clone());
}
}
if found { Some(reports) } else { None }
}
Expand All @@ -69,9 +73,10 @@ impl ServerLinterDiagnostics {
}

pub fn get_cached_files_of_diagnostics(&self) -> Vec<String> {
let mut files = Vec::new();
let isolated_files = self.isolated_linter.pin().keys().cloned().collect::<Vec<_>>();
let tsgo_files = self.tsgo_linter.pin().keys().cloned().collect::<Vec<_>>();

let mut files = Vec::with_capacity(isolated_files.len() + tsgo_files.len());
files.extend(isolated_files);
files.extend(tsgo_files);
files.dedup();
Expand Down Expand Up @@ -407,9 +412,11 @@ mod test {
use std::path::{Path, PathBuf};

use crate::{
ConcurrentHashMap,
linter::{
error_with_position::DiagnosticReport,
options::{LintOptions, Run, UnusedDisableDirectives},
server_linter::{ServerLinter, normalize_path},
server_linter::{ServerLinter, ServerLinterDiagnostics, normalize_path},
},
tester::{Tester, get_file_path},
};
Expand Down Expand Up @@ -457,6 +464,45 @@ mod test {
assert!(configs_dirs[0].ends_with("init_nested_configs"));
}

#[test]
fn test_get_diagnostics_found_and_none_entries() {
let key = "file:///test.js".to_string();

// Case 1: Both entries present, Some diagnostics
let diag = DiagnosticReport::default();
let diag_map = ConcurrentHashMap::default();
diag_map.pin().insert(key.clone(), Some(vec![diag.clone()]));
let tsgo_map = ConcurrentHashMap::default();
tsgo_map.pin().insert(key.clone(), Some(vec![diag]));

let server_diag = super::ServerLinterDiagnostics {
isolated_linter: std::sync::Arc::new(diag_map),
tsgo_linter: std::sync::Arc::new(tsgo_map),
};
let result = server_diag.get_diagnostics(&key);
assert!(result.is_some());
assert_eq!(result.unwrap().len(), 2);

// Case 2: Entry present, but value is None
let diag_map_none = ConcurrentHashMap::default();
diag_map_none.pin().insert(key.clone(), None);
let tsgo_map_none = ConcurrentHashMap::default();
tsgo_map_none.pin().insert(key.clone(), None);

let server_diag_none = ServerLinterDiagnostics {
isolated_linter: std::sync::Arc::new(diag_map_none),
tsgo_linter: std::sync::Arc::new(tsgo_map_none),
};
let result_none = server_diag_none.get_diagnostics(&key);
assert!(result_none.is_some());
assert_eq!(result_none.unwrap().len(), 0);

// Case 3: No entry at all
let server_diag_empty = ServerLinterDiagnostics::default();
let result_empty = server_diag_empty.get_diagnostics(&key);
assert!(result_empty.is_none());
}

#[test]
#[cfg(not(target_endian = "big"))]
fn test_lint_on_run_on_type_on_type() {
Expand Down
7 changes: 4 additions & 3 deletions editors/vscode/tests/code_actions.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ import {
activateExtension,
fixturesWorkspaceUri,
loadFixture,
sleep
sleep,
testSingleFolderMode
} from './test-helpers';
import assert = require('assert');

Expand All @@ -35,11 +36,11 @@ teardown(async () => {
});

suite('code actions', () => {
test('listed code actions', async () => {
// flaky test for multi workspace mode
testSingleFolderMode('listed code actions', async () => {
await loadFixture('debugger');
const fileUri = Uri.joinPath(fixturesWorkspaceUri(), 'fixtures', 'debugger.js');
// await window.showTextDocument(fileUri); -- should also work without opening the file
await sleep(500); // ¯\_(ツ)_/¯ -- test it again when adding/removing tests

const codeActions: ProviderResult<Array<CodeAction>> = await commands.executeCommand(
'vscode.executeCodeActionProvider',
Expand Down
Loading