aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_expand/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir_expand/src')
-rw-r--r--crates/ra_hir_expand/src/proc_macro.rs106
1 files changed, 96 insertions, 10 deletions
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
3use crate::{db::AstDatabase, LazyMacroId}; 3use crate::{db::AstDatabase, LazyMacroId};
4use ra_db::{CrateId, ProcMacroId}; 4use ra_db::{CrateId, ProcMacroId};
5use tt::buffer::{Cursor, TokenBuffer};
5 6
6#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] 7#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
7pub struct ProcMacroExpander { 8pub 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
46fn remove_derive_atr(tt: &tt::Subtree, _name: &str) -> Option<tt::Subtree> { 47fn 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
57fn 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
67fn 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
77fn 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)]
104mod 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#"
127SUBTREE $
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}