aboutsummaryrefslogtreecommitdiff
path: root/crates/proc_macro_srv
diff options
context:
space:
mode:
Diffstat (limited to 'crates/proc_macro_srv')
-rw-r--r--crates/proc_macro_srv/Cargo.toml4
-rw-r--r--crates/proc_macro_srv/src/dylib.rs6
-rw-r--r--crates/proc_macro_srv/src/proc_macro/bridge/client.rs2
-rw-r--r--crates/proc_macro_srv/src/proc_macro/bridge/mod.rs2
-rw-r--r--crates/proc_macro_srv/src/rustc_server.rs183
-rw-r--r--crates/proc_macro_srv/src/tests/fixtures/test_serialize_proc_macro.txt2
-rw-r--r--crates/proc_macro_srv/src/tests/utils.rs5
7 files changed, 136 insertions, 68 deletions
diff --git a/crates/proc_macro_srv/Cargo.toml b/crates/proc_macro_srv/Cargo.toml
index 6c8c28980..63b3f1532 100644
--- a/crates/proc_macro_srv/Cargo.toml
+++ b/crates/proc_macro_srv/Cargo.toml
@@ -17,10 +17,10 @@ memmap2 = "0.2.0"
17tt = { path = "../tt", version = "0.0.0" } 17tt = { path = "../tt", version = "0.0.0" }
18mbe = { path = "../mbe", version = "0.0.0" } 18mbe = { path = "../mbe", version = "0.0.0" }
19proc_macro_api = { path = "../proc_macro_api", version = "0.0.0" } 19proc_macro_api = { path = "../proc_macro_api", version = "0.0.0" }
20test_utils = { path = "../test_utils", version = "0.0.0" }
21 20
22[dev-dependencies] 21[dev-dependencies]
23cargo_metadata = "0.12.2" 22test_utils = { path = "../test_utils" }
23cargo_metadata = "0.13"
24 24
25# used as proc macro test targets 25# used as proc macro test targets
26serde_derive = "1.0.106" 26serde_derive = "1.0.106"
diff --git a/crates/proc_macro_srv/src/dylib.rs b/crates/proc_macro_srv/src/dylib.rs
index 28a6ee547..baf10fea9 100644
--- a/crates/proc_macro_srv/src/dylib.rs
+++ b/crates/proc_macro_srv/src/dylib.rs
@@ -138,7 +138,7 @@ impl Expander {
138 parsed_body, 138 parsed_body,
139 false, 139 false,
140 ); 140 );
141 return res.map(|it| it.subtree); 141 return res.map(|it| it.into_subtree());
142 } 142 }
143 bridge::client::ProcMacro::Bang { name, client } if *name == macro_name => { 143 bridge::client::ProcMacro::Bang { name, client } if *name == macro_name => {
144 let res = client.run( 144 let res = client.run(
@@ -147,7 +147,7 @@ impl Expander {
147 parsed_body, 147 parsed_body,
148 false, 148 false,
149 ); 149 );
150 return res.map(|it| it.subtree); 150 return res.map(|it| it.into_subtree());
151 } 151 }
152 bridge::client::ProcMacro::Attr { name, client } if *name == macro_name => { 152 bridge::client::ProcMacro::Attr { name, client } if *name == macro_name => {
153 let res = client.run( 153 let res = client.run(
@@ -157,7 +157,7 @@ impl Expander {
157 parsed_body, 157 parsed_body,
158 false, 158 false,
159 ); 159 );
160 return res.map(|it| it.subtree); 160 return res.map(|it| it.into_subtree());
161 } 161 }
162 _ => continue, 162 _ => continue,
163 } 163 }
diff --git a/crates/proc_macro_srv/src/proc_macro/bridge/client.rs b/crates/proc_macro_srv/src/proc_macro/bridge/client.rs
index ca6749b9b..b036d4e20 100644
--- a/crates/proc_macro_srv/src/proc_macro/bridge/client.rs
+++ b/crates/proc_macro_srv/src/proc_macro/bridge/client.rs
@@ -238,7 +238,7 @@ macro_rules! define_client_side {
238 $(impl $name { 238 $(impl $name {
239 #[allow(unused)] 239 #[allow(unused)]
240 $(pub(crate) fn $method($($arg: $arg_ty),*) $(-> $ret_ty)* { 240 $(pub(crate) fn $method($($arg: $arg_ty),*) $(-> $ret_ty)* {
241 panic!("hello"); 241 panic!("crates should be linked against the sysroot version of proc_macro, not this one from rust-analyzer");
242 // Bridge::with(|bridge| { 242 // Bridge::with(|bridge| {
243 // let mut b = bridge.cached_buffer.take(); 243 // let mut b = bridge.cached_buffer.take();
244 244
diff --git a/crates/proc_macro_srv/src/proc_macro/bridge/mod.rs b/crates/proc_macro_srv/src/proc_macro/bridge/mod.rs
index e4006a5ab..e67902682 100644
--- a/crates/proc_macro_srv/src/proc_macro/bridge/mod.rs
+++ b/crates/proc_macro_srv/src/proc_macro/bridge/mod.rs
@@ -268,7 +268,7 @@ trait Mark {
268 fn mark(unmarked: Self::Unmarked) -> Self; 268 fn mark(unmarked: Self::Unmarked) -> Self;
269} 269}
270 270
271/// Unwrap types wrapped by `Mark::mark` (see `Mark` for details). 271/// Unwrap types wrapped by `cov_mark::mark` (see `Mark` for details).
272trait Unmark { 272trait Unmark {
273 type Unmarked; 273 type Unmarked;
274 fn unmark(self) -> Self::Unmarked; 274 fn unmark(self) -> Self::Unmarked;
diff --git a/crates/proc_macro_srv/src/rustc_server.rs b/crates/proc_macro_srv/src/rustc_server.rs
index a8504f762..ceefd187d 100644
--- a/crates/proc_macro_srv/src/rustc_server.rs
+++ b/crates/proc_macro_srv/src/rustc_server.rs
@@ -14,7 +14,6 @@ use std::collections::HashMap;
14use std::hash::Hash; 14use std::hash::Hash;
15use std::iter::FromIterator; 15use std::iter::FromIterator;
16use std::ops::Bound; 16use std::ops::Bound;
17use std::str::FromStr;
18use std::{ascii, vec::IntoIter}; 17use std::{ascii, vec::IntoIter};
19 18
20type Group = tt::Subtree; 19type Group = tt::Subtree;
@@ -26,27 +25,35 @@ type Span = tt::TokenId;
26 25
27#[derive(Debug, Clone)] 26#[derive(Debug, Clone)]
28pub struct TokenStream { 27pub struct TokenStream {
29 pub subtree: tt::Subtree, 28 pub token_trees: Vec<TokenTree>,
30} 29}
31 30
32impl TokenStream { 31impl TokenStream {
33 pub fn new() -> Self { 32 pub fn new() -> Self {
34 TokenStream { subtree: Default::default() } 33 TokenStream { token_trees: Default::default() }
35 } 34 }
36 35
37 pub fn with_subtree(subtree: tt::Subtree) -> Self { 36 pub fn with_subtree(subtree: tt::Subtree) -> Self {
38 TokenStream { subtree } 37 if subtree.delimiter.is_some() {
38 TokenStream { token_trees: vec![TokenTree::Subtree(subtree)] }
39 } else {
40 TokenStream { token_trees: subtree.token_trees }
41 }
42 }
43
44 pub fn into_subtree(self) -> tt::Subtree {
45 tt::Subtree { delimiter: None, token_trees: self.token_trees }
39 } 46 }
40 47
41 pub fn is_empty(&self) -> bool { 48 pub fn is_empty(&self) -> bool {
42 self.subtree.token_trees.is_empty() 49 self.token_trees.is_empty()
43 } 50 }
44} 51}
45 52
46/// Creates a token stream containing a single token tree. 53/// Creates a token stream containing a single token tree.
47impl From<TokenTree> for TokenStream { 54impl From<TokenTree> for TokenStream {
48 fn from(tree: TokenTree) -> TokenStream { 55 fn from(tree: TokenTree) -> TokenStream {
49 TokenStream { subtree: tt::Subtree { delimiter: None, token_trees: vec![tree] } } 56 TokenStream { token_trees: vec![tree] }
50 } 57 }
51} 58}
52 59
@@ -79,10 +86,10 @@ impl Extend<TokenStream> for TokenStream {
79 for tkn in item { 86 for tkn in item {
80 match tkn { 87 match tkn {
81 tt::TokenTree::Subtree(subtree) if subtree.delimiter.is_none() => { 88 tt::TokenTree::Subtree(subtree) if subtree.delimiter.is_none() => {
82 self.subtree.token_trees.extend(subtree.token_trees); 89 self.token_trees.extend(subtree.token_trees);
83 } 90 }
84 _ => { 91 _ => {
85 self.subtree.token_trees.push(tkn); 92 self.token_trees.push(tkn);
86 } 93 }
87 } 94 }
88 } 95 }
@@ -165,7 +172,7 @@ pub mod token_stream {
165 type IntoIter = super::IntoIter<TokenTree>; 172 type IntoIter = super::IntoIter<TokenTree>;
166 173
167 fn into_iter(self) -> Self::IntoIter { 174 fn into_iter(self) -> Self::IntoIter {
168 self.subtree.token_trees.into_iter() 175 self.token_trees.into_iter()
169 } 176 }
170 } 177 }
171 178
@@ -185,28 +192,23 @@ pub mod token_stream {
185 let (subtree, _token_map) = 192 let (subtree, _token_map) =
186 mbe::parse_to_token_tree(src).ok_or("Failed to parse from mbe")?; 193 mbe::parse_to_token_tree(src).ok_or("Failed to parse from mbe")?;
187 194
188 Ok(TokenStream { subtree }) 195 let subtree = subtree_replace_token_ids_with_unspecified(subtree);
196 Ok(TokenStream::with_subtree(subtree))
189 } 197 }
190 } 198 }
191 199
192 impl ToString for TokenStream { 200 impl ToString for TokenStream {
193 fn to_string(&self) -> String { 201 fn to_string(&self) -> String {
194 let tt = self.subtree.clone().into(); 202 return tokentrees_to_text(&self.token_trees[..]);
195 to_text(&tt)
196 }
197 }
198 203
199 fn to_text(tkn: &tt::TokenTree) -> String { 204 fn tokentrees_to_text(tkns: &[tt::TokenTree]) -> String {
200 match tkn { 205 tkns.iter()
201 tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) => ident.text.clone().into(),
202 tt::TokenTree::Leaf(tt::Leaf::Literal(literal)) => literal.text.clone().into(),
203 tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) => format!("{}", punct.char),
204 tt::TokenTree::Subtree(subtree) => {
205 let content = subtree
206 .token_trees
207 .iter()
208 .fold((String::new(), true), |(last, last_to_joint), tkn| { 206 .fold((String::new(), true), |(last, last_to_joint), tkn| {
209 let s = [last, to_text(tkn)].join(if last_to_joint { "" } else { " " }); 207 let s = [last, tokentree_to_text(tkn)].join(if last_to_joint {
208 ""
209 } else {
210 " "
211 });
210 let mut is_joint = false; 212 let mut is_joint = false;
211 if let tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) = tkn { 213 if let tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) = tkn {
212 if punct.spacing == tt::Spacing::Joint { 214 if punct.spacing == tt::Spacing::Joint {
@@ -215,15 +217,63 @@ pub mod token_stream {
215 } 217 }
216 (s, is_joint) 218 (s, is_joint)
217 }) 219 })
218 .0; 220 .0
219 221 }
220 let (open, close) = match subtree.delimiter.map(|it| it.kind) { 222
221 None => ("", ""), 223 fn tokentree_to_text(tkn: &tt::TokenTree) -> String {
222 Some(tt::DelimiterKind::Brace) => ("{", "}"), 224 match tkn {
223 Some(tt::DelimiterKind::Parenthesis) => ("(", ")"), 225 tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) => ident.text.clone().into(),
224 Some(tt::DelimiterKind::Bracket) => ("[", "]"), 226 tt::TokenTree::Leaf(tt::Leaf::Literal(literal)) => literal.text.clone().into(),
225 }; 227 tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) => format!("{}", punct.char),
226 format!("{}{}{}", open, content, close) 228 tt::TokenTree::Subtree(subtree) => {
229 let content = tokentrees_to_text(&subtree.token_trees);
230 let (open, close) = match subtree.delimiter.map(|it| it.kind) {
231 None => ("", ""),
232 Some(tt::DelimiterKind::Brace) => ("{", "}"),
233 Some(tt::DelimiterKind::Parenthesis) => ("(", ")"),
234 Some(tt::DelimiterKind::Bracket) => ("[", "]"),
235 };
236 format!("{}{}{}", open, content, close)
237 }
238 }
239 }
240 }
241 }
242
243 fn subtree_replace_token_ids_with_unspecified(subtree: tt::Subtree) -> tt::Subtree {
244 tt::Subtree {
245 delimiter: subtree
246 .delimiter
247 .map(|d| tt::Delimiter { id: tt::TokenId::unspecified(), ..d }),
248 token_trees: subtree
249 .token_trees
250 .into_iter()
251 .map(|t| token_tree_replace_token_ids_with_unspecified(t))
252 .collect(),
253 }
254 }
255
256 fn token_tree_replace_token_ids_with_unspecified(tt: tt::TokenTree) -> tt::TokenTree {
257 match tt {
258 tt::TokenTree::Leaf(leaf) => {
259 tt::TokenTree::Leaf(leaf_replace_token_ids_with_unspecified(leaf))
260 }
261 tt::TokenTree::Subtree(subtree) => {
262 tt::TokenTree::Subtree(subtree_replace_token_ids_with_unspecified(subtree))
263 }
264 }
265 }
266
267 fn leaf_replace_token_ids_with_unspecified(leaf: tt::Leaf) -> tt::Leaf {
268 match leaf {
269 tt::Leaf::Literal(lit) => {
270 tt::Leaf::Literal(tt::Literal { id: tt::TokenId::unspecified(), ..lit })
271 }
272 tt::Leaf::Punct(punct) => {
273 tt::Leaf::Punct(tt::Punct { id: tt::TokenId::unspecified(), ..punct })
274 }
275 tt::Leaf::Ident(ident) => {
276 tt::Leaf::Ident(tt::Ident { id: tt::TokenId::unspecified(), ..ident })
227 } 277 }
228 } 278 }
229 } 279 }
@@ -287,6 +337,8 @@ impl server::TokenStream for Rustc {
287 stream.is_empty() 337 stream.is_empty()
288 } 338 }
289 fn from_str(&mut self, src: &str) -> Self::TokenStream { 339 fn from_str(&mut self, src: &str) -> Self::TokenStream {
340 use std::str::FromStr;
341
290 Self::TokenStream::from_str(src).expect("cannot parse string") 342 Self::TokenStream::from_str(src).expect("cannot parse string")
291 } 343 }
292 fn to_string(&mut self, stream: &Self::TokenStream) -> String { 344 fn to_string(&mut self, stream: &Self::TokenStream) -> String {
@@ -393,10 +445,7 @@ fn spacing_to_external(spacing: Spacing) -> bridge::Spacing {
393 445
394impl server::Group for Rustc { 446impl server::Group for Rustc {
395 fn new(&mut self, delimiter: bridge::Delimiter, stream: Self::TokenStream) -> Self::Group { 447 fn new(&mut self, delimiter: bridge::Delimiter, stream: Self::TokenStream) -> Self::Group {
396 Self::Group { 448 Self::Group { delimiter: delim_to_internal(delimiter), token_trees: stream.token_trees }
397 delimiter: delim_to_internal(delimiter),
398 token_trees: stream.subtree.token_trees,
399 }
400 } 449 }
401 fn delimiter(&mut self, group: &Self::Group) -> bridge::Delimiter { 450 fn delimiter(&mut self, group: &Self::Group) -> bridge::Delimiter {
402 delim_to_external(group.delimiter) 451 delim_to_external(group.delimiter)
@@ -404,9 +453,7 @@ impl server::Group for Rustc {
404 453
405 // NOTE: Return value of do not include delimiter 454 // NOTE: Return value of do not include delimiter
406 fn stream(&mut self, group: &Self::Group) -> Self::TokenStream { 455 fn stream(&mut self, group: &Self::Group) -> Self::TokenStream {
407 TokenStream { 456 TokenStream { token_trees: group.token_trees.clone() }
408 subtree: tt::Subtree { delimiter: None, token_trees: group.token_trees.clone() },
409 }
410 } 457 }
411 458
412 fn span(&mut self, group: &Self::Group) -> Self::Span { 459 fn span(&mut self, group: &Self::Group) -> Self::Span {
@@ -715,28 +762,48 @@ mod tests {
715 #[test] 762 #[test]
716 fn test_rustc_server_to_string() { 763 fn test_rustc_server_to_string() {
717 let s = TokenStream { 764 let s = TokenStream {
718 subtree: tt::Subtree { 765 token_trees: vec![
719 delimiter: None, 766 tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident {
720 token_trees: vec![ 767 text: "struct".into(),
721 tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { 768 id: tt::TokenId::unspecified(),
722 text: "struct".into(), 769 })),
723 id: tt::TokenId::unspecified(), 770 tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident {
724 })), 771 text: "T".into(),
725 tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { 772 id: tt::TokenId::unspecified(),
726 text: "T".into(), 773 })),
774 tt::TokenTree::Subtree(tt::Subtree {
775 delimiter: Some(tt::Delimiter {
727 id: tt::TokenId::unspecified(), 776 id: tt::TokenId::unspecified(),
728 })), 777 kind: tt::DelimiterKind::Brace,
729 tt::TokenTree::Subtree(tt::Subtree {
730 delimiter: Some(tt::Delimiter {
731 id: tt::TokenId::unspecified(),
732 kind: tt::DelimiterKind::Brace,
733 }),
734 token_trees: vec![],
735 }), 778 }),
736 ], 779 token_trees: vec![],
737 }, 780 }),
781 ],
738 }; 782 };
739 783
740 assert_eq!(s.to_string(), "struct T {}"); 784 assert_eq!(s.to_string(), "struct T {}");
741 } 785 }
786
787 #[test]
788 fn test_rustc_server_from_str() {
789 use std::str::FromStr;
790 let subtree_paren_a = tt::TokenTree::Subtree(tt::Subtree {
791 delimiter: Some(tt::Delimiter {
792 id: tt::TokenId::unspecified(),
793 kind: tt::DelimiterKind::Parenthesis,
794 }),
795 token_trees: vec![tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident {
796 text: "a".into(),
797 id: tt::TokenId::unspecified(),
798 }))],
799 });
800
801 let t1 = TokenStream::from_str("(a)").unwrap();
802 assert_eq!(t1.token_trees.len(), 1);
803 assert_eq!(t1.token_trees[0], subtree_paren_a);
804
805 let t2 = TokenStream::from_str("(a);").unwrap();
806 assert_eq!(t2.token_trees.len(), 2);
807 assert_eq!(t2.token_trees[0], subtree_paren_a);
808 }
742} 809}
diff --git a/crates/proc_macro_srv/src/tests/fixtures/test_serialize_proc_macro.txt b/crates/proc_macro_srv/src/tests/fixtures/test_serialize_proc_macro.txt
index ea34e688f..fa581f110 100644
--- a/crates/proc_macro_srv/src/tests/fixtures/test_serialize_proc_macro.txt
+++ b/crates/proc_macro_srv/src/tests/fixtures/test_serialize_proc_macro.txt
@@ -101,7 +101,7 @@ SUBTREE $
101 PUNCH : [alone] 4294967295 101 PUNCH : [alone] 4294967295
102 IDENT Serialize 4294967295 102 IDENT Serialize 4294967295
103 IDENT for 4294967295 103 IDENT for 4294967295
104 IDENT Foo 1 104 IDENT Foo 4294967295
105 SUBTREE {} 4294967295 105 SUBTREE {} 4294967295
106 IDENT fn 4294967295 106 IDENT fn 4294967295
107 IDENT serialize 4294967295 107 IDENT serialize 4294967295
diff --git a/crates/proc_macro_srv/src/tests/utils.rs b/crates/proc_macro_srv/src/tests/utils.rs
index 196abb8fc..0484c3af4 100644
--- a/crates/proc_macro_srv/src/tests/utils.rs
+++ b/crates/proc_macro_srv/src/tests/utils.rs
@@ -8,6 +8,7 @@ use test_utils::assert_eq_text;
8 8
9mod fixtures { 9mod fixtures {
10 use cargo_metadata::Message; 10 use cargo_metadata::Message;
11 use std::path::PathBuf;
11 use std::process::Command; 12 use std::process::Command;
12 13
13 // Use current project metadata to get the proc-macro dylib path 14 // Use current project metadata to get the proc-macro dylib path
@@ -24,7 +25,7 @@ mod fixtures {
24 if artifact.target.kind.contains(&"proc-macro".to_string()) { 25 if artifact.target.kind.contains(&"proc-macro".to_string()) {
25 let repr = format!("{} {}", crate_name, version); 26 let repr = format!("{} {}", crate_name, version);
26 if artifact.package_id.repr.starts_with(&repr) { 27 if artifact.package_id.repr.starts_with(&repr) {
27 return artifact.filenames[0].clone(); 28 return PathBuf::from(&artifact.filenames[0]);
28 } 29 }
29 } 30 }
30 } 31 }
@@ -51,7 +52,7 @@ pub fn assert_expand(
51 let expander = dylib::Expander::new(&path).unwrap(); 52 let expander = dylib::Expander::new(&path).unwrap();
52 let fixture = parse_string(ra_fixture).unwrap(); 53 let fixture = parse_string(ra_fixture).unwrap();
53 54
54 let res = expander.expand(macro_name, &fixture.subtree, None).unwrap(); 55 let res = expander.expand(macro_name, &fixture.into_subtree(), None).unwrap();
55 assert_eq_text!(&expect.trim(), &format!("{:?}", res)); 56 assert_eq_text!(&expect.trim(), &format!("{:?}", res));
56} 57}
57 58