Skip to content

Commit 8887d20

Browse files
bors[bot]Veykril
andauthored
Merge #11193
11193: feat: Add config to replace specific proc-macros with dummy expanders r=Veykril a=Veykril With this one can specify proc-macros from crates to expand into their input as a (temporary) workaround for the current completion problems with some of the bigger attribute proc-macros like `async_trait`. This could've been done by just not expanding these macros, but that would require fiddling with nameres. I felt like this approach was simpler to pull off while also keeping the behaviour of the attributes/proc-macro in that they still expand instead of being dead syntax to us. Fixes #11052 Usage(`async_trait` as example): ```jsonc "rust-analyzer.procMacro.dummies": { "async-trait": [ // crate name(as per its cargo.toml definition, not the dependency name) "async_trait" // exported proc-macro name ] }, ``` Co-authored-by: Lukas Wirth <[email protected]>
2 parents 7111c27 + f6eba28 commit 8887d20

File tree

7 files changed

+91
-18
lines changed

7 files changed

+91
-18
lines changed

crates/project_model/src/tests.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ fn rooted_project_json(data: ProjectJsonData) -> ProjectJson {
8888
}
8989

9090
fn to_crate_graph(project_workspace: ProjectWorkspace) -> CrateGraph {
91-
project_workspace.to_crate_graph(&mut |_| Vec::new(), &mut {
91+
project_workspace.to_crate_graph(&Default::default(), &mut |_, _| Vec::new(), &mut {
9292
let mut counter = 0;
9393
move |_path| {
9494
counter += 1;

crates/project_model/src/workspace.rs

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -387,10 +387,14 @@ impl ProjectWorkspace {
387387

388388
pub fn to_crate_graph(
389389
&self,
390-
load_proc_macro: &mut dyn FnMut(&AbsPath) -> Vec<ProcMacro>,
390+
dummy_replace: &FxHashMap<Box<str>, Box<[Box<str>]>>,
391+
load_proc_macro: &mut dyn FnMut(&AbsPath, &[Box<str>]) -> Vec<ProcMacro>,
391392
load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
392393
) -> CrateGraph {
393394
let _p = profile::span("ProjectWorkspace::to_crate_graph");
395+
let load_proc_macro = &mut |crate_name: &_, path: &_| {
396+
load_proc_macro(path, dummy_replace.get(crate_name).map(|it| &**it).unwrap_or_default())
397+
};
394398

395399
let mut crate_graph = match self {
396400
ProjectWorkspace::Json { project, sysroot, rustc_cfg } => project_json_to_crate_graph(
@@ -432,7 +436,7 @@ impl ProjectWorkspace {
432436

433437
fn project_json_to_crate_graph(
434438
rustc_cfg: Vec<CfgFlag>,
435-
load_proc_macro: &mut dyn FnMut(&AbsPath) -> Vec<ProcMacro>,
439+
load_proc_macro: &mut dyn FnMut(&str, &AbsPath) -> Vec<ProcMacro>,
436440
load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
437441
project: &ProjectJson,
438442
sysroot: &Option<Sysroot>,
@@ -452,7 +456,12 @@ fn project_json_to_crate_graph(
452456
})
453457
.map(|(crate_id, krate, file_id)| {
454458
let env = krate.env.clone().into_iter().collect();
455-
let proc_macro = krate.proc_macro_dylib_path.clone().map(|it| load_proc_macro(&it));
459+
let proc_macro = krate.proc_macro_dylib_path.clone().map(|it| {
460+
load_proc_macro(
461+
krate.display_name.as_ref().map(|it| it.canonical_name()).unwrap_or(""),
462+
&it,
463+
)
464+
});
456465

457466
let target_cfgs = match krate.target.as_deref() {
458467
Some(target) => {
@@ -513,7 +522,7 @@ fn project_json_to_crate_graph(
513522
fn cargo_to_crate_graph(
514523
rustc_cfg: Vec<CfgFlag>,
515524
override_cfg: &CfgOverrides,
516-
load_proc_macro: &mut dyn FnMut(&AbsPath) -> Vec<ProcMacro>,
525+
load_proc_macro: &mut dyn FnMut(&str, &AbsPath) -> Vec<ProcMacro>,
517526
load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
518527
cargo: &CargoWorkspace,
519528
build_scripts: &WorkspaceBuildScripts,
@@ -571,7 +580,7 @@ fn cargo_to_crate_graph(
571580
&cargo[pkg],
572581
build_scripts.outputs.get(pkg),
573582
cfg_options,
574-
load_proc_macro,
583+
&mut |path| load_proc_macro(&cargo[tgt].name, path),
575584
file_id,
576585
&cargo[tgt].name,
577586
);
@@ -702,7 +711,7 @@ fn handle_rustc_crates(
702711
load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
703712
crate_graph: &mut CrateGraph,
704713
cfg_options: &CfgOptions,
705-
load_proc_macro: &mut dyn FnMut(&AbsPath) -> Vec<ProcMacro>,
714+
load_proc_macro: &mut dyn FnMut(&str, &AbsPath) -> Vec<ProcMacro>,
706715
pkg_to_lib_crate: &mut FxHashMap<la_arena::Idx<crate::PackageData>, CrateId>,
707716
public_deps: &SysrootPublicDeps,
708717
cargo: &CargoWorkspace,
@@ -738,7 +747,7 @@ fn handle_rustc_crates(
738747
&rustc_workspace[pkg],
739748
None,
740749
cfg_options,
741-
load_proc_macro,
750+
&mut |path| load_proc_macro(&rustc_workspace[tgt].name, path),
742751
file_id,
743752
&rustc_workspace[tgt].name,
744753
);

crates/rust-analyzer/src/cli/load_cargo.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,8 @@ pub fn load_workspace(
6666
};
6767

6868
let crate_graph = ws.to_crate_graph(
69-
&mut |path: &AbsPath| load_proc_macro(proc_macro_client.as_ref(), path),
69+
&Default::default(),
70+
&mut |path: &AbsPath, _| load_proc_macro(proc_macro_client.as_ref(), path, &[]),
7071
&mut |path: &AbsPath| {
7172
let contents = loader.load_sync(path);
7273
let path = vfs::VfsPath::from(path.to_path_buf());

crates/rust-analyzer/src/config.rs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,10 @@ config_data! {
301301
/// Internal config, path to proc-macro server executable (typically,
302302
/// this is rust-analyzer itself, but we override this in tests).
303303
procMacro_server: Option<PathBuf> = "null",
304+
/// These proc-macros will be ignored when trying to expand them.
305+
///
306+
/// This config takes a map of crate names with the exported proc-macro names to ignore as values.
307+
procMacro_ignored: FxHashMap<Box<str>, Box<[Box<str>]>> = "{}",
304308

305309
/// Command to be executed instead of 'cargo' for runnables.
306310
runnables_overrideCargo: Option<String> = "null",
@@ -716,6 +720,9 @@ impl Config {
716720
};
717721
Some((path, vec!["proc-macro".into()]))
718722
}
723+
pub fn dummy_replacements(&self) -> &FxHashMap<Box<str>, Box<[Box<str>]>> {
724+
&self.data.procMacro_ignored
725+
}
719726
pub fn expand_proc_attr_macros(&self) -> bool {
720727
self.data.experimental_procAttrMacros
721728
}
@@ -1163,7 +1170,13 @@ fn get_field<T: DeserializeOwned>(
11631170
.find_map(move |field| {
11641171
let mut pointer = field.replace('_', "/");
11651172
pointer.insert(0, '/');
1166-
json.pointer_mut(&pointer).and_then(|it| serde_json::from_value(it.take()).ok())
1173+
json.pointer_mut(&pointer).and_then(|it| match serde_json::from_value(it.take()) {
1174+
Ok(it) => Some(it),
1175+
Err(e) => {
1176+
tracing::warn!("Failed to deserialize config field at {}: {:?}", pointer, e);
1177+
None
1178+
}
1179+
})
11671180
})
11681181
.unwrap_or(default)
11691182
}
@@ -1224,6 +1237,9 @@ fn field_props(field: &str, ty: &str, doc: &[&str], default: &str) -> serde_json
12241237
"items": { "type": "string" },
12251238
"uniqueItems": true,
12261239
},
1240+
"FxHashMap<Box<str>, Box<[Box<str>]>>" => set! {
1241+
"type": "object",
1242+
},
12271243
"FxHashMap<String, SnippetDef>" => set! {
12281244
"type": "object",
12291245
},

crates/rust-analyzer/src/reload.rs

Lines changed: 43 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use ide_db::base_db::{
1010
};
1111
use proc_macro_api::{MacroDylib, ProcMacroServer};
1212
use project_model::{ProjectWorkspace, WorkspaceBuildScripts};
13+
use syntax::SmolStr;
1314
use vfs::{file_set::FileSetConfig, AbsPath, AbsPathBuf, ChangeKind};
1415

1516
use crate::{
@@ -306,8 +307,9 @@ impl GlobalState {
306307
// Create crate graph from all the workspaces
307308
let crate_graph = {
308309
let proc_macro_client = self.proc_macro_client.as_ref();
309-
let mut load_proc_macro =
310-
move |path: &AbsPath| load_proc_macro(proc_macro_client, path);
310+
let mut load_proc_macro = move |path: &AbsPath, dummy_replace: &_| {
311+
load_proc_macro(proc_macro_client, path, dummy_replace)
312+
};
311313

312314
let vfs = &mut self.vfs.write().0;
313315
let loader = &mut self.loader;
@@ -328,7 +330,11 @@ impl GlobalState {
328330

329331
let mut crate_graph = CrateGraph::default();
330332
for ws in self.workspaces.iter() {
331-
crate_graph.extend(ws.to_crate_graph(&mut load_proc_macro, &mut load));
333+
crate_graph.extend(ws.to_crate_graph(
334+
self.config.dummy_replacements(),
335+
&mut load_proc_macro,
336+
&mut load,
337+
));
332338
}
333339
crate_graph
334340
};
@@ -505,7 +511,13 @@ impl SourceRootConfig {
505511
}
506512
}
507513

508-
pub(crate) fn load_proc_macro(client: Option<&ProcMacroServer>, path: &AbsPath) -> Vec<ProcMacro> {
514+
/// Load the proc-macros for the given lib path, replacing all expanders whose names are in `dummy_replace`
515+
/// with an identity dummy expander.
516+
pub(crate) fn load_proc_macro(
517+
client: Option<&ProcMacroServer>,
518+
path: &AbsPath,
519+
dummy_replace: &[Box<str>],
520+
) -> Vec<ProcMacro> {
509521
let dylib = match MacroDylib::new(path.to_path_buf()) {
510522
Ok(it) => it,
511523
Err(err) => {
@@ -532,17 +544,25 @@ pub(crate) fn load_proc_macro(client: Option<&ProcMacroServer>, path: &AbsPath)
532544
Vec::new()
533545
}
534546
})
535-
.map(expander_to_proc_macro)
547+
.map(|expander| expander_to_proc_macro(expander, dummy_replace))
536548
.collect();
537549

538-
fn expander_to_proc_macro(expander: proc_macro_api::ProcMacro) -> ProcMacro {
539-
let name = expander.name().into();
550+
fn expander_to_proc_macro(
551+
expander: proc_macro_api::ProcMacro,
552+
dummy_replace: &[Box<str>],
553+
) -> ProcMacro {
554+
let name = SmolStr::from(expander.name());
540555
let kind = match expander.kind() {
541556
proc_macro_api::ProcMacroKind::CustomDerive => ProcMacroKind::CustomDerive,
542557
proc_macro_api::ProcMacroKind::FuncLike => ProcMacroKind::FuncLike,
543558
proc_macro_api::ProcMacroKind::Attr => ProcMacroKind::Attr,
544559
};
545-
let expander = Arc::new(Expander(expander));
560+
let expander: Arc<dyn ProcMacroExpander> =
561+
if dummy_replace.iter().any(|replace| &**replace == name) {
562+
Arc::new(DummyExpander)
563+
} else {
564+
Arc::new(Expander(expander))
565+
};
546566
ProcMacro { name, kind, expander }
547567
}
548568

@@ -564,6 +584,21 @@ pub(crate) fn load_proc_macro(client: Option<&ProcMacroServer>, path: &AbsPath)
564584
}
565585
}
566586
}
587+
588+
/// Dummy identity expander, used for proc-macros that are deliberately ignored by the user.
589+
#[derive(Debug)]
590+
struct DummyExpander;
591+
592+
impl ProcMacroExpander for DummyExpander {
593+
fn expand(
594+
&self,
595+
subtree: &tt::Subtree,
596+
_: Option<&tt::Subtree>,
597+
_: &Env,
598+
) -> Result<tt::Subtree, ProcMacroExpansionError> {
599+
Ok(subtree.clone())
600+
}
601+
}
567602
}
568603

569604
pub(crate) fn should_refresh_for_change(path: &AbsPath, change_kind: ChangeKind) -> bool {

docs/user/generated_config.adoc

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -455,6 +455,13 @@ Enable support for procedural macros, implies `#rust-analyzer.cargo.runBuildScri
455455
Internal config, path to proc-macro server executable (typically,
456456
this is rust-analyzer itself, but we override this in tests).
457457
--
458+
[[rust-analyzer.procMacro.ignored]]rust-analyzer.procMacro.ignored (default: `{}`)::
459+
+
460+
--
461+
These proc-macros will be ignored when trying to expand them.
462+
463+
This config takes a map of crate names with the exported proc-macro names to ignore as values.
464+
--
458465
[[rust-analyzer.runnables.overrideCargo]]rust-analyzer.runnables.overrideCargo (default: `null`)::
459466
+
460467
--

editors/code/package.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -880,6 +880,11 @@
880880
"string"
881881
]
882882
},
883+
"rust-analyzer.procMacro.ignored": {
884+
"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.",
885+
"default": {},
886+
"type": "object"
887+
},
883888
"rust-analyzer.runnables.overrideCargo": {
884889
"markdownDescription": "Command to be executed instead of 'cargo' for runnables.",
885890
"default": null,

0 commit comments

Comments
 (0)