about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--crates/project_model/src/tests.rs2
-rw-r--r--crates/project_model/src/workspace.rs23
-rw-r--r--crates/rust-analyzer/src/cli/load_cargo.rs3
-rw-r--r--crates/rust-analyzer/src/config.rs18
-rw-r--r--crates/rust-analyzer/src/reload.rs51
-rw-r--r--docs/user/generated_config.adoc7
-rw-r--r--editors/code/package.json5
7 files changed, 91 insertions, 18 deletions
diff --git a/crates/project_model/src/tests.rs b/crates/project_model/src/tests.rs
index edf26736618..2977ff74e2a 100644
--- a/crates/project_model/src/tests.rs
+++ b/crates/project_model/src/tests.rs
@@ -88,7 +88,7 @@ fn rooted_project_json(data: ProjectJsonData) -> ProjectJson {
 }
 
 fn to_crate_graph(project_workspace: ProjectWorkspace) -> CrateGraph {
-    project_workspace.to_crate_graph(&mut |_| Vec::new(), &mut {
+    project_workspace.to_crate_graph(&Default::default(), &mut |_, _| Vec::new(), &mut {
         let mut counter = 0;
         move |_path| {
             counter += 1;
diff --git a/crates/project_model/src/workspace.rs b/crates/project_model/src/workspace.rs
index 60f99f368bd..869b064e1da 100644
--- a/crates/project_model/src/workspace.rs
+++ b/crates/project_model/src/workspace.rs
@@ -387,10 +387,14 @@ impl ProjectWorkspace {
 
     pub fn to_crate_graph(
         &self,
-        load_proc_macro: &mut dyn FnMut(&AbsPath) -> Vec<ProcMacro>,
+        dummy_replace: &FxHashMap<Box<str>, Box<[Box<str>]>>,
+        load_proc_macro: &mut dyn FnMut(&AbsPath, &[Box<str>]) -> Vec<ProcMacro>,
         load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
     ) -> CrateGraph {
         let _p = profile::span("ProjectWorkspace::to_crate_graph");
+        let load_proc_macro = &mut |crate_name: &_, path: &_| {
+            load_proc_macro(path, dummy_replace.get(crate_name).map(|it| &**it).unwrap_or_default())
+        };
 
         let mut crate_graph = match self {
             ProjectWorkspace::Json { project, sysroot, rustc_cfg } => project_json_to_crate_graph(
@@ -432,7 +436,7 @@ impl ProjectWorkspace {
 
 fn project_json_to_crate_graph(
     rustc_cfg: Vec<CfgFlag>,
-    load_proc_macro: &mut dyn FnMut(&AbsPath) -> Vec<ProcMacro>,
+    load_proc_macro: &mut dyn FnMut(&str, &AbsPath) -> Vec<ProcMacro>,
     load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
     project: &ProjectJson,
     sysroot: &Option<Sysroot>,
@@ -452,7 +456,12 @@ fn project_json_to_crate_graph(
         })
         .map(|(crate_id, krate, file_id)| {
             let env = krate.env.clone().into_iter().collect();
-            let proc_macro = krate.proc_macro_dylib_path.clone().map(|it| load_proc_macro(&it));
+            let proc_macro = krate.proc_macro_dylib_path.clone().map(|it| {
+                load_proc_macro(
+                    krate.display_name.as_ref().map(|it| it.canonical_name()).unwrap_or(""),
+                    &it,
+                )
+            });
 
             let target_cfgs = match krate.target.as_deref() {
                 Some(target) => {
@@ -513,7 +522,7 @@ fn project_json_to_crate_graph(
 fn cargo_to_crate_graph(
     rustc_cfg: Vec<CfgFlag>,
     override_cfg: &CfgOverrides,
-    load_proc_macro: &mut dyn FnMut(&AbsPath) -> Vec<ProcMacro>,
+    load_proc_macro: &mut dyn FnMut(&str, &AbsPath) -> Vec<ProcMacro>,
     load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
     cargo: &CargoWorkspace,
     build_scripts: &WorkspaceBuildScripts,
@@ -571,7 +580,7 @@ fn cargo_to_crate_graph(
                     &cargo[pkg],
                     build_scripts.outputs.get(pkg),
                     cfg_options,
-                    load_proc_macro,
+                    &mut |path| load_proc_macro(&cargo[tgt].name, path),
                     file_id,
                     &cargo[tgt].name,
                 );
@@ -702,7 +711,7 @@ fn handle_rustc_crates(
     load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
     crate_graph: &mut CrateGraph,
     cfg_options: &CfgOptions,
-    load_proc_macro: &mut dyn FnMut(&AbsPath) -> Vec<ProcMacro>,
+    load_proc_macro: &mut dyn FnMut(&str, &AbsPath) -> Vec<ProcMacro>,
     pkg_to_lib_crate: &mut FxHashMap<la_arena::Idx<crate::PackageData>, CrateId>,
     public_deps: &SysrootPublicDeps,
     cargo: &CargoWorkspace,
@@ -738,7 +747,7 @@ fn handle_rustc_crates(
                         &rustc_workspace[pkg],
                         None,
                         cfg_options,
-                        load_proc_macro,
+                        &mut |path| load_proc_macro(&rustc_workspace[tgt].name, path),
                         file_id,
                         &rustc_workspace[tgt].name,
                     );
diff --git a/crates/rust-analyzer/src/cli/load_cargo.rs b/crates/rust-analyzer/src/cli/load_cargo.rs
index d60861a6274..19ce86e3ffa 100644
--- a/crates/rust-analyzer/src/cli/load_cargo.rs
+++ b/crates/rust-analyzer/src/cli/load_cargo.rs
@@ -66,7 +66,8 @@ pub fn load_workspace(
     };
 
     let crate_graph = ws.to_crate_graph(
-        &mut |path: &AbsPath| load_proc_macro(proc_macro_client.as_ref(), path),
+        &Default::default(),
+        &mut |path: &AbsPath, _| load_proc_macro(proc_macro_client.as_ref(), path, &[]),
         &mut |path: &AbsPath| {
             let contents = loader.load_sync(path);
             let path = vfs::VfsPath::from(path.to_path_buf());
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index 818aab35157..a7041392554 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/crates/rust-analyzer/src/config.rs
@@ -301,6 +301,10 @@ config_data! {
         /// Internal config, path to proc-macro server executable (typically,
         /// this is rust-analyzer itself, but we override this in tests).
         procMacro_server: Option<PathBuf>          = "null",
+        /// These proc-macros will be ignored when trying to expand them.
+        ///
+        /// This config takes a map of crate names with the exported proc-macro names to ignore as values.
+        procMacro_ignored: FxHashMap<Box<str>, Box<[Box<str>]>>          = "{}",
 
         /// Command to be executed instead of 'cargo' for runnables.
         runnables_overrideCargo: Option<String> = "null",
@@ -716,6 +720,9 @@ impl Config {
         };
         Some((path, vec!["proc-macro".into()]))
     }
+    pub fn dummy_replacements(&self) -> &FxHashMap<Box<str>, Box<[Box<str>]>> {
+        &self.data.procMacro_ignored
+    }
     pub fn expand_proc_attr_macros(&self) -> bool {
         self.data.experimental_procAttrMacros
     }
@@ -1163,7 +1170,13 @@ fn get_field<T: DeserializeOwned>(
         .find_map(move |field| {
             let mut pointer = field.replace('_', "/");
             pointer.insert(0, '/');
-            json.pointer_mut(&pointer).and_then(|it| serde_json::from_value(it.take()).ok())
+            json.pointer_mut(&pointer).and_then(|it| match serde_json::from_value(it.take()) {
+                Ok(it) => Some(it),
+                Err(e) => {
+                    tracing::warn!("Failed to deserialize config field at {}: {:?}", pointer, e);
+                    None
+                }
+            })
         })
         .unwrap_or(default)
 }
@@ -1224,6 +1237,9 @@ fn field_props(field: &str, ty: &str, doc: &[&str], default: &str) -> serde_json
             "items": { "type": "string" },
             "uniqueItems": true,
         },
+        "FxHashMap<Box<str>, Box<[Box<str>]>>" => set! {
+            "type": "object",
+        },
         "FxHashMap<String, SnippetDef>" => set! {
             "type": "object",
         },
diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs
index b14b3dbcfa9..eecc83e02ac 100644
--- a/crates/rust-analyzer/src/reload.rs
+++ b/crates/rust-analyzer/src/reload.rs
@@ -10,6 +10,7 @@ use ide_db::base_db::{
 };
 use proc_macro_api::{MacroDylib, ProcMacroServer};
 use project_model::{ProjectWorkspace, WorkspaceBuildScripts};
+use syntax::SmolStr;
 use vfs::{file_set::FileSetConfig, AbsPath, AbsPathBuf, ChangeKind};
 
 use crate::{
@@ -306,8 +307,9 @@ impl GlobalState {
         // Create crate graph from all the workspaces
         let crate_graph = {
             let proc_macro_client = self.proc_macro_client.as_ref();
-            let mut load_proc_macro =
-                move |path: &AbsPath| load_proc_macro(proc_macro_client, path);
+            let mut load_proc_macro = move |path: &AbsPath, dummy_replace: &_| {
+                load_proc_macro(proc_macro_client, path, dummy_replace)
+            };
 
             let vfs = &mut self.vfs.write().0;
             let loader = &mut self.loader;
@@ -328,7 +330,11 @@ impl GlobalState {
 
             let mut crate_graph = CrateGraph::default();
             for ws in self.workspaces.iter() {
-                crate_graph.extend(ws.to_crate_graph(&mut load_proc_macro, &mut load));
+                crate_graph.extend(ws.to_crate_graph(
+                    self.config.dummy_replacements(),
+                    &mut load_proc_macro,
+                    &mut load,
+                ));
             }
             crate_graph
         };
@@ -505,7 +511,13 @@ impl SourceRootConfig {
     }
 }
 
-pub(crate) fn load_proc_macro(client: Option<&ProcMacroServer>, path: &AbsPath) -> Vec<ProcMacro> {
+/// 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(
+    client: Option<&ProcMacroServer>,
+    path: &AbsPath,
+    dummy_replace: &[Box<str>],
+) -> Vec<ProcMacro> {
     let dylib = match MacroDylib::new(path.to_path_buf()) {
         Ok(it) => it,
         Err(err) => {
@@ -532,17 +544,25 @@ pub(crate) fn load_proc_macro(client: Option<&ProcMacroServer>, path: &AbsPath)
                 Vec::new()
             }
         })
-        .map(expander_to_proc_macro)
+        .map(|expander| expander_to_proc_macro(expander, dummy_replace))
         .collect();
 
-    fn expander_to_proc_macro(expander: proc_macro_api::ProcMacro) -> ProcMacro {
-        let name = expander.name().into();
+    fn expander_to_proc_macro(
+        expander: proc_macro_api::ProcMacro,
+        dummy_replace: &[Box<str>],
+    ) -> ProcMacro {
+        let name = SmolStr::from(expander.name());
         let kind = match expander.kind() {
             proc_macro_api::ProcMacroKind::CustomDerive => ProcMacroKind::CustomDerive,
             proc_macro_api::ProcMacroKind::FuncLike => ProcMacroKind::FuncLike,
             proc_macro_api::ProcMacroKind::Attr => ProcMacroKind::Attr,
         };
-        let expander = Arc::new(Expander(expander));
+        let expander: Arc<dyn ProcMacroExpander> =
+            if dummy_replace.iter().any(|replace| &**replace == name) {
+                Arc::new(DummyExpander)
+            } else {
+                Arc::new(Expander(expander))
+            };
         ProcMacro { name, kind, expander }
     }
 
@@ -564,6 +584,21 @@ pub(crate) fn load_proc_macro(client: Option<&ProcMacroServer>, path: &AbsPath)
             }
         }
     }
+
+    /// Dummy identity expander, used for proc-macros that are deliberately ignored by the user.
+    #[derive(Debug)]
+    struct DummyExpander;
+
+    impl ProcMacroExpander for DummyExpander {
+        fn expand(
+            &self,
+            subtree: &tt::Subtree,
+            _: Option<&tt::Subtree>,
+            _: &Env,
+        ) -> Result<tt::Subtree, ProcMacroExpansionError> {
+            Ok(subtree.clone())
+        }
+    }
 }
 
 pub(crate) fn should_refresh_for_change(path: &AbsPath, change_kind: ChangeKind) -> bool {
diff --git a/docs/user/generated_config.adoc b/docs/user/generated_config.adoc
index 494051b3060..f46dda2351f 100644
--- a/docs/user/generated_config.adoc
+++ b/docs/user/generated_config.adoc
@@ -455,6 +455,13 @@ Enable support for procedural macros, implies `#rust-analyzer.cargo.runBuildScri
 Internal config, path to proc-macro server executable (typically,
 this is rust-analyzer itself, but we override this in tests).
 --
+[[rust-analyzer.procMacro.ignored]]rust-analyzer.procMacro.ignored (default: `{}`)::
++
+--
+These proc-macros will be ignored when trying to expand them.
+
+This config takes a map of crate names with the exported proc-macro names to ignore as values.
+--
 [[rust-analyzer.runnables.overrideCargo]]rust-analyzer.runnables.overrideCargo (default: `null`)::
 +
 --
diff --git a/editors/code/package.json b/editors/code/package.json
index 57757553a7c..d4188684748 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -880,6 +880,11 @@
                         "string"
                     ]
                 },
+                "rust-analyzer.procMacro.ignored": {
+                    "markdownDescription": "These proc-macros will be ignored when trying to expand them.\n\nThis config takes a map of crate names with the exported proc-macro names to ignore as values.",
+                    "default": {},
+                    "type": "object"
+                },
                 "rust-analyzer.runnables.overrideCargo": {
                     "markdownDescription": "Command to be executed instead of 'cargo' for runnables.",
                     "default": null,