22//! requests/replies and notifications back to the client.
33use std:: {
44 fmt,
5+ ops:: Deref ,
56 sync:: Arc ,
67 time:: { Duration , Instant } ,
78} ;
89
910use always_assert:: always;
1011use crossbeam_channel:: { select, Receiver } ;
11- use ide_db:: base_db:: { SourceDatabaseExt , VfsPath } ;
12+ use ide_db:: base_db:: { SourceDatabase , SourceDatabaseExt , VfsPath } ;
13+ use itertools:: Itertools ;
1214use lsp_server:: { Connection , Notification , Request } ;
1315use lsp_types:: notification:: Notification as _;
1416use vfs:: { ChangeKind , FileId } ;
@@ -371,7 +373,7 @@ impl GlobalState {
371373 let _p = profile:: span ( "GlobalState::handle_event/flycheck" ) ;
372374 loop {
373375 match task {
374- flycheck:: Message :: AddDiagnostic { workspace_root, diagnostic } => {
376+ flycheck:: Message :: AddDiagnostic { id , workspace_root, diagnostic } => {
375377 let snap = self . snapshot ( ) ;
376378 let diagnostics =
377379 crate :: diagnostics:: to_proto:: map_rust_diagnostic_to_lsp (
@@ -383,6 +385,7 @@ impl GlobalState {
383385 for diag in diagnostics {
384386 match url_to_file_id ( & self . vfs . read ( ) . 0 , & diag. url ) {
385387 Ok ( file_id) => self . diagnostics . add_check_diagnostic (
388+ id,
386389 file_id,
387390 diag. diagnostic ,
388391 diag. fix ,
@@ -400,7 +403,7 @@ impl GlobalState {
400403 flycheck:: Message :: Progress { id, progress } => {
401404 let ( state, message) = match progress {
402405 flycheck:: Progress :: DidStart => {
403- self . diagnostics . clear_check ( ) ;
406+ self . diagnostics . clear_check ( id ) ;
404407 ( Progress :: Begin , None )
405408 }
406409 flycheck:: Progress :: DidCheckCrate ( target) => {
@@ -444,7 +447,10 @@ impl GlobalState {
444447 let memdocs_added_or_removed = self . mem_docs . take_changes ( ) ;
445448
446449 if self . is_quiescent ( ) {
447- if !was_quiescent {
450+ if !was_quiescent
451+ && !self . fetch_workspaces_queue . op_requested ( )
452+ && !self . fetch_build_data_queue . op_requested ( )
453+ {
448454 for flycheck in & self . flycheck {
449455 flycheck. update ( ) ;
450456 }
@@ -734,13 +740,76 @@ impl GlobalState {
734740 Ok ( ( ) )
735741 } ) ?
736742 . on :: < lsp_types:: notification:: DidSaveTextDocument > ( |this, params| {
737- for flycheck in & this. flycheck {
738- flycheck. update ( ) ;
743+ let mut updated = false ;
744+ if let Ok ( vfs_path) = from_proto:: vfs_path ( & params. text_document . uri ) {
745+ let ( vfs, _) = & * this. vfs . read ( ) ;
746+ if let Some ( file_id) = vfs. file_id ( & vfs_path) {
747+ let analysis = this. analysis_host . analysis ( ) ;
748+ // Crates containing or depending on the saved file
749+ let crate_ids: Vec < _ > = analysis
750+ . crate_for ( file_id) ?
751+ . into_iter ( )
752+ . flat_map ( |id| {
753+ this. analysis_host
754+ . raw_database ( )
755+ . crate_graph ( )
756+ . transitive_rev_deps ( id)
757+ } )
758+ . sorted ( )
759+ . unique ( )
760+ . collect ( ) ;
761+
762+ let crate_root_paths: Vec < _ > = crate_ids
763+ . iter ( )
764+ . filter_map ( |& crate_id| {
765+ analysis
766+ . crate_root ( crate_id)
767+ . map ( |file_id| {
768+ vfs. file_path ( file_id) . as_path ( ) . map ( ToOwned :: to_owned)
769+ } )
770+ . transpose ( )
771+ } )
772+ . collect :: < ide:: Cancellable < _ > > ( ) ?;
773+ let crate_root_paths: Vec < _ > =
774+ crate_root_paths. iter ( ) . map ( Deref :: deref) . collect ( ) ;
775+
776+ // Find all workspaces that have at least one target containing the saved file
777+ let workspace_ids =
778+ this. workspaces . iter ( ) . enumerate ( ) . filter ( |( _, ws) | match ws {
779+ project_model:: ProjectWorkspace :: Cargo { cargo, .. } => {
780+ cargo. packages ( ) . any ( |pkg| {
781+ cargo[ pkg] . targets . iter ( ) . any ( |& it| {
782+ crate_root_paths. contains ( & cargo[ it] . root . as_path ( ) )
783+ } )
784+ } )
785+ }
786+ project_model:: ProjectWorkspace :: Json { project, .. } => project
787+ . crates ( )
788+ . any ( |( c, _) | crate_ids. iter ( ) . any ( |& crate_id| crate_id == c) ) ,
789+ project_model:: ProjectWorkspace :: DetachedFiles { .. } => false ,
790+ } ) ;
791+
792+ // Find and trigger corresponding flychecks
793+ for flycheck in & this. flycheck {
794+ for ( id, _) in workspace_ids. clone ( ) {
795+ if id == flycheck. id ( ) {
796+ updated = true ;
797+ flycheck. update ( ) ;
798+ continue ;
799+ }
800+ }
801+ }
802+ }
803+ if let Some ( abs_path) = vfs_path. as_path ( ) {
804+ if reload:: should_refresh_for_change ( & abs_path, ChangeKind :: Modify ) {
805+ this. fetch_workspaces_queue
806+ . request_op ( format ! ( "DidSaveTextDocument {}" , abs_path. display( ) ) ) ;
807+ }
808+ }
739809 }
740- if let Ok ( abs_path) = from_proto:: abs_path ( & params. text_document . uri ) {
741- if reload:: should_refresh_for_change ( & abs_path, ChangeKind :: Modify ) {
742- this. fetch_workspaces_queue
743- . request_op ( format ! ( "DidSaveTextDocument {}" , abs_path. display( ) ) ) ;
810+ if !updated {
811+ for flycheck in & this. flycheck {
812+ flycheck. update ( ) ;
744813 }
745814 }
746815 Ok ( ( ) )
0 commit comments