aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEdwin Cheng <[email protected]>2020-03-26 20:26:34 +0000
committerEdwin Cheng <[email protected]>2020-03-31 15:20:18 +0100
commit503cbd3f4b54f3be224d7a4221fa023f0e35d228 (patch)
tree101dcec6de8da790766a6e76d8f983242d8fcbfd
parentfa3c7742af9fbfe5146f4158a6119fa727dcc87a (diff)
Implement ra_proc_macro client logic
-rw-r--r--Cargo.lock5
-rw-r--r--crates/ra_hir_expand/src/proc_macro.rs27
-rw-r--r--crates/ra_proc_macro/Cargo.toml5
-rw-r--r--crates/ra_proc_macro/src/lib.rs83
-rw-r--r--crates/ra_proc_macro/src/msg.rs218
-rw-r--r--crates/ra_proc_macro/src/process.rs202
-rw-r--r--crates/ra_proc_macro/src/rpc.rs260
-rw-r--r--crates/ra_project_model/src/cargo_workspace.rs22
-rw-r--r--crates/ra_tt/src/lib.rs7
-rw-r--r--crates/rust-analyzer/src/main_loop.rs1
-rw-r--r--crates/rust-analyzer/src/world.rs20
11 files changed, 827 insertions, 23 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 196a37743..7887bc217 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1075,7 +1075,12 @@ dependencies = [
1075name = "ra_proc_macro" 1075name = "ra_proc_macro"
1076version = "0.1.0" 1076version = "0.1.0"
1077dependencies = [ 1077dependencies = [
1078 "crossbeam-channel",
1079 "log",
1078 "ra_tt", 1080 "ra_tt",
1081 "serde",
1082 "serde_derive",
1083 "serde_json",
1079] 1084]
1080 1085
1081[[package]] 1086[[package]]
diff --git a/crates/ra_hir_expand/src/proc_macro.rs b/crates/ra_hir_expand/src/proc_macro.rs
index 4d270e0de..97d1208ec 100644
--- a/crates/ra_hir_expand/src/proc_macro.rs
+++ b/crates/ra_hir_expand/src/proc_macro.rs
@@ -9,6 +9,15 @@ pub struct ProcMacroExpander {
9 proc_macro_id: ProcMacroId, 9 proc_macro_id: ProcMacroId,
10} 10}
11 11
12macro_rules! err {
13 ($fmt:literal, $($tt:tt),*) => {
14 mbe::ExpandError::ProcMacroError(tt::ExpansionError::Unknown(format!($fmt, $($tt),*)))
15 };
16 ($fmt:literal) => {
17 mbe::ExpandError::ProcMacroError(tt::ExpansionError::Unknown($fmt.to_string()))
18 }
19}
20
12impl ProcMacroExpander { 21impl ProcMacroExpander {
13 pub fn new(krate: CrateId, proc_macro_id: ProcMacroId) -> ProcMacroExpander { 22 pub fn new(krate: CrateId, proc_macro_id: ProcMacroId) -> ProcMacroExpander {
14 ProcMacroExpander { krate, proc_macro_id } 23 ProcMacroExpander { krate, proc_macro_id }
@@ -25,8 +34,24 @@ impl ProcMacroExpander {
25 .proc_macro 34 .proc_macro
26 .get(self.proc_macro_id.0 as usize) 35 .get(self.proc_macro_id.0 as usize)
27 .clone() 36 .clone()
28 .ok_or_else(|| mbe::ExpandError::ConversionError)?; 37 .ok_or_else(|| err!("No derive macro found."))?;
38
39 let tt = remove_derive_atr(tt, &proc_macro.name)
40 .ok_or_else(|| err!("Fail to remove derive for custom derive"))?;
29 41
30 proc_macro.expander.expand(&tt, None).map_err(mbe::ExpandError::from) 42 proc_macro.expander.expand(&tt, None).map_err(mbe::ExpandError::from)
31 } 43 }
32} 44}
45
46fn remove_derive_atr(tt: &tt::Subtree, _name: &str) -> Option<tt::Subtree> {
47 // FIXME: proper handle the remove derive
48 // We assume the first 2 tokens are #[derive(name)]
49 if tt.token_trees.len() > 2 {
50 let mut tt = tt.clone();
51 tt.token_trees.remove(0);
52 tt.token_trees.remove(0);
53 return Some(tt);
54 }
55
56 None
57}
diff --git a/crates/ra_proc_macro/Cargo.toml b/crates/ra_proc_macro/Cargo.toml
index bc2c37296..7b4ff993f 100644
--- a/crates/ra_proc_macro/Cargo.toml
+++ b/crates/ra_proc_macro/Cargo.toml
@@ -10,3 +10,8 @@ doctest = false
10 10
11[dependencies] 11[dependencies]
12ra_tt = { path = "../ra_tt" } 12ra_tt = { path = "../ra_tt" }
13serde_derive = "1.0.104"
14serde = "1.0.104"
15serde_json = "1.0.48"
16log = "0.4.8"
17crossbeam-channel = "0.4.0"
diff --git a/crates/ra_proc_macro/src/lib.rs b/crates/ra_proc_macro/src/lib.rs
index 5e21dd487..a0a478dc8 100644
--- a/crates/ra_proc_macro/src/lib.rs
+++ b/crates/ra_proc_macro/src/lib.rs
@@ -5,55 +5,102 @@
5//! is used to provide basic infrastructure for communication between two 5//! is used to provide basic infrastructure for communication between two
6//! processes: Client (RA itself), Server (the external program) 6//! processes: Client (RA itself), Server (the external program)
7 7
8mod rpc;
9mod process;
10pub mod msg;
11
12use process::ProcMacroProcessSrv;
8use ra_tt::{SmolStr, Subtree}; 13use ra_tt::{SmolStr, Subtree};
14use rpc::ProcMacroKind;
9use std::{ 15use std::{
10 path::{Path, PathBuf}, 16 path::{Path, PathBuf},
11 sync::Arc, 17 sync::Arc,
12}; 18};
13 19
14#[derive(Debug, Clone, PartialEq, Eq)] 20pub use rpc::{ExpansionResult, ExpansionTask};
21
22#[derive(Debug, Clone)]
15pub struct ProcMacroProcessExpander { 23pub struct ProcMacroProcessExpander {
16 process: Arc<ProcMacroProcessSrv>, 24 process: Arc<ProcMacroProcessSrv>,
25 dylib_path: PathBuf,
17 name: SmolStr, 26 name: SmolStr,
18} 27}
19 28
29impl Eq for ProcMacroProcessExpander {}
30impl PartialEq for ProcMacroProcessExpander {
31 fn eq(&self, other: &Self) -> bool {
32 self.name == other.name
33 && self.dylib_path == other.dylib_path
34 && Arc::ptr_eq(&self.process, &other.process)
35 }
36}
37
20impl ra_tt::TokenExpander for ProcMacroProcessExpander { 38impl ra_tt::TokenExpander for ProcMacroProcessExpander {
21 fn expand( 39 fn expand(
22 &self, 40 &self,
23 _subtree: &Subtree, 41 subtree: &Subtree,
24 _attr: Option<&Subtree>, 42 _attr: Option<&Subtree>,
25 ) -> Result<Subtree, ra_tt::ExpansionError> { 43 ) -> Result<Subtree, ra_tt::ExpansionError> {
26 // FIXME: do nothing for now 44 self.process.custom_derive(&self.dylib_path, subtree, &self.name)
27 Ok(Subtree::default())
28 } 45 }
29} 46}
30 47
31#[derive(Debug, Clone, PartialEq, Eq)] 48#[derive(Debug, Clone)]
32pub struct ProcMacroProcessSrv { 49enum ProcMacroClientKind {
33 path: PathBuf,
34}
35
36#[derive(Debug, Clone, PartialEq, Eq)]
37pub enum ProcMacroClient {
38 Process { process: Arc<ProcMacroProcessSrv> }, 50 Process { process: Arc<ProcMacroProcessSrv> },
39 Dummy, 51 Dummy,
40} 52}
41 53
54#[derive(Debug, Clone)]
55pub struct ProcMacroClient {
56 kind: ProcMacroClientKind,
57}
58
42impl ProcMacroClient { 59impl ProcMacroClient {
43 pub fn extern_process(process_path: &Path) -> ProcMacroClient { 60 pub fn extern_process(process_path: &Path) -> Result<ProcMacroClient, std::io::Error> {
44 let process = ProcMacroProcessSrv { path: process_path.into() }; 61 let process = ProcMacroProcessSrv::run(process_path)?;
45 ProcMacroClient::Process { process: Arc::new(process) } 62 Ok(ProcMacroClient { kind: ProcMacroClientKind::Process { process: Arc::new(process) } })
46 } 63 }
47 64
48 pub fn dummy() -> ProcMacroClient { 65 pub fn dummy() -> ProcMacroClient {
49 ProcMacroClient::Dummy 66 ProcMacroClient { kind: ProcMacroClientKind::Dummy }
50 } 67 }
51 68
52 pub fn by_dylib_path( 69 pub fn by_dylib_path(
53 &self, 70 &self,
54 _dylib_path: &Path, 71 dylib_path: &Path,
55 ) -> Vec<(SmolStr, Arc<dyn ra_tt::TokenExpander>)> { 72 ) -> Vec<(SmolStr, Arc<dyn ra_tt::TokenExpander>)> {
56 // FIXME: return empty for now 73 match &self.kind {
57 vec![] 74 ProcMacroClientKind::Dummy => vec![],
75 ProcMacroClientKind::Process { process } => {
76 let macros = match process.find_proc_macros(dylib_path) {
77 Err(err) => {
78 eprintln!("Fail to find proc macro. Error: {:#?}", err);
79 return vec![];
80 }
81 Ok(macros) => macros,
82 };
83
84 macros
85 .into_iter()
86 .filter_map(|(name, kind)| {
87 // FIXME: Support custom derive only for now.
88 match kind {
89 ProcMacroKind::CustomDerive => {
90 let name = SmolStr::new(&name);
91 let expander: Arc<dyn ra_tt::TokenExpander> =
92 Arc::new(ProcMacroProcessExpander {
93 process: process.clone(),
94 name: name.clone(),
95 dylib_path: dylib_path.into(),
96 });
97 Some((name, expander))
98 }
99 _ => None,
100 }
101 })
102 .collect()
103 }
104 }
58 } 105 }
59} 106}
diff --git a/crates/ra_proc_macro/src/msg.rs b/crates/ra_proc_macro/src/msg.rs
new file mode 100644
index 000000000..2fb065d32
--- /dev/null
+++ b/crates/ra_proc_macro/src/msg.rs
@@ -0,0 +1,218 @@
1//! A simplified version of lsp base protocol for rpc
2
3use std::{
4 fmt,
5 io::{self, BufRead, Write},
6};
7
8use serde::{de::DeserializeOwned, Deserialize, Serialize};
9
10#[derive(Serialize, Deserialize, Debug, Clone)]
11#[serde(untagged)]
12pub enum Message {
13 Request(Request),
14 Response(Response),
15}
16
17impl From<Request> for Message {
18 fn from(request: Request) -> Message {
19 Message::Request(request)
20 }
21}
22
23impl From<Response> for Message {
24 fn from(response: Response) -> Message {
25 Message::Response(response)
26 }
27}
28
29#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
30#[serde(transparent)]
31pub struct RequestId(IdRepr);
32
33#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
34#[serde(untagged)]
35enum IdRepr {
36 U64(u64),
37 String(String),
38}
39
40impl From<u64> for RequestId {
41 fn from(id: u64) -> RequestId {
42 RequestId(IdRepr::U64(id))
43 }
44}
45
46impl From<String> for RequestId {
47 fn from(id: String) -> RequestId {
48 RequestId(IdRepr::String(id))
49 }
50}
51
52impl fmt::Display for RequestId {
53 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
54 match &self.0 {
55 IdRepr::U64(it) => fmt::Display::fmt(it, f),
56 IdRepr::String(it) => fmt::Display::fmt(it, f),
57 }
58 }
59}
60
61#[derive(Debug, Serialize, Deserialize, Clone)]
62pub struct Request {
63 pub id: RequestId,
64 pub method: String,
65 pub params: serde_json::Value,
66}
67
68#[derive(Debug, Serialize, Deserialize, Clone)]
69pub struct Response {
70 // JSON RPC allows this to be null if it was impossible
71 // to decode the request's id. Ignore this special case
72 // and just die horribly.
73 pub id: RequestId,
74 #[serde(skip_serializing_if = "Option::is_none")]
75 pub result: Option<serde_json::Value>,
76 #[serde(skip_serializing_if = "Option::is_none")]
77 pub error: Option<ResponseError>,
78}
79
80#[derive(Debug, Serialize, Deserialize, Clone)]
81pub struct ResponseError {
82 pub code: i32,
83 pub message: String,
84 #[serde(skip_serializing_if = "Option::is_none")]
85 pub data: Option<serde_json::Value>,
86}
87
88#[derive(Clone, Copy, Debug)]
89#[allow(unused)]
90pub enum ErrorCode {
91 // Defined by JSON RPC
92 ParseError = -32700,
93 InvalidRequest = -32600,
94 MethodNotFound = -32601,
95 InvalidParams = -32602,
96 InternalError = -32603,
97 ServerErrorStart = -32099,
98 ServerErrorEnd = -32000,
99 ServerNotInitialized = -32002,
100 UnknownErrorCode = -32001,
101
102 // Defined by protocol
103 ExpansionError = -32900,
104}
105
106#[derive(Debug, Serialize, Deserialize, Clone)]
107pub struct Notification {
108 pub method: String,
109 pub params: serde_json::Value,
110}
111
112impl Message {
113 pub fn read(r: &mut impl BufRead) -> io::Result<Option<Message>> {
114 let text = match read_msg_text(r)? {
115 None => return Ok(None),
116 Some(text) => text,
117 };
118 let msg = serde_json::from_str(&text)?;
119 Ok(Some(msg))
120 }
121 pub fn write(self, w: &mut impl Write) -> io::Result<()> {
122 #[derive(Serialize)]
123 struct JsonRpc {
124 jsonrpc: &'static str,
125 #[serde(flatten)]
126 msg: Message,
127 }
128 let text = serde_json::to_string(&JsonRpc { jsonrpc: "2.0", msg: self })?;
129 write_msg_text(w, &text)
130 }
131}
132
133impl Response {
134 pub fn new_ok<R: Serialize>(id: RequestId, result: R) -> Response {
135 Response { id, result: Some(serde_json::to_value(result).unwrap()), error: None }
136 }
137 pub fn new_err(id: RequestId, code: i32, message: String) -> Response {
138 let error = ResponseError { code, message, data: None };
139 Response { id, result: None, error: Some(error) }
140 }
141}
142
143impl Request {
144 pub fn new<P: Serialize>(id: RequestId, method: String, params: P) -> Request {
145 Request { id, method, params: serde_json::to_value(params).unwrap() }
146 }
147 pub fn extract<P: DeserializeOwned>(self, method: &str) -> Result<(RequestId, P), Request> {
148 if self.method == method {
149 let params = serde_json::from_value(self.params).unwrap_or_else(|err| {
150 panic!("Invalid request\nMethod: {}\n error: {}", method, err)
151 });
152 Ok((self.id, params))
153 } else {
154 Err(self)
155 }
156 }
157}
158
159impl Notification {
160 pub fn new(method: String, params: impl Serialize) -> Notification {
161 Notification { method, params: serde_json::to_value(params).unwrap() }
162 }
163 pub fn extract<P: DeserializeOwned>(self, method: &str) -> Result<P, Notification> {
164 if self.method == method {
165 let params = serde_json::from_value(self.params).unwrap();
166 Ok(params)
167 } else {
168 Err(self)
169 }
170 }
171}
172
173fn read_msg_text(inp: &mut impl BufRead) -> io::Result<Option<String>> {
174 fn invalid_data(error: impl Into<Box<dyn std::error::Error + Send + Sync>>) -> io::Error {
175 io::Error::new(io::ErrorKind::InvalidData, error)
176 }
177 macro_rules! invalid_data {
178 ($($tt:tt)*) => (invalid_data(format!($($tt)*)))
179 }
180
181 let mut size = None;
182 let mut buf = String::new();
183 loop {
184 buf.clear();
185 if inp.read_line(&mut buf)? == 0 {
186 return Ok(None);
187 }
188 if !buf.ends_with("\r\n") {
189 return Err(invalid_data!("malformed header: {:?}", buf));
190 }
191 let buf = &buf[..buf.len() - 2];
192 if buf.is_empty() {
193 break;
194 }
195 let mut parts = buf.splitn(2, ": ");
196 let header_name = parts.next().unwrap();
197 let header_value =
198 parts.next().ok_or_else(|| invalid_data!("malformed header: {:?}", buf))?;
199 if header_name == "Content-Length" {
200 size = Some(header_value.parse::<usize>().map_err(invalid_data)?);
201 }
202 }
203 let size: usize = size.ok_or_else(|| invalid_data!("no Content-Length"))?;
204 let mut buf = buf.into_bytes();
205 buf.resize(size, 0);
206 inp.read_exact(&mut buf)?;
207 let buf = String::from_utf8(buf).map_err(invalid_data)?;
208 log::debug!("< {}", buf);
209 Ok(Some(buf))
210}
211
212fn write_msg_text(out: &mut impl Write, msg: &str) -> io::Result<()> {
213 log::debug!("> {}", msg);
214 write!(out, "Content-Length: {}\r\n\r\n", msg.len())?;
215 out.write_all(msg.as_bytes())?;
216 out.flush()?;
217 Ok(())
218}
diff --git a/crates/ra_proc_macro/src/process.rs b/crates/ra_proc_macro/src/process.rs
new file mode 100644
index 000000000..a9095af11
--- /dev/null
+++ b/crates/ra_proc_macro/src/process.rs
@@ -0,0 +1,202 @@
1use crossbeam_channel::{bounded, Receiver, Sender};
2use ra_tt::Subtree;
3
4use crate::msg::{ErrorCode, Message, Request, Response, ResponseError};
5use crate::rpc::{ExpansionResult, ExpansionTask, ListMacrosResult, ListMacrosTask, ProcMacroKind};
6
7use io::{BufRead, BufReader};
8use std::{
9 io::{self, Write},
10 path::{Path, PathBuf},
11 process::{Child, Command, Stdio},
12 thread::spawn,
13};
14
15#[derive(Debug, Default)]
16pub(crate) struct ProcMacroProcessSrv {
17 inner: Option<Handle>,
18}
19
20struct Task {
21 req: Message,
22 result_tx: Sender<Message>,
23}
24
25#[derive(Debug)]
26struct Handle {
27 sender: Sender<Task>,
28}
29
30struct Process {
31 path: PathBuf,
32 child: Child,
33}
34
35impl Process {
36 fn run(process_path: &Path) -> Result<Process, io::Error> {
37 let child = Command::new(process_path.clone())
38 .stdin(Stdio::piped())
39 .stdout(Stdio::piped())
40 .spawn()?;
41
42 Ok(Process { path: process_path.into(), child })
43 }
44
45 fn restart(&mut self) -> Result<(), io::Error> {
46 let _ = self.child.kill();
47 self.child =
48 Command::new(self.path.clone()).stdin(Stdio::piped()).stdout(Stdio::piped()).spawn()?;
49 Ok(())
50 }
51
52 fn stdio(&mut self) -> Option<(impl Write, impl BufRead)> {
53 let stdin = self.child.stdin.take()?;
54 let stdout = self.child.stdout.take()?;
55 let read = BufReader::new(stdout);
56
57 Some((stdin, read))
58 }
59}
60
61impl ProcMacroProcessSrv {
62 pub fn run(process_path: &Path) -> Result<ProcMacroProcessSrv, io::Error> {
63 let process = Process::run(process_path)?;
64
65 let (task_tx, task_rx) = bounded(0);
66
67 let _ = spawn(move || {
68 client_loop(task_rx, process);
69 });
70 Ok(ProcMacroProcessSrv { inner: Some(Handle { sender: task_tx }) })
71 }
72
73 pub fn find_proc_macros(
74 &self,
75 dylib_path: &Path,
76 ) -> Result<Vec<(String, ProcMacroKind)>, ra_tt::ExpansionError> {
77 let task = ListMacrosTask { lib: dylib_path.to_path_buf() };
78
79 let result: ListMacrosResult = self.send_task("list_macros", task)?;
80 Ok(result.macros)
81 }
82
83 pub fn custom_derive(
84 &self,
85 dylib_path: &Path,
86 subtree: &Subtree,
87 derive_name: &str,
88 ) -> Result<Subtree, ra_tt::ExpansionError> {
89 let task = ExpansionTask {
90 macro_body: subtree.clone(),
91 macro_name: derive_name.to_string(),
92 attributes: None,
93 lib: dylib_path.to_path_buf(),
94 };
95
96 let result: ExpansionResult = self.send_task("custom_derive", task)?;
97 Ok(result.expansion)
98 }
99
100 pub fn send_task<'a, T, R>(&self, method: &str, task: T) -> Result<R, ra_tt::ExpansionError>
101 where
102 T: serde::Serialize,
103 R: serde::de::DeserializeOwned + Default,
104 {
105 let handle = match &self.inner {
106 None => return Err(ra_tt::ExpansionError::Unknown("No handle is found.".to_string())),
107 Some(it) => it,
108 };
109
110 let msg = serde_json::to_value(task).unwrap();
111
112 // FIXME: use a proper request id
113 let id = 0;
114 let req = Request { id: id.into(), method: method.into(), params: msg };
115
116 let (result_tx, result_rx) = bounded(0);
117
118 handle.sender.send(Task { req: req.into(), result_tx }).unwrap();
119 let response = result_rx.recv().unwrap();
120
121 match response {
122 Message::Request(_) => {
123 return Err(ra_tt::ExpansionError::Unknown(
124 "Return request from ra_proc_srv".into(),
125 ))
126 }
127 Message::Response(res) => {
128 if let Some(err) = res.error {
129 return Err(ra_tt::ExpansionError::ExpansionError(err.message));
130 }
131 match res.result {
132 None => Ok(R::default()),
133 Some(res) => {
134 let result: R = serde_json::from_value(res)
135 .map_err(|err| ra_tt::ExpansionError::JsonError(err.to_string()))?;
136 Ok(result)
137 }
138 }
139 }
140 }
141 }
142}
143
144fn client_loop(task_rx: Receiver<Task>, mut process: Process) {
145 let (mut stdin, mut stdout) = match process.stdio() {
146 None => return,
147 Some(it) => it,
148 };
149
150 loop {
151 let task = match task_rx.recv() {
152 Ok(task) => task,
153 Err(_) => break,
154 };
155
156 let res = match send_message(&mut stdin, &mut stdout, task.req) {
157 Ok(res) => res,
158 Err(_err) => {
159 let res = Response {
160 id: 0.into(),
161 result: None,
162 error: Some(ResponseError {
163 code: ErrorCode::ServerErrorEnd as i32,
164 message: "Server closed".into(),
165 data: None,
166 }),
167 };
168 if task.result_tx.send(res.into()).is_err() {
169 break;
170 }
171 // Restart the process
172 if process.restart().is_err() {
173 break;
174 }
175 let stdio = match process.stdio() {
176 None => break,
177 Some(it) => it,
178 };
179 stdin = stdio.0;
180 stdout = stdio.1;
181 continue;
182 }
183 };
184
185 if let Some(res) = res {
186 if task.result_tx.send(res).is_err() {
187 break;
188 }
189 }
190 }
191
192 let _ = process.child.kill();
193}
194
195fn send_message(
196 mut writer: &mut impl Write,
197 mut reader: &mut impl BufRead,
198 msg: Message,
199) -> Result<Option<Message>, io::Error> {
200 msg.write(&mut writer)?;
201 Ok(Message::read(&mut reader)?)
202}
diff --git a/crates/ra_proc_macro/src/rpc.rs b/crates/ra_proc_macro/src/rpc.rs
new file mode 100644
index 000000000..e7eaf7c15
--- /dev/null
+++ b/crates/ra_proc_macro/src/rpc.rs
@@ -0,0 +1,260 @@
1//! Data struture serialization related stuffs for RPC
2
3use ra_tt::{
4 Delimiter, DelimiterKind, Ident, Leaf, Literal, Punct, SmolStr, Spacing, Subtree, TokenId,
5 TokenTree,
6};
7use serde::{Deserialize, Serialize};
8use std::path::PathBuf;
9
10#[derive(Clone, Eq, PartialEq, Debug, Serialize, Deserialize)]
11pub struct ListMacrosTask {
12 pub lib: PathBuf,
13}
14
15#[derive(Clone, Eq, PartialEq, Debug, Serialize, Deserialize)]
16pub enum ProcMacroKind {
17 CustomDerive,
18 FuncLike,
19 Attr,
20}
21
22#[derive(Clone, Eq, PartialEq, Debug, Default, Serialize, Deserialize)]
23pub struct ListMacrosResult {
24 pub macros: Vec<(String, ProcMacroKind)>,
25}
26
27#[derive(Clone, Eq, PartialEq, Debug, Serialize, Deserialize)]
28pub struct ExpansionTask {
29 /// Argument of macro call.
30 ///
31 /// In custom derive that would be a struct or enum; in attribute-like macro - underlying
32 /// item; in function-like macro - the macro body.
33 #[serde(with = "SubtreeDef")]
34 pub macro_body: Subtree,
35
36 /// Names of macros to expand.
37 ///
38 /// In custom derive those are names of derived traits (`Serialize`, `Getters`, etc.). In
39 /// attribute-like and functiona-like macros - single name of macro itself (`show_streams`).
40 pub macro_name: String,
41
42 /// Possible attributes for the attribute-like macros.
43 #[serde(with = "opt_subtree_def")]
44 pub attributes: Option<Subtree>,
45
46 pub lib: PathBuf,
47}
48
49#[derive(Clone, Eq, PartialEq, Debug, Default, Serialize, Deserialize)]
50pub struct ExpansionResult {
51 #[serde(with = "SubtreeDef")]
52 pub expansion: Subtree,
53}
54
55#[derive(Serialize, Deserialize)]
56#[serde(remote = "DelimiterKind")]
57enum DelimiterKindDef {
58 Parenthesis,
59 Brace,
60 Bracket,
61}
62
63#[derive(Serialize, Deserialize)]
64#[serde(remote = "TokenId")]
65struct TokenIdDef(u32);
66
67#[derive(Serialize, Deserialize)]
68#[serde(remote = "Delimiter")]
69struct DelimiterDef {
70 #[serde(with = "TokenIdDef")]
71 pub id: TokenId,
72 #[serde(with = "DelimiterKindDef")]
73 pub kind: DelimiterKind,
74}
75
76#[derive(Serialize, Deserialize)]
77#[serde(remote = "Subtree")]
78struct SubtreeDef {
79 #[serde(default, with = "opt_delimiter_def")]
80 pub delimiter: Option<Delimiter>,
81 #[serde(with = "vec_token_tree")]
82 pub token_trees: Vec<TokenTree>,
83}
84
85#[derive(Serialize, Deserialize)]
86#[serde(remote = "TokenTree")]
87enum TokenTreeDef {
88 #[serde(with = "LeafDef")]
89 Leaf(Leaf),
90 #[serde(with = "SubtreeDef")]
91 Subtree(Subtree),
92}
93
94#[derive(Serialize, Deserialize)]
95#[serde(remote = "Leaf")]
96enum LeafDef {
97 #[serde(with = "LiteralDef")]
98 Literal(Literal),
99 #[serde(with = "PunctDef")]
100 Punct(Punct),
101 #[serde(with = "IdentDef")]
102 Ident(Ident),
103}
104
105#[derive(Serialize, Deserialize)]
106#[serde(remote = "Literal")]
107struct LiteralDef {
108 pub text: SmolStr,
109 #[serde(with = "TokenIdDef")]
110 pub id: TokenId,
111}
112
113#[derive(Serialize, Deserialize)]
114#[serde(remote = "Punct")]
115struct PunctDef {
116 pub char: char,
117 #[serde(with = "SpacingDef")]
118 pub spacing: Spacing,
119 #[serde(with = "TokenIdDef")]
120 pub id: TokenId,
121}
122
123#[derive(Serialize, Deserialize)]
124#[serde(remote = "Spacing")]
125enum SpacingDef {
126 Alone,
127 Joint,
128}
129
130#[derive(Serialize, Deserialize)]
131#[serde(remote = "Ident")]
132struct IdentDef {
133 pub text: SmolStr,
134 #[serde(with = "TokenIdDef")]
135 pub id: TokenId,
136}
137
138mod opt_delimiter_def {
139 use super::{Delimiter, DelimiterDef};
140 use serde::{Deserialize, Deserializer, Serialize, Serializer};
141
142 pub fn serialize<S>(value: &Option<Delimiter>, serializer: S) -> Result<S::Ok, S::Error>
143 where
144 S: Serializer,
145 {
146 #[derive(Serialize)]
147 struct Helper<'a>(#[serde(with = "DelimiterDef")] &'a Delimiter);
148 value.as_ref().map(Helper).serialize(serializer)
149 }
150
151 pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<Delimiter>, D::Error>
152 where
153 D: Deserializer<'de>,
154 {
155 #[derive(Deserialize)]
156 struct Helper(#[serde(with = "DelimiterDef")] Delimiter);
157 let helper = Option::deserialize(deserializer)?;
158 Ok(helper.map(|Helper(external)| external))
159 }
160}
161
162mod opt_subtree_def {
163 use super::{Subtree, SubtreeDef};
164 use serde::{Deserialize, Deserializer, Serialize, Serializer};
165
166 pub fn serialize<S>(value: &Option<Subtree>, serializer: S) -> Result<S::Ok, S::Error>
167 where
168 S: Serializer,
169 {
170 #[derive(Serialize)]
171 struct Helper<'a>(#[serde(with = "SubtreeDef")] &'a Subtree);
172 value.as_ref().map(Helper).serialize(serializer)
173 }
174
175 pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<Subtree>, D::Error>
176 where
177 D: Deserializer<'de>,
178 {
179 #[derive(Deserialize)]
180 struct Helper(#[serde(with = "SubtreeDef")] Subtree);
181 let helper = Option::deserialize(deserializer)?;
182 Ok(helper.map(|Helper(external)| external))
183 }
184}
185
186mod vec_token_tree {
187 use super::{TokenTree, TokenTreeDef};
188 use serde::{ser::SerializeSeq, Deserialize, Deserializer, Serialize, Serializer};
189
190 pub fn serialize<S>(value: &Vec<TokenTree>, serializer: S) -> Result<S::Ok, S::Error>
191 where
192 S: Serializer,
193 {
194 #[derive(Serialize)]
195 struct Helper<'a>(#[serde(with = "TokenTreeDef")] &'a TokenTree);
196
197 let items: Vec<_> = value.iter().map(Helper).collect();
198 let mut seq = serializer.serialize_seq(Some(items.len()))?;
199 for element in items {
200 seq.serialize_element(&element)?;
201 }
202 seq.end()
203 }
204
205 pub fn deserialize<'de, D>(deserializer: D) -> Result<Vec<TokenTree>, D::Error>
206 where
207 D: Deserializer<'de>,
208 {
209 #[derive(Deserialize)]
210 struct Helper(#[serde(with = "TokenTreeDef")] TokenTree);
211
212 let helper = Vec::deserialize(deserializer)?;
213 Ok(helper.into_iter().map(|Helper(external)| external).collect())
214 }
215}
216
217#[cfg(test)]
218mod tests {
219 use super::*;
220
221 fn fixture_token_tree() -> Subtree {
222 let mut subtree = Subtree::default();
223 subtree
224 .token_trees
225 .push(TokenTree::Leaf(Ident { text: "struct".into(), id: TokenId(0) }.into()));
226 subtree
227 .token_trees
228 .push(TokenTree::Leaf(Ident { text: "Foo".into(), id: TokenId(1) }.into()));
229 subtree.token_trees.push(TokenTree::Subtree(
230 Subtree {
231 delimiter: Some(Delimiter { id: TokenId(2), kind: DelimiterKind::Brace }),
232 token_trees: vec![],
233 }
234 .into(),
235 ));
236 subtree
237 }
238
239 #[test]
240 fn test_proc_macro_rpc_works() {
241 let tt = fixture_token_tree();
242 let task = ExpansionTask {
243 macro_body: tt.clone(),
244 macro_name: Default::default(),
245 attributes: None,
246 lib: Default::default(),
247 };
248
249 let json = serde_json::to_string(&task).unwrap();
250 let back: ExpansionTask = serde_json::from_str(&json).unwrap();
251
252 assert_eq!(task.macro_body, back.macro_body);
253
254 let result = ExpansionResult { expansion: tt.clone() };
255 let json = serde_json::to_string(&task).unwrap();
256 let back: ExpansionResult = serde_json::from_str(&json).unwrap();
257
258 assert_eq!(result, back);
259 }
260}
diff --git a/crates/ra_project_model/src/cargo_workspace.rs b/crates/ra_project_model/src/cargo_workspace.rs
index 738fd6f61..32592e660 100644
--- a/crates/ra_project_model/src/cargo_workspace.rs
+++ b/crates/ra_project_model/src/cargo_workspace.rs
@@ -1,6 +1,7 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use std::{ 3use std::{
4 ffi::OsStr,
4 ops, 5 ops,
5 path::{Path, PathBuf}, 6 path::{Path, PathBuf},
6}; 7};
@@ -299,7 +300,10 @@ pub fn load_extern_resources(cargo_toml: &Path, cargo_features: &CargoFeatures)
299 Message::CompilerArtifact(message) => { 300 Message::CompilerArtifact(message) => {
300 if message.target.kind.contains(&"proc-macro".to_string()) { 301 if message.target.kind.contains(&"proc-macro".to_string()) {
301 let package_id = message.package_id; 302 let package_id = message.package_id;
302 if let Some(filename) = message.filenames.get(0) { 303 // Skip rmeta file
304 if let Some(filename) =
305 message.filenames.iter().filter(|name| is_dylib(name)).next()
306 {
303 acc.proc_dylib_paths.insert(package_id, filename.clone()); 307 acc.proc_dylib_paths.insert(package_id, filename.clone());
304 } 308 }
305 } 309 }
@@ -316,3 +320,19 @@ pub fn load_extern_resources(cargo_toml: &Path, cargo_features: &CargoFeatures)
316 320
317 acc 321 acc
318} 322}
323
324// FIXME: File a better way to know if it is a dylib
325fn is_dylib(path: &Path) -> bool {
326 let ext = match path.extension().and_then(OsStr::to_str).map(|it| it.to_string().to_lowercase())
327 {
328 None => return false,
329 Some(ext) => ext,
330 };
331
332 match ext.as_str() {
333 "dll" => true,
334 "dylib" => true,
335 "so" => true,
336 _ => false,
337 }
338}
diff --git a/crates/ra_tt/src/lib.rs b/crates/ra_tt/src/lib.rs
index 1015ce0a6..bd484aa30 100644
--- a/crates/ra_tt/src/lib.rs
+++ b/crates/ra_tt/src/lib.rs
@@ -189,7 +189,12 @@ impl Subtree {
189pub mod buffer; 189pub mod buffer;
190 190
191#[derive(Debug, PartialEq, Eq)] 191#[derive(Debug, PartialEq, Eq)]
192pub enum ExpansionError {} 192pub enum ExpansionError {
193 IOError(String),
194 JsonError(String),
195 Unknown(String),
196 ExpansionError(String),
197}
193 198
194pub trait TokenExpander: Debug + Send + Sync + RefUnwindSafe { 199pub trait TokenExpander: Debug + Send + Sync + RefUnwindSafe {
195 fn expand(&self, subtree: &Subtree, attrs: Option<&Subtree>) 200 fn expand(&self, subtree: &Subtree, attrs: Option<&Subtree>)
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs
index c233f72ff..9fd568601 100644
--- a/crates/rust-analyzer/src/main_loop.rs
+++ b/crates/rust-analyzer/src/main_loop.rs
@@ -109,6 +109,7 @@ fn get_config(
109 }, 109 },
110 rustfmt_args: config.rustfmt_args.clone(), 110 rustfmt_args: config.rustfmt_args.clone(),
111 vscode_lldb: config.vscode_lldb, 111 vscode_lldb: config.vscode_lldb,
112 proc_macro_srv: None, // FIXME: get this from config
112 } 113 }
113} 114}
114 115
diff --git a/crates/rust-analyzer/src/world.rs b/crates/rust-analyzer/src/world.rs
index a15a7085f..b97fc7c53 100644
--- a/crates/rust-analyzer/src/world.rs
+++ b/crates/rust-analyzer/src/world.rs
@@ -58,6 +58,7 @@ pub struct Config {
58 pub rustfmt_args: Vec<String>, 58 pub rustfmt_args: Vec<String>,
59 pub check: CheckConfig, 59 pub check: CheckConfig,
60 pub vscode_lldb: bool, 60 pub vscode_lldb: bool,
61 pub proc_macro_srv: Option<String>,
61} 62}
62 63
63/// `WorldState` is the primary mutable state of the language server 64/// `WorldState` is the primary mutable state of the language server
@@ -167,8 +168,23 @@ impl WorldState {
167 vfs_file.map(|f| FileId(f.0)) 168 vfs_file.map(|f| FileId(f.0))
168 }; 169 };
169 170
170 let proc_macro_client = 171 let proc_macro_client = match &options.proc_macro_srv {
171 ProcMacroClient::extern_process(std::path::Path::new("ra_proc_macro_srv")); 172 None => ProcMacroClient::dummy(),
173 Some(srv) => {
174 let path = Path::new(&srv);
175 match ProcMacroClient::extern_process(path) {
176 Ok(it) => it,
177 Err(err) => {
178 log::error!(
179 "Fail to run ra_proc_macro_srv from path {}, error : {}",
180 path.to_string_lossy(),
181 err
182 );
183 ProcMacroClient::dummy()
184 }
185 }
186 }
187 };
172 188
173 workspaces 189 workspaces
174 .iter() 190 .iter()