about summary refs log tree commit diff
diff options
context:
space:
mode:
authorLukas Wirth <lukastw97@gmail.com>2025-03-29 07:24:39 +0000
committerGitHub <noreply@github.com>2025-03-29 07:24:39 +0000
commit281ca97ba331c6316cf4a4f967521062a3d50a8e (patch)
treedf9cf7c25e01182bd173285546f45e4cff3a5fad
parent82440954730c8eb2984d628e3455010756f57f2f (diff)
parent03cab8680b46716f99f94f2a6b0f6a8439653661 (diff)
downloadrust-281ca97ba331c6316cf4a4f967521062a3d50a8e.tar.gz
rust-281ca97ba331c6316cf4a4f967521062a3d50a8e.zip
Merge pull request #19474 from Veykril/push-nokkzzvwynnt
fix: Fix, clarify and require a value for `proc_macro_cwd` of `CrateData`
-rw-r--r--src/tools/rust-analyzer/.github/workflows/ci.yaml8
-rw-r--r--src/tools/rust-analyzer/Cargo.lock1
-rw-r--r--src/tools/rust-analyzer/crates/base-db/src/input.rs31
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs9
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/proc_macro.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/lib.rs8
-rw-r--r--src/tools/rust-analyzer/crates/load-cargo/src/lib.rs2
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs4
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/workspace.rs43
-rw-r--r--src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model.txt20
-rw-r--r--src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt20
-rw-r--r--src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_wildcard_overrides.txt20
-rw-r--r--src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_cfg_groups.txt8
-rw-r--r--src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt4
-rw-r--r--src/tools/rust-analyzer/crates/test-fixture/Cargo.toml1
-rw-r--r--src/tools/rust-analyzer/crates/test-fixture/src/lib.rs30
17 files changed, 143 insertions, 74 deletions
diff --git a/src/tools/rust-analyzer/.github/workflows/ci.yaml b/src/tools/rust-analyzer/.github/workflows/ci.yaml
index 610f8d00aae..0e023bfe91b 100644
--- a/src/tools/rust-analyzer/.github/workflows/ci.yaml
+++ b/src/tools/rust-analyzer/.github/workflows/ci.yaml
@@ -24,7 +24,6 @@ jobs:
       pull-requests: read
     outputs:
       typescript: ${{ steps.filter.outputs.typescript }}
-      proc_macros: ${{ steps.filter.outputs.proc_macros }}
     steps:
       - uses: actions/checkout@v4
       - uses: dorny/paths-filter@1441771bbfdd59dcd748680ee64ebd8faab1a242
@@ -33,15 +32,10 @@ jobs:
           filters: |
             typescript:
               - 'editors/code/**'
-            proc_macros:
-              - 'crates/tt/**'
-              - 'crates/proc-macro-api/**'
-              - 'crates/proc-macro-srv/**'
-              - 'crates/proc-macro-srv-cli/**'
 
   proc-macro-srv:
     needs: changes
-    if: github.repository == 'rust-lang/rust-analyzer' && needs.changes.outputs.proc_macros == 'true'
+    if: github.repository == 'rust-lang/rust-analyzer'
     name: proc-macro-srv
     runs-on: ubuntu-latest
     env:
diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock
index 2c421451213..b6a32d5b642 100644
--- a/src/tools/rust-analyzer/Cargo.lock
+++ b/src/tools/rust-analyzer/Cargo.lock
@@ -2305,6 +2305,7 @@ dependencies = [
  "cfg",
  "hir-expand",
  "intern",
+ "paths",
  "rustc-hash 2.1.1",
  "span",
  "stdx",
diff --git a/src/tools/rust-analyzer/crates/base-db/src/input.rs b/src/tools/rust-analyzer/crates/base-db/src/input.rs
index 343aba1a169..cfc22b72465 100644
--- a/src/tools/rust-analyzer/crates/base-db/src/input.rs
+++ b/src/tools/rust-analyzer/crates/base-db/src/input.rs
@@ -303,9 +303,11 @@ pub struct CrateData<Id> {
     pub dependencies: Vec<Dependency<Id>>,
     pub origin: CrateOrigin,
     pub is_proc_macro: bool,
-    /// The working directory to run proc-macros in. This is the workspace root of the cargo workspace
-    /// for workspace members, the crate manifest dir otherwise.
-    pub proc_macro_cwd: Option<AbsPathBuf>,
+    /// The working directory to run proc-macros in invoked in the context of this crate.
+    /// This is the workspace root of the cargo workspace for workspace members, the crate manifest
+    /// dir otherwise.
+    // FIXME: This ought to be a `VfsPath` or something opaque.
+    pub proc_macro_cwd: Arc<AbsPathBuf>,
 }
 
 pub type CrateDataBuilder = CrateData<CrateBuilderId>;
@@ -425,7 +427,7 @@ impl CrateGraphBuilder {
         mut env: Env,
         origin: CrateOrigin,
         is_proc_macro: bool,
-        proc_macro_cwd: Option<AbsPathBuf>,
+        proc_macro_cwd: Arc<AbsPathBuf>,
         ws_data: Arc<CrateWorkspaceData>,
     ) -> CrateBuilderId {
         env.entries.shrink_to_fit();
@@ -861,6 +863,7 @@ impl fmt::Display for CyclicDependenciesError {
 #[cfg(test)]
 mod tests {
     use triomphe::Arc;
+    use vfs::AbsPathBuf;
 
     use crate::{CrateWorkspaceData, DependencyBuilder};
 
@@ -883,7 +886,7 @@ mod tests {
             Env::default(),
             CrateOrigin::Local { repo: None, name: None },
             false,
-            None,
+            Arc::new(AbsPathBuf::assert_utf8(std::env::current_dir().unwrap())),
             empty_ws_data(),
         );
         let crate2 = graph.add_crate_root(
@@ -896,7 +899,7 @@ mod tests {
             Env::default(),
             CrateOrigin::Local { repo: None, name: None },
             false,
-            None,
+            Arc::new(AbsPathBuf::assert_utf8(std::env::current_dir().unwrap())),
             empty_ws_data(),
         );
         let crate3 = graph.add_crate_root(
@@ -909,7 +912,7 @@ mod tests {
             Env::default(),
             CrateOrigin::Local { repo: None, name: None },
             false,
-            None,
+            Arc::new(AbsPathBuf::assert_utf8(std::env::current_dir().unwrap())),
             empty_ws_data(),
         );
         assert!(
@@ -942,7 +945,7 @@ mod tests {
             Env::default(),
             CrateOrigin::Local { repo: None, name: None },
             false,
-            None,
+            Arc::new(AbsPathBuf::assert_utf8(std::env::current_dir().unwrap())),
             empty_ws_data(),
         );
         let crate2 = graph.add_crate_root(
@@ -955,7 +958,7 @@ mod tests {
             Env::default(),
             CrateOrigin::Local { repo: None, name: None },
             false,
-            None,
+            Arc::new(AbsPathBuf::assert_utf8(std::env::current_dir().unwrap())),
             empty_ws_data(),
         );
         assert!(
@@ -983,7 +986,7 @@ mod tests {
             Env::default(),
             CrateOrigin::Local { repo: None, name: None },
             false,
-            None,
+            Arc::new(AbsPathBuf::assert_utf8(std::env::current_dir().unwrap())),
             empty_ws_data(),
         );
         let crate2 = graph.add_crate_root(
@@ -996,7 +999,7 @@ mod tests {
             Env::default(),
             CrateOrigin::Local { repo: None, name: None },
             false,
-            None,
+            Arc::new(AbsPathBuf::assert_utf8(std::env::current_dir().unwrap())),
             empty_ws_data(),
         );
         let crate3 = graph.add_crate_root(
@@ -1009,7 +1012,7 @@ mod tests {
             Env::default(),
             CrateOrigin::Local { repo: None, name: None },
             false,
-            None,
+            Arc::new(AbsPathBuf::assert_utf8(std::env::current_dir().unwrap())),
             empty_ws_data(),
         );
         assert!(
@@ -1037,7 +1040,7 @@ mod tests {
             Env::default(),
             CrateOrigin::Local { repo: None, name: None },
             false,
-            None,
+            Arc::new(AbsPathBuf::assert_utf8(std::env::current_dir().unwrap())),
             empty_ws_data(),
         );
         let crate2 = graph.add_crate_root(
@@ -1050,7 +1053,7 @@ mod tests {
             Env::default(),
             CrateOrigin::Local { repo: None, name: None },
             false,
-            None,
+            Arc::new(AbsPathBuf::assert_utf8(std::env::current_dir().unwrap())),
             empty_ws_data(),
         );
         assert!(
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs
index d9fbf4b17c5..15eb5db0569 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs
@@ -362,7 +362,7 @@ impl ProcMacroExpander for IdentityWhenValidProcMacroExpander {
         _: Span,
         _: Span,
         _: Span,
-        _: Option<String>,
+        _: String,
     ) -> Result<TopSubtree, ProcMacroExpansionError> {
         let (parse, _) = syntax_bridge::token_tree_to_syntax_node(
             subtree,
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs
index 14653c64a61..d3663182c99 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs
@@ -52,6 +52,7 @@ pub const BAZ: u32 = 0;
     {
         // Add a dependency a -> b.
         let mut new_crate_graph = CrateGraphBuilder::default();
+
         let mut add_crate = |crate_name, root_file_idx: usize| {
             new_crate_graph.add_crate_root(
                 files[root_file_idx].file_id(),
@@ -63,7 +64,13 @@ pub const BAZ: u32 = 0;
                 Env::default(),
                 CrateOrigin::Local { repo: None, name: Some(Symbol::intern(crate_name)) },
                 false,
-                None,
+                Arc::new(
+                    // FIXME: This is less than ideal
+                    TryFrom::try_from(
+                        &*std::env::current_dir().unwrap().as_path().to_string_lossy(),
+                    )
+                    .unwrap(),
+                ),
                 Arc::new(CrateWorkspaceData { data_layout: Err("".into()), toolchain: None }),
             )
         };
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/proc_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/proc_macro.rs
index ceb6972a50c..4920d90a974 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/proc_macro.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/proc_macro.rs
@@ -41,7 +41,7 @@ pub trait ProcMacroExpander: fmt::Debug + Send + Sync + RefUnwindSafe + AsAny {
         def_site: Span,
         call_site: Span,
         mixed_site: Span,
-        current_dir: Option<String>,
+        current_dir: String,
     ) -> Result<tt::TopSubtree, ProcMacroExpansionError>;
 
     fn eq_dyn(&self, other: &dyn ProcMacroExpander) -> bool;
@@ -318,8 +318,8 @@ impl CustomProcMacroExpander {
 
                 // Proc macros have access to the environment variables of the invoking crate.
                 let env = calling_crate.env(db);
-                let current_dir =
-                    calling_crate.data(db).proc_macro_cwd.as_deref().map(ToString::to_string);
+                // FIXME: Can we avoid the string allocation here?
+                let current_dir = calling_crate.data(db).proc_macro_cwd.to_string();
 
                 match proc_macro.expander.expand(
                     tt,
diff --git a/src/tools/rust-analyzer/crates/ide/src/lib.rs b/src/tools/rust-analyzer/crates/ide/src/lib.rs
index f85a7bf2f25..434059cdfbd 100644
--- a/src/tools/rust-analyzer/crates/ide/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/lib.rs
@@ -244,6 +244,12 @@ impl Analysis {
         // FIXME: cfg options
         // Default to enable test for single file.
         let mut cfg_options = CfgOptions::default();
+
+        // FIXME: This is less than ideal
+        let proc_macro_cwd = Arc::new(
+            TryFrom::try_from(&*std::env::current_dir().unwrap().as_path().to_string_lossy())
+                .unwrap(),
+        );
         cfg_options.insert_atom(sym::test.clone());
         crate_graph.add_crate_root(
             file_id,
@@ -255,7 +261,7 @@ impl Analysis {
             Env::default(),
             CrateOrigin::Local { repo: None, name: None },
             false,
-            None,
+            proc_macro_cwd,
             Arc::new(CrateWorkspaceData {
                 data_layout: Err("fixture has no layout".into()),
                 toolchain: None,
diff --git a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs
index 243619bb09f..c85eda70462 100644
--- a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs
@@ -496,7 +496,7 @@ impl ProcMacroExpander for Expander {
         def_site: Span,
         call_site: Span,
         mixed_site: Span,
-        current_dir: Option<String>,
+        current_dir: String,
     ) -> Result<tt::TopSubtree<Span>, ProcMacroExpansionError> {
         match self.0.expand(
             subtree.view(),
diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs b/src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs
index c692d5a549f..d67d6058d50 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs
@@ -170,7 +170,7 @@ impl ProcMacro {
         def_site: Span,
         call_site: Span,
         mixed_site: Span,
-        current_dir: Option<String>,
+        current_dir: String,
     ) -> Result<Result<tt::TopSubtree<Span>, PanicMessage>, ServerError> {
         let version = self.process.version();
 
@@ -198,7 +198,7 @@ impl ProcMacro {
             },
             lib: self.dylib_path.to_path_buf().into(),
             env,
-            current_dir,
+            current_dir: Some(current_dir),
         };
 
         let response = self.process.send_task(Request::ExpandMacro(Box::new(task)))?;
diff --git a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
index 95148bb1d0c..857ea84d9b1 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
@@ -988,6 +988,7 @@ fn project_json_to_crate_graph(
     );
 
     let mut cfg_cache: FxHashMap<&str, Vec<CfgAtom>> = FxHashMap::default();
+    let project_root = Arc::new(project.project_root().to_path_buf());
 
     let idx_to_crate_id: FxHashMap<CrateArrayIdx, _> = project
         .crates()
@@ -1067,7 +1068,10 @@ fn project_json_to_crate_graph(
                         CrateOrigin::Local { repo: None, name: None }
                     },
                     *is_proc_macro,
-                    proc_macro_cwd.clone(),
+                    match proc_macro_cwd {
+                        Some(path) => Arc::new(path.clone()),
+                        None => project_root.clone(),
+                    },
                     crate_ws_data.clone(),
                 );
                 debug!(
@@ -1139,6 +1143,7 @@ fn cargo_to_crate_graph(
     let mut pkg_crates = FxHashMap::default();
     // Does any crate signal to rust-analyzer that they need the rustc_private crates?
     let mut has_private = false;
+    let workspace_proc_macro_cwd = Arc::new(cargo.workspace_root().to_path_buf());
 
     // Next, create crates for each package, target pair
     for pkg in cargo.packages() {
@@ -1161,8 +1166,9 @@ fn cargo_to_crate_graph(
 
         let mut lib_tgt = None;
         for &tgt in cargo[pkg].targets.iter() {
+            let pkg_data = &cargo[pkg];
             if !matches!(cargo[tgt].kind, TargetKind::Lib { .. })
-                && (!cargo[pkg].is_member || cargo.is_sysroot())
+                && (!pkg_data.is_member || cargo.is_sysroot())
             {
                 // For non-workspace-members, Cargo does not resolve dev-dependencies, so we don't
                 // add any targets except the library target, since those will not work correctly if
@@ -1176,7 +1182,6 @@ fn cargo_to_crate_graph(
             let Some(file_id) = load(root) else { continue };
 
             let build_data = build_scripts.get_output(pkg);
-            let pkg_data = &cargo[pkg];
             let crate_id = add_target_crate_root(
                 crate_graph,
                 proc_macros,
@@ -1203,6 +1208,11 @@ fn cargo_to_crate_graph(
                     }
                 },
                 crate_ws_data.clone(),
+                if pkg_data.is_member {
+                    workspace_proc_macro_cwd.clone()
+                } else {
+                    Arc::new(pkg_data.manifest.parent().to_path_buf())
+                },
             );
             if let TargetKind::Lib { .. } = kind {
                 lib_tgt = Some((crate_id, name.clone()));
@@ -1364,7 +1374,7 @@ fn detached_file_to_crate_graph(
             name: display_name.map(|n| n.canonical_name().to_owned()),
         },
         false,
-        None,
+        Arc::new(detached_file.parent().to_path_buf()),
         crate_ws_data,
     );
 
@@ -1372,6 +1382,7 @@ fn detached_file_to_crate_graph(
     (crate_graph, FxHashMap::default())
 }
 
+// FIXME: There shouldn't really be a need for duplicating all of this?
 fn handle_rustc_crates(
     crate_graph: &mut CrateGraphBuilder,
     proc_macros: &mut ProcMacroPaths,
@@ -1391,6 +1402,7 @@ fn handle_rustc_crates(
     // The root package of the rustc-dev component is rustc_driver, so we match that
     let root_pkg =
         rustc_workspace.packages().find(|&package| rustc_workspace[package].name == "rustc_driver");
+    let workspace_proc_macro_cwd = Arc::new(cargo.workspace_root().to_path_buf());
     // The rustc workspace might be incomplete (such as if rustc-dev is not
     // installed for the current toolchain) and `rustc_source` is set to discover.
     if let Some(root_pkg) = root_pkg {
@@ -1404,14 +1416,15 @@ fn handle_rustc_crates(
             if rustc_pkg_crates.contains_key(&pkg) {
                 continue;
             }
-            for dep in &rustc_workspace[pkg].dependencies {
+            let pkg_data = &rustc_workspace[pkg];
+            for dep in &pkg_data.dependencies {
                 queue.push_back(dep.pkg);
             }
 
             let mut cfg_options = cfg_options.clone();
-            override_cfg.apply(&mut cfg_options, &rustc_workspace[pkg].name);
+            override_cfg.apply(&mut cfg_options, &pkg_data.name);
 
-            for &tgt in rustc_workspace[pkg].targets.iter() {
+            for &tgt in pkg_data.targets.iter() {
                 let kind @ TargetKind::Lib { is_proc_macro } = rustc_workspace[tgt].kind else {
                     continue;
                 };
@@ -1421,14 +1434,19 @@ fn handle_rustc_crates(
                         crate_graph,
                         proc_macros,
                         rustc_workspace,
-                        &rustc_workspace[pkg],
+                        pkg_data,
                         build_scripts.get_output(pkg).zip(Some(build_scripts.error().is_some())),
                         cfg_options.clone(),
                         file_id,
                         &rustc_workspace[tgt].name,
                         kind,
-                        CrateOrigin::Rustc { name: Symbol::intern(&rustc_workspace[pkg].name) },
+                        CrateOrigin::Rustc { name: Symbol::intern(&pkg_data.name) },
                         crate_ws_data.clone(),
+                        if pkg_data.is_member {
+                            workspace_proc_macro_cwd.clone()
+                        } else {
+                            Arc::new(pkg_data.manifest.parent().to_path_buf())
+                        },
                     );
                     pkg_to_lib_crate.insert(pkg, crate_id);
                     // Add dependencies on core / std / alloc for this crate
@@ -1490,6 +1508,7 @@ fn add_target_crate_root(
     kind: TargetKind,
     origin: CrateOrigin,
     crate_ws_data: Arc<CrateWorkspaceData>,
+    proc_macro_cwd: Arc<AbsPathBuf>,
 ) -> CrateBuilderId {
     let edition = pkg.edition;
     let potential_cfg_options = if pkg.features.is_empty() {
@@ -1531,9 +1550,7 @@ fn add_target_crate_root(
         env,
         origin,
         matches!(kind, TargetKind::Lib { is_proc_macro: true }),
-        matches!(kind, TargetKind::Lib { is_proc_macro: true }).then(|| {
-            if pkg.is_member { cargo.workspace_root() } else { pkg.manifest.parent() }.to_path_buf()
-        }),
+        proc_macro_cwd,
         crate_ws_data,
     );
     if let TargetKind::Lib { is_proc_macro: true } = kind {
@@ -1706,7 +1723,7 @@ fn sysroot_to_crate_graph(
                         Env::default(),
                         CrateOrigin::Lang(LangCrateOrigin::from(&*stitched[krate].name)),
                         false,
-                        None,
+                        Arc::new(stitched[krate].root.parent().to_path_buf()),
                         crate_ws_data.clone(),
                     );
                     Some((krate, crate_id))
diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model.txt b/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model.txt
index d30d67ed1f3..4ef9d816119 100644
--- a/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model.txt
+++ b/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model.txt
@@ -22,7 +22,9 @@
                 ),
             },
             is_proc_macro: false,
-            proc_macro_cwd: None,
+            proc_macro_cwd: AbsPathBuf(
+                "$ROOT$hello-world",
+            ),
         },
         extra: ExtraCrateData {
             version: Some(
@@ -104,7 +106,9 @@
                 ),
             },
             is_proc_macro: false,
-            proc_macro_cwd: None,
+            proc_macro_cwd: AbsPathBuf(
+                "$ROOT$hello-world",
+            ),
         },
         extra: ExtraCrateData {
             version: Some(
@@ -186,7 +190,9 @@
                 ),
             },
             is_proc_macro: false,
-            proc_macro_cwd: None,
+            proc_macro_cwd: AbsPathBuf(
+                "$ROOT$hello-world",
+            ),
         },
         extra: ExtraCrateData {
             version: Some(
@@ -268,7 +274,9 @@
                 ),
             },
             is_proc_macro: false,
-            proc_macro_cwd: None,
+            proc_macro_cwd: AbsPathBuf(
+                "$ROOT$hello-world",
+            ),
         },
         extra: ExtraCrateData {
             version: Some(
@@ -333,7 +341,9 @@
                 name: "libc",
             },
             is_proc_macro: false,
-            proc_macro_cwd: None,
+            proc_macro_cwd: AbsPathBuf(
+                "$ROOT$.cargo/registry/src/github.com-1ecc6299db9ec823/libc-0.2.98",
+            ),
         },
         extra: ExtraCrateData {
             version: Some(
diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt b/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt
index d30d67ed1f3..4ef9d816119 100644
--- a/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt
+++ b/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt
@@ -22,7 +22,9 @@
                 ),
             },
             is_proc_macro: false,
-            proc_macro_cwd: None,
+            proc_macro_cwd: AbsPathBuf(
+                "$ROOT$hello-world",
+            ),
         },
         extra: ExtraCrateData {
             version: Some(
@@ -104,7 +106,9 @@
                 ),
             },
             is_proc_macro: false,
-            proc_macro_cwd: None,
+            proc_macro_cwd: AbsPathBuf(
+                "$ROOT$hello-world",
+            ),
         },
         extra: ExtraCrateData {
             version: Some(
@@ -186,7 +190,9 @@
                 ),
             },
             is_proc_macro: false,
-            proc_macro_cwd: None,
+            proc_macro_cwd: AbsPathBuf(
+                "$ROOT$hello-world",
+            ),
         },
         extra: ExtraCrateData {
             version: Some(
@@ -268,7 +274,9 @@
                 ),
             },
             is_proc_macro: false,
-            proc_macro_cwd: None,
+            proc_macro_cwd: AbsPathBuf(
+                "$ROOT$hello-world",
+            ),
         },
         extra: ExtraCrateData {
             version: Some(
@@ -333,7 +341,9 @@
                 name: "libc",
             },
             is_proc_macro: false,
-            proc_macro_cwd: None,
+            proc_macro_cwd: AbsPathBuf(
+                "$ROOT$.cargo/registry/src/github.com-1ecc6299db9ec823/libc-0.2.98",
+            ),
         },
         extra: ExtraCrateData {
             version: Some(
diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_wildcard_overrides.txt b/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_wildcard_overrides.txt
index 925233ceb41..52089d1dbc2 100644
--- a/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_wildcard_overrides.txt
+++ b/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_wildcard_overrides.txt
@@ -22,7 +22,9 @@
                 ),
             },
             is_proc_macro: false,
-            proc_macro_cwd: None,
+            proc_macro_cwd: AbsPathBuf(
+                "$ROOT$hello-world",
+            ),
         },
         extra: ExtraCrateData {
             version: Some(
@@ -103,7 +105,9 @@
                 ),
             },
             is_proc_macro: false,
-            proc_macro_cwd: None,
+            proc_macro_cwd: AbsPathBuf(
+                "$ROOT$hello-world",
+            ),
         },
         extra: ExtraCrateData {
             version: Some(
@@ -184,7 +188,9 @@
                 ),
             },
             is_proc_macro: false,
-            proc_macro_cwd: None,
+            proc_macro_cwd: AbsPathBuf(
+                "$ROOT$hello-world",
+            ),
         },
         extra: ExtraCrateData {
             version: Some(
@@ -265,7 +271,9 @@
                 ),
             },
             is_proc_macro: false,
-            proc_macro_cwd: None,
+            proc_macro_cwd: AbsPathBuf(
+                "$ROOT$hello-world",
+            ),
         },
         extra: ExtraCrateData {
             version: Some(
@@ -329,7 +337,9 @@
                 name: "libc",
             },
             is_proc_macro: false,
-            proc_macro_cwd: None,
+            proc_macro_cwd: AbsPathBuf(
+                "$ROOT$.cargo/registry/src/github.com-1ecc6299db9ec823/libc-0.2.98",
+            ),
         },
         extra: ExtraCrateData {
             version: Some(
diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_cfg_groups.txt b/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_cfg_groups.txt
index 5f18d5e3f08..98fe598eb3a 100644
--- a/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_cfg_groups.txt
+++ b/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_cfg_groups.txt
@@ -13,7 +13,9 @@
                 ),
             },
             is_proc_macro: false,
-            proc_macro_cwd: None,
+            proc_macro_cwd: AbsPathBuf(
+                "$ROOT$",
+            ),
         },
         extra: ExtraCrateData {
             version: None,
@@ -61,7 +63,9 @@
                 ),
             },
             is_proc_macro: false,
-            proc_macro_cwd: None,
+            proc_macro_cwd: AbsPathBuf(
+                "$ROOT$",
+            ),
         },
         extra: ExtraCrateData {
             version: None,
diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt b/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt
index 5cb9992b203..0dc373b5b47 100644
--- a/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt
+++ b/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt
@@ -13,7 +13,9 @@
                 ),
             },
             is_proc_macro: false,
-            proc_macro_cwd: None,
+            proc_macro_cwd: AbsPathBuf(
+                "$ROOT$",
+            ),
         },
         extra: ExtraCrateData {
             version: None,
diff --git a/src/tools/rust-analyzer/crates/test-fixture/Cargo.toml b/src/tools/rust-analyzer/crates/test-fixture/Cargo.toml
index 2547a02a291..353d4c312db 100644
--- a/src/tools/rust-analyzer/crates/test-fixture/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/test-fixture/Cargo.toml
@@ -19,6 +19,7 @@ span.workspace = true
 stdx.workspace = true
 intern.workspace = true
 triomphe.workspace = true
+paths.workspace = true
 
 [lints]
 workspace = true
diff --git a/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs b/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs
index f0b85b4ab33..0509a39bda8 100644
--- a/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs
@@ -19,6 +19,7 @@ use hir_expand::{
     tt::{Leaf, TokenTree, TopSubtree, TopSubtreeBuilder, TtElement, TtIter},
 };
 use intern::{Symbol, sym};
+use paths::AbsPathBuf;
 use rustc_hash::FxHashMap;
 use span::{Edition, EditionedFileId, FileId, Span};
 use stdx::itertools::Itertools;
@@ -162,6 +163,9 @@ impl ChangeFixture {
         let crate_ws_data =
             Arc::new(CrateWorkspaceData { data_layout: target_data_layout, toolchain });
 
+        // FIXME: This is less than ideal
+        let proc_macro_cwd = Arc::new(AbsPathBuf::assert_utf8(std::env::current_dir().unwrap()));
+
         for entry in fixture {
             let mut range_or_offset = None;
             let text = if entry.text.contains(CURSOR_MARKER) {
@@ -213,7 +217,7 @@ impl ChangeFixture {
                     meta.env,
                     origin,
                     false,
-                    None,
+                    proc_macro_cwd.clone(),
                     crate_ws_data.clone(),
                 );
                 let prev = crates.insert(crate_name.clone(), crate_id);
@@ -254,7 +258,7 @@ impl ChangeFixture {
                 default_env,
                 CrateOrigin::Local { repo: None, name: None },
                 false,
-                None,
+                proc_macro_cwd.clone(),
                 crate_ws_data.clone(),
             );
         } else {
@@ -296,7 +300,7 @@ impl ChangeFixture {
                 )]),
                 CrateOrigin::Lang(LangCrateOrigin::Core),
                 false,
-                None,
+                proc_macro_cwd.clone(),
                 crate_ws_data.clone(),
             );
 
@@ -345,7 +349,7 @@ impl ChangeFixture {
                 )]),
                 CrateOrigin::Local { repo: None, name: None },
                 true,
-                None,
+                proc_macro_cwd.clone(),
                 crate_ws_data,
             );
             proc_macros.insert(proc_macros_crate, Ok(proc_macro));
@@ -650,7 +654,7 @@ impl ProcMacroExpander for IdentityProcMacroExpander {
         _: Span,
         _: Span,
         _: Span,
-        _: Option<String>,
+        _: String,
     ) -> Result<TopSubtree, ProcMacroExpansionError> {
         Ok(subtree.clone())
     }
@@ -672,7 +676,7 @@ impl ProcMacroExpander for Issue18089ProcMacroExpander {
         _: Span,
         call_site: Span,
         _: Span,
-        _: Option<String>,
+        _: String,
     ) -> Result<TopSubtree, ProcMacroExpansionError> {
         let tt::TokenTree::Leaf(macro_name) = &subtree.0[2] else {
             return Err(ProcMacroExpansionError::Panic("incorrect input".to_owned()));
@@ -707,7 +711,7 @@ impl ProcMacroExpander for AttributeInputReplaceProcMacroExpander {
         _: Span,
         _: Span,
         _: Span,
-        _: Option<String>,
+        _: String,
     ) -> Result<TopSubtree, ProcMacroExpansionError> {
         attrs
             .cloned()
@@ -730,7 +734,7 @@ impl ProcMacroExpander for Issue18840ProcMacroExpander {
         def_site: Span,
         _: Span,
         _: Span,
-        _: Option<String>,
+        _: String,
     ) -> Result<TopSubtree, ProcMacroExpansionError> {
         // Input:
         // ```
@@ -765,7 +769,7 @@ impl ProcMacroExpander for MirrorProcMacroExpander {
         _: Span,
         _: Span,
         _: Span,
-        _: Option<String>,
+        _: String,
     ) -> Result<TopSubtree, ProcMacroExpansionError> {
         fn traverse(builder: &mut TopSubtreeBuilder, iter: TtIter<'_>) {
             for tt in iter.collect_vec().into_iter().rev() {
@@ -803,7 +807,7 @@ impl ProcMacroExpander for ShortenProcMacroExpander {
         _: Span,
         _: Span,
         _: Span,
-        _: Option<String>,
+        _: String,
     ) -> Result<TopSubtree, ProcMacroExpansionError> {
         let mut result = input.0.clone();
         for it in &mut result {
@@ -845,7 +849,7 @@ impl ProcMacroExpander for Issue17479ProcMacroExpander {
         _: Span,
         _: Span,
         _: Span,
-        _: Option<String>,
+        _: String,
     ) -> Result<TopSubtree, ProcMacroExpansionError> {
         let TokenTree::Leaf(Leaf::Literal(lit)) = &subtree.0[1] else {
             return Err(ProcMacroExpansionError::Panic("incorrect Input".into()));
@@ -874,7 +878,7 @@ impl ProcMacroExpander for Issue18898ProcMacroExpander {
         def_site: Span,
         _: Span,
         _: Span,
-        _: Option<String>,
+        _: String,
     ) -> Result<TopSubtree, ProcMacroExpansionError> {
         let span = subtree
             .token_trees()
@@ -929,7 +933,7 @@ impl ProcMacroExpander for DisallowCfgProcMacroExpander {
         _: Span,
         _: Span,
         _: Span,
-        _: Option<String>,
+        _: String,
     ) -> Result<TopSubtree, ProcMacroExpansionError> {
         for tt in subtree.token_trees().flat_tokens() {
             if let tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) = tt {