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