rust_analyzer/
main_loop.rs

1//! The main loop of `rust-analyzer` responsible for dispatching LSP
2//! requests/replies and notifications back to the client.
3
4use std::{
5    fmt,
6    ops::Div as _,
7    panic::AssertUnwindSafe,
8    time::{Duration, Instant},
9};
10
11use crossbeam_channel::{Receiver, never, select};
12use ide_db::base_db::{SourceDatabase, VfsPath, salsa::Database as _};
13use lsp_server::{Connection, Notification, Request};
14use lsp_types::{TextDocumentIdentifier, notification::Notification as _};
15use stdx::thread::ThreadIntent;
16use tracing::{Level, error, span};
17use vfs::{AbsPathBuf, FileId, loader::LoadingProgress};
18
19use crate::{
20    config::Config,
21    diagnostics::{DiagnosticsGeneration, NativeDiagnosticsFetchKind, fetch_native_diagnostics},
22    discover::{DiscoverArgument, DiscoverCommand, DiscoverProjectMessage},
23    flycheck::{self, ClearDiagnosticsKind, FlycheckMessage},
24    global_state::{
25        FetchBuildDataResponse, FetchWorkspaceRequest, FetchWorkspaceResponse, GlobalState,
26        file_id_to_url, url_to_file_id,
27    },
28    handlers::{
29        dispatch::{NotificationDispatcher, RequestDispatcher},
30        request::empty_diagnostic_report,
31    },
32    lsp::{
33        from_proto, to_proto,
34        utils::{Progress, notification_is},
35    },
36    lsp_ext,
37    reload::{BuildDataProgress, ProcMacroProgress, ProjectWorkspaceProgress},
38    test_runner::{CargoTestMessage, CargoTestOutput, TestState},
39};
40
41pub fn main_loop(config: Config, connection: Connection) -> anyhow::Result<()> {
42    tracing::info!("initial config: {:#?}", config);
43
44    // Windows scheduler implements priority boosts: if thread waits for an
45    // event (like a condvar), and event fires, priority of the thread is
46    // temporary bumped. This optimization backfires in our case: each time the
47    // `main_loop` schedules a task to run on a threadpool, the worker threads
48    // gets a higher priority, and (on a machine with fewer cores) displaces the
49    // main loop! We work around this by marking the main loop as a
50    // higher-priority thread.
51    //
52    // https://docs.microsoft.com/en-us/windows/win32/procthread/scheduling-priorities
53    // https://docs.microsoft.com/en-us/windows/win32/procthread/priority-boosts
54    // https://github.com/rust-lang/rust-analyzer/issues/2835
55    #[cfg(windows)]
56    unsafe {
57        use windows_sys::Win32::System::Threading::*;
58        let thread = GetCurrentThread();
59        let thread_priority_above_normal = 1;
60        SetThreadPriority(thread, thread_priority_above_normal);
61    }
62
63    GlobalState::new(connection.sender, config).run(connection.receiver)
64}
65
66enum Event {
67    Lsp(lsp_server::Message),
68    Task(Task),
69    QueuedTask(QueuedTask),
70    Vfs(vfs::loader::Message),
71    Flycheck(FlycheckMessage),
72    TestResult(CargoTestMessage),
73    DiscoverProject(DiscoverProjectMessage),
74    FetchWorkspaces(FetchWorkspaceRequest),
75}
76
77impl fmt::Display for Event {
78    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
79        match self {
80            Event::Lsp(_) => write!(f, "Event::Lsp"),
81            Event::Task(_) => write!(f, "Event::Task"),
82            Event::Vfs(_) => write!(f, "Event::Vfs"),
83            Event::Flycheck(_) => write!(f, "Event::Flycheck"),
84            Event::QueuedTask(_) => write!(f, "Event::QueuedTask"),
85            Event::TestResult(_) => write!(f, "Event::TestResult"),
86            Event::DiscoverProject(_) => write!(f, "Event::DiscoverProject"),
87            Event::FetchWorkspaces(_) => write!(f, "Event::SwitchWorkspaces"),
88        }
89    }
90}
91
92#[derive(Debug)]
93pub(crate) enum QueuedTask {
94    CheckIfIndexed(lsp_types::Url),
95    CheckProcMacroSources(Vec<FileId>),
96}
97
98#[derive(Debug)]
99pub(crate) enum DiagnosticsTaskKind {
100    Syntax(DiagnosticsGeneration, Vec<(FileId, Vec<lsp_types::Diagnostic>)>),
101    Semantic(DiagnosticsGeneration, Vec<(FileId, Vec<lsp_types::Diagnostic>)>),
102}
103
104#[derive(Debug)]
105pub(crate) enum Task {
106    Response(lsp_server::Response),
107    DiscoverLinkedProjects(DiscoverProjectParam),
108    Retry(lsp_server::Request),
109    Diagnostics(DiagnosticsTaskKind),
110    DiscoverTest(lsp_ext::DiscoverTestResults),
111    PrimeCaches(PrimeCachesProgress),
112    FetchWorkspace(ProjectWorkspaceProgress),
113    FetchBuildData(BuildDataProgress),
114    LoadProcMacros(ProcMacroProgress),
115    // FIXME: Remove this in favor of a more general QueuedTask, see `handle_did_save_text_document`
116    BuildDepsHaveChanged,
117}
118
119#[derive(Debug)]
120pub(crate) enum DiscoverProjectParam {
121    Buildfile(AbsPathBuf),
122    Path(AbsPathBuf),
123}
124
125#[derive(Debug)]
126pub(crate) enum PrimeCachesProgress {
127    Begin,
128    Report(ide::ParallelPrimeCachesProgress),
129    End { cancelled: bool },
130}
131
132impl fmt::Debug for Event {
133    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
134        let debug_non_verbose = |not: &Notification, f: &mut fmt::Formatter<'_>| {
135            f.debug_struct("Notification").field("method", &not.method).finish()
136        };
137
138        match self {
139            Event::Lsp(lsp_server::Message::Notification(not)) => {
140                if notification_is::<lsp_types::notification::DidOpenTextDocument>(not)
141                    || notification_is::<lsp_types::notification::DidChangeTextDocument>(not)
142                {
143                    return debug_non_verbose(not, f);
144                }
145            }
146            Event::Task(Task::Response(resp)) => {
147                return f
148                    .debug_struct("Response")
149                    .field("id", &resp.id)
150                    .field("error", &resp.error)
151                    .finish();
152            }
153            _ => (),
154        }
155
156        match self {
157            Event::Lsp(it) => fmt::Debug::fmt(it, f),
158            Event::Task(it) => fmt::Debug::fmt(it, f),
159            Event::QueuedTask(it) => fmt::Debug::fmt(it, f),
160            Event::Vfs(it) => fmt::Debug::fmt(it, f),
161            Event::Flycheck(it) => fmt::Debug::fmt(it, f),
162            Event::TestResult(it) => fmt::Debug::fmt(it, f),
163            Event::DiscoverProject(it) => fmt::Debug::fmt(it, f),
164            Event::FetchWorkspaces(it) => fmt::Debug::fmt(it, f),
165        }
166    }
167}
168
169impl GlobalState {
170    fn run(mut self, inbox: Receiver<lsp_server::Message>) -> anyhow::Result<()> {
171        self.update_status_or_notify();
172
173        if self.config.did_save_text_document_dynamic_registration() {
174            let additional_patterns = self
175                .config
176                .discover_workspace_config()
177                .map(|cfg| cfg.files_to_watch.clone().into_iter())
178                .into_iter()
179                .flatten()
180                .map(|f| format!("**/{f}"));
181            self.register_did_save_capability(additional_patterns);
182        }
183
184        if self.config.discover_workspace_config().is_none() {
185            self.fetch_workspaces_queue.request_op(
186                "startup".to_owned(),
187                FetchWorkspaceRequest { path: None, force_crate_graph_reload: false },
188            );
189            if let Some((cause, FetchWorkspaceRequest { path, force_crate_graph_reload })) =
190                self.fetch_workspaces_queue.should_start_op()
191            {
192                self.fetch_workspaces(cause, path, force_crate_graph_reload);
193            }
194        }
195
196        while let Ok(event) = self.next_event(&inbox) {
197            let Some(event) = event else {
198                anyhow::bail!("client exited without proper shutdown sequence");
199            };
200            if matches!(
201                &event,
202                Event::Lsp(lsp_server::Message::Notification(Notification { method, .. }))
203                if method == lsp_types::notification::Exit::METHOD
204            ) {
205                return Ok(());
206            }
207            self.handle_event(event);
208        }
209
210        Err(anyhow::anyhow!("A receiver has been dropped, something panicked!"))
211    }
212
213    fn register_did_save_capability(&mut self, additional_patterns: impl Iterator<Item = String>) {
214        let additional_filters = additional_patterns.map(|pattern| lsp_types::DocumentFilter {
215            language: None,
216            scheme: None,
217            pattern: (Some(pattern)),
218        });
219
220        let mut selectors = vec![
221            lsp_types::DocumentFilter {
222                language: None,
223                scheme: None,
224                pattern: Some("**/*.rs".into()),
225            },
226            lsp_types::DocumentFilter {
227                language: None,
228                scheme: None,
229                pattern: Some("**/Cargo.toml".into()),
230            },
231            lsp_types::DocumentFilter {
232                language: None,
233                scheme: None,
234                pattern: Some("**/Cargo.lock".into()),
235            },
236        ];
237        selectors.extend(additional_filters);
238
239        let save_registration_options = lsp_types::TextDocumentSaveRegistrationOptions {
240            include_text: Some(false),
241            text_document_registration_options: lsp_types::TextDocumentRegistrationOptions {
242                document_selector: Some(selectors),
243            },
244        };
245
246        let registration = lsp_types::Registration {
247            id: "textDocument/didSave".to_owned(),
248            method: "textDocument/didSave".to_owned(),
249            register_options: Some(serde_json::to_value(save_registration_options).unwrap()),
250        };
251        self.send_request::<lsp_types::request::RegisterCapability>(
252            lsp_types::RegistrationParams { registrations: vec![registration] },
253            |_, _| (),
254        );
255    }
256
257    fn next_event(
258        &mut self,
259        inbox: &Receiver<lsp_server::Message>,
260    ) -> Result<Option<Event>, crossbeam_channel::RecvError> {
261        // Make sure we reply to formatting requests ASAP so the editor doesn't block
262        if let Ok(task) = self.fmt_pool.receiver.try_recv() {
263            return Ok(Some(Event::Task(task)));
264        }
265
266        select! {
267            recv(inbox) -> msg =>
268                return Ok(msg.ok().map(Event::Lsp)),
269
270            recv(self.task_pool.receiver) -> task =>
271                task.map(Event::Task),
272
273            recv(self.deferred_task_queue.receiver) -> task =>
274                task.map(Event::QueuedTask),
275
276            recv(self.fmt_pool.receiver) -> task =>
277                task.map(Event::Task),
278
279            recv(self.loader.receiver) -> task =>
280                task.map(Event::Vfs),
281
282            recv(self.flycheck_receiver) -> task =>
283                task.map(Event::Flycheck),
284
285            recv(self.test_run_receiver) -> task =>
286                task.map(Event::TestResult),
287
288            recv(self.discover_receiver) -> task =>
289                task.map(Event::DiscoverProject),
290
291            recv(self.fetch_ws_receiver.as_ref().map_or(&never(), |(chan, _)| chan)) -> _instant => {
292                Ok(Event::FetchWorkspaces(self.fetch_ws_receiver.take().unwrap().1))
293            },
294        }
295        .map(Some)
296    }
297
298    fn handle_event(&mut self, event: Event) {
299        let loop_start = Instant::now();
300        let _p = tracing::info_span!("GlobalState::handle_event", event = %event).entered();
301
302        let event_dbg_msg = format!("{event:?}");
303        tracing::debug!(?loop_start, ?event, "handle_event");
304        if tracing::enabled!(tracing::Level::INFO) {
305            let task_queue_len = self.task_pool.handle.len();
306            if task_queue_len > 0 {
307                tracing::info!("task queue len: {}", task_queue_len);
308            }
309        }
310
311        let was_quiescent = self.is_quiescent();
312        match event {
313            Event::Lsp(msg) => match msg {
314                lsp_server::Message::Request(req) => self.on_new_request(loop_start, req),
315                lsp_server::Message::Notification(not) => self.on_notification(not),
316                lsp_server::Message::Response(resp) => self.complete_request(resp),
317            },
318            Event::QueuedTask(task) => {
319                let _p = tracing::info_span!("GlobalState::handle_event/queued_task").entered();
320                self.handle_queued_task(task);
321                // Coalesce multiple task events into one loop turn
322                while let Ok(task) = self.deferred_task_queue.receiver.try_recv() {
323                    self.handle_queued_task(task);
324                }
325            }
326            Event::Task(task) => {
327                let _p = tracing::info_span!("GlobalState::handle_event/task").entered();
328                let mut prime_caches_progress = Vec::new();
329
330                self.handle_task(&mut prime_caches_progress, task);
331                // Coalesce multiple task events into one loop turn
332                while let Ok(task) = self.task_pool.receiver.try_recv() {
333                    self.handle_task(&mut prime_caches_progress, task);
334                }
335
336                for progress in prime_caches_progress {
337                    let (state, message, fraction, title);
338                    match progress {
339                        PrimeCachesProgress::Begin => {
340                            state = Progress::Begin;
341                            message = None;
342                            fraction = 0.0;
343                            title = "Indexing";
344                        }
345                        PrimeCachesProgress::Report(report) => {
346                            state = Progress::Report;
347                            title = report.work_type;
348
349                            message = match &*report.crates_currently_indexing {
350                                [crate_name] => Some(format!(
351                                    "{}/{} ({})",
352                                    report.crates_done,
353                                    report.crates_total,
354                                    crate_name.as_str(),
355                                )),
356                                [crate_name, rest @ ..] => Some(format!(
357                                    "{}/{} ({} + {} more)",
358                                    report.crates_done,
359                                    report.crates_total,
360                                    crate_name.as_str(),
361                                    rest.len()
362                                )),
363                                _ => None,
364                            };
365
366                            fraction = Progress::fraction(report.crates_done, report.crates_total);
367                        }
368                        PrimeCachesProgress::End { cancelled } => {
369                            state = Progress::End;
370                            message = None;
371                            fraction = 1.0;
372                            title = "Indexing";
373
374                            self.analysis_host.raw_database_mut().trigger_lru_eviction();
375                            self.prime_caches_queue.op_completed(());
376                            if cancelled {
377                                self.prime_caches_queue
378                                    .request_op("restart after cancellation".to_owned(), ());
379                            }
380                        }
381                    };
382
383                    self.report_progress(
384                        title,
385                        state,
386                        message,
387                        Some(fraction),
388                        Some("rustAnalyzer/cachePriming".to_owned()),
389                    );
390                }
391            }
392            Event::Vfs(message) => {
393                let _p = tracing::info_span!("GlobalState::handle_event/vfs").entered();
394                self.handle_vfs_msg(message);
395                // Coalesce many VFS event into a single loop turn
396                while let Ok(message) = self.loader.receiver.try_recv() {
397                    self.handle_vfs_msg(message);
398                }
399            }
400            Event::Flycheck(message) => {
401                let _p = tracing::info_span!("GlobalState::handle_event/flycheck").entered();
402                self.handle_flycheck_msg(message);
403                // Coalesce many flycheck updates into a single loop turn
404                while let Ok(message) = self.flycheck_receiver.try_recv() {
405                    self.handle_flycheck_msg(message);
406                }
407            }
408            Event::TestResult(message) => {
409                let _p = tracing::info_span!("GlobalState::handle_event/test_result").entered();
410                self.handle_cargo_test_msg(message);
411                // Coalesce many test result event into a single loop turn
412                while let Ok(message) = self.test_run_receiver.try_recv() {
413                    self.handle_cargo_test_msg(message);
414                }
415            }
416            Event::DiscoverProject(message) => {
417                self.handle_discover_msg(message);
418                // Coalesce many project discovery events into a single loop turn.
419                while let Ok(message) = self.discover_receiver.try_recv() {
420                    self.handle_discover_msg(message);
421                }
422            }
423            Event::FetchWorkspaces(req) => {
424                self.fetch_workspaces_queue.request_op("project structure change".to_owned(), req)
425            }
426        }
427        let event_handling_duration = loop_start.elapsed();
428        let (state_changed, memdocs_added_or_removed) = if self.vfs_done {
429            if let Some(cause) = self.wants_to_switch.take() {
430                self.switch_workspaces(cause);
431            }
432            (self.process_changes(), self.mem_docs.take_changes())
433        } else {
434            (false, false)
435        };
436
437        if self.is_quiescent() {
438            let became_quiescent = !was_quiescent;
439            if became_quiescent {
440                if self.config.check_on_save(None)
441                    && self.config.flycheck_workspace(None)
442                    && !self.fetch_build_data_queue.op_requested()
443                {
444                    // Project has loaded properly, kick off initial flycheck
445                    self.flycheck.iter().for_each(|flycheck| flycheck.restart_workspace(None));
446                }
447                if self.config.prefill_caches() {
448                    self.prime_caches_queue.request_op("became quiescent".to_owned(), ());
449                }
450            }
451
452            let client_refresh = became_quiescent || state_changed;
453            if client_refresh {
454                // Refresh semantic tokens if the client supports it.
455                if self.config.semantic_tokens_refresh() {
456                    self.semantic_tokens_cache.lock().clear();
457                    self.send_request::<lsp_types::request::SemanticTokensRefresh>((), |_, _| ());
458                }
459
460                // Refresh code lens if the client supports it.
461                if self.config.code_lens_refresh() {
462                    self.send_request::<lsp_types::request::CodeLensRefresh>((), |_, _| ());
463                }
464
465                // Refresh inlay hints if the client supports it.
466                if self.config.inlay_hints_refresh() {
467                    self.send_request::<lsp_types::request::InlayHintRefreshRequest>((), |_, _| ());
468                }
469
470                if self.config.diagnostics_refresh() {
471                    self.send_request::<lsp_types::request::WorkspaceDiagnosticRefresh>(
472                        (),
473                        |_, _| (),
474                    );
475                }
476            }
477
478            let project_or_mem_docs_changed =
479                became_quiescent || state_changed || memdocs_added_or_removed;
480            if project_or_mem_docs_changed
481                && !self.config.text_document_diagnostic()
482                && self.config.publish_diagnostics(None)
483            {
484                self.update_diagnostics();
485            }
486            if project_or_mem_docs_changed && self.config.test_explorer() {
487                self.update_tests();
488            }
489        }
490
491        if let Some(diagnostic_changes) = self.diagnostics.take_changes() {
492            for file_id in diagnostic_changes {
493                let uri = file_id_to_url(&self.vfs.read().0, file_id);
494                let version = from_proto::vfs_path(&uri)
495                    .ok()
496                    .and_then(|path| self.mem_docs.get(&path).map(|it| it.version));
497
498                let diagnostics =
499                    self.diagnostics.diagnostics_for(file_id).cloned().collect::<Vec<_>>();
500                self.publish_diagnostics(uri, version, diagnostics);
501            }
502        }
503
504        if (self.config.cargo_autoreload_config(None)
505            || self.config.discover_workspace_config().is_some())
506            && let Some((cause, FetchWorkspaceRequest { path, force_crate_graph_reload })) =
507                self.fetch_workspaces_queue.should_start_op()
508        {
509            self.fetch_workspaces(cause, path, force_crate_graph_reload);
510        }
511
512        if !self.fetch_workspaces_queue.op_in_progress() {
513            if let Some((cause, ())) = self.fetch_build_data_queue.should_start_op() {
514                self.fetch_build_data(cause);
515            } else if let Some((cause, (change, paths))) =
516                self.fetch_proc_macros_queue.should_start_op()
517            {
518                self.fetch_proc_macros(cause, change, paths);
519            }
520        }
521
522        if let Some((cause, ())) = self.prime_caches_queue.should_start_op() {
523            self.prime_caches(cause);
524        }
525
526        self.update_status_or_notify();
527
528        let loop_duration = loop_start.elapsed();
529        if loop_duration > Duration::from_millis(100) && was_quiescent {
530            tracing::warn!(
531                "overly long loop turn took {loop_duration:?} (event handling took {event_handling_duration:?}): {event_dbg_msg}"
532            );
533            self.poke_rust_analyzer_developer(format!(
534                "overly long loop turn took {loop_duration:?} (event handling took {event_handling_duration:?}): {event_dbg_msg}"
535            ));
536        }
537    }
538
539    fn prime_caches(&mut self, cause: String) {
540        tracing::debug!(%cause, "will prime caches");
541        let num_worker_threads = self.config.prime_caches_num_threads();
542
543        self.task_pool.handle.spawn_with_sender(ThreadIntent::Worker, {
544            let analysis = AssertUnwindSafe(self.snapshot().analysis);
545            move |sender| {
546                sender.send(Task::PrimeCaches(PrimeCachesProgress::Begin)).unwrap();
547                let res = analysis.parallel_prime_caches(num_worker_threads, |progress| {
548                    let report = PrimeCachesProgress::Report(progress);
549                    sender.send(Task::PrimeCaches(report)).unwrap();
550                });
551                sender
552                    .send(Task::PrimeCaches(PrimeCachesProgress::End { cancelled: res.is_err() }))
553                    .unwrap();
554            }
555        });
556    }
557
558    fn update_diagnostics(&mut self) {
559        let db = self.analysis_host.raw_database();
560        let generation = self.diagnostics.next_generation();
561        let subscriptions = {
562            let vfs = &self.vfs.read().0;
563            self.mem_docs
564                .iter()
565                .map(|path| vfs.file_id(path).unwrap())
566                .filter_map(|(file_id, excluded)| {
567                    (excluded == vfs::FileExcluded::No).then_some(file_id)
568                })
569                .filter(|&file_id| {
570                    let source_root_id = db.file_source_root(file_id).source_root_id(db);
571                    let source_root = db.source_root(source_root_id).source_root(db);
572                    // Only publish diagnostics for files in the workspace, not from crates.io deps
573                    // or the sysroot.
574                    // While theoretically these should never have errors, we have quite a few false
575                    // positives particularly in the stdlib, and those diagnostics would stay around
576                    // forever if we emitted them here.
577                    !source_root.is_library
578                })
579                .collect::<std::sync::Arc<_>>()
580        };
581        tracing::trace!("updating notifications for {:?}", subscriptions);
582        // Split up the work on multiple threads, but we don't wanna fill the entire task pool with
583        // diagnostic tasks, so we limit the number of tasks to a quarter of the total thread pool.
584        let max_tasks = self.config.main_loop_num_threads().div(4).max(1);
585        let chunk_length = subscriptions.len() / max_tasks;
586        let remainder = subscriptions.len() % max_tasks;
587
588        let mut start = 0;
589        for task_idx in 0..max_tasks {
590            let extra = if task_idx < remainder { 1 } else { 0 };
591            let end = start + chunk_length + extra;
592            let slice = start..end;
593            if slice.is_empty() {
594                break;
595            }
596            // Diagnostics are triggered by the user typing
597            // so we run them on a latency sensitive thread.
598            let snapshot = self.snapshot();
599            self.task_pool.handle.spawn_with_sender(ThreadIntent::LatencySensitive, {
600                let subscriptions = subscriptions.clone();
601                // Do not fetch semantic diagnostics (and populate query results) if we haven't even
602                // loaded the initial workspace yet.
603                let fetch_semantic =
604                    self.vfs_done && self.fetch_workspaces_queue.last_op_result().is_some();
605                move |sender| {
606                    // We aren't observing the semantics token cache here
607                    let snapshot = AssertUnwindSafe(&snapshot);
608                    let Ok(diags) = std::panic::catch_unwind(|| {
609                        fetch_native_diagnostics(
610                            &snapshot,
611                            subscriptions.clone(),
612                            slice.clone(),
613                            NativeDiagnosticsFetchKind::Syntax,
614                        )
615                    }) else {
616                        return;
617                    };
618                    sender
619                        .send(Task::Diagnostics(DiagnosticsTaskKind::Syntax(generation, diags)))
620                        .unwrap();
621
622                    if fetch_semantic {
623                        let Ok(diags) = std::panic::catch_unwind(|| {
624                            fetch_native_diagnostics(
625                                &snapshot,
626                                subscriptions.clone(),
627                                slice.clone(),
628                                NativeDiagnosticsFetchKind::Semantic,
629                            )
630                        }) else {
631                            return;
632                        };
633                        sender
634                            .send(Task::Diagnostics(DiagnosticsTaskKind::Semantic(
635                                generation, diags,
636                            )))
637                            .unwrap();
638                    }
639                }
640            });
641            start = end;
642        }
643    }
644
645    fn update_tests(&mut self) {
646        if !self.vfs_done {
647            return;
648        }
649        let db = self.analysis_host.raw_database();
650        let subscriptions = self
651            .mem_docs
652            .iter()
653            .map(|path| self.vfs.read().0.file_id(path).unwrap())
654            .filter_map(|(file_id, excluded)| {
655                (excluded == vfs::FileExcluded::No).then_some(file_id)
656            })
657            .filter(|&file_id| {
658                let source_root_id = db.file_source_root(file_id).source_root_id(db);
659                let source_root = db.source_root(source_root_id).source_root(db);
660                !source_root.is_library
661            })
662            .collect::<Vec<_>>();
663        tracing::trace!("updating tests for {:?}", subscriptions);
664
665        // Updating tests are triggered by the user typing
666        // so we run them on a latency sensitive thread.
667        self.task_pool.handle.spawn(ThreadIntent::LatencySensitive, {
668            let snapshot = self.snapshot();
669            move || {
670                let tests = subscriptions
671                    .iter()
672                    .copied()
673                    .filter_map(|f| snapshot.analysis.discover_tests_in_file(f).ok())
674                    .flatten()
675                    .collect::<Vec<_>>();
676
677                Task::DiscoverTest(lsp_ext::DiscoverTestResults {
678                    tests: tests
679                        .into_iter()
680                        .filter_map(|t| {
681                            let line_index = t.file.and_then(|f| snapshot.file_line_index(f).ok());
682                            to_proto::test_item(&snapshot, t, line_index.as_ref())
683                        })
684                        .collect(),
685                    scope: None,
686                    scope_file: Some(
687                        subscriptions
688                            .into_iter()
689                            .map(|f| TextDocumentIdentifier { uri: to_proto::url(&snapshot, f) })
690                            .collect(),
691                    ),
692                })
693            }
694        });
695    }
696
697    fn update_status_or_notify(&mut self) {
698        let status = self.current_status();
699        if self.last_reported_status != status {
700            self.last_reported_status = status.clone();
701
702            if self.config.server_status_notification() {
703                self.send_notification::<lsp_ext::ServerStatusNotification>(status);
704            } else if let (
705                health @ (lsp_ext::Health::Warning | lsp_ext::Health::Error),
706                Some(message),
707            ) = (status.health, &status.message)
708            {
709                let open_log_button = tracing::enabled!(tracing::Level::ERROR)
710                    && (self.fetch_build_data_error().is_err()
711                        || self.fetch_workspace_error().is_err());
712                self.show_message(
713                    match health {
714                        lsp_ext::Health::Ok => lsp_types::MessageType::INFO,
715                        lsp_ext::Health::Warning => lsp_types::MessageType::WARNING,
716                        lsp_ext::Health::Error => lsp_types::MessageType::ERROR,
717                    },
718                    message.clone(),
719                    open_log_button,
720                );
721            }
722        }
723    }
724
725    fn handle_task(&mut self, prime_caches_progress: &mut Vec<PrimeCachesProgress>, task: Task) {
726        match task {
727            Task::Response(response) => self.respond(response),
728            // Only retry requests that haven't been cancelled. Otherwise we do unnecessary work.
729            Task::Retry(req) if !self.is_completed(&req) => self.on_request(req),
730            Task::Retry(_) => (),
731            Task::Diagnostics(kind) => {
732                self.diagnostics.set_native_diagnostics(kind);
733            }
734            Task::PrimeCaches(progress) => match progress {
735                PrimeCachesProgress::Begin => prime_caches_progress.push(progress),
736                PrimeCachesProgress::Report(_) => {
737                    match prime_caches_progress.last_mut() {
738                        Some(last @ PrimeCachesProgress::Report(_)) => {
739                            // Coalesce subsequent update events.
740                            *last = progress;
741                        }
742                        _ => prime_caches_progress.push(progress),
743                    }
744                }
745                PrimeCachesProgress::End { .. } => prime_caches_progress.push(progress),
746            },
747            Task::FetchWorkspace(progress) => {
748                let (state, msg) = match progress {
749                    ProjectWorkspaceProgress::Begin => (Progress::Begin, None),
750                    ProjectWorkspaceProgress::Report(msg) => (Progress::Report, Some(msg)),
751                    ProjectWorkspaceProgress::End(workspaces, force_crate_graph_reload) => {
752                        let resp = FetchWorkspaceResponse { workspaces, force_crate_graph_reload };
753                        self.fetch_workspaces_queue.op_completed(resp);
754                        if let Err(e) = self.fetch_workspace_error() {
755                            error!("FetchWorkspaceError: {e}");
756                        }
757                        self.wants_to_switch = Some("fetched workspace".to_owned());
758                        self.diagnostics.clear_check_all();
759                        (Progress::End, None)
760                    }
761                };
762
763                self.report_progress("Fetching", state, msg, None, None);
764            }
765            Task::DiscoverLinkedProjects(arg) => {
766                if let Some(cfg) = self.config.discover_workspace_config()
767                    && !self.discover_workspace_queue.op_in_progress()
768                {
769                    // the clone is unfortunately necessary to avoid a borrowck error when
770                    // `self.report_progress` is called later
771                    let title = &cfg.progress_label.clone();
772                    let command = cfg.command.clone();
773                    let discover = DiscoverCommand::new(self.discover_sender.clone(), command);
774
775                    self.report_progress(title, Progress::Begin, None, None, None);
776                    self.discover_workspace_queue
777                        .request_op("Discovering workspace".to_owned(), ());
778                    let _ = self.discover_workspace_queue.should_start_op();
779
780                    let arg = match arg {
781                        DiscoverProjectParam::Buildfile(it) => DiscoverArgument::Buildfile(it),
782                        DiscoverProjectParam::Path(it) => DiscoverArgument::Path(it),
783                    };
784
785                    let handle = discover.spawn(
786                        arg,
787                        &std::env::current_dir()
788                            .expect("Failed to get cwd during project discovery"),
789                    );
790                    self.discover_handle = Some(handle.unwrap_or_else(|e| {
791                        panic!("Failed to spawn project discovery command: {e}")
792                    }));
793                }
794            }
795            Task::FetchBuildData(progress) => {
796                let (state, msg) = match progress {
797                    BuildDataProgress::Begin => (Some(Progress::Begin), None),
798                    BuildDataProgress::Report(msg) => (Some(Progress::Report), Some(msg)),
799                    BuildDataProgress::End((workspaces, build_scripts)) => {
800                        let resp = FetchBuildDataResponse { workspaces, build_scripts };
801                        self.fetch_build_data_queue.op_completed(resp);
802
803                        if let Err(e) = self.fetch_build_data_error() {
804                            error!("FetchBuildDataError: {e}");
805                        }
806
807                        if self.wants_to_switch.is_none() {
808                            self.wants_to_switch = Some("fetched build data".to_owned());
809                        }
810                        (Some(Progress::End), None)
811                    }
812                };
813
814                if let Some(state) = state {
815                    self.report_progress("Building compile-time-deps", state, msg, None, None);
816                }
817            }
818            Task::LoadProcMacros(progress) => {
819                let (state, msg) = match progress {
820                    ProcMacroProgress::Begin => (Some(Progress::Begin), None),
821                    ProcMacroProgress::Report(msg) => (Some(Progress::Report), Some(msg)),
822                    ProcMacroProgress::End(change) => {
823                        self.fetch_proc_macros_queue.op_completed(true);
824                        self.analysis_host.apply_change(change);
825                        self.finish_loading_crate_graph();
826                        (Some(Progress::End), None)
827                    }
828                };
829
830                if let Some(state) = state {
831                    self.report_progress("Loading proc-macros", state, msg, None, None);
832                }
833            }
834            Task::BuildDepsHaveChanged => self.build_deps_changed = true,
835            Task::DiscoverTest(tests) => {
836                self.send_notification::<lsp_ext::DiscoveredTests>(tests);
837            }
838        }
839    }
840
841    fn handle_vfs_msg(&mut self, message: vfs::loader::Message) {
842        let _p = tracing::info_span!("GlobalState::handle_vfs_msg").entered();
843        let is_changed = matches!(message, vfs::loader::Message::Changed { .. });
844        match message {
845            vfs::loader::Message::Changed { files } | vfs::loader::Message::Loaded { files } => {
846                let _p = tracing::info_span!("GlobalState::handle_vfs_msg{changed/load}").entered();
847                self.debounce_workspace_fetch();
848                let vfs = &mut self.vfs.write().0;
849                for (path, contents) in files {
850                    let path = VfsPath::from(path);
851                    // if the file is in mem docs, it's managed by the client via notifications
852                    // so only set it if its not in there
853                    if !self.mem_docs.contains(&path)
854                        && (is_changed || vfs.file_id(&path).is_none())
855                    {
856                        vfs.set_file_contents(path, contents);
857                    }
858                }
859            }
860            vfs::loader::Message::Progress { n_total, n_done, dir, config_version } => {
861                let _p = span!(Level::INFO, "GlobalState::handle_vfs_msg/progress").entered();
862                stdx::always!(config_version <= self.vfs_config_version);
863
864                let (n_done, state) = match n_done {
865                    LoadingProgress::Started => {
866                        self.vfs_span =
867                            Some(span!(Level::INFO, "vfs_load", total = n_total).entered());
868                        (0, Progress::Begin)
869                    }
870                    LoadingProgress::Progress(n_done) => (n_done.min(n_total), Progress::Report),
871                    LoadingProgress::Finished => {
872                        self.vfs_span = None;
873                        (n_total, Progress::End)
874                    }
875                };
876
877                self.vfs_progress_config_version = config_version;
878                self.vfs_done = state == Progress::End;
879
880                let mut message = format!("{n_done}/{n_total}");
881                if let Some(dir) = dir {
882                    message += &format!(
883                        ": {}",
884                        match dir.strip_prefix(self.config.root_path()) {
885                            Some(relative_path) => relative_path.as_utf8_path(),
886                            None => dir.as_ref(),
887                        }
888                    );
889                }
890
891                self.report_progress(
892                    "Roots Scanned",
893                    state,
894                    Some(message),
895                    Some(Progress::fraction(n_done, n_total)),
896                    None,
897                );
898            }
899        }
900    }
901
902    fn handle_queued_task(&mut self, task: QueuedTask) {
903        match task {
904            QueuedTask::CheckIfIndexed(uri) => {
905                let snap = self.snapshot();
906
907                self.task_pool.handle.spawn_with_sender(ThreadIntent::Worker, move |sender| {
908                    let _p = tracing::info_span!("GlobalState::check_if_indexed").entered();
909                    tracing::debug!(?uri, "handling uri");
910                    let Some(id) = from_proto::file_id(&snap, &uri).expect("unable to get FileId")
911                    else {
912                        return;
913                    };
914                    if let Ok(crates) = &snap.analysis.crates_for(id) {
915                        if crates.is_empty() {
916                            if snap.config.discover_workspace_config().is_some() {
917                                let path =
918                                    from_proto::abs_path(&uri).expect("Unable to get AbsPath");
919                                let arg = DiscoverProjectParam::Path(path);
920                                sender.send(Task::DiscoverLinkedProjects(arg)).unwrap();
921                            }
922                        } else {
923                            tracing::debug!(?uri, "is indexed");
924                        }
925                    }
926                });
927            }
928            QueuedTask::CheckProcMacroSources(modified_rust_files) => {
929                let analysis = AssertUnwindSafe(self.snapshot().analysis);
930                self.task_pool.handle.spawn_with_sender(stdx::thread::ThreadIntent::Worker, {
931                    move |sender| {
932                        if modified_rust_files.into_iter().any(|file_id| {
933                            // FIXME: Check whether these files could be build script related
934                            match analysis.crates_for(file_id) {
935                                Ok(crates) => crates.iter().any(|&krate| {
936                                    analysis.is_proc_macro_crate(krate).is_ok_and(|it| it)
937                                }),
938                                _ => false,
939                            }
940                        }) {
941                            sender.send(Task::BuildDepsHaveChanged).unwrap();
942                        }
943                    }
944                });
945            }
946        }
947    }
948
949    fn handle_discover_msg(&mut self, message: DiscoverProjectMessage) {
950        let title = self
951            .config
952            .discover_workspace_config()
953            .map(|cfg| cfg.progress_label.clone())
954            .expect("No title could be found; this is a bug");
955        match message {
956            DiscoverProjectMessage::Finished { project, buildfile } => {
957                self.discover_handle = None;
958                self.report_progress(&title, Progress::End, None, None, None);
959                self.discover_workspace_queue.op_completed(());
960
961                let mut config = Config::clone(&*self.config);
962                config.add_discovered_project_from_command(project, buildfile);
963                self.update_configuration(config);
964            }
965            DiscoverProjectMessage::Progress { message } => {
966                self.report_progress(&title, Progress::Report, Some(message), None, None)
967            }
968            DiscoverProjectMessage::Error { error, source } => {
969                self.discover_handle = None;
970                let message = format!("Project discovery failed: {error}");
971                self.discover_workspace_queue.op_completed(());
972                self.show_and_log_error(message.clone(), source);
973                self.report_progress(&title, Progress::End, Some(message), None, None)
974            }
975        }
976    }
977
978    fn handle_cargo_test_msg(&mut self, message: CargoTestMessage) {
979        match message.output {
980            CargoTestOutput::Test { name, state } => {
981                let state = match state {
982                    TestState::Started => lsp_ext::TestState::Started,
983                    TestState::Ignored => lsp_ext::TestState::Skipped,
984                    TestState::Ok => lsp_ext::TestState::Passed,
985                    TestState::Failed { stdout } => lsp_ext::TestState::Failed { message: stdout },
986                };
987
988                // The notification requires the namespace form (with underscores) of the target
989                let test_id = format!("{}::{name}", message.target.target.replace('-', "_"));
990
991                self.send_notification::<lsp_ext::ChangeTestState>(
992                    lsp_ext::ChangeTestStateParams { test_id, state },
993                );
994            }
995            CargoTestOutput::Suite => (),
996            CargoTestOutput::Finished => {
997                self.test_run_remaining_jobs = self.test_run_remaining_jobs.saturating_sub(1);
998                if self.test_run_remaining_jobs == 0 {
999                    self.send_notification::<lsp_ext::EndRunTest>(());
1000                    self.test_run_session = None;
1001                }
1002            }
1003            CargoTestOutput::Custom { text } => {
1004                self.send_notification::<lsp_ext::AppendOutputToRunTest>(text);
1005            }
1006        }
1007    }
1008
1009    fn handle_flycheck_msg(&mut self, message: FlycheckMessage) {
1010        match message {
1011            FlycheckMessage::AddDiagnostic {
1012                id,
1013                generation,
1014                workspace_root,
1015                diagnostic,
1016                package_id,
1017            } => {
1018                let snap = self.snapshot();
1019                let diagnostics = crate::diagnostics::to_proto::map_rust_diagnostic_to_lsp(
1020                    &self.config.diagnostics_map(None),
1021                    &diagnostic,
1022                    &workspace_root,
1023                    &snap,
1024                );
1025                for diag in diagnostics {
1026                    match url_to_file_id(&self.vfs.read().0, &diag.url) {
1027                        Ok(Some(file_id)) => self.diagnostics.add_check_diagnostic(
1028                            id,
1029                            generation,
1030                            &package_id,
1031                            file_id,
1032                            diag.diagnostic,
1033                            diag.fix,
1034                        ),
1035                        Ok(None) => {}
1036                        Err(err) => {
1037                            error!(
1038                                "flycheck {id}: File with cargo diagnostic not found in VFS: {}",
1039                                err
1040                            );
1041                        }
1042                    };
1043                }
1044            }
1045            FlycheckMessage::ClearDiagnostics { id, kind: ClearDiagnosticsKind::All } => {
1046                self.diagnostics.clear_check(id)
1047            }
1048            FlycheckMessage::ClearDiagnostics {
1049                id,
1050                kind: ClearDiagnosticsKind::OlderThan(generation),
1051            } => self.diagnostics.clear_check_older_than(id, generation),
1052            FlycheckMessage::ClearDiagnostics {
1053                id,
1054                kind: ClearDiagnosticsKind::Package(package_id),
1055            } => self.diagnostics.clear_check_for_package(id, package_id),
1056            FlycheckMessage::Progress { id, progress } => {
1057                let (state, message) = match progress {
1058                    flycheck::Progress::DidStart => (Progress::Begin, None),
1059                    flycheck::Progress::DidCheckCrate(target) => (Progress::Report, Some(target)),
1060                    flycheck::Progress::DidCancel => {
1061                        self.last_flycheck_error = None;
1062                        (Progress::End, None)
1063                    }
1064                    flycheck::Progress::DidFailToRestart(err) => {
1065                        self.last_flycheck_error =
1066                            Some(format!("cargo check failed to start: {err}"));
1067                        return;
1068                    }
1069                    flycheck::Progress::DidFinish(result) => {
1070                        self.last_flycheck_error =
1071                            result.err().map(|err| format!("cargo check failed to start: {err}"));
1072                        (Progress::End, None)
1073                    }
1074                };
1075
1076                // When we're running multiple flychecks, we have to include a disambiguator in
1077                // the title, or the editor complains. Note that this is a user-facing string.
1078                let title = if self.flycheck.len() == 1 {
1079                    format!("{}", self.config.flycheck(None))
1080                } else {
1081                    format!("{} (#{})", self.config.flycheck(None), id + 1)
1082                };
1083                self.report_progress(
1084                    &title,
1085                    state,
1086                    message,
1087                    None,
1088                    Some(format!("rust-analyzer/flycheck/{id}")),
1089                );
1090            }
1091        }
1092    }
1093
1094    /// Registers and handles a request. This should only be called once per incoming request.
1095    fn on_new_request(&mut self, request_received: Instant, req: Request) {
1096        let _p =
1097            span!(Level::INFO, "GlobalState::on_new_request", req.method = ?req.method).entered();
1098        self.register_request(&req, request_received);
1099        self.on_request(req);
1100    }
1101
1102    /// Handles a request.
1103    fn on_request(&mut self, req: Request) {
1104        let mut dispatcher = RequestDispatcher { req: Some(req), global_state: self };
1105        dispatcher.on_sync_mut::<lsp_types::request::Shutdown>(|s, ()| {
1106            s.shutdown_requested = true;
1107            Ok(())
1108        });
1109
1110        match &mut dispatcher {
1111            RequestDispatcher { req: Some(req), global_state: this } if this.shutdown_requested => {
1112                this.respond(lsp_server::Response::new_err(
1113                    req.id.clone(),
1114                    lsp_server::ErrorCode::InvalidRequest as i32,
1115                    "Shutdown already requested.".to_owned(),
1116                ));
1117                return;
1118            }
1119            _ => (),
1120        }
1121
1122        use crate::handlers::request as handlers;
1123        use lsp_types::request as lsp_request;
1124
1125        const RETRY: bool = true;
1126        const NO_RETRY: bool = false;
1127
1128        #[rustfmt::skip]
1129        dispatcher
1130            // Request handlers that must run on the main thread
1131            // because they mutate GlobalState:
1132            .on_sync_mut::<lsp_ext::ReloadWorkspace>(handlers::handle_workspace_reload)
1133            .on_sync_mut::<lsp_ext::RebuildProcMacros>(handlers::handle_proc_macros_rebuild)
1134            .on_sync_mut::<lsp_ext::MemoryUsage>(handlers::handle_memory_usage)
1135            .on_sync_mut::<lsp_ext::RunTest>(handlers::handle_run_test)
1136            // Request handlers which are related to the user typing
1137            // are run on the main thread to reduce latency:
1138            .on_sync::<lsp_ext::JoinLines>(handlers::handle_join_lines)
1139            .on_sync::<lsp_ext::OnEnter>(handlers::handle_on_enter)
1140            .on_sync::<lsp_request::SelectionRangeRequest>(handlers::handle_selection_range)
1141            .on_sync::<lsp_ext::MatchingBrace>(handlers::handle_matching_brace)
1142            .on_sync::<lsp_ext::OnTypeFormatting>(handlers::handle_on_type_formatting)
1143            // Formatting should be done immediately as the editor might wait on it, but we can't
1144            // put it on the main thread as we do not want the main thread to block on rustfmt.
1145            // So we have an extra thread just for formatting requests to make sure it gets handled
1146            // as fast as possible.
1147            .on_fmt_thread::<lsp_request::Formatting>(handlers::handle_formatting)
1148            .on_fmt_thread::<lsp_request::RangeFormatting>(handlers::handle_range_formatting)
1149            // We can’t run latency-sensitive request handlers which do semantic
1150            // analysis on the main thread because that would block other
1151            // requests. Instead, we run these request handlers on higher priority
1152            // threads in the threadpool.
1153            // FIXME: Retrying can make the result of this stale?
1154            .on_latency_sensitive::<RETRY, lsp_request::Completion>(handlers::handle_completion)
1155            // FIXME: Retrying can make the result of this stale
1156            .on_latency_sensitive::<RETRY, lsp_request::ResolveCompletionItem>(handlers::handle_completion_resolve)
1157            .on_latency_sensitive::<RETRY, lsp_request::SemanticTokensFullRequest>(handlers::handle_semantic_tokens_full)
1158            .on_latency_sensitive::<RETRY, lsp_request::SemanticTokensFullDeltaRequest>(handlers::handle_semantic_tokens_full_delta)
1159            .on_latency_sensitive::<NO_RETRY, lsp_request::SemanticTokensRangeRequest>(handlers::handle_semantic_tokens_range)
1160            // FIXME: Some of these NO_RETRY could be retries if the file they are interested didn't change.
1161            // All other request handlers
1162            .on_with_vfs_default::<lsp_request::DocumentDiagnosticRequest>(handlers::handle_document_diagnostics, empty_diagnostic_report, || lsp_server::ResponseError {
1163                code: lsp_server::ErrorCode::ServerCancelled as i32,
1164                message: "server cancelled the request".to_owned(),
1165                data: serde_json::to_value(lsp_types::DiagnosticServerCancellationData {
1166                    retrigger_request: true
1167                }).ok(),
1168            })
1169            .on::<RETRY, lsp_request::DocumentSymbolRequest>(handlers::handle_document_symbol)
1170            .on::<RETRY, lsp_request::FoldingRangeRequest>(handlers::handle_folding_range)
1171            .on::<NO_RETRY, lsp_request::SignatureHelpRequest>(handlers::handle_signature_help)
1172            .on::<RETRY, lsp_request::WillRenameFiles>(handlers::handle_will_rename_files)
1173            .on::<NO_RETRY, lsp_request::GotoDefinition>(handlers::handle_goto_definition)
1174            .on::<NO_RETRY, lsp_request::GotoDeclaration>(handlers::handle_goto_declaration)
1175            .on::<NO_RETRY, lsp_request::GotoImplementation>(handlers::handle_goto_implementation)
1176            .on::<NO_RETRY, lsp_request::GotoTypeDefinition>(handlers::handle_goto_type_definition)
1177            .on::<NO_RETRY, lsp_request::InlayHintRequest>(handlers::handle_inlay_hints)
1178            .on_identity::<NO_RETRY, lsp_request::InlayHintResolveRequest, _>(handlers::handle_inlay_hints_resolve)
1179            .on::<NO_RETRY, lsp_request::CodeLensRequest>(handlers::handle_code_lens)
1180            .on_identity::<NO_RETRY, lsp_request::CodeLensResolve, _>(handlers::handle_code_lens_resolve)
1181            .on::<NO_RETRY, lsp_request::PrepareRenameRequest>(handlers::handle_prepare_rename)
1182            .on::<NO_RETRY, lsp_request::Rename>(handlers::handle_rename)
1183            .on::<NO_RETRY, lsp_request::References>(handlers::handle_references)
1184            .on::<NO_RETRY, lsp_request::DocumentHighlightRequest>(handlers::handle_document_highlight)
1185            .on::<NO_RETRY, lsp_request::CallHierarchyPrepare>(handlers::handle_call_hierarchy_prepare)
1186            .on::<NO_RETRY, lsp_request::CallHierarchyIncomingCalls>(handlers::handle_call_hierarchy_incoming)
1187            .on::<NO_RETRY, lsp_request::CallHierarchyOutgoingCalls>(handlers::handle_call_hierarchy_outgoing)
1188            // All other request handlers (lsp extension)
1189            .on::<RETRY, lsp_ext::FetchDependencyList>(handlers::fetch_dependency_list)
1190            .on::<RETRY, lsp_ext::AnalyzerStatus>(handlers::handle_analyzer_status)
1191            .on::<RETRY, lsp_ext::ViewFileText>(handlers::handle_view_file_text)
1192            .on::<RETRY, lsp_ext::ViewCrateGraph>(handlers::handle_view_crate_graph)
1193            .on::<RETRY, lsp_ext::ViewItemTree>(handlers::handle_view_item_tree)
1194            .on::<RETRY, lsp_ext::DiscoverTest>(handlers::handle_discover_test)
1195            .on::<RETRY, lsp_ext::WorkspaceSymbol>(handlers::handle_workspace_symbol)
1196            .on::<NO_RETRY, lsp_ext::Ssr>(handlers::handle_ssr)
1197            .on::<NO_RETRY, lsp_ext::ViewRecursiveMemoryLayout>(handlers::handle_view_recursive_memory_layout)
1198            .on::<NO_RETRY, lsp_ext::ViewSyntaxTree>(handlers::handle_view_syntax_tree)
1199            .on::<NO_RETRY, lsp_ext::ViewHir>(handlers::handle_view_hir)
1200            .on::<NO_RETRY, lsp_ext::ViewMir>(handlers::handle_view_mir)
1201            .on::<NO_RETRY, lsp_ext::InterpretFunction>(handlers::handle_interpret_function)
1202            .on::<NO_RETRY, lsp_ext::ExpandMacro>(handlers::handle_expand_macro)
1203            .on::<NO_RETRY, lsp_ext::ParentModule>(handlers::handle_parent_module)
1204            .on::<NO_RETRY, lsp_ext::ChildModules>(handlers::handle_child_modules)
1205            .on::<NO_RETRY, lsp_ext::Runnables>(handlers::handle_runnables)
1206            .on::<NO_RETRY, lsp_ext::RelatedTests>(handlers::handle_related_tests)
1207            .on::<NO_RETRY, lsp_ext::CodeActionRequest>(handlers::handle_code_action)
1208            .on_identity::<RETRY, lsp_ext::CodeActionResolveRequest, _>(handlers::handle_code_action_resolve)
1209            .on::<NO_RETRY, lsp_ext::HoverRequest>(handlers::handle_hover)
1210            .on::<NO_RETRY, lsp_ext::ExternalDocs>(handlers::handle_open_docs)
1211            .on::<NO_RETRY, lsp_ext::OpenCargoToml>(handlers::handle_open_cargo_toml)
1212            .on::<NO_RETRY, lsp_ext::MoveItem>(handlers::handle_move_item)
1213            //
1214            .on::<NO_RETRY, lsp_ext::InternalTestingFetchConfig>(handlers::internal_testing_fetch_config)
1215            .finish();
1216    }
1217
1218    /// Handles an incoming notification.
1219    fn on_notification(&mut self, not: Notification) {
1220        let _p =
1221            span!(Level::INFO, "GlobalState::on_notification", not.method = ?not.method).entered();
1222        use crate::handlers::notification as handlers;
1223        use lsp_types::notification as notifs;
1224
1225        NotificationDispatcher { not: Some(not), global_state: self }
1226            .on_sync_mut::<notifs::Cancel>(handlers::handle_cancel)
1227            .on_sync_mut::<notifs::WorkDoneProgressCancel>(
1228                handlers::handle_work_done_progress_cancel,
1229            )
1230            .on_sync_mut::<notifs::DidOpenTextDocument>(handlers::handle_did_open_text_document)
1231            .on_sync_mut::<notifs::DidChangeTextDocument>(handlers::handle_did_change_text_document)
1232            .on_sync_mut::<notifs::DidCloseTextDocument>(handlers::handle_did_close_text_document)
1233            .on_sync_mut::<notifs::DidSaveTextDocument>(handlers::handle_did_save_text_document)
1234            .on_sync_mut::<notifs::DidChangeConfiguration>(
1235                handlers::handle_did_change_configuration,
1236            )
1237            .on_sync_mut::<notifs::DidChangeWorkspaceFolders>(
1238                handlers::handle_did_change_workspace_folders,
1239            )
1240            .on_sync_mut::<notifs::DidChangeWatchedFiles>(handlers::handle_did_change_watched_files)
1241            .on_sync_mut::<lsp_ext::CancelFlycheck>(handlers::handle_cancel_flycheck)
1242            .on_sync_mut::<lsp_ext::ClearFlycheck>(handlers::handle_clear_flycheck)
1243            .on_sync_mut::<lsp_ext::RunFlycheck>(handlers::handle_run_flycheck)
1244            .on_sync_mut::<lsp_ext::AbortRunTest>(handlers::handle_abort_run_test)
1245            .finish();
1246    }
1247}