Skip to content
Merged
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
83 changes: 12 additions & 71 deletions crates/oxc_language_server/src/linter/server_linter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,37 +29,10 @@ pub struct ServerLinter {
isolated_linter: Arc<Mutex<IsolatedLintHandler>>,
ignore_matcher: LintIgnoreMatcher,
gitignore_glob: Vec<Gitignore>,
diagnostics: ServerLinterDiagnostics,
diagnostics: Arc<ConcurrentHashMap<String, Option<Vec<DiagnosticReport>>>>,
extended_paths: FxHashSet<PathBuf>,
}

#[derive(Debug, Default)]
struct ServerLinterDiagnostics {
isolated_linter: Arc<ConcurrentHashMap<String, Option<Vec<DiagnosticReport>>>>,
}

impl ServerLinterDiagnostics {
pub fn get_diagnostics(&self, path: &str) -> Option<Vec<DiagnosticReport>> {
let mut reports = Vec::new();
let mut found = false;
if let Some(entry) = self.isolated_linter.pin().get(path) {
found = true;
if let Some(diagnostics) = entry {
reports.extend(diagnostics.clone());
}
}
if found { Some(reports) } else { None }
}

pub fn remove_diagnostics(&self, path: &str) {
self.isolated_linter.pin().remove(path);
}

pub fn get_cached_files_of_diagnostics(&self) -> Vec<String> {
self.isolated_linter.pin().keys().cloned().collect::<Vec<_>>()
}
}

impl ServerLinter {
/// # Panics
/// Panics if the root URI cannot be converted to a file path.
Expand Down Expand Up @@ -153,7 +126,7 @@ impl ServerLinter {
),
gitignore_glob: Self::create_ignore_glob(&root_path),
extended_paths,
diagnostics: ServerLinterDiagnostics::default(),
diagnostics: Arc::new(ConcurrentHashMap::default()),
}
}

Expand Down Expand Up @@ -242,19 +215,20 @@ impl ServerLinter {
}

pub fn remove_diagnostics(&self, uri: &Uri) {
self.diagnostics.remove_diagnostics(&uri.to_string());
self.diagnostics.pin().remove(&uri.to_string());
}

pub fn get_cached_diagnostics(&self, uri: &Uri) -> Option<Vec<DiagnosticReport>> {
self.diagnostics.get_diagnostics(&uri.to_string())
if let Some(diagnostics) = self.diagnostics.pin().get(&uri.to_string()) {
// when the uri is ignored, diagnostics is None.
// We want to return Some(vec![]), so the Worker knows there are no diagnostics for this file.
return Some(diagnostics.clone().unwrap_or_default());
}
None
}

pub fn get_cached_files_of_diagnostics(&self) -> Vec<Uri> {
self.diagnostics
.get_cached_files_of_diagnostics()
.into_iter()
.filter_map(|s| Uri::from_str(&s).ok())
.collect()
self.diagnostics.pin().keys().filter_map(|s| Uri::from_str(s).ok()).collect()
}

pub async fn revalidate_diagnostics(&self, uris: Vec<Uri>) -> Vec<(String, Vec<Diagnostic>)> {
Expand Down Expand Up @@ -306,7 +280,7 @@ impl ServerLinter {
isolated_linter.run_single(uri, content.clone())
};

self.diagnostics.isolated_linter.pin().insert(uri.to_string(), diagnostics.clone());
self.diagnostics.pin().insert(uri.to_string(), diagnostics.clone());

diagnostics
}
Expand Down Expand Up @@ -360,11 +334,9 @@ mod test {
use std::path::{Path, PathBuf};

use crate::{
ConcurrentHashMap,
linter::{
error_with_position::DiagnosticReport,
options::{LintFixKindFlag, LintOptions, Run, UnusedDisableDirectives},
server_linter::{ServerLinter, ServerLinterDiagnostics},
server_linter::ServerLinter,
},
tester::{Tester, get_file_path},
};
Expand Down Expand Up @@ -400,37 +372,6 @@ 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: Entry present, Some diagnostics
let diag = DiagnosticReport::default();
let diag_map = ConcurrentHashMap::default();
diag_map.pin().insert(key.clone(), Some(vec![diag]));

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

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

let server_diag_none =
ServerLinterDiagnostics { isolated_linter: std::sync::Arc::new(diag_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]
fn test_no_errors() {
Tester::new("fixtures/linter/no_errors", None)
Expand Down
Loading