diff options
Diffstat (limited to 'crates/ra_hir_expand')
-rw-r--r-- | crates/ra_hir_expand/Cargo.toml | 1 | ||||
-rw-r--r-- | crates/ra_hir_expand/src/proc_macro.rs | 106 |
2 files changed, 97 insertions, 10 deletions
diff --git a/crates/ra_hir_expand/Cargo.toml b/crates/ra_hir_expand/Cargo.toml index d6e3c1f76..2cd522766 100644 --- a/crates/ra_hir_expand/Cargo.toml +++ b/crates/ra_hir_expand/Cargo.toml | |||
@@ -18,3 +18,4 @@ ra_parser = { path = "../ra_parser" } | |||
18 | ra_prof = { path = "../ra_prof" } | 18 | ra_prof = { path = "../ra_prof" } |
19 | tt = { path = "../ra_tt", package = "ra_tt" } | 19 | tt = { path = "../ra_tt", package = "ra_tt" } |
20 | mbe = { path = "../ra_mbe", package = "ra_mbe" } | 20 | mbe = { path = "../ra_mbe", package = "ra_mbe" } |
21 | test_utils = { path = "../test_utils"} | ||
diff --git a/crates/ra_hir_expand/src/proc_macro.rs b/crates/ra_hir_expand/src/proc_macro.rs index 97d1208ec..4e0e069c8 100644 --- a/crates/ra_hir_expand/src/proc_macro.rs +++ b/crates/ra_hir_expand/src/proc_macro.rs | |||
@@ -2,6 +2,7 @@ | |||
2 | 2 | ||
3 | use crate::{db::AstDatabase, LazyMacroId}; | 3 | use crate::{db::AstDatabase, LazyMacroId}; |
4 | use ra_db::{CrateId, ProcMacroId}; | 4 | use ra_db::{CrateId, ProcMacroId}; |
5 | use tt::buffer::{Cursor, TokenBuffer}; | ||
5 | 6 | ||
6 | #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] | 7 | #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] |
7 | pub struct ProcMacroExpander { | 8 | pub struct ProcMacroExpander { |
@@ -36,22 +37,107 @@ impl ProcMacroExpander { | |||
36 | .clone() | 37 | .clone() |
37 | .ok_or_else(|| err!("No derive macro found."))?; | 38 | .ok_or_else(|| err!("No derive macro found."))?; |
38 | 39 | ||
39 | let tt = remove_derive_atr(tt, &proc_macro.name) | 40 | let tt = remove_derive_attrs(tt) |
40 | .ok_or_else(|| err!("Fail to remove derive for custom derive"))?; | 41 | .ok_or_else(|| err!("Fail to remove derive for custom derive"))?; |
41 | 42 | ||
42 | proc_macro.expander.expand(&tt, None).map_err(mbe::ExpandError::from) | 43 | proc_macro.expander.expand(&tt, None).map_err(mbe::ExpandError::from) |
43 | } | 44 | } |
44 | } | 45 | } |
45 | 46 | ||
46 | fn remove_derive_atr(tt: &tt::Subtree, _name: &str) -> Option<tt::Subtree> { | 47 | fn eat_punct(cursor: &mut Cursor, c: char) -> bool { |
47 | // FIXME: proper handle the remove derive | 48 | if let Some(tt::TokenTree::Leaf(tt::Leaf::Punct(punct))) = cursor.token_tree() { |
48 | // We assume the first 2 tokens are #[derive(name)] | 49 | if punct.char == c { |
49 | if tt.token_trees.len() > 2 { | 50 | *cursor = cursor.bump(); |
50 | let mut tt = tt.clone(); | 51 | return true; |
51 | tt.token_trees.remove(0); | 52 | } |
52 | tt.token_trees.remove(0); | ||
53 | return Some(tt); | ||
54 | } | 53 | } |
54 | false | ||
55 | } | ||
56 | |||
57 | fn eat_subtree(cursor: &mut Cursor, kind: tt::DelimiterKind) -> bool { | ||
58 | if let Some(tt::TokenTree::Subtree(subtree)) = cursor.token_tree() { | ||
59 | if Some(kind) == subtree.delimiter_kind() { | ||
60 | *cursor = cursor.bump_subtree(); | ||
61 | return true; | ||
62 | } | ||
63 | } | ||
64 | false | ||
65 | } | ||
66 | |||
67 | fn eat_ident(cursor: &mut Cursor, t: &str) -> bool { | ||
68 | if let Some(tt::TokenTree::Leaf(tt::Leaf::Ident(ident))) = cursor.token_tree() { | ||
69 | if t == ident.text.as_str() { | ||
70 | *cursor = cursor.bump(); | ||
71 | return true; | ||
72 | } | ||
73 | } | ||
74 | false | ||
75 | } | ||
76 | |||
77 | fn remove_derive_attrs(tt: &tt::Subtree) -> Option<tt::Subtree> { | ||
78 | let buffer = TokenBuffer::new(&tt.token_trees); | ||
79 | let mut p = buffer.begin(); | ||
80 | let mut result = tt::Subtree::default(); | ||
81 | |||
82 | while !p.eof() { | ||
83 | let curr = p; | ||
55 | 84 | ||
56 | None | 85 | if eat_punct(&mut p, '#') { |
86 | eat_punct(&mut p, '!'); | ||
87 | let parent = p; | ||
88 | if eat_subtree(&mut p, tt::DelimiterKind::Bracket) { | ||
89 | if eat_ident(&mut p, "derive") { | ||
90 | p = parent.bump(); | ||
91 | continue; | ||
92 | } | ||
93 | } | ||
94 | } | ||
95 | |||
96 | result.token_trees.push(curr.token_tree()?.clone()); | ||
97 | p = curr.bump(); | ||
98 | } | ||
99 | |||
100 | Some(result) | ||
101 | } | ||
102 | |||
103 | #[cfg(test)] | ||
104 | mod test { | ||
105 | use super::*; | ||
106 | use test_utils::assert_eq_text; | ||
107 | |||
108 | #[test] | ||
109 | fn test_remove_derive_attrs() { | ||
110 | let tt = mbe::parse_to_token_tree( | ||
111 | r#" | ||
112 | #[allow(unused)] | ||
113 | #[derive(Copy)] | ||
114 | #[derive(Hello)] | ||
115 | struct A { | ||
116 | bar: u32 | ||
117 | } | ||
118 | "#, | ||
119 | ) | ||
120 | .unwrap() | ||
121 | .0; | ||
122 | let result = format!("{:#?}", remove_derive_attrs(&tt).unwrap()); | ||
123 | |||
124 | assert_eq_text!( | ||
125 | &result, | ||
126 | r#" | ||
127 | SUBTREE $ | ||
128 | PUNCH # [alone] 0 | ||
129 | SUBTREE [] 1 | ||
130 | IDENT allow 2 | ||
131 | SUBTREE () 3 | ||
132 | IDENT unused 4 | ||
133 | IDENT struct 15 | ||
134 | IDENT A 16 | ||
135 | SUBTREE {} 17 | ||
136 | IDENT bar 18 | ||
137 | PUNCH : [alone] 19 | ||
138 | IDENT u32 20 | ||
139 | "# | ||
140 | .trim() | ||
141 | ); | ||
142 | } | ||
57 | } | 143 | } |