proc_macro_api/
legacy_protocol.rs

1//! The initial proc-macro-srv protocol, soon to be deprecated.
2
3pub mod json;
4pub mod msg;
5
6use std::{
7    io::{BufRead, Write},
8    sync::Arc,
9};
10
11use paths::AbsPath;
12use span::Span;
13
14use crate::{
15    ProcMacro, ProcMacroKind, ServerError,
16    legacy_protocol::{
17        json::{read_json, write_json},
18        msg::{
19            ExpandMacro, ExpandMacroData, ExpnGlobals, FlatTree, Message, Request, Response,
20            ServerConfig, SpanDataIndexMap, deserialize_span_data_index_map,
21            flat::serialize_span_data_index_map,
22        },
23    },
24    process::ProcMacroServerProcess,
25    version,
26};
27
28pub(crate) use crate::legacy_protocol::msg::SpanMode;
29
30/// Legacy span type, only defined here as it is still used by the proc-macro server.
31/// While rust-analyzer doesn't use this anymore at all, RustRover relies on the legacy type for
32/// proc-macro expansion.
33#[derive(Clone, Copy, PartialEq, Eq, Hash)]
34pub struct SpanId(pub u32);
35
36impl std::fmt::Debug for SpanId {
37    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
38        self.0.fmt(f)
39    }
40}
41
42pub(crate) fn version_check(srv: &ProcMacroServerProcess) -> Result<u32, ServerError> {
43    let request = Request::ApiVersionCheck {};
44    let response = send_task(srv, request)?;
45
46    match response {
47        Response::ApiVersionCheck(version) => Ok(version),
48        _ => Err(ServerError { message: "unexpected response".to_owned(), io: None }),
49    }
50}
51
52/// Enable support for rust-analyzer span mode if the server supports it.
53pub(crate) fn enable_rust_analyzer_spans(
54    srv: &ProcMacroServerProcess,
55) -> Result<SpanMode, ServerError> {
56    let request = Request::SetConfig(ServerConfig { span_mode: SpanMode::RustAnalyzer });
57    let response = send_task(srv, request)?;
58
59    match response {
60        Response::SetConfig(ServerConfig { span_mode }) => Ok(span_mode),
61        _ => Err(ServerError { message: "unexpected response".to_owned(), io: None }),
62    }
63}
64
65/// Finds proc-macros in a given dynamic library.
66pub(crate) fn find_proc_macros(
67    srv: &ProcMacroServerProcess,
68    dylib_path: &AbsPath,
69) -> Result<Result<Vec<(String, ProcMacroKind)>, String>, ServerError> {
70    let request = Request::ListMacros { dylib_path: dylib_path.to_path_buf().into() };
71
72    let response = send_task(srv, request)?;
73
74    match response {
75        Response::ListMacros(it) => Ok(it),
76        _ => Err(ServerError { message: "unexpected response".to_owned(), io: None }),
77    }
78}
79
80pub(crate) fn expand(
81    proc_macro: &ProcMacro,
82    subtree: tt::SubtreeView<'_, Span>,
83    attr: Option<tt::SubtreeView<'_, Span>>,
84    env: Vec<(String, String)>,
85    def_site: Span,
86    call_site: Span,
87    mixed_site: Span,
88    current_dir: String,
89) -> Result<Result<tt::TopSubtree<span::SpanData<span::SyntaxContext>>, String>, crate::ServerError>
90{
91    let version = proc_macro.process.version();
92    let mut span_data_table = SpanDataIndexMap::default();
93    let def_site = span_data_table.insert_full(def_site).0;
94    let call_site = span_data_table.insert_full(call_site).0;
95    let mixed_site = span_data_table.insert_full(mixed_site).0;
96    let task = ExpandMacro {
97        data: ExpandMacroData {
98            macro_body: FlatTree::new(subtree, version, &mut span_data_table),
99            macro_name: proc_macro.name.to_string(),
100            attributes: attr.map(|subtree| FlatTree::new(subtree, version, &mut span_data_table)),
101            has_global_spans: ExpnGlobals {
102                serialize: version >= version::HAS_GLOBAL_SPANS,
103                def_site,
104                call_site,
105                mixed_site,
106            },
107            span_data_table: if proc_macro.process.rust_analyzer_spans() {
108                serialize_span_data_index_map(&span_data_table)
109            } else {
110                Vec::new()
111            },
112        },
113        lib: proc_macro.dylib_path.to_path_buf().into(),
114        env,
115        current_dir: Some(current_dir),
116    };
117
118    let response = send_task(&proc_macro.process, Request::ExpandMacro(Box::new(task)))?;
119
120    match response {
121        Response::ExpandMacro(it) => Ok(it
122            .map(|tree| {
123                let mut expanded = FlatTree::to_subtree_resolved(tree, version, &span_data_table);
124                if proc_macro.needs_fixup_change() {
125                    proc_macro.change_fixup_to_match_old_server(&mut expanded);
126                }
127                expanded
128            })
129            .map_err(|msg| msg.0)),
130        Response::ExpandMacroExtended(it) => Ok(it
131            .map(|resp| {
132                let mut expanded = FlatTree::to_subtree_resolved(
133                    resp.tree,
134                    version,
135                    &deserialize_span_data_index_map(&resp.span_data_table),
136                );
137                if proc_macro.needs_fixup_change() {
138                    proc_macro.change_fixup_to_match_old_server(&mut expanded);
139                }
140                expanded
141            })
142            .map_err(|msg| msg.0)),
143        _ => Err(ServerError { message: "unexpected response".to_owned(), io: None }),
144    }
145}
146
147/// Sends a request to the proc-macro server and waits for a response.
148fn send_task(srv: &ProcMacroServerProcess, req: Request) -> Result<Response, ServerError> {
149    if let Some(server_error) = srv.exited() {
150        return Err(server_error.clone());
151    }
152
153    srv.send_task(send_request, req)
154}
155
156/// Sends a request to the server and reads the response.
157fn send_request(
158    mut writer: &mut dyn Write,
159    mut reader: &mut dyn BufRead,
160    req: Request,
161    buf: &mut String,
162) -> Result<Option<Response>, ServerError> {
163    req.write(write_json, &mut writer).map_err(|err| ServerError {
164        message: "failed to write request".into(),
165        io: Some(Arc::new(err)),
166    })?;
167    let res = Response::read(read_json, &mut reader, buf).map_err(|err| ServerError {
168        message: "failed to read response".into(),
169        io: Some(Arc::new(err)),
170    })?;
171    Ok(res)
172}