aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_expand
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir_expand')
-rw-r--r--crates/ra_hir_expand/Cargo.toml1
-rw-r--r--crates/ra_hir_expand/src/ast_id_map.rs2
-rw-r--r--crates/ra_hir_expand/src/builtin_macro.rs8
-rw-r--r--crates/ra_hir_expand/src/proc_macro.rs106
4 files changed, 102 insertions, 15 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" }
18ra_prof = { path = "../ra_prof" } 18ra_prof = { path = "../ra_prof" }
19tt = { path = "../ra_tt", package = "ra_tt" } 19tt = { path = "../ra_tt", package = "ra_tt" }
20mbe = { path = "../ra_mbe", package = "ra_mbe" } 20mbe = { path = "../ra_mbe", package = "ra_mbe" }
21test_utils = { path = "../test_utils"}
diff --git a/crates/ra_hir_expand/src/ast_id_map.rs b/crates/ra_hir_expand/src/ast_id_map.rs
index a3ca302c2..d19569245 100644
--- a/crates/ra_hir_expand/src/ast_id_map.rs
+++ b/crates/ra_hir_expand/src/ast_id_map.rs
@@ -66,7 +66,7 @@ impl AstIdMap {
66 // change parent's id. This means that, say, adding a new function to a 66 // change parent's id. This means that, say, adding a new function to a
67 // trait does not change ids of top-level items, which helps caching. 67 // trait does not change ids of top-level items, which helps caching.
68 bfs(node, |it| { 68 bfs(node, |it| {
69 if let Some(module_item) = ast::ModuleItem::cast(it.clone()) { 69 if let Some(module_item) = ast::ModuleItem::cast(it) {
70 res.alloc(module_item.syntax()); 70 res.alloc(module_item.syntax());
71 } 71 }
72 }); 72 });
diff --git a/crates/ra_hir_expand/src/builtin_macro.rs b/crates/ra_hir_expand/src/builtin_macro.rs
index f9d3787f6..3da137f2e 100644
--- a/crates/ra_hir_expand/src/builtin_macro.rs
+++ b/crates/ra_hir_expand/src/builtin_macro.rs
@@ -301,7 +301,7 @@ fn relative_file(db: &dyn AstDatabase, call_id: MacroCallId, path: &str) -> Opti
301 } 301 }
302 302
303 // Extern paths ? 303 // Extern paths ?
304 let krate = db.relevant_crates(call_site).get(0)?.clone(); 304 let krate = *db.relevant_crates(call_site).get(0)?;
305 let (extern_source_id, relative_file) = 305 let (extern_source_id, relative_file) =
306 db.crate_graph()[krate].extern_source.extern_path(path)?; 306 db.crate_graph()[krate].extern_source.extern_path(path)?;
307 307
@@ -329,7 +329,7 @@ fn include_expand(
329 329
330 // FIXME: 330 // FIXME:
331 // Handle include as expression 331 // Handle include as expression
332 let res = parse_to_token_tree(&db.file_text(file_id.into())) 332 let res = parse_to_token_tree(&db.file_text(file_id))
333 .ok_or_else(|| mbe::ExpandError::ConversionError)? 333 .ok_or_else(|| mbe::ExpandError::ConversionError)?
334 .0; 334 .0;
335 335
@@ -340,7 +340,7 @@ fn get_env_inner(db: &dyn AstDatabase, arg_id: EagerMacroId, key: &str) -> Optio
340 let call_id: MacroCallId = arg_id.into(); 340 let call_id: MacroCallId = arg_id.into();
341 let original_file = call_id.as_file().original_file(db); 341 let original_file = call_id.as_file().original_file(db);
342 342
343 let krate = db.relevant_crates(original_file).get(0)?.clone(); 343 let krate = *db.relevant_crates(original_file).get(0)?;
344 db.crate_graph()[krate].env.get(key) 344 db.crate_graph()[krate].env.get(key)
345} 345}
346 346
@@ -447,7 +447,7 @@ mod tests {
447 file_id: file_id.into(), 447 file_id: file_id.into(),
448 }; 448 };
449 449
450 let id: MacroCallId = db.intern_eager_expansion(eager.into()).into(); 450 let id: MacroCallId = db.intern_eager_expansion(eager).into();
451 id.as_file() 451 id.as_file()
452 } 452 }
453 }; 453 };
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}