about summary refs log tree commit diff
path: root/src/tools/rust-analyzer/crates/proc-macro-srv
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools/rust-analyzer/crates/proc-macro-srv')
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-srv/Cargo.toml2
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-srv/src/dylib.rs215
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-srv/src/dylib/proc_macros.rs (renamed from src/tools/rust-analyzer/crates/proc-macro-srv/src/proc_macros.rs)23
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs71
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl.rs2
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_id.rs53
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/utils.rs16
7 files changed, 193 insertions, 189 deletions
diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/Cargo.toml b/src/tools/rust-analyzer/crates/proc-macro-srv/Cargo.toml
index 4034f244393..d037e715e70 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-srv/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/proc-macro-srv/Cargo.toml
@@ -16,6 +16,7 @@ doctest = false
 object.workspace = true
 libloading.workspace = true
 memmap2.workspace = true
+temp-dir.workspace = true
 
 tt.workspace = true
 syntax-bridge.workspace = true
@@ -26,6 +27,7 @@ intern.workspace = true
 
 ra-ap-rustc_lexer.workspace = true
 
+
 [target.'cfg(unix)'.dependencies]
 libc.workspace = true
 
diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/dylib.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/dylib.rs
index c49159df991..c8513a10675 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/dylib.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/dylib.rs
@@ -1,65 +1,66 @@
 //! Handles dynamic library loading for proc macro
 
+mod proc_macros;
 mod version;
 
 use proc_macro::bridge;
 use std::{fmt, fs, io, time::SystemTime};
+use temp_dir::TempDir;
 
 use libloading::Library;
 use object::Object;
 use paths::{Utf8Path, Utf8PathBuf};
 
-use crate::{ProcMacroKind, ProcMacroSrvSpan, proc_macros::ProcMacros, server_impl::TopSubtree};
+use crate::{
+    PanicMessage, ProcMacroKind, ProcMacroSrvSpan, dylib::proc_macros::ProcMacros,
+    server_impl::TopSubtree,
+};
 
-/// Loads dynamic library in platform dependent manner.
-///
-/// For unix, you have to use RTLD_DEEPBIND flag to escape problems described
-/// [here](https://github.com/fedochet/rust-proc-macro-panic-inside-panic-expample)
-/// and [here](https://github.com/rust-lang/rust/issues/60593).
-///
-/// Usage of RTLD_DEEPBIND
-/// [here](https://github.com/fedochet/rust-proc-macro-panic-inside-panic-expample/issues/1)
-///
-/// It seems that on Windows that behaviour is default, so we do nothing in that case.
-///
-/// # Safety
-///
-/// The caller is responsible for ensuring that the path is valid proc-macro library
-#[cfg(windows)]
-unsafe fn load_library(file: &Utf8Path) -> Result<Library, libloading::Error> {
-    // SAFETY: The caller is responsible for ensuring that the path is valid proc-macro library
-    unsafe { Library::new(file) }
+pub(crate) struct Expander {
+    inner: ProcMacroLibrary,
+    modified_time: SystemTime,
 }
 
-/// Loads dynamic library in platform dependent manner.
-///
-/// For unix, you have to use RTLD_DEEPBIND flag to escape problems described
-/// [here](https://github.com/fedochet/rust-proc-macro-panic-inside-panic-expample)
-/// and [here](https://github.com/rust-lang/rust/issues/60593).
-///
-/// Usage of RTLD_DEEPBIND
-/// [here](https://github.com/fedochet/rust-proc-macro-panic-inside-panic-expample/issues/1)
-///
-/// It seems that on Windows that behaviour is default, so we do nothing in that case.
-///
-/// # Safety
-///
-/// The caller is responsible for ensuring that the path is valid proc-macro library
-#[cfg(unix)]
-unsafe fn load_library(file: &Utf8Path) -> Result<Library, libloading::Error> {
-    // not defined by POSIX, different values on mips vs other targets
-    #[cfg(target_env = "gnu")]
-    use libc::RTLD_DEEPBIND;
-    use libloading::os::unix::Library as UnixLibrary;
-    // defined by POSIX
-    use libloading::os::unix::RTLD_NOW;
+impl Expander {
+    pub(crate) fn new(
+        temp_dir: &TempDir,
+        lib: &Utf8Path,
+    ) -> Result<Expander, LoadProcMacroDylibError> {
+        // Some libraries for dynamic loading require canonicalized path even when it is
+        // already absolute
+        let lib = lib.canonicalize_utf8()?;
+        let modified_time = fs::metadata(&lib).and_then(|it| it.modified())?;
 
-    // MUSL and bionic don't have it..
-    #[cfg(not(target_env = "gnu"))]
-    const RTLD_DEEPBIND: std::os::raw::c_int = 0x0;
+        let path = ensure_file_with_lock_free_access(temp_dir, &lib)?;
+        let library = ProcMacroLibrary::open(path.as_ref())?;
 
-    // SAFETY: The caller is responsible for ensuring that the path is valid proc-macro library
-    unsafe { UnixLibrary::open(Some(file), RTLD_NOW | RTLD_DEEPBIND).map(|lib| lib.into()) }
+        Ok(Expander { inner: library, modified_time })
+    }
+
+    pub(crate) fn expand<S: ProcMacroSrvSpan>(
+        &self,
+        macro_name: &str,
+        macro_body: TopSubtree<S>,
+        attributes: Option<TopSubtree<S>>,
+        def_site: S,
+        call_site: S,
+        mixed_site: S,
+    ) -> Result<TopSubtree<S>, PanicMessage>
+    where
+        <S::Server as bridge::server::Types>::TokenStream: Default,
+    {
+        self.inner
+            .proc_macros
+            .expand(macro_name, macro_body, attributes, def_site, call_site, mixed_site)
+    }
+
+    pub(crate) fn list_macros(&self) -> impl Iterator<Item = (&str, ProcMacroKind)> {
+        self.inner.proc_macros.list_macros()
+    }
+
+    pub(crate) fn modified_time(&self) -> SystemTime {
+        self.modified_time
+    }
 }
 
 #[derive(Debug)]
@@ -133,54 +134,6 @@ impl ProcMacroLibrary {
     }
 }
 
-// Drop order matters as we can't remove the dylib before the library is unloaded
-pub(crate) struct Expander {
-    inner: ProcMacroLibrary,
-    _remove_on_drop: RemoveFileOnDrop,
-    modified_time: SystemTime,
-}
-
-impl Expander {
-    pub(crate) fn new(lib: &Utf8Path) -> Result<Expander, LoadProcMacroDylibError> {
-        // Some libraries for dynamic loading require canonicalized path even when it is
-        // already absolute
-        let lib = lib.canonicalize_utf8()?;
-        let modified_time = fs::metadata(&lib).and_then(|it| it.modified())?;
-
-        let path = ensure_file_with_lock_free_access(&lib)?;
-        let library = ProcMacroLibrary::open(path.as_ref())?;
-
-        Ok(Expander { inner: library, _remove_on_drop: RemoveFileOnDrop(path), modified_time })
-    }
-
-    pub(crate) fn expand<S: ProcMacroSrvSpan>(
-        &self,
-        macro_name: &str,
-        macro_body: TopSubtree<S>,
-        attributes: Option<TopSubtree<S>>,
-        def_site: S,
-        call_site: S,
-        mixed_site: S,
-    ) -> Result<TopSubtree<S>, String>
-    where
-        <S::Server as bridge::server::Types>::TokenStream: Default,
-    {
-        let result = self
-            .inner
-            .proc_macros
-            .expand(macro_name, macro_body, attributes, def_site, call_site, mixed_site);
-        result.map_err(|e| e.into_string().unwrap_or_default())
-    }
-
-    pub(crate) fn list_macros(&self) -> Vec<(String, ProcMacroKind)> {
-        self.inner.proc_macros.list_macros()
-    }
-
-    pub(crate) fn modified_time(&self) -> SystemTime {
-        self.modified_time
-    }
-}
-
 fn invalid_data_err(e: impl Into<Box<dyn std::error::Error + Send + Sync>>) -> io::Error {
     io::Error::new(io::ErrorKind::InvalidData, e)
 }
@@ -210,18 +163,12 @@ fn find_registrar_symbol(obj: &object::File<'_>) -> object::Result<Option<String
         }))
 }
 
-struct RemoveFileOnDrop(Utf8PathBuf);
-impl Drop for RemoveFileOnDrop {
-    fn drop(&mut self) {
-        #[cfg(windows)]
-        std::fs::remove_file(&self.0).unwrap();
-        _ = self.0;
-    }
-}
-
 /// Copy the dylib to temp directory to prevent locking in Windows
 #[cfg(windows)]
-fn ensure_file_with_lock_free_access(path: &Utf8Path) -> io::Result<Utf8PathBuf> {
+fn ensure_file_with_lock_free_access(
+    temp_dir: &TempDir,
+    path: &Utf8Path,
+) -> io::Result<Utf8PathBuf> {
     use std::collections::hash_map::RandomState;
     use std::hash::{BuildHasher, Hasher};
 
@@ -229,9 +176,7 @@ fn ensure_file_with_lock_free_access(path: &Utf8Path) -> io::Result<Utf8PathBuf>
         return Ok(path.to_path_buf());
     }
 
-    let mut to = Utf8PathBuf::from_path_buf(std::env::temp_dir()).unwrap();
-    to.push("rust-analyzer-proc-macros");
-    _ = fs::create_dir(&to);
+    let mut to = Utf8Path::from_path(temp_dir.path()).unwrap().to_owned();
 
     let file_name = path.file_stem().ok_or_else(|| {
         io::Error::new(io::ErrorKind::InvalidInput, format!("File path is invalid: {path}"))
@@ -248,6 +193,60 @@ fn ensure_file_with_lock_free_access(path: &Utf8Path) -> io::Result<Utf8PathBuf>
 }
 
 #[cfg(unix)]
-fn ensure_file_with_lock_free_access(path: &Utf8Path) -> io::Result<Utf8PathBuf> {
+fn ensure_file_with_lock_free_access(
+    _temp_dir: &TempDir,
+    path: &Utf8Path,
+) -> io::Result<Utf8PathBuf> {
     Ok(path.to_owned())
 }
+
+/// Loads dynamic library in platform dependent manner.
+///
+/// For unix, you have to use RTLD_DEEPBIND flag to escape problems described
+/// [here](https://github.com/fedochet/rust-proc-macro-panic-inside-panic-expample)
+/// and [here](https://github.com/rust-lang/rust/issues/60593).
+///
+/// Usage of RTLD_DEEPBIND
+/// [here](https://github.com/fedochet/rust-proc-macro-panic-inside-panic-expample/issues/1)
+///
+/// It seems that on Windows that behaviour is default, so we do nothing in that case.
+///
+/// # Safety
+///
+/// The caller is responsible for ensuring that the path is valid proc-macro library
+#[cfg(windows)]
+unsafe fn load_library(file: &Utf8Path) -> Result<Library, libloading::Error> {
+    // SAFETY: The caller is responsible for ensuring that the path is valid proc-macro library
+    unsafe { Library::new(file) }
+}
+
+/// Loads dynamic library in platform dependent manner.
+///
+/// For unix, you have to use RTLD_DEEPBIND flag to escape problems described
+/// [here](https://github.com/fedochet/rust-proc-macro-panic-inside-panic-expample)
+/// and [here](https://github.com/rust-lang/rust/issues/60593).
+///
+/// Usage of RTLD_DEEPBIND
+/// [here](https://github.com/fedochet/rust-proc-macro-panic-inside-panic-expample/issues/1)
+///
+/// It seems that on Windows that behaviour is default, so we do nothing in that case.
+///
+/// # Safety
+///
+/// The caller is responsible for ensuring that the path is valid proc-macro library
+#[cfg(unix)]
+unsafe fn load_library(file: &Utf8Path) -> Result<Library, libloading::Error> {
+    // not defined by POSIX, different values on mips vs other targets
+    #[cfg(target_env = "gnu")]
+    use libc::RTLD_DEEPBIND;
+    use libloading::os::unix::Library as UnixLibrary;
+    // defined by POSIX
+    use libloading::os::unix::RTLD_NOW;
+
+    // MUSL and bionic don't have it..
+    #[cfg(not(target_env = "gnu"))]
+    const RTLD_DEEPBIND: std::os::raw::c_int = 0x0;
+
+    // SAFETY: The caller is responsible for ensuring that the path is valid proc-macro library
+    unsafe { UnixLibrary::open(Some(file), RTLD_NOW | RTLD_DEEPBIND).map(|lib| lib.into()) }
+}
diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/proc_macros.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/dylib/proc_macros.rs
index 18532706c4a..9b5721e370a 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/proc_macros.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/dylib/proc_macros.rs
@@ -75,20 +75,13 @@ impl ProcMacros {
         Err(bridge::PanicMessage::String(format!("proc-macro `{macro_name}` is missing")).into())
     }
 
-    pub(crate) fn list_macros(&self) -> Vec<(String, ProcMacroKind)> {
-        self.0
-            .iter()
-            .map(|proc_macro| match proc_macro {
-                bridge::client::ProcMacro::CustomDerive { trait_name, .. } => {
-                    (trait_name.to_string(), ProcMacroKind::CustomDerive)
-                }
-                bridge::client::ProcMacro::Bang { name, .. } => {
-                    (name.to_string(), ProcMacroKind::Bang)
-                }
-                bridge::client::ProcMacro::Attr { name, .. } => {
-                    (name.to_string(), ProcMacroKind::Attr)
-                }
-            })
-            .collect()
+    pub(crate) fn list_macros(&self) -> impl Iterator<Item = (&str, ProcMacroKind)> {
+        self.0.iter().map(|proc_macro| match *proc_macro {
+            bridge::client::ProcMacro::CustomDerive { trait_name, .. } => {
+                (trait_name, ProcMacroKind::CustomDerive)
+            }
+            bridge::client::ProcMacro::Bang { name, .. } => (name, ProcMacroKind::Bang),
+            bridge::client::ProcMacro::Attr { name, .. } => (name, ProcMacroKind::Attr),
+        })
     }
 }
diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs
index 223c5a54b70..cb97882c585 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs
@@ -27,7 +27,6 @@ extern crate ra_ap_rustc_lexer as rustc_lexer;
 extern crate rustc_lexer;
 
 mod dylib;
-mod proc_macros;
 mod server_impl;
 
 use std::{
@@ -41,10 +40,13 @@ use std::{
 };
 
 use paths::{Utf8Path, Utf8PathBuf};
-use span::{Span, TokenId};
+use span::Span;
+use temp_dir::TempDir;
 
 use crate::server_impl::TokenStream;
 
+pub use crate::server_impl::token_id::SpanId;
+
 #[derive(Copy, Clone, Eq, PartialEq, Debug)]
 pub enum ProcMacroKind {
     CustomDerive,
@@ -57,11 +59,16 @@ pub const RUSTC_VERSION_STRING: &str = env!("RUSTC_VERSION");
 pub struct ProcMacroSrv<'env> {
     expanders: Mutex<HashMap<Utf8PathBuf, Arc<dylib::Expander>>>,
     env: &'env EnvSnapshot,
+    temp_dir: TempDir,
 }
 
 impl<'env> ProcMacroSrv<'env> {
     pub fn new(env: &'env EnvSnapshot) -> Self {
-        Self { expanders: Default::default(), env }
+        Self {
+            expanders: Default::default(),
+            env,
+            temp_dir: TempDir::with_prefix("proc-macro-srv").unwrap(),
+        }
     }
 }
 
@@ -71,18 +78,19 @@ impl ProcMacroSrv<'_> {
     pub fn expand<S: ProcMacroSrvSpan>(
         &self,
         lib: impl AsRef<Utf8Path>,
-        env: Vec<(String, String)>,
+        env: &[(String, String)],
         current_dir: Option<impl AsRef<Path>>,
-        macro_name: String,
+        macro_name: &str,
         macro_body: tt::TopSubtree<S>,
         attribute: Option<tt::TopSubtree<S>>,
         def_site: S,
         call_site: S,
         mixed_site: S,
-    ) -> Result<Vec<tt::TokenTree<S>>, String> {
+    ) -> Result<Vec<tt::TokenTree<S>>, PanicMessage> {
         let snapped_env = self.env;
-        let expander =
-            self.expander(lib.as_ref()).map_err(|err| format!("failed to load macro: {err}"))?;
+        let expander = self.expander(lib.as_ref()).map_err(|err| PanicMessage {
+            message: Some(format!("failed to load macro: {err}")),
+        })?;
 
         let prev_env = EnvChange::apply(snapped_env, env, current_dir.as_ref().map(<_>::as_ref));
 
@@ -91,11 +99,11 @@ impl ProcMacroSrv<'_> {
         let result = thread::scope(|s| {
             let thread = thread::Builder::new()
                 .stack_size(EXPANDER_STACK_SIZE)
-                .name(macro_name.clone())
+                .name(macro_name.to_owned())
                 .spawn_scoped(s, move || {
                     expander
                         .expand(
-                            &macro_name,
+                            macro_name,
                             server_impl::TopSubtree(macro_body.0.into_vec()),
                             attribute.map(|it| server_impl::TopSubtree(it.0.into_vec())),
                             def_site,
@@ -104,12 +112,7 @@ impl ProcMacroSrv<'_> {
                         )
                         .map(|tt| tt.0)
                 });
-            let res = match thread {
-                Ok(handle) => handle.join(),
-                Err(e) => return Err(e.to_string()),
-            };
-
-            match res {
+            match thread.unwrap().join() {
                 Ok(res) => res,
                 Err(e) => std::panic::resume_unwind(e),
             }
@@ -124,12 +127,12 @@ impl ProcMacroSrv<'_> {
         dylib_path: &Utf8Path,
     ) -> Result<Vec<(String, ProcMacroKind)>, String> {
         let expander = self.expander(dylib_path)?;
-        Ok(expander.list_macros())
+        Ok(expander.list_macros().map(|(k, v)| (k.to_owned(), v)).collect())
     }
 
     fn expander(&self, path: &Utf8Path) -> Result<Arc<dylib::Expander>, String> {
         let expander = || {
-            let expander = dylib::Expander::new(path)
+            let expander = dylib::Expander::new(&self.temp_dir, path)
                 .map_err(|err| format!("Cannot create expander for {path}: {err}",));
             expander.map(Arc::new)
         };
@@ -159,8 +162,8 @@ pub trait ProcMacroSrvSpan: Copy + Send {
     fn make_server(call_site: Self, def_site: Self, mixed_site: Self) -> Self::Server;
 }
 
-impl ProcMacroSrvSpan for TokenId {
-    type Server = server_impl::token_id::TokenIdServer;
+impl ProcMacroSrvSpan for SpanId {
+    type Server = server_impl::token_id::SpanIdServer;
 
     fn make_server(call_site: Self, def_site: Self, mixed_site: Self) -> Self::Server {
         Self::Server { call_site, def_site, mixed_site }
@@ -178,6 +181,8 @@ impl ProcMacroSrvSpan for Span {
         }
     }
 }
+
+#[derive(Debug, Clone)]
 pub struct PanicMessage {
     message: Option<String>,
 }
@@ -201,7 +206,7 @@ impl Default for EnvSnapshot {
 static ENV_LOCK: std::sync::Mutex<()> = std::sync::Mutex::new(());
 
 struct EnvChange<'snap> {
-    changed_vars: Vec<String>,
+    changed_vars: Vec<&'snap str>,
     prev_working_dir: Option<PathBuf>,
     snap: &'snap EnvSnapshot,
     _guard: std::sync::MutexGuard<'snap, ()>,
@@ -210,7 +215,7 @@ struct EnvChange<'snap> {
 impl<'snap> EnvChange<'snap> {
     fn apply(
         snap: &'snap EnvSnapshot,
-        new_vars: Vec<(String, String)>,
+        new_vars: &'snap [(String, String)],
         current_dir: Option<&Path>,
     ) -> EnvChange<'snap> {
         let guard = ENV_LOCK.lock().unwrap_or_else(std::sync::PoisonError::into_inner);
@@ -230,11 +235,11 @@ impl<'snap> EnvChange<'snap> {
         EnvChange {
             snap,
             changed_vars: new_vars
-                .into_iter()
+                .iter()
                 .map(|(k, v)| {
                     // SAFETY: We have acquired the environment lock
-                    unsafe { env::set_var(&k, v) };
-                    k
+                    unsafe { env::set_var(k, v) };
+                    &**k
                 })
                 .collect(),
             prev_working_dir,
@@ -257,14 +262,14 @@ impl Drop for EnvChange<'_> {
             }
         }
 
-        if let Some(dir) = &self.prev_working_dir {
-            if let Err(err) = std::env::set_current_dir(dir) {
-                eprintln!(
-                    "Failed to set the current working dir to {}. Error: {:?}",
-                    dir.display(),
-                    err
-                )
-            }
+        if let Some(dir) = &self.prev_working_dir
+            && let Err(err) = std::env::set_current_dir(dir)
+        {
+            eprintln!(
+                "Failed to set the current working dir to {}. Error: {:?}",
+                dir.display(),
+                err
+            )
         }
     }
 }
diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl.rs
index 662f6257642..32ad32731ba 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl.rs
@@ -209,7 +209,7 @@ pub(super) fn from_token_tree<Span: Copy>(
                 token_trees.push(tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct {
                     spacing: tt::Spacing::Alone,
                     span: literal.span,
-                    char: '-' as char,
+                    char: '-',
                 })));
                 symbol = Symbol::intern(&symbol.as_str()[1..]);
             }
diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_id.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_id.rs
index b493b325e83..91e70ea243a 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_id.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_id.rs
@@ -1,4 +1,4 @@
-//! proc-macro server backend based on [`proc_macro_api::msg::TokenId`] as the backing span.
+//! proc-macro server backend based on [`proc_macro_api::msg::SpanId`] as the backing span.
 //! This backend is rather inflexible, used by RustRover and older rust-analyzer versions.
 use std::ops::{Bound, Range};
 
@@ -7,25 +7,34 @@ use proc_macro::bridge::{self, server};
 
 use crate::server_impl::{from_token_tree, literal_from_str, token_stream::TokenStreamBuilder};
 
-type Span = span::TokenId;
+#[derive(Clone, Copy, PartialEq, Eq, Hash)]
+pub struct SpanId(pub u32);
+
+impl std::fmt::Debug for SpanId {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        self.0.fmt(f)
+    }
+}
+
+type Span = SpanId;
 type TokenStream = crate::server_impl::TokenStream<Span>;
 
 pub struct FreeFunctions;
 
-pub struct TokenIdServer {
+pub struct SpanIdServer {
     pub call_site: Span,
     pub def_site: Span,
     pub mixed_site: Span,
 }
 
-impl server::Types for TokenIdServer {
+impl server::Types for SpanIdServer {
     type FreeFunctions = FreeFunctions;
     type TokenStream = TokenStream;
     type Span = Span;
     type Symbol = Symbol;
 }
 
-impl server::FreeFunctions for TokenIdServer {
+impl server::FreeFunctions for SpanIdServer {
     fn injected_env_var(&mut self, _: &str) -> Option<std::string::String> {
         None
     }
@@ -41,7 +50,7 @@ impl server::FreeFunctions for TokenIdServer {
     fn emit_diagnostic(&mut self, _: bridge::Diagnostic<Self::Span>) {}
 }
 
-impl server::TokenStream for TokenIdServer {
+impl server::TokenStream for SpanIdServer {
     fn is_empty(&mut self, stream: &Self::TokenStream) -> bool {
         stream.is_empty()
     }
@@ -102,12 +111,12 @@ impl server::TokenStream for TokenIdServer {
         &mut self,
         stream: Self::TokenStream,
     ) -> Vec<bridge::TokenTree<Self::TokenStream, Self::Span, Self::Symbol>> {
-        // Can't join with `TokenId`.
+        // Can't join with `SpanId`.
         stream.into_bridge(&mut |first, _second| first)
     }
 }
 
-impl server::Span for TokenIdServer {
+impl server::Span for SpanIdServer {
     fn debug(&mut self, span: Self::Span) -> String {
         format!("{:?}", span.0)
     }
@@ -174,14 +183,14 @@ impl server::Span for TokenIdServer {
     }
 }
 
-impl server::Symbol for TokenIdServer {
+impl server::Symbol for SpanIdServer {
     fn normalize_and_validate_ident(&mut self, string: &str) -> Result<Self::Symbol, ()> {
         // FIXME: nfc-normalize and validate idents
         Ok(<Self as server::Server>::intern_symbol(string))
     }
 }
 
-impl server::Server for TokenIdServer {
+impl server::Server for SpanIdServer {
     fn globals(&mut self) -> bridge::ExpnGlobals<Self::Span> {
         bridge::ExpnGlobals {
             def_site: self.def_site,
@@ -201,8 +210,6 @@ impl server::Server for TokenIdServer {
 
 #[cfg(test)]
 mod tests {
-    use span::TokenId;
-
     use super::*;
 
     #[test]
@@ -211,18 +218,18 @@ mod tests {
             token_trees: vec![
                 tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident {
                     sym: Symbol::intern("struct"),
-                    span: TokenId(0),
+                    span: SpanId(0),
                     is_raw: tt::IdentIsRaw::No,
                 })),
                 tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident {
                     sym: Symbol::intern("T"),
-                    span: TokenId(0),
+                    span: SpanId(0),
                     is_raw: tt::IdentIsRaw::No,
                 })),
                 tt::TokenTree::Subtree(tt::Subtree {
                     delimiter: tt::Delimiter {
-                        open: TokenId(0),
-                        close: TokenId(0),
+                        open: SpanId(0),
+                        close: SpanId(0),
                         kind: tt::DelimiterKind::Brace,
                     },
                     len: 0,
@@ -238,8 +245,8 @@ mod tests {
         let subtree_paren_a = vec![
             tt::TokenTree::Subtree(tt::Subtree {
                 delimiter: tt::Delimiter {
-                    open: TokenId(0),
-                    close: TokenId(0),
+                    open: SpanId(0),
+                    close: SpanId(0),
                     kind: tt::DelimiterKind::Parenthesis,
                 },
                 len: 1,
@@ -247,24 +254,24 @@ mod tests {
             tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident {
                 is_raw: tt::IdentIsRaw::No,
                 sym: Symbol::intern("a"),
-                span: TokenId(0),
+                span: SpanId(0),
             })),
         ];
 
-        let t1 = TokenStream::from_str("(a)", TokenId(0)).unwrap();
+        let t1 = TokenStream::from_str("(a)", SpanId(0)).unwrap();
         assert_eq!(t1.token_trees.len(), 2);
         assert!(t1.token_trees[0..2] == subtree_paren_a);
 
-        let t2 = TokenStream::from_str("(a);", TokenId(0)).unwrap();
+        let t2 = TokenStream::from_str("(a);", SpanId(0)).unwrap();
         assert_eq!(t2.token_trees.len(), 3);
         assert!(t2.token_trees[0..2] == subtree_paren_a);
 
-        let underscore = TokenStream::from_str("_", TokenId(0)).unwrap();
+        let underscore = TokenStream::from_str("_", SpanId(0)).unwrap();
         assert!(
             underscore.token_trees[0]
                 == tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident {
                     sym: Symbol::intern("_"),
-                    span: TokenId(0),
+                    span: SpanId(0),
                     is_raw: tt::IdentIsRaw::No,
                 }))
         );
diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/utils.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/utils.rs
index 10af5662b5c..f5a76e30bbc 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/utils.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/utils.rs
@@ -1,14 +1,12 @@
 //! utils used in proc-macro tests
 
 use expect_test::Expect;
-use span::{
-    EditionedFileId, FileId, ROOT_ERASED_FILE_AST_ID, Span, SpanAnchor, SyntaxContext, TokenId,
-};
+use span::{EditionedFileId, FileId, ROOT_ERASED_FILE_AST_ID, Span, SpanAnchor, SyntaxContext};
 use tt::TextRange;
 
-use crate::{EnvSnapshot, ProcMacroSrv, dylib, proc_macro_test_dylib_path};
+use crate::{EnvSnapshot, ProcMacroSrv, SpanId, dylib, proc_macro_test_dylib_path};
 
-fn parse_string(call_site: TokenId, src: &str) -> crate::server_impl::TokenStream<TokenId> {
+fn parse_string(call_site: SpanId, src: &str) -> crate::server_impl::TokenStream<SpanId> {
     crate::server_impl::TokenStream::with_subtree(crate::server_impl::TopSubtree(
         syntax_bridge::parse_to_token_tree_static_span(span::Edition::CURRENT, call_site, src)
             .unwrap()
@@ -57,11 +55,11 @@ fn assert_expand_impl(
     expect_spanned: Expect,
 ) {
     let path = proc_macro_test_dylib_path();
-    let expander = dylib::Expander::new(&path).unwrap();
+    let expander = dylib::Expander::new(&temp_dir::TempDir::new().unwrap(), &path).unwrap();
 
-    let def_site = TokenId(0);
-    let call_site = TokenId(1);
-    let mixed_site = TokenId(2);
+    let def_site = SpanId(0);
+    let call_site = SpanId(1);
+    let mixed_site = SpanId(2);
     let input_ts = parse_string(call_site, input).into_subtree(call_site);
     let attr_ts = attr.map(|attr| parse_string(call_site, attr).into_subtree(call_site));
     let input_ts_string = format!("{input_ts:?}");