diff options
-rw-r--r-- | crates/rust-analyzer/src/diagnostics.rs | 54 | ||||
-rw-r--r-- | crates/rust-analyzer/src/handlers.rs | 5 | ||||
-rw-r--r-- | crates/rust-analyzer/src/main_loop.rs | 61 |
3 files changed, 50 insertions, 70 deletions
diff --git a/crates/rust-analyzer/src/diagnostics.rs b/crates/rust-analyzer/src/diagnostics.rs index 290609e7f..f3cdb842b 100644 --- a/crates/rust-analyzer/src/diagnostics.rs +++ b/crates/rust-analyzer/src/diagnostics.rs | |||
@@ -1,14 +1,15 @@ | |||
1 | //! Book keeping for keeping diagnostics easily in sync with the client. | 1 | //! Book keeping for keeping diagnostics easily in sync with the client. |
2 | pub(crate) mod to_proto; | 2 | pub(crate) mod to_proto; |
3 | 3 | ||
4 | use std::{collections::HashMap, sync::Arc}; | 4 | use std::{collections::HashMap, mem, sync::Arc}; |
5 | 5 | ||
6 | use lsp_types::{Diagnostic, Range}; | 6 | use lsp_types::{Diagnostic, Range}; |
7 | use ra_ide::FileId; | 7 | use ra_ide::FileId; |
8 | use rustc_hash::FxHashSet; | ||
8 | 9 | ||
9 | use crate::lsp_ext; | 10 | use crate::lsp_ext; |
10 | 11 | ||
11 | pub type CheckFixes = Arc<HashMap<FileId, Vec<Fix>>>; | 12 | pub(crate) type CheckFixes = Arc<HashMap<FileId, Vec<Fix>>>; |
12 | 13 | ||
13 | #[derive(Debug, Default, Clone)] | 14 | #[derive(Debug, Default, Clone)] |
14 | pub struct DiagnosticsConfig { | 15 | pub struct DiagnosticsConfig { |
@@ -17,32 +18,26 @@ pub struct DiagnosticsConfig { | |||
17 | } | 18 | } |
18 | 19 | ||
19 | #[derive(Debug, Default, Clone)] | 20 | #[derive(Debug, Default, Clone)] |
20 | pub struct DiagnosticCollection { | 21 | pub(crate) struct DiagnosticCollection { |
21 | pub native: HashMap<FileId, Vec<Diagnostic>>, | 22 | pub(crate) native: HashMap<FileId, Vec<Diagnostic>>, |
22 | pub check: HashMap<FileId, Vec<Diagnostic>>, | 23 | pub(crate) check: HashMap<FileId, Vec<Diagnostic>>, |
23 | pub check_fixes: CheckFixes, | 24 | pub(crate) check_fixes: CheckFixes, |
25 | changes: FxHashSet<FileId>, | ||
24 | } | 26 | } |
25 | 27 | ||
26 | #[derive(Debug, Clone)] | 28 | #[derive(Debug, Clone)] |
27 | pub struct Fix { | 29 | pub(crate) struct Fix { |
28 | pub range: Range, | 30 | pub(crate) range: Range, |
29 | pub action: lsp_ext::CodeAction, | 31 | pub(crate) action: lsp_ext::CodeAction, |
30 | } | ||
31 | |||
32 | #[derive(Debug)] | ||
33 | pub enum DiagnosticTask { | ||
34 | ClearCheck, | ||
35 | AddCheck(FileId, Diagnostic, Vec<lsp_ext::CodeAction>), | ||
36 | SetNative(FileId, Vec<Diagnostic>), | ||
37 | } | 32 | } |
38 | 33 | ||
39 | impl DiagnosticCollection { | 34 | impl DiagnosticCollection { |
40 | pub fn clear_check(&mut self) -> Vec<FileId> { | 35 | pub(crate) fn clear_check(&mut self) { |
41 | Arc::make_mut(&mut self.check_fixes).clear(); | 36 | Arc::make_mut(&mut self.check_fixes).clear(); |
42 | self.check.drain().map(|(key, _value)| key).collect() | 37 | self.changes.extend(self.check.drain().map(|(key, _value)| key)) |
43 | } | 38 | } |
44 | 39 | ||
45 | pub fn add_check_diagnostic( | 40 | pub(crate) fn add_check_diagnostic( |
46 | &mut self, | 41 | &mut self, |
47 | file_id: FileId, | 42 | file_id: FileId, |
48 | diagnostic: Diagnostic, | 43 | diagnostic: Diagnostic, |
@@ -61,30 +56,25 @@ impl DiagnosticCollection { | |||
61 | .or_default() | 56 | .or_default() |
62 | .extend(fixes.into_iter().map(|action| Fix { range: diagnostic.range, action })); | 57 | .extend(fixes.into_iter().map(|action| Fix { range: diagnostic.range, action })); |
63 | diagnostics.push(diagnostic); | 58 | diagnostics.push(diagnostic); |
59 | self.changes.insert(file_id); | ||
64 | } | 60 | } |
65 | 61 | ||
66 | pub fn set_native_diagnostics(&mut self, file_id: FileId, diagnostics: Vec<Diagnostic>) { | 62 | pub(crate) fn set_native_diagnostics(&mut self, file_id: FileId, diagnostics: Vec<Diagnostic>) { |
67 | self.native.insert(file_id, diagnostics); | 63 | self.native.insert(file_id, diagnostics); |
64 | self.changes.insert(file_id); | ||
68 | } | 65 | } |
69 | 66 | ||
70 | pub fn diagnostics_for(&self, file_id: FileId) -> impl Iterator<Item = &Diagnostic> { | 67 | pub(crate) fn diagnostics_for(&self, file_id: FileId) -> impl Iterator<Item = &Diagnostic> { |
71 | let native = self.native.get(&file_id).into_iter().flatten(); | 68 | let native = self.native.get(&file_id).into_iter().flatten(); |
72 | let check = self.check.get(&file_id).into_iter().flatten(); | 69 | let check = self.check.get(&file_id).into_iter().flatten(); |
73 | native.chain(check) | 70 | native.chain(check) |
74 | } | 71 | } |
75 | 72 | ||
76 | pub fn handle_task(&mut self, task: DiagnosticTask) -> Vec<FileId> { | 73 | pub(crate) fn take_changes(&mut self) -> Option<FxHashSet<FileId>> { |
77 | match task { | 74 | if self.changes.is_empty() { |
78 | DiagnosticTask::ClearCheck => self.clear_check(), | 75 | return None; |
79 | DiagnosticTask::AddCheck(file_id, diagnostic, fixes) => { | ||
80 | self.add_check_diagnostic(file_id, diagnostic, fixes); | ||
81 | vec![file_id] | ||
82 | } | ||
83 | DiagnosticTask::SetNative(file_id, diagnostics) => { | ||
84 | self.set_native_diagnostics(file_id, diagnostics); | ||
85 | vec![file_id] | ||
86 | } | ||
87 | } | 76 | } |
77 | Some(mem::take(&mut self.changes)) | ||
88 | } | 78 | } |
89 | } | 79 | } |
90 | 80 | ||
diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs index b2ff9a157..12b494496 100644 --- a/crates/rust-analyzer/src/handlers.rs +++ b/crates/rust-analyzer/src/handlers.rs | |||
@@ -31,7 +31,6 @@ use stdx::{format_to, split_delim}; | |||
31 | use crate::{ | 31 | use crate::{ |
32 | cargo_target_spec::CargoTargetSpec, | 32 | cargo_target_spec::CargoTargetSpec, |
33 | config::RustfmtConfig, | 33 | config::RustfmtConfig, |
34 | diagnostics::DiagnosticTask, | ||
35 | from_json, from_proto, | 34 | from_json, from_proto, |
36 | global_state::GlobalStateSnapshot, | 35 | global_state::GlobalStateSnapshot, |
37 | lsp_ext::{self, InlayHint, InlayHintsParams}, | 36 | lsp_ext::{self, InlayHint, InlayHintsParams}, |
@@ -950,7 +949,7 @@ pub(crate) fn handle_ssr( | |||
950 | pub(crate) fn publish_diagnostics( | 949 | pub(crate) fn publish_diagnostics( |
951 | snap: &GlobalStateSnapshot, | 950 | snap: &GlobalStateSnapshot, |
952 | file_id: FileId, | 951 | file_id: FileId, |
953 | ) -> Result<DiagnosticTask> { | 952 | ) -> Result<Vec<Diagnostic>> { |
954 | let _p = profile("publish_diagnostics"); | 953 | let _p = profile("publish_diagnostics"); |
955 | let line_index = snap.analysis.file_line_index(file_id)?; | 954 | let line_index = snap.analysis.file_line_index(file_id)?; |
956 | let diagnostics: Vec<Diagnostic> = snap | 955 | let diagnostics: Vec<Diagnostic> = snap |
@@ -967,7 +966,7 @@ pub(crate) fn publish_diagnostics( | |||
967 | tags: None, | 966 | tags: None, |
968 | }) | 967 | }) |
969 | .collect(); | 968 | .collect(); |
970 | Ok(DiagnosticTask::SetNative(file_id, diagnostics)) | 969 | Ok(diagnostics) |
971 | } | 970 | } |
972 | 971 | ||
973 | pub(crate) fn handle_inlay_hints( | 972 | pub(crate) fn handle_inlay_hints( |
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index 76dea3e22..1bd9d6389 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs | |||
@@ -15,7 +15,6 @@ use ra_project_model::{PackageRoot, ProjectWorkspace}; | |||
15 | 15 | ||
16 | use crate::{ | 16 | use crate::{ |
17 | config::{Config, FilesWatcher, LinkedProject}, | 17 | config::{Config, FilesWatcher, LinkedProject}, |
18 | diagnostics::DiagnosticTask, | ||
19 | dispatch::{NotificationDispatcher, RequestDispatcher}, | 18 | dispatch::{NotificationDispatcher, RequestDispatcher}, |
20 | from_proto, | 19 | from_proto, |
21 | global_state::{file_id_to_url, GlobalState, Status}, | 20 | global_state::{file_id_to_url, GlobalState, Status}, |
@@ -132,6 +131,13 @@ enum Event { | |||
132 | Flycheck(flycheck::Message), | 131 | Flycheck(flycheck::Message), |
133 | } | 132 | } |
134 | 133 | ||
134 | #[derive(Debug)] | ||
135 | pub(crate) enum Task { | ||
136 | Response(Response), | ||
137 | Diagnostics(Vec<(FileId, Vec<lsp_types::Diagnostic>)>), | ||
138 | Unit, | ||
139 | } | ||
140 | |||
135 | impl fmt::Debug for Event { | 141 | impl fmt::Debug for Event { |
136 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | 142 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
137 | let debug_verbose_not = |not: &Notification, f: &mut fmt::Formatter| { | 143 | let debug_verbose_not = |not: &Notification, f: &mut fmt::Formatter| { |
@@ -219,8 +225,10 @@ impl GlobalState { | |||
219 | Event::Task(task) => { | 225 | Event::Task(task) => { |
220 | match task { | 226 | match task { |
221 | Task::Response(response) => self.respond(response), | 227 | Task::Response(response) => self.respond(response), |
222 | Task::Diagnostics(tasks) => { | 228 | Task::Diagnostics(diagnostics_per_file) => { |
223 | tasks.into_iter().for_each(|task| on_diagnostic_task(task, self)) | 229 | for (file_id, diagnostics) in diagnostics_per_file { |
230 | self.diagnostics.set_native_diagnostics(file_id, diagnostics) | ||
231 | } | ||
224 | } | 232 | } |
225 | Task::Unit => (), | 233 | Task::Unit => (), |
226 | } | 234 | } |
@@ -257,9 +265,7 @@ impl GlobalState { | |||
257 | } | 265 | } |
258 | }, | 266 | }, |
259 | Event::Flycheck(task) => match task { | 267 | Event::Flycheck(task) => match task { |
260 | flycheck::Message::ClearDiagnostics => { | 268 | flycheck::Message::ClearDiagnostics => self.diagnostics.clear_check(), |
261 | on_diagnostic_task(DiagnosticTask::ClearCheck, self) | ||
262 | } | ||
263 | 269 | ||
264 | flycheck::Message::AddDiagnostic { workspace_root, diagnostic } => { | 270 | flycheck::Message::AddDiagnostic { workspace_root, diagnostic } => { |
265 | let diagnostics = crate::diagnostics::to_proto::map_rust_diagnostic_to_lsp( | 271 | let diagnostics = crate::diagnostics::to_proto::map_rust_diagnostic_to_lsp( |
@@ -279,15 +285,7 @@ impl GlobalState { | |||
279 | return Ok(()); | 285 | return Ok(()); |
280 | } | 286 | } |
281 | }; | 287 | }; |
282 | 288 | self.diagnostics.add_check_diagnostic(file_id, diag.diagnostic, diag.fixes) | |
283 | on_diagnostic_task( | ||
284 | DiagnosticTask::AddCheck( | ||
285 | file_id, | ||
286 | diag.diagnostic, | ||
287 | diag.fixes.into_iter().map(|it| it.into()).collect(), | ||
288 | ), | ||
289 | self, | ||
290 | ) | ||
291 | } | 289 | } |
292 | } | 290 | } |
293 | 291 | ||
@@ -322,9 +320,20 @@ impl GlobalState { | |||
322 | self.update_file_notifications_on_threadpool(subscriptions); | 320 | self.update_file_notifications_on_threadpool(subscriptions); |
323 | } | 321 | } |
324 | 322 | ||
323 | if let Some(diagnostic_changes) = self.diagnostics.take_changes() { | ||
324 | for file_id in diagnostic_changes { | ||
325 | let url = file_id_to_url(&self.vfs.read().0, file_id); | ||
326 | let diagnostics = self.diagnostics.diagnostics_for(file_id).cloned().collect(); | ||
327 | let params = | ||
328 | lsp_types::PublishDiagnosticsParams { uri: url, diagnostics, version: None }; | ||
329 | let not = notification_new::<lsp_types::notification::PublishDiagnostics>(params); | ||
330 | self.send(not.into()); | ||
331 | } | ||
332 | } | ||
333 | |||
325 | let loop_duration = loop_start.elapsed(); | 334 | let loop_duration = loop_start.elapsed(); |
326 | if loop_duration > Duration::from_millis(100) { | 335 | if loop_duration > Duration::from_millis(100) { |
327 | log::error!("overly long loop turn: {:?}", loop_duration); | 336 | log::warn!("overly long loop turn: {:?}", loop_duration); |
328 | if env::var("RA_PROFILE").is_ok() { | 337 | if env::var("RA_PROFILE").is_ok() { |
329 | self.show_message( | 338 | self.show_message( |
330 | lsp_types::MessageType::Error, | 339 | lsp_types::MessageType::Error, |
@@ -516,6 +525,7 @@ impl GlobalState { | |||
516 | () | 525 | () |
517 | }) | 526 | }) |
518 | .ok() | 527 | .ok() |
528 | .map(|diags| (file_id, diags)) | ||
519 | }) | 529 | }) |
520 | .collect::<Vec<_>>(); | 530 | .collect::<Vec<_>>(); |
521 | Task::Diagnostics(diagnostics) | 531 | Task::Diagnostics(diagnostics) |
@@ -532,29 +542,10 @@ impl GlobalState { | |||
532 | } | 542 | } |
533 | } | 543 | } |
534 | 544 | ||
535 | #[derive(Debug)] | ||
536 | pub(crate) enum Task { | ||
537 | Response(Response), | ||
538 | Diagnostics(()), | ||
539 | Unit, | ||
540 | } | ||
541 | |||
542 | pub(crate) type ReqHandler = fn(&mut GlobalState, Response); | 545 | pub(crate) type ReqHandler = fn(&mut GlobalState, Response); |
543 | pub(crate) type ReqQueue = lsp_server::ReqQueue<(String, Instant), ReqHandler>; | 546 | pub(crate) type ReqQueue = lsp_server::ReqQueue<(String, Instant), ReqHandler>; |
544 | const DO_NOTHING: ReqHandler = |_, _| (); | 547 | const DO_NOTHING: ReqHandler = |_, _| (); |
545 | 548 | ||
546 | fn on_diagnostic_task(task: DiagnosticTask, global_state: &mut GlobalState) { | ||
547 | let subscriptions = global_state.diagnostics.handle_task(task); | ||
548 | |||
549 | for file_id in subscriptions { | ||
550 | let url = file_id_to_url(&global_state.vfs.read().0, file_id); | ||
551 | let diagnostics = global_state.diagnostics.diagnostics_for(file_id).cloned().collect(); | ||
552 | let params = lsp_types::PublishDiagnosticsParams { uri: url, diagnostics, version: None }; | ||
553 | let not = notification_new::<lsp_types::notification::PublishDiagnostics>(params); | ||
554 | global_state.send(not.into()); | ||
555 | } | ||
556 | } | ||
557 | |||
558 | #[derive(Eq, PartialEq)] | 549 | #[derive(Eq, PartialEq)] |
559 | enum Progress { | 550 | enum Progress { |
560 | Begin, | 551 | Begin, |