mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-10-28 10:39:45 +00:00
Properly clean proc-macro-srv proc-macro temp dir
This commit is contained in:
parent
4d5bb86ad7
commit
a7a365e8f8
8 changed files with 125 additions and 18 deletions
|
|
@ -4,6 +4,7 @@ mod version;
|
|||
|
||||
use proc_macro::bridge;
|
||||
use std::{fmt, fs, io, time::SystemTime};
|
||||
use temp_dir::TempDir;
|
||||
|
||||
use libloading::Library;
|
||||
use object::Object;
|
||||
|
|
@ -141,13 +142,16 @@ pub(crate) struct Expander {
|
|||
}
|
||||
|
||||
impl Expander {
|
||||
pub(crate) fn new(lib: &Utf8Path) -> Result<Expander, LoadProcMacroDylibError> {
|
||||
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())?;
|
||||
|
||||
let path = ensure_file_with_lock_free_access(&lib)?;
|
||||
let path = ensure_file_with_lock_free_access(temp_dir, &lib)?;
|
||||
let library = ProcMacroLibrary::open(path.as_ref())?;
|
||||
|
||||
Ok(Expander { inner: library, _remove_on_drop: RemoveFileOnDrop(path), modified_time })
|
||||
|
|
@ -221,7 +225,10 @@ impl Drop for RemoveFileOnDrop {
|
|||
|
||||
/// 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 +236,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 +253,9 @@ 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())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ use std::{
|
|||
|
||||
use paths::{Utf8Path, Utf8PathBuf};
|
||||
use span::Span;
|
||||
use temp_dir::TempDir;
|
||||
|
||||
use crate::server_impl::TokenStream;
|
||||
|
||||
|
|
@ -59,11 +60,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(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -73,7 +79,7 @@ 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_body: tt::TopSubtree<S>,
|
||||
|
|
@ -131,7 +137,7 @@ impl ProcMacroSrv<'_> {
|
|||
|
||||
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)
|
||||
};
|
||||
|
|
@ -203,7 +209,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, ()>,
|
||||
|
|
@ -212,7 +218,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);
|
||||
|
|
@ -232,11 +238,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,
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ 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 = SpanId(0);
|
||||
let call_site = SpanId(1);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue