]> git.lizzy.rs Git - rust.git/blobdiff - crates/rust-analyzer/src/reload.rs
Auto merge of #12808 - Veykril:check-workspace, r=Veykril
[rust.git] / crates / rust-analyzer / src / reload.rs
index 579ba380273ab608be0ae957747d13407e3c6a1a..c90291eb5e29ad337dba58b8117eeed2bffbf76d 100644 (file)
@@ -303,24 +303,62 @@ fn eq_ignore_build_data<'a>(
         let files_config = self.config.files();
         let project_folders = ProjectFolders::new(&self.workspaces, &files_config.exclude);
 
-        if self.proc_macro_client.is_none() {
+        let standalone_server_name =
+            format!("rust-analyzer-proc-macro-srv{}", std::env::consts::EXE_SUFFIX);
+
+        if self.proc_macro_clients.is_empty() {
             if let Some((path, args)) = self.config.proc_macro_srv() {
-                match ProcMacroServer::spawn(path.clone(), args) {
-                    Ok(it) => self.proc_macro_client = Some(it),
-                    Err(err) => {
-                        tracing::error!(
-                            "Failed to run proc_macro_srv from path {}, error: {:?}",
+                self.proc_macro_clients = self
+                    .workspaces
+                    .iter()
+                    .map(|ws| {
+                        let mut args = args.clone();
+                        let mut path = path.clone();
+
+                        if let ProjectWorkspace::Cargo { sysroot, .. } = ws {
+                            tracing::info!("Found a cargo workspace...");
+                            if let Some(sysroot) = sysroot.as_ref() {
+                                tracing::info!("Found a cargo workspace with a sysroot...");
+                                let server_path =
+                                    sysroot.root().join("libexec").join(&standalone_server_name);
+                                if std::fs::metadata(&server_path).is_ok() {
+                                    tracing::info!(
+                                        "And the server exists at {}",
+                                        server_path.display()
+                                    );
+                                    path = server_path;
+                                    args = vec![];
+                                } else {
+                                    tracing::info!(
+                                        "And the server does not exist at {}",
+                                        server_path.display()
+                                    );
+                                }
+                            }
+                        }
+
+                        tracing::info!(
+                            "Using proc-macro server at {} with args {:?}",
                             path.display(),
-                            err
+                            args
                         );
-                    }
-                }
+                        ProcMacroServer::spawn(path.clone(), args.clone()).map_err(|err| {
+                            let error = format!(
+                                "Failed to run proc_macro_srv from path {}, error: {:?}",
+                                path.display(),
+                                err
+                            );
+                            tracing::error!(error);
+                            error
+                        })
+                    })
+                    .collect();
             }
         }
 
         let watch = match files_config.watcher {
             FilesWatcher::Client => vec![],
-            FilesWatcher::Notify => project_folders.watch,
+            FilesWatcher::Server => project_folders.watch,
         };
         self.vfs_config_version += 1;
         self.loader.handle.set_config(vfs::loader::Config {
@@ -331,15 +369,7 @@ fn eq_ignore_build_data<'a>(
 
         // Create crate graph from all the workspaces
         let crate_graph = {
-            let proc_macro_client = self.proc_macro_client.as_ref();
             let dummy_replacements = self.config.dummy_replacements();
-            let mut load_proc_macro = move |crate_name: &str, path: &AbsPath| {
-                load_proc_macro(
-                    proc_macro_client,
-                    path,
-                    dummy_replacements.get(crate_name).map(|v| &**v).unwrap_or_default(),
-                )
-            };
 
             let vfs = &mut self.vfs.write().0;
             let loader = &mut self.loader;
@@ -359,7 +389,18 @@ fn eq_ignore_build_data<'a>(
             };
 
             let mut crate_graph = CrateGraph::default();
-            for ws in self.workspaces.iter() {
+            for (idx, ws) in self.workspaces.iter().enumerate() {
+                let proc_macro_client = match self.proc_macro_clients.get(idx) {
+                    Some(res) => res.as_ref().map_err(|e| &**e),
+                    None => Err("Proc macros are disabled"),
+                };
+                let mut load_proc_macro = move |crate_name: &str, path: &AbsPath| {
+                    load_proc_macro(
+                        proc_macro_client,
+                        path,
+                        dummy_replacements.get(crate_name).map(|v| &**v).unwrap_or_default(),
+                    )
+                };
                 crate_graph.extend(ws.to_crate_graph(&mut load_proc_macro, &mut load));
             }
             crate_graph
@@ -536,14 +577,14 @@ pub(crate) fn partition(&self, vfs: &vfs::Vfs) -> Vec<SourceRoot> {
 /// Load the proc-macros for the given lib path, replacing all expanders whose names are in `dummy_replace`
 /// with an identity dummy expander.
 pub(crate) fn load_proc_macro(
-    server: Option<&ProcMacroServer>,
+    server: Result<&ProcMacroServer, &str>,
     path: &AbsPath,
     dummy_replace: &[Box<str>],
 ) -> ProcMacroLoadResult {
     let res: Result<Vec<_>, String> = (|| {
         let dylib = MacroDylib::new(path.to_path_buf())
             .map_err(|io| format!("Proc-macro dylib loading failed: {io}"))?;
-        let server = server.ok_or_else(|| format!("Proc-macro server not started"))?;
+        let server = server.map_err(ToOwned::to_owned)?;
         let vec = server.load_dylib(dylib).map_err(|e| format!("{e}"))?;
         if vec.is_empty() {
             return Err("proc macro library returned no proc macros".to_string());
@@ -580,7 +621,10 @@ fn expander_to_proc_macro(
         };
         let expander: Arc<dyn ProcMacroExpander> =
             if dummy_replace.iter().any(|replace| &**replace == name) {
-                Arc::new(DummyExpander)
+                match kind {
+                    ProcMacroKind::Attr => Arc::new(IdentityExpander),
+                    _ => Arc::new(EmptyExpander),
+                }
             } else {
                 Arc::new(Expander(expander))
             };
@@ -606,11 +650,11 @@ fn expand(
         }
     }
 
-    /// Dummy identity expander, used for proc-macros that are deliberately ignored by the user.
+    /// Dummy identity expander, used for attribute proc-macros that are deliberately ignored by the user.
     #[derive(Debug)]
-    struct DummyExpander;
+    struct IdentityExpander;
 
-    impl ProcMacroExpander for DummyExpander {
+    impl ProcMacroExpander for IdentityExpander {
         fn expand(
             &self,
             subtree: &tt::Subtree,
@@ -620,6 +664,21 @@ fn expand(
             Ok(subtree.clone())
         }
     }
+
+    /// Empty expander, used for proc-macros that are deliberately ignored by the user.
+    #[derive(Debug)]
+    struct EmptyExpander;
+
+    impl ProcMacroExpander for EmptyExpander {
+        fn expand(
+            &self,
+            _: &tt::Subtree,
+            _: Option<&tt::Subtree>,
+            _: &Env,
+        ) -> Result<tt::Subtree, ProcMacroExpansionError> {
+            Ok(tt::Subtree::default())
+        }
+    }
 }
 
 pub(crate) fn should_refresh_for_change(path: &AbsPath, change_kind: ChangeKind) -> bool {