diff options
| author | Laurențiu Nicola <lnicola@dend.ro> | 2023-06-05 12:04:23 +0300 |
|---|---|---|
| committer | Laurențiu Nicola <lnicola@dend.ro> | 2023-06-05 12:04:23 +0300 |
| commit | b8a7d439db0cfd765ed4bfedd2bbaeeee58b05a5 (patch) | |
| tree | 5adcbc6cf50af3bebc2cd4f42d5252a4d728690e /src/tools/rust-analyzer/crates/proc-macro-api | |
| parent | 51f714c8c5021fe25442e46798b1cbef2f2249ed (diff) | |
| parent | aa9bc8612514d216f84eec218dfd19ab83f3598a (diff) | |
| download | rust-b8a7d439db0cfd765ed4bfedd2bbaeeee58b05a5.tar.gz rust-b8a7d439db0cfd765ed4bfedd2bbaeeee58b05a5.zip | |
Merge commit 'aa9bc8612514d216f84eec218dfd19ab83f3598a' into sync-from-ra
Diffstat (limited to 'src/tools/rust-analyzer/crates/proc-macro-api')
5 files changed, 75 insertions, 65 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 28469b83246..d3486e75575 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-api/Cargo.toml +++ b/src/tools/rust-analyzer/crates/proc-macro-api/Cargo.toml @@ -19,9 +19,10 @@ object = { version = "0.30.2", default-features = false, features = [ "macho", "pe", ] } -serde = { version = "1.0.137", features = ["derive"] } -serde_json = { version = "1.0.81", features = ["unbounded_depth"] } +serde.workspace = true +serde_json = { workspace = true, features = ["unbounded_depth"] } tracing = "0.1.37" +triomphe.workspace = true memmap2 = "0.5.4" snap = "1.1.0" 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 90d06967e8f..1603458f756 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 @@ -12,11 +12,8 @@ mod process; mod version; use paths::AbsPathBuf; -use std::{ - ffi::OsStr, - fmt, io, - sync::{Arc, Mutex}, -}; +use std::{fmt, io, sync::Mutex}; +use triomphe::Arc; use serde::{Deserialize, Serialize}; @@ -54,18 +51,8 @@ pub struct MacroDylib { } impl MacroDylib { - // FIXME: this is buggy due to TOCTOU, we should check the version in the - // macro process instead. - pub fn new(path: AbsPathBuf) -> io::Result<MacroDylib> { - let _p = profile::span("MacroDylib::new"); - - let info = version::read_dylib_info(&path)?; - if info.version.0 < 1 || info.version.1 < 47 { - let msg = format!("proc-macro {} built by {info:#?} is not supported by rust-analyzer, please update your Rust version.", path.display()); - return Err(io::Error::new(io::ErrorKind::InvalidData, msg)); - } - - Ok(MacroDylib { path }) + pub fn new(path: AbsPathBuf) -> MacroDylib { + MacroDylib { path } } } @@ -113,11 +100,8 @@ pub struct MacroPanic { 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>> + Clone, - ) -> io::Result<ProcMacroServer> { - let process = ProcMacroProcessSrv::run(process_path, args)?; + pub fn spawn(process_path: AbsPathBuf) -> io::Result<ProcMacroServer> { + let process = ProcMacroProcessSrv::run(process_path)?; Ok(ProcMacroServer { process: Arc::new(Mutex::new(process)) }) } @@ -156,15 +140,16 @@ impl ProcMacro { attr: Option<&tt::Subtree>, env: Vec<(String, String)>, ) -> Result<Result<tt::Subtree, PanicMessage>, ServerError> { + let version = self.process.lock().unwrap_or_else(|e| e.into_inner()).version(); let current_dir = env .iter() .find(|(name, _)| name == "CARGO_MANIFEST_DIR") .map(|(_, value)| value.clone()); let task = ExpandMacro { - macro_body: FlatTree::new(subtree), + macro_body: FlatTree::new(subtree, version), macro_name: self.name.to_string(), - attributes: attr.map(FlatTree::new), + attributes: attr.map(|subtree| FlatTree::new(subtree, version)), lib: self.dylib_path.to_path_buf().into(), env, current_dir, @@ -173,7 +158,9 @@ impl ProcMacro { let request = msg::Request::ExpandMacro(task); 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::ExpandMacro(it) => { + Ok(it.map(|tree| FlatTree::to_subtree(tree, version))) + } 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 4040efe93f0..4b01643c2a2 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,8 +12,12 @@ use crate::ProcMacroKind; pub use crate::msg::flat::FlatTree; +// The versions of the server protocol pub const NO_VERSION_CHECK_VERSION: u32 = 0; -pub const CURRENT_API_VERSION: u32 = 1; +pub const VERSION_CHECK_VERSION: u32 = 1; +pub const ENCODE_CLOSE_SPAN_VERSION: u32 = 2; + +pub const CURRENT_API_VERSION: u32 = ENCODE_CLOSE_SPAN_VERSION; #[derive(Debug, Serialize, Deserialize)] pub enum Request { @@ -146,7 +150,7 @@ mod tests { fn test_proc_macro_rpc_works() { let tt = fixture_token_tree(); let task = ExpandMacro { - macro_body: FlatTree::new(&tt), + macro_body: FlatTree::new(&tt, CURRENT_API_VERSION), macro_name: Default::default(), attributes: None, lib: std::env::current_dir().unwrap(), @@ -158,6 +162,6 @@ mod tests { // println!("{}", json); let back: ExpandMacro = serde_json::from_str(&json).unwrap(); - assert_eq!(tt, back.macro_body.to_subtree()); + assert_eq!(tt, back.macro_body.to_subtree(CURRENT_API_VERSION)); } } 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 fd3202e0b28..44245336f01 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 @@ -39,7 +39,10 @@ use std::collections::{HashMap, VecDeque}; use serde::{Deserialize, Serialize}; -use crate::tt::{self, TokenId}; +use crate::{ + msg::ENCODE_CLOSE_SPAN_VERSION, + tt::{self, TokenId}, +}; #[derive(Serialize, Deserialize, Debug)] pub struct FlatTree { @@ -52,7 +55,8 @@ pub struct FlatTree { } struct SubtreeRepr { - id: tt::TokenId, + open: tt::TokenId, + close: tt::TokenId, kind: tt::DelimiterKind, tt: [u32; 2], } @@ -74,7 +78,7 @@ struct IdentRepr { } impl FlatTree { - pub fn new(subtree: &tt::Subtree) -> FlatTree { + pub fn new(subtree: &tt::Subtree, version: u32) -> FlatTree { let mut w = Writer { string_table: HashMap::new(), work: VecDeque::new(), @@ -89,7 +93,11 @@ impl FlatTree { w.write(subtree); return FlatTree { - subtree: write_vec(w.subtree, SubtreeRepr::write), + subtree: if version >= ENCODE_CLOSE_SPAN_VERSION { + write_vec(w.subtree, SubtreeRepr::write_with_close_span) + } else { + write_vec(w.subtree, SubtreeRepr::write) + }, literal: write_vec(w.literal, LiteralRepr::write), punct: write_vec(w.punct, PunctRepr::write), ident: write_vec(w.ident, IdentRepr::write), @@ -102,9 +110,13 @@ impl FlatTree { } } - pub fn to_subtree(self) -> tt::Subtree { + pub fn to_subtree(self, version: u32) -> tt::Subtree { return Reader { - subtree: read_vec(self.subtree, SubtreeRepr::read), + subtree: if version >= ENCODE_CLOSE_SPAN_VERSION { + read_vec(self.subtree, SubtreeRepr::read_with_close_span) + } else { + read_vec(self.subtree, SubtreeRepr::read) + }, literal: read_vec(self.literal, LiteralRepr::read), punct: read_vec(self.punct, PunctRepr::read), ident: read_vec(self.ident, IdentRepr::read), @@ -130,9 +142,9 @@ impl SubtreeRepr { tt::DelimiterKind::Brace => 2, tt::DelimiterKind::Bracket => 3, }; - [self.id.0, kind, self.tt[0], self.tt[1]] + [self.open.0, kind, self.tt[0], self.tt[1]] } - fn read([id, kind, lo, len]: [u32; 4]) -> SubtreeRepr { + fn read([open, kind, lo, len]: [u32; 4]) -> SubtreeRepr { let kind = match kind { 0 => tt::DelimiterKind::Invisible, 1 => tt::DelimiterKind::Parenthesis, @@ -140,7 +152,26 @@ impl SubtreeRepr { 3 => tt::DelimiterKind::Bracket, other => panic!("bad kind {other}"), }; - SubtreeRepr { id: TokenId(id), kind, tt: [lo, len] } + SubtreeRepr { open: TokenId(open), close: TokenId::UNSPECIFIED, kind, tt: [lo, len] } + } + fn write_with_close_span(self) -> [u32; 5] { + let kind = match self.kind { + tt::DelimiterKind::Invisible => 0, + tt::DelimiterKind::Parenthesis => 1, + tt::DelimiterKind::Brace => 2, + tt::DelimiterKind::Bracket => 3, + }; + [self.open.0, self.close.0, kind, self.tt[0], self.tt[1]] + } + fn read_with_close_span([open, close, kind, lo, len]: [u32; 5]) -> SubtreeRepr { + let kind = match kind { + 0 => tt::DelimiterKind::Invisible, + 1 => tt::DelimiterKind::Parenthesis, + 2 => tt::DelimiterKind::Brace, + 3 => tt::DelimiterKind::Bracket, + other => panic!("bad kind {other}"), + }; + SubtreeRepr { open: TokenId(open), close: TokenId(close), kind, tt: [lo, len] } } } @@ -244,9 +275,10 @@ impl<'a> Writer<'a> { fn enqueue(&mut self, subtree: &'a tt::Subtree) -> u32 { let idx = self.subtree.len(); - let delimiter_id = subtree.delimiter.open; + let open = subtree.delimiter.open; + let close = subtree.delimiter.close; let delimiter_kind = subtree.delimiter.kind; - self.subtree.push(SubtreeRepr { id: delimiter_id, kind: delimiter_kind, tt: [!0, !0] }); + self.subtree.push(SubtreeRepr { open, close, kind: delimiter_kind, tt: [!0, !0] }); self.work.push_back((idx, subtree)); idx as u32 } @@ -277,11 +309,7 @@ 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: tt::Delimiter { - open: repr.id, - close: TokenId::UNSPECIFIED, - kind: repr.kind, - }, + delimiter: tt::Delimiter { open: repr.open, close: repr.close, kind: repr.kind }, token_trees: token_trees .iter() .copied() 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 1ccbd780fdd..9a20fa63ed7 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 @@ -1,7 +1,6 @@ //! Handle process life-time and message passing for proc-macro client use std::{ - ffi::{OsStr, OsString}, io::{self, BufRead, BufReader, Write}, process::{Child, ChildStdin, ChildStdout, Command, Stdio}, }; @@ -23,12 +22,9 @@ pub(crate) struct ProcMacroProcessSrv { } impl ProcMacroProcessSrv { - pub(crate) fn run( - process_path: AbsPathBuf, - args: impl IntoIterator<Item = impl AsRef<OsStr>> + Clone, - ) -> io::Result<ProcMacroProcessSrv> { + pub(crate) fn run(process_path: AbsPathBuf) -> io::Result<ProcMacroProcessSrv> { let create_srv = |null_stderr| { - let mut process = Process::run(process_path.clone(), args.clone(), null_stderr)?; + let mut process = Process::run(process_path.clone(), null_stderr)?; let (stdin, stdout) = process.stdio().expect("couldn't access child stdio"); io::Result::Ok(ProcMacroProcessSrv { _process: process, stdin, stdout, version: 0 }) @@ -56,6 +52,10 @@ impl ProcMacroProcessSrv { } } + pub(crate) fn version(&self) -> u32 { + self.version + } + pub(crate) fn version_check(&mut self) -> Result<u32, ServerError> { let request = Request::ApiVersionCheck {}; let response = self.send_task(request)?; @@ -96,13 +96,8 @@ struct Process { } 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, null_stderr)?); + fn run(path: AbsPathBuf, null_stderr: bool) -> io::Result<Process> { + let child = JodChild(mk_child(&path, null_stderr)?); Ok(Process { child }) } @@ -115,13 +110,8 @@ impl Process { } } -fn mk_child( - path: &AbsPath, - args: impl IntoIterator<Item = impl AsRef<OsStr>>, - null_stderr: bool, -) -> io::Result<Child> { +fn mk_child(path: &AbsPath, 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()) |
