internal: make sure that proc macro machinery doesn't depend on cwd

This commit is contained in:
Aleksey Kladov 2021-07-17 16:54:48 +03:00
parent 9318c643f1
commit 8df38aa797
9 changed files with 52 additions and 22 deletions

4
Cargo.lock generated
View file

@ -1042,6 +1042,9 @@ dependencies = [
[[package]]
name = "paths"
version = "0.0.0"
dependencies = [
"serde",
]
[[package]]
name = "percent-encoding"
@ -1109,6 +1112,7 @@ dependencies = [
"log",
"memmap2",
"object",
"paths",
"profile",
"serde",
"serde_json",

View file

@ -7,3 +7,6 @@ edition = "2018"
[lib]
doctest = false
[dependencies]
serde = "1"

View file

@ -66,6 +66,27 @@ impl PartialEq<AbsPath> for AbsPathBuf {
}
}
impl serde::Serialize for AbsPathBuf {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
self.0.serialize(serializer)
}
}
impl<'de> serde::Deserialize<'de> for AbsPathBuf {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let path = PathBuf::deserialize(deserializer)?;
AbsPathBuf::try_from(path).map_err(|path| {
serde::de::Error::custom(format!("expected absolute path, got {}", path.display()))
})
}
}
impl AbsPathBuf {
/// Wrap the given absolute path in `AbsPathBuf`
///

View file

@ -18,6 +18,7 @@ memmap2 = "0.3.0"
object = { version = "0.25.3", default-features = false, features = ["std", "read_core", "elf", "macho", "pe"] }
snap = "1.0"
paths = { path = "../paths", version = "0.0.0" }
tt = { path = "../tt", version = "0.0.0" }
base_db = { path = "../base_db", version = "0.0.0" }
stdx = { path = "../stdx", version = "0.0.0" }

View file

@ -11,10 +11,10 @@ mod rpc;
mod version;
use base_db::{Env, ProcMacro};
use paths::{AbsPath, AbsPathBuf};
use std::{
ffi::OsStr,
io,
path::{Path, PathBuf},
sync::{Arc, Mutex},
};
@ -28,7 +28,7 @@ pub use version::{read_dylib_info, RustCInfo};
#[derive(Debug, Clone)]
struct ProcMacroProcessExpander {
process: Arc<Mutex<ProcMacroProcessSrv>>,
dylib_path: PathBuf,
dylib_path: AbsPathBuf,
name: SmolStr,
}
@ -79,26 +79,25 @@ pub struct ProcMacroClient {
impl ProcMacroClient {
/// Spawns an external process as the proc macro server and returns a client connected to it.
pub fn extern_process(
process_path: PathBuf,
process_path: AbsPathBuf,
args: impl IntoIterator<Item = impl AsRef<OsStr>>,
) -> io::Result<ProcMacroClient> {
let process = ProcMacroProcessSrv::run(process_path, args)?;
Ok(ProcMacroClient { process: Arc::new(Mutex::new(process)) })
}
// TODO: use paths::AbsPath here
pub fn by_dylib_path(&self, dylib_path: &Path) -> Vec<ProcMacro> {
pub fn by_dylib_path(&self, dylib_path: &AbsPath) -> Vec<ProcMacro> {
let _p = profile::span("ProcMacroClient::by_dylib_path");
match version::read_dylib_info(dylib_path) {
Ok(info) => {
if info.version.0 < 1 || info.version.1 < 47 {
eprintln!("proc-macro {} built by {:#?} is not supported by Rust Analyzer, please update your rust version.", dylib_path.to_string_lossy(), info);
eprintln!("proc-macro {} built by {:#?} is not supported by Rust Analyzer, please update your rust version.", dylib_path.display(), info);
}
}
Err(err) => {
eprintln!(
"proc-macro {} failed to find the given version. Reason: {}",
dylib_path.to_string_lossy(),
dylib_path.display(),
err
);
}
@ -129,7 +128,7 @@ impl ProcMacroClient {
let expander = Arc::new(ProcMacroProcessExpander {
process: self.process.clone(),
name: name.clone(),
dylib_path: dylib_path.into(),
dylib_path: dylib_path.to_path_buf(),
});
ProcMacro { name, kind, expander }

View file

@ -4,10 +4,10 @@ use std::{
convert::{TryFrom, TryInto},
ffi::{OsStr, OsString},
io::{self, BufRead, BufReader, Write},
path::{Path, PathBuf},
process::{Child, ChildStdin, ChildStdout, Command, Stdio},
};
use paths::{AbsPath, AbsPathBuf};
use stdx::JodChild;
use crate::{
@ -24,7 +24,7 @@ pub(crate) struct ProcMacroProcessSrv {
impl ProcMacroProcessSrv {
pub(crate) fn run(
process_path: PathBuf,
process_path: AbsPathBuf,
args: impl IntoIterator<Item = impl AsRef<OsStr>>,
) -> io::Result<ProcMacroProcessSrv> {
let mut process = Process::run(process_path, args)?;
@ -37,7 +37,7 @@ impl ProcMacroProcessSrv {
pub(crate) fn find_proc_macros(
&mut self,
dylib_path: &Path,
dylib_path: &AbsPath,
) -> Result<Vec<(String, ProcMacroKind)>, tt::ExpansionError> {
let task = ListMacrosTask { lib: dylib_path.to_path_buf() };
@ -84,7 +84,7 @@ struct Process {
impl Process {
fn run(
path: PathBuf,
path: AbsPathBuf,
args: impl IntoIterator<Item = impl AsRef<OsStr>>,
) -> io::Result<Process> {
let args: Vec<OsString> = args.into_iter().map(|s| s.as_ref().into()).collect();
@ -101,8 +101,11 @@ impl Process {
}
}
fn mk_child(path: &Path, args: impl IntoIterator<Item = impl AsRef<OsStr>>) -> io::Result<Child> {
Command::new(&path)
fn mk_child(
path: &AbsPath,
args: impl IntoIterator<Item = impl AsRef<OsStr>>,
) -> io::Result<Child> {
Command::new(path.as_os_str())
.args(args)
.stdin(Stdio::piped())
.stdout(Stdio::piped())

View file

@ -6,8 +6,7 @@
//! to be much easier, we deliberately duplicate `tt` structs with `#[serde(with = "XXDef")]`
//! for separation of code responsibility.
use std::path::PathBuf;
use paths::AbsPathBuf;
use serde::{Deserialize, Serialize};
use tt::{
Delimiter, DelimiterKind, Ident, Leaf, Literal, Punct, SmolStr, Spacing, Subtree, TokenId,
@ -16,7 +15,7 @@ use tt::{
#[derive(Clone, Eq, PartialEq, Debug, Serialize, Deserialize)]
pub struct ListMacrosTask {
pub lib: PathBuf,
pub lib: AbsPathBuf,
}
#[derive(Copy, Clone, Eq, PartialEq, Debug, Serialize, Deserialize)]
@ -50,7 +49,7 @@ pub struct ExpansionTask {
#[serde(with = "opt_subtree_def")]
pub attributes: Option<Subtree>,
pub lib: PathBuf,
pub lib: AbsPathBuf,
/// Environment variables to set during macro expansion.
pub env: Vec<(String, String)>,

View file

@ -3,11 +3,11 @@
use std::{
fs::File,
io::{self, Read},
path::Path,
};
use memmap2::Mmap;
use object::read::{File as BinaryFile, Object, ObjectSection};
use paths::AbsPath;
use snap::read::FrameDecoder as SnapDecoder;
#[derive(Debug)]
@ -19,7 +19,7 @@ pub struct RustCInfo {
}
/// Read rustc dylib information
pub fn read_dylib_info(dylib_path: &Path) -> io::Result<RustCInfo> {
pub fn read_dylib_info(dylib_path: &AbsPath) -> io::Result<RustCInfo> {
macro_rules! err {
($e:literal) => {
io::Error::new(io::ErrorKind::InvalidData, $e)
@ -96,7 +96,7 @@ fn read_section<'a>(dylib_binary: &'a [u8], section_name: &str) -> io::Result<&'
/// * [some more bytes that we don really care but still there] :-)
/// Check this issue for more about the bytes layout:
/// <https://github.com/rust-analyzer/rust-analyzer/issues/6174>
fn read_version(dylib_path: &Path) -> io::Result<String> {
fn read_version(dylib_path: &AbsPath) -> io::Result<String> {
let dylib_file = File::open(dylib_path)?;
let dylib_mmaped = unsafe { Mmap::map(&dylib_file) }?;

View file

@ -312,7 +312,7 @@ impl ProjectWorkspace {
) -> CrateGraph {
let _p = profile::span("ProjectWorkspace::to_crate_graph");
let proc_macro_loader = |path: &AbsPath| match proc_macro_client {
Some(client) => client.by_dylib_path(path.as_ref()), // TODO
Some(client) => client.by_dylib_path(path),
None => Vec::new(),
};