summaryrefslogtreecommitdiffstats
path: root/src/tools/rust-analyzer/crates/proc-macro-api
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools/rust-analyzer/crates/proc-macro-api')
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-api/Cargo.toml23
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs17
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-api/src/msg.rs23
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-api/src/msg/flat.rs43
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-api/src/process.rs54
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-api/src/version.rs13
6 files changed, 115 insertions, 58 deletions
diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/Cargo.toml b/src/tools/rust-analyzer/crates/proc-macro-api/Cargo.toml
index f261f3def..28469b832 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-api/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/proc-macro-api/Cargo.toml
@@ -2,15 +2,17 @@
name = "proc-macro-api"
version = "0.0.0"
description = "TBD"
-license = "MIT OR Apache-2.0"
-edition = "2021"
-rust-version = "1.65"
+
+authors.workspace = true
+edition.workspace = true
+license.workspace = true
+rust-version.workspace = true
[lib]
doctest = false
[dependencies]
-object = { version = "0.29.0", default-features = false, features = [
+object = { version = "0.30.2", default-features = false, features = [
"std",
"read_core",
"elf",
@@ -21,11 +23,12 @@ serde = { version = "1.0.137", features = ["derive"] }
serde_json = { version = "1.0.81", features = ["unbounded_depth"] }
tracing = "0.1.37"
memmap2 = "0.5.4"
-snap = "1.0.5"
+snap = "1.1.0"
-paths = { path = "../paths", version = "0.0.0" }
-tt = { path = "../tt", version = "0.0.0" }
-stdx = { path = "../stdx", version = "0.0.0" }
-profile = { path = "../profile", version = "0.0.0" }
+# local deps
+paths.workspace = true
+tt.workspace = true
+stdx.workspace = true
+profile.workspace = true
# Intentionally *not* depend on anything salsa-related
-# base-db = { path = "../base-db", version = "0.0.0" }
+# base-db.workspace = true
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 7921fda33..90d06967e 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
@@ -19,7 +19,8 @@ use std::{
};
use serde::{Deserialize, Serialize};
-use tt::Subtree;
+
+use ::tt::token_id as tt;
use crate::{
msg::{ExpandMacro, FlatTree, PanicMessage},
@@ -70,7 +71,7 @@ impl MacroDylib {
/// A handle to a specific macro (a `#[proc_macro]` annotated function).
///
-/// It exists withing a context of a specific [`ProcMacroProcess`] -- currently
+/// It exists within a context of a specific [`ProcMacroProcess`] -- currently
/// we share a single expander process for all macros.
#[derive(Debug, Clone)]
pub struct ProcMacro {
@@ -114,14 +115,14 @@ impl ProcMacroServer {
/// Spawns an external process as the proc macro server and returns a client connected to it.
pub fn spawn(
process_path: AbsPathBuf,
- args: impl IntoIterator<Item = impl AsRef<OsStr>>,
+ args: impl IntoIterator<Item = impl AsRef<OsStr>> + Clone,
) -> io::Result<ProcMacroServer> {
let process = ProcMacroProcessSrv::run(process_path, args)?;
Ok(ProcMacroServer { process: Arc::new(Mutex::new(process)) })
}
pub fn load_dylib(&self, dylib: MacroDylib) -> Result<Vec<ProcMacro>, ServerError> {
- let _p = profile::span("ProcMacroClient::by_dylib_path");
+ let _p = profile::span("ProcMacroClient::load_dylib");
let macros =
self.process.lock().unwrap_or_else(|e| e.into_inner()).find_proc_macros(&dylib.path)?;
@@ -151,10 +152,10 @@ impl ProcMacro {
pub fn expand(
&self,
- subtree: &Subtree,
- attr: Option<&Subtree>,
+ subtree: &tt::Subtree,
+ attr: Option<&tt::Subtree>,
env: Vec<(String, String)>,
- ) -> Result<Result<Subtree, PanicMessage>, ServerError> {
+ ) -> Result<Result<tt::Subtree, PanicMessage>, ServerError> {
let current_dir = env
.iter()
.find(|(name, _)| name == "CARGO_MANIFEST_DIR")
@@ -173,7 +174,7 @@ impl ProcMacro {
let response = self.process.lock().unwrap_or_else(|e| e.into_inner()).send_task(request)?;
match response {
msg::Response::ExpandMacro(it) => Ok(it.map(FlatTree::to_subtree)),
- msg::Response::ListMacros { .. } => {
+ msg::Response::ListMacros(..) | msg::Response::ApiVersionCheck(..) => {
Err(ServerError { message: "unexpected response".to_string(), io: None })
}
}
diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/src/msg.rs b/src/tools/rust-analyzer/crates/proc-macro-api/src/msg.rs
index f9c2b9fda..4040efe93 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-api/src/msg.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-api/src/msg.rs
@@ -12,16 +12,21 @@ use crate::ProcMacroKind;
pub use crate::msg::flat::FlatTree;
+pub const NO_VERSION_CHECK_VERSION: u32 = 0;
+pub const CURRENT_API_VERSION: u32 = 1;
+
#[derive(Debug, Serialize, Deserialize)]
pub enum Request {
ListMacros { dylib_path: PathBuf },
ExpandMacro(ExpandMacro),
+ ApiVersionCheck {},
}
#[derive(Debug, Serialize, Deserialize)]
pub enum Response {
ListMacros(Result<Vec<(String, ProcMacroKind)>, String>),
ExpandMacro(Result<FlatTree, PanicMessage>),
+ ApiVersionCheck(u32),
}
#[derive(Debug, Serialize, Deserialize)]
@@ -107,27 +112,31 @@ fn write_json(out: &mut impl Write, msg: &str) -> io::Result<()> {
#[cfg(test)]
mod tests {
use super::*;
- use tt::*;
+ use crate::tt::*;
fn fixture_token_tree() -> Subtree {
- let mut subtree = Subtree::default();
+ let mut subtree = Subtree { delimiter: Delimiter::unspecified(), token_trees: Vec::new() };
subtree
.token_trees
- .push(TokenTree::Leaf(Ident { text: "struct".into(), id: TokenId(0) }.into()));
+ .push(TokenTree::Leaf(Ident { text: "struct".into(), span: TokenId(0) }.into()));
subtree
.token_trees
- .push(TokenTree::Leaf(Ident { text: "Foo".into(), id: TokenId(1) }.into()));
+ .push(TokenTree::Leaf(Ident { text: "Foo".into(), span: TokenId(1) }.into()));
subtree.token_trees.push(TokenTree::Leaf(Leaf::Literal(Literal {
text: "Foo".into(),
- id: TokenId::unspecified(),
+ span: TokenId::unspecified(),
})));
subtree.token_trees.push(TokenTree::Leaf(Leaf::Punct(Punct {
char: '@',
- id: TokenId::unspecified(),
+ span: TokenId::unspecified(),
spacing: Spacing::Joint,
})));
subtree.token_trees.push(TokenTree::Subtree(Subtree {
- delimiter: Some(Delimiter { id: TokenId(2), kind: DelimiterKind::Brace }),
+ delimiter: Delimiter {
+ open: TokenId(2),
+ close: TokenId::UNSPECIFIED,
+ kind: DelimiterKind::Brace,
+ },
token_trees: vec![],
}));
subtree
diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/src/msg/flat.rs b/src/tools/rust-analyzer/crates/proc-macro-api/src/msg/flat.rs
index b178c4626..fd3202e0b 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-api/src/msg/flat.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-api/src/msg/flat.rs
@@ -38,7 +38,8 @@
use std::collections::{HashMap, VecDeque};
use serde::{Deserialize, Serialize};
-use tt::TokenId;
+
+use crate::tt::{self, TokenId};
#[derive(Serialize, Deserialize, Debug)]
pub struct FlatTree {
@@ -52,7 +53,7 @@ pub struct FlatTree {
struct SubtreeRepr {
id: tt::TokenId,
- kind: Option<tt::DelimiterKind>,
+ kind: tt::DelimiterKind,
tt: [u32; 2],
}
@@ -124,19 +125,19 @@ impl FlatTree {
impl SubtreeRepr {
fn write(self) -> [u32; 4] {
let kind = match self.kind {
- None => 0,
- Some(tt::DelimiterKind::Parenthesis) => 1,
- Some(tt::DelimiterKind::Brace) => 2,
- Some(tt::DelimiterKind::Bracket) => 3,
+ tt::DelimiterKind::Invisible => 0,
+ tt::DelimiterKind::Parenthesis => 1,
+ tt::DelimiterKind::Brace => 2,
+ tt::DelimiterKind::Bracket => 3,
};
[self.id.0, kind, self.tt[0], self.tt[1]]
}
fn read([id, kind, lo, len]: [u32; 4]) -> SubtreeRepr {
let kind = match kind {
- 0 => None,
- 1 => Some(tt::DelimiterKind::Parenthesis),
- 2 => Some(tt::DelimiterKind::Brace),
- 3 => Some(tt::DelimiterKind::Bracket),
+ 0 => tt::DelimiterKind::Invisible,
+ 1 => tt::DelimiterKind::Parenthesis,
+ 2 => tt::DelimiterKind::Brace,
+ 3 => tt::DelimiterKind::Bracket,
other => panic!("bad kind {other}"),
};
SubtreeRepr { id: TokenId(id), kind, tt: [lo, len] }
@@ -216,7 +217,7 @@ impl<'a> Writer<'a> {
tt::Leaf::Literal(lit) => {
let idx = self.literal.len() as u32;
let text = self.intern(&lit.text);
- self.literal.push(LiteralRepr { id: lit.id, text });
+ self.literal.push(LiteralRepr { id: lit.span, text });
idx << 2 | 0b01
}
tt::Leaf::Punct(punct) => {
@@ -224,14 +225,14 @@ impl<'a> Writer<'a> {
self.punct.push(PunctRepr {
char: punct.char,
spacing: punct.spacing,
- id: punct.id,
+ id: punct.span,
});
idx << 2 | 0b10
}
tt::Leaf::Ident(ident) => {
let idx = self.ident.len() as u32;
let text = self.intern(&ident.text);
- self.ident.push(IdentRepr { id: ident.id, text });
+ self.ident.push(IdentRepr { id: ident.span, text });
idx << 2 | 0b11
}
},
@@ -243,8 +244,8 @@ impl<'a> Writer<'a> {
fn enqueue(&mut self, subtree: &'a tt::Subtree) -> u32 {
let idx = self.subtree.len();
- let delimiter_id = subtree.delimiter.map_or(TokenId::unspecified(), |it| it.id);
- let delimiter_kind = subtree.delimiter.map(|it| it.kind);
+ let delimiter_id = subtree.delimiter.open;
+ let delimiter_kind = subtree.delimiter.kind;
self.subtree.push(SubtreeRepr { id: delimiter_id, kind: delimiter_kind, tt: [!0, !0] });
self.work.push_back((idx, subtree));
idx as u32
@@ -276,7 +277,11 @@ impl Reader {
let repr = &self.subtree[i];
let token_trees = &self.token_tree[repr.tt[0] as usize..repr.tt[1] as usize];
let s = tt::Subtree {
- delimiter: repr.kind.map(|kind| tt::Delimiter { id: repr.id, kind }),
+ delimiter: tt::Delimiter {
+ open: repr.id,
+ close: TokenId::UNSPECIFIED,
+ kind: repr.kind,
+ },
token_trees: token_trees
.iter()
.copied()
@@ -291,7 +296,7 @@ impl Reader {
let repr = &self.literal[idx];
tt::Leaf::Literal(tt::Literal {
text: self.text[repr.text as usize].as_str().into(),
- id: repr.id,
+ span: repr.id,
})
.into()
}
@@ -300,7 +305,7 @@ impl Reader {
tt::Leaf::Punct(tt::Punct {
char: repr.char,
spacing: repr.spacing,
- id: repr.id,
+ span: repr.id,
})
.into()
}
@@ -308,7 +313,7 @@ impl Reader {
let repr = &self.ident[idx];
tt::Leaf::Ident(tt::Ident {
text: self.text[repr.text as usize].as_str().into(),
- id: repr.id,
+ span: repr.id,
})
.into()
}
diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/src/process.rs b/src/tools/rust-analyzer/crates/proc-macro-api/src/process.rs
index 54dcb17f4..1ccbd780f 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-api/src/process.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-api/src/process.rs
@@ -10,7 +10,7 @@ use paths::{AbsPath, AbsPathBuf};
use stdx::JodChild;
use crate::{
- msg::{Message, Request, Response},
+ msg::{Message, Request, Response, CURRENT_API_VERSION},
ProcMacroKind, ServerError,
};
@@ -19,19 +19,53 @@ pub(crate) struct ProcMacroProcessSrv {
_process: Process,
stdin: ChildStdin,
stdout: BufReader<ChildStdout>,
+ version: u32,
}
impl ProcMacroProcessSrv {
pub(crate) fn run(
process_path: AbsPathBuf,
- args: impl IntoIterator<Item = impl AsRef<OsStr>>,
+ args: impl IntoIterator<Item = impl AsRef<OsStr>> + Clone,
) -> io::Result<ProcMacroProcessSrv> {
- let mut process = Process::run(process_path, args)?;
- let (stdin, stdout) = process.stdio().expect("couldn't access child stdio");
+ let create_srv = |null_stderr| {
+ let mut process = Process::run(process_path.clone(), args.clone(), null_stderr)?;
+ let (stdin, stdout) = process.stdio().expect("couldn't access child stdio");
+
+ io::Result::Ok(ProcMacroProcessSrv { _process: process, stdin, stdout, version: 0 })
+ };
+ let mut srv = create_srv(true)?;
+ tracing::info!("sending version check");
+ match srv.version_check() {
+ Ok(v) if v > CURRENT_API_VERSION => Err(io::Error::new(
+ io::ErrorKind::Other,
+ format!(
+ "proc-macro server's api version ({}) is newer than rust-analyzer's ({})",
+ v, CURRENT_API_VERSION
+ ),
+ )),
+ Ok(v) => {
+ tracing::info!("got version {v}");
+ srv = create_srv(false)?;
+ srv.version = v;
+ Ok(srv)
+ }
+ Err(e) => {
+ tracing::info!(%e, "proc-macro version check failed, restarting and assuming version 0");
+ create_srv(false)
+ }
+ }
+ }
- let srv = ProcMacroProcessSrv { _process: process, stdin, stdout };
+ pub(crate) fn version_check(&mut self) -> Result<u32, ServerError> {
+ let request = Request::ApiVersionCheck {};
+ let response = self.send_task(request)?;
- Ok(srv)
+ match response {
+ Response::ApiVersionCheck(version) => Ok(version),
+ Response::ExpandMacro { .. } | Response::ListMacros { .. } => {
+ Err(ServerError { message: "unexpected response".to_string(), io: None })
+ }
+ }
}
pub(crate) fn find_proc_macros(
@@ -44,7 +78,7 @@ impl ProcMacroProcessSrv {
match response {
Response::ListMacros(it) => Ok(it),
- Response::ExpandMacro { .. } => {
+ Response::ExpandMacro { .. } | Response::ApiVersionCheck { .. } => {
Err(ServerError { message: "unexpected response".to_string(), io: None })
}
}
@@ -65,9 +99,10 @@ impl Process {
fn run(
path: AbsPathBuf,
args: impl IntoIterator<Item = impl AsRef<OsStr>>,
+ null_stderr: bool,
) -> io::Result<Process> {
let args: Vec<OsString> = args.into_iter().map(|s| s.as_ref().into()).collect();
- let child = JodChild(mk_child(&path, args)?);
+ let child = JodChild(mk_child(&path, args, null_stderr)?);
Ok(Process { child })
}
@@ -83,13 +118,14 @@ impl Process {
fn mk_child(
path: &AbsPath,
args: impl IntoIterator<Item = impl AsRef<OsStr>>,
+ null_stderr: bool,
) -> io::Result<Child> {
Command::new(path.as_os_str())
.args(args)
.env("RUST_ANALYZER_INTERNALS_DO_NOT_USE", "this is unstable")
.stdin(Stdio::piped())
.stdout(Stdio::piped())
- .stderr(Stdio::inherit())
+ .stderr(if null_stderr { Stdio::null() } else { Stdio::inherit() })
.spawn()
}
diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/src/version.rs b/src/tools/rust-analyzer/crates/proc-macro-api/src/version.rs
index 40125c2a5..cf637ec35 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-api/src/version.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-api/src/version.rs
@@ -120,17 +120,20 @@ pub fn read_version(dylib_path: &AbsPath) -> io::Result<String> {
let version = u32::from_be_bytes([dot_rustc[4], dot_rustc[5], dot_rustc[6], dot_rustc[7]]);
// Last supported version is:
// https://github.com/rust-lang/rust/commit/0696e79f2740ad89309269b460579e548a5cd632
- match version {
- 5 | 6 => {}
+ let snappy_portion = match version {
+ 5 | 6 => &dot_rustc[8..],
+ 7 => {
+ let len_bytes = &dot_rustc[8..12];
+ let data_len = u32::from_be_bytes(len_bytes.try_into().unwrap()) as usize;
+ &dot_rustc[12..data_len + 12]
+ }
_ => {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
format!("unsupported metadata version {version}"),
));
}
- }
-
- let snappy_portion = &dot_rustc[8..];
+ };
let mut snappy_decoder = SnapDecoder::new(snappy_portion);