about summary refs log tree commit diff
diff options
context:
space:
mode:
authorLukas Wirth <lukastw97@gmail.com>2022-07-18 20:30:07 +0200
committerLukas Wirth <lukastw97@gmail.com>2022-07-18 20:30:58 +0200
commita63b5d3c846b74b917b8029aa00cb448faba409f (patch)
treeb958289e2e759d3d01f4de2e5dfe9f31cb99dc2d
parentea416175d5401b85a3774a6b2c1e03281dac40c3 (diff)
downloadrust-a63b5d3c846b74b917b8029aa00cb448faba409f.tar.gz
rust-a63b5d3c846b74b917b8029aa00cb448faba409f.zip
feat: Only flycheck workspace that belongs to saved file
-rw-r--r--crates/flycheck/src/lib.rs7
-rw-r--r--crates/paths/src/lib.rs8
-rw-r--r--crates/rust-analyzer/src/main_loop.rs62
3 files changed, 70 insertions, 7 deletions
diff --git a/crates/flycheck/src/lib.rs b/crates/flycheck/src/lib.rs
index f683fe61fe3..973f2a53c1a 100644
--- a/crates/flycheck/src/lib.rs
+++ b/crates/flycheck/src/lib.rs
@@ -55,6 +55,7 @@ pub struct FlycheckHandle {
     // XXX: drop order is significant
     sender: Sender<Restart>,
     _thread: jod_thread::JoinHandle,
+    id: usize,
 }
 
 impl FlycheckHandle {
@@ -70,13 +71,17 @@ impl FlycheckHandle {
             .name("Flycheck".to_owned())
             .spawn(move || actor.run(receiver))
             .expect("failed to spawn thread");
-        FlycheckHandle { sender, _thread: thread }
+        FlycheckHandle { id, sender, _thread: thread }
     }
 
     /// Schedule a re-start of the cargo check worker.
     pub fn update(&self) {
         self.sender.send(Restart).unwrap();
     }
+
+    pub fn id(&self) -> usize {
+        self.id
+    }
 }
 
 pub enum Message {
diff --git a/crates/paths/src/lib.rs b/crates/paths/src/lib.rs
index b4beb40e746..cf06bf0c27b 100644
--- a/crates/paths/src/lib.rs
+++ b/crates/paths/src/lib.rs
@@ -103,6 +103,14 @@ impl AsRef<Path> for AbsPath {
     }
 }
 
+impl ToOwned for AbsPath {
+    type Owned = AbsPathBuf;
+
+    fn to_owned(&self) -> Self::Owned {
+        AbsPathBuf(self.0.to_owned())
+    }
+}
+
 impl<'a> TryFrom<&'a Path> for &'a AbsPath {
     type Error = &'a Path;
     fn try_from(path: &'a Path) -> Result<&'a AbsPath, &'a Path> {
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs
index 49b83941119..262c30f132c 100644
--- a/crates/rust-analyzer/src/main_loop.rs
+++ b/crates/rust-analyzer/src/main_loop.rs
@@ -2,6 +2,7 @@
 //! requests/replies and notifications back to the client.
 use std::{
     fmt,
+    ops::Deref,
     sync::Arc,
     time::{Duration, Instant},
 };
@@ -720,13 +721,62 @@ impl GlobalState {
                 Ok(())
             })?
             .on::<lsp_types::notification::DidSaveTextDocument>(|this, params| {
-                for flycheck in &this.flycheck {
-                    flycheck.update();
+                let mut updated = false;
+                if let Ok(vfs_path) = from_proto::vfs_path(&params.text_document.uri) {
+                    let (vfs, _) = &*this.vfs.read();
+                    if let Some(file_id) = vfs.file_id(&vfs_path) {
+                        let analysis = this.analysis_host.analysis();
+                        let crate_ids = analysis.crate_for(file_id)?;
+
+                        let paths: Vec<_> = crate_ids
+                            .iter()
+                            .filter_map(|&crate_id| {
+                                analysis
+                                    .crate_root(crate_id)
+                                    .map(|file_id| {
+                                        vfs.file_path(file_id).as_path().map(ToOwned::to_owned)
+                                    })
+                                    .transpose()
+                            })
+                            .collect::<ide::Cancellable<_>>()?;
+                        let paths: Vec<_> = paths.iter().map(Deref::deref).collect();
+
+                        let workspace_ids =
+                            this.workspaces.iter().enumerate().filter(|(_, ws)| match ws {
+                                project_model::ProjectWorkspace::Cargo { cargo, .. } => {
+                                    cargo.packages().filter(|&pkg| cargo[pkg].is_member).any(
+                                        |pkg| {
+                                            cargo[pkg].targets.iter().any(|&it| {
+                                                paths.contains(&cargo[it].root.as_path())
+                                            })
+                                        },
+                                    )
+                                }
+                                project_model::ProjectWorkspace::Json { project, .. } => project
+                                    .crates()
+                                    .any(|(c, _)| crate_ids.iter().any(|&crate_id| crate_id == c)),
+                                project_model::ProjectWorkspace::DetachedFiles { .. } => false,
+                            });
+                        'workspace: for (id, _) in workspace_ids {
+                            for flycheck in &this.flycheck {
+                                if id == flycheck.id() {
+                                    updated = true;
+                                    flycheck.update();
+                                    continue 'workspace;
+                                }
+                            }
+                        }
+                    }
+                    if let Some(abs_path) = vfs_path.as_path() {
+                        if reload::should_refresh_for_change(&abs_path, ChangeKind::Modify) {
+                            this.fetch_workspaces_queue
+                                .request_op(format!("DidSaveTextDocument {}", abs_path.display()));
+                        }
+                    }
                 }
-                if let Ok(abs_path) = from_proto::abs_path(&params.text_document.uri) {
-                    if reload::should_refresh_for_change(&abs_path, ChangeKind::Modify) {
-                        this.fetch_workspaces_queue
-                            .request_op(format!("DidSaveTextDocument {}", abs_path.display()));
+                if !updated {
+                    for flycheck in &this.flycheck {
+                        flycheck.update();
                     }
                 }
                 Ok(())