Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/proc-macro-api/src/legacy_protocol.rs')
-rw-r--r--crates/proc-macro-api/src/legacy_protocol.rs172
1 files changed, 172 insertions, 0 deletions
diff --git a/crates/proc-macro-api/src/legacy_protocol.rs b/crates/proc-macro-api/src/legacy_protocol.rs
new file mode 100644
index 0000000000..ee96b899fe
--- /dev/null
+++ b/crates/proc-macro-api/src/legacy_protocol.rs
@@ -0,0 +1,172 @@
+//! The initial proc-macro-srv protocol, soon to be deprecated.
+
+pub mod json;
+pub mod msg;
+
+use std::{
+ io::{BufRead, Write},
+ sync::Arc,
+};
+
+use paths::AbsPath;
+use span::Span;
+
+use crate::{
+ ProcMacro, ProcMacroKind, ServerError,
+ legacy_protocol::{
+ json::{read_json, write_json},
+ msg::{
+ ExpandMacro, ExpandMacroData, ExpnGlobals, FlatTree, Message, Request, Response,
+ ServerConfig, SpanDataIndexMap, deserialize_span_data_index_map,
+ flat::serialize_span_data_index_map,
+ },
+ },
+ process::ProcMacroServerProcess,
+ version,
+};
+
+pub(crate) use crate::legacy_protocol::msg::SpanMode;
+
+/// Legacy span type, only defined here as it is still used by the proc-macro server.
+/// While rust-analyzer doesn't use this anymore at all, RustRover relies on the legacy type for
+/// proc-macro expansion.
+#[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)
+ }
+}
+
+pub(crate) fn version_check(srv: &ProcMacroServerProcess) -> Result<u32, ServerError> {
+ let request = Request::ApiVersionCheck {};
+ let response = send_task(srv, request)?;
+
+ match response {
+ Response::ApiVersionCheck(version) => Ok(version),
+ _ => Err(ServerError { message: "unexpected response".to_owned(), io: None }),
+ }
+}
+
+/// Enable support for rust-analyzer span mode if the server supports it.
+pub(crate) fn enable_rust_analyzer_spans(
+ srv: &ProcMacroServerProcess,
+) -> Result<SpanMode, ServerError> {
+ let request = Request::SetConfig(ServerConfig { span_mode: SpanMode::RustAnalyzer });
+ let response = send_task(srv, request)?;
+
+ match response {
+ Response::SetConfig(ServerConfig { span_mode }) => Ok(span_mode),
+ _ => Err(ServerError { message: "unexpected response".to_owned(), io: None }),
+ }
+}
+
+/// Finds proc-macros in a given dynamic library.
+pub(crate) fn find_proc_macros(
+ srv: &ProcMacroServerProcess,
+ dylib_path: &AbsPath,
+) -> Result<Result<Vec<(String, ProcMacroKind)>, String>, ServerError> {
+ let request = Request::ListMacros { dylib_path: dylib_path.to_path_buf().into() };
+
+ let response = send_task(srv, request)?;
+
+ match response {
+ Response::ListMacros(it) => Ok(it),
+ _ => Err(ServerError { message: "unexpected response".to_owned(), io: None }),
+ }
+}
+
+pub(crate) fn expand(
+ proc_macro: &ProcMacro,
+ subtree: tt::SubtreeView<'_, Span>,
+ attr: Option<tt::SubtreeView<'_, Span>>,
+ env: Vec<(String, String)>,
+ def_site: Span,
+ call_site: Span,
+ mixed_site: Span,
+ current_dir: String,
+) -> Result<Result<tt::TopSubtree<span::SpanData<span::SyntaxContext>>, String>, crate::ServerError>
+{
+ let version = proc_macro.process.version();
+ let mut span_data_table = SpanDataIndexMap::default();
+ let def_site = span_data_table.insert_full(def_site).0;
+ let call_site = span_data_table.insert_full(call_site).0;
+ let mixed_site = span_data_table.insert_full(mixed_site).0;
+ let task = ExpandMacro {
+ data: ExpandMacroData {
+ macro_body: FlatTree::new(subtree, version, &mut span_data_table),
+ macro_name: proc_macro.name.to_string(),
+ attributes: attr.map(|subtree| FlatTree::new(subtree, version, &mut span_data_table)),
+ has_global_spans: ExpnGlobals {
+ serialize: version >= version::HAS_GLOBAL_SPANS,
+ def_site,
+ call_site,
+ mixed_site,
+ },
+ span_data_table: if proc_macro.process.rust_analyzer_spans() {
+ serialize_span_data_index_map(&span_data_table)
+ } else {
+ Vec::new()
+ },
+ },
+ lib: proc_macro.dylib_path.to_path_buf().into(),
+ env,
+ current_dir: Some(current_dir),
+ };
+
+ let response = send_task(&proc_macro.process, Request::ExpandMacro(Box::new(task)))?;
+
+ match response {
+ Response::ExpandMacro(it) => Ok(it
+ .map(|tree| {
+ let mut expanded = FlatTree::to_subtree_resolved(tree, version, &span_data_table);
+ if proc_macro.needs_fixup_change() {
+ proc_macro.change_fixup_to_match_old_server(&mut expanded);
+ }
+ expanded
+ })
+ .map_err(|msg| msg.0)),
+ Response::ExpandMacroExtended(it) => Ok(it
+ .map(|resp| {
+ let mut expanded = FlatTree::to_subtree_resolved(
+ resp.tree,
+ version,
+ &deserialize_span_data_index_map(&resp.span_data_table),
+ );
+ if proc_macro.needs_fixup_change() {
+ proc_macro.change_fixup_to_match_old_server(&mut expanded);
+ }
+ expanded
+ })
+ .map_err(|msg| msg.0)),
+ _ => Err(ServerError { message: "unexpected response".to_owned(), io: None }),
+ }
+}
+
+/// Sends a request to the proc-macro server and waits for a response.
+fn send_task(srv: &ProcMacroServerProcess, req: Request) -> Result<Response, ServerError> {
+ if let Some(server_error) = srv.exited() {
+ return Err(server_error.clone());
+ }
+
+ srv.send_task(send_request, req)
+}
+
+/// Sends a request to the server and reads the response.
+fn send_request(
+ mut writer: &mut dyn Write,
+ mut reader: &mut dyn BufRead,
+ req: Request,
+ buf: &mut String,
+) -> Result<Option<Response>, ServerError> {
+ req.write(write_json, &mut writer).map_err(|err| ServerError {
+ message: "failed to write request".into(),
+ io: Some(Arc::new(err)),
+ })?;
+ let res = Response::read(read_json, &mut reader, buf).map_err(|err| ServerError {
+ message: "failed to read response".into(),
+ io: Some(Arc::new(err)),
+ })?;
+ Ok(res)
+}