diff options
author | Florian Diebold <[email protected]> | 2019-12-05 14:10:33 +0000 |
---|---|---|
committer | Florian Diebold <[email protected]> | 2019-12-05 16:23:09 +0000 |
commit | 18f6a995d0fc1f45099f3cc810a5d55d5401b41b (patch) | |
tree | 808cb0f025b488f59935007802d1bb85f1cf0044 /crates/ra_hir_expand/src | |
parent | 4c0bd068da39e74c66104206e27c270454e3562e (diff) |
Add expansion infrastructure for derive macros
Diffstat (limited to 'crates/ra_hir_expand/src')
-rw-r--r-- | crates/ra_hir_expand/src/ast_id_map.rs | 12 | ||||
-rw-r--r-- | crates/ra_hir_expand/src/builtin_derive.rs | 64 | ||||
-rw-r--r-- | crates/ra_hir_expand/src/builtin_macro.rs | 37 | ||||
-rw-r--r-- | crates/ra_hir_expand/src/db.rs | 19 | ||||
-rw-r--r-- | crates/ra_hir_expand/src/hygiene.rs | 3 | ||||
-rw-r--r-- | crates/ra_hir_expand/src/lib.rs | 76 | ||||
-rw-r--r-- | crates/ra_hir_expand/src/name.rs | 10 |
7 files changed, 170 insertions, 51 deletions
diff --git a/crates/ra_hir_expand/src/ast_id_map.rs b/crates/ra_hir_expand/src/ast_id_map.rs index cb464c3ff..a764bdf24 100644 --- a/crates/ra_hir_expand/src/ast_id_map.rs +++ b/crates/ra_hir_expand/src/ast_id_map.rs | |||
@@ -39,6 +39,16 @@ impl<N: AstNode> Hash for FileAstId<N> { | |||
39 | } | 39 | } |
40 | } | 40 | } |
41 | 41 | ||
42 | impl<N: AstNode> FileAstId<N> { | ||
43 | // Can't make this a From implementation because of coherence | ||
44 | pub fn upcast<M: AstNode>(self) -> FileAstId<M> | ||
45 | where | ||
46 | M: From<N>, | ||
47 | { | ||
48 | FileAstId { raw: self.raw, _ty: PhantomData } | ||
49 | } | ||
50 | } | ||
51 | |||
42 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] | 52 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] |
43 | struct ErasedFileAstId(RawId); | 53 | struct ErasedFileAstId(RawId); |
44 | impl_arena_id!(ErasedFileAstId); | 54 | impl_arena_id!(ErasedFileAstId); |
@@ -53,7 +63,7 @@ impl AstIdMap { | |||
53 | pub(crate) fn from_source(node: &SyntaxNode) -> AstIdMap { | 63 | pub(crate) fn from_source(node: &SyntaxNode) -> AstIdMap { |
54 | assert!(node.parent().is_none()); | 64 | assert!(node.parent().is_none()); |
55 | let mut res = AstIdMap { arena: Arena::default() }; | 65 | let mut res = AstIdMap { arena: Arena::default() }; |
56 | // By walking the tree in bread-first order we make sure that parents | 66 | // By walking the tree in breadth-first order we make sure that parents |
57 | // get lower ids then children. That is, adding a new child does not | 67 | // get lower ids then children. That is, adding a new child does not |
58 | // change parent's id. This means that, say, adding a new function to a | 68 | // change parent's id. This means that, say, adding a new function to a |
59 | // trait does not change ids of top-level items, which helps caching. | 69 | // trait does not change ids of top-level items, which helps caching. |
diff --git a/crates/ra_hir_expand/src/builtin_derive.rs b/crates/ra_hir_expand/src/builtin_derive.rs new file mode 100644 index 000000000..0a70c63c0 --- /dev/null +++ b/crates/ra_hir_expand/src/builtin_derive.rs | |||
@@ -0,0 +1,64 @@ | |||
1 | //! Builtin derives. | ||
2 | use crate::db::AstDatabase; | ||
3 | use crate::{name, MacroCallId, MacroDefId, MacroDefKind}; | ||
4 | |||
5 | use crate::quote; | ||
6 | |||
7 | macro_rules! register_builtin { | ||
8 | ( $(($name:ident, $kind: ident) => $expand:ident),* ) => { | ||
9 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
10 | pub enum BuiltinDeriveExpander { | ||
11 | $($kind),* | ||
12 | } | ||
13 | |||
14 | impl BuiltinDeriveExpander { | ||
15 | pub fn expand( | ||
16 | &self, | ||
17 | db: &dyn AstDatabase, | ||
18 | id: MacroCallId, | ||
19 | tt: &tt::Subtree, | ||
20 | ) -> Result<tt::Subtree, mbe::ExpandError> { | ||
21 | let expander = match *self { | ||
22 | $( BuiltinDeriveExpander::$kind => $expand, )* | ||
23 | }; | ||
24 | expander(db, id, tt) | ||
25 | } | ||
26 | } | ||
27 | |||
28 | pub fn find_builtin_derive(ident: &name::Name) -> Option<MacroDefId> { | ||
29 | let kind = match ident { | ||
30 | $( id if id == &name::$name => BuiltinDeriveExpander::$kind, )* | ||
31 | _ => return None, | ||
32 | }; | ||
33 | |||
34 | Some(MacroDefId { krate: None, ast_id: None, kind: MacroDefKind::BuiltInDerive(kind) }) | ||
35 | } | ||
36 | }; | ||
37 | } | ||
38 | |||
39 | register_builtin! { | ||
40 | (COPY_TRAIT, Copy) => copy_expand, | ||
41 | (CLONE_TRAIT, Clone) => clone_expand | ||
42 | } | ||
43 | |||
44 | fn copy_expand( | ||
45 | _db: &dyn AstDatabase, | ||
46 | _id: MacroCallId, | ||
47 | _tt: &tt::Subtree, | ||
48 | ) -> Result<tt::Subtree, mbe::ExpandError> { | ||
49 | let expanded = quote! { | ||
50 | impl Copy for Foo {} | ||
51 | }; | ||
52 | Ok(expanded) | ||
53 | } | ||
54 | |||
55 | fn clone_expand( | ||
56 | _db: &dyn AstDatabase, | ||
57 | _id: MacroCallId, | ||
58 | _tt: &tt::Subtree, | ||
59 | ) -> Result<tt::Subtree, mbe::ExpandError> { | ||
60 | let expanded = quote! { | ||
61 | impl Clone for Foo {} | ||
62 | }; | ||
63 | Ok(expanded) | ||
64 | } | ||
diff --git a/crates/ra_hir_expand/src/builtin_macro.rs b/crates/ra_hir_expand/src/builtin_macro.rs index d370dfb34..35f99b2bc 100644 --- a/crates/ra_hir_expand/src/builtin_macro.rs +++ b/crates/ra_hir_expand/src/builtin_macro.rs | |||
@@ -39,7 +39,7 @@ macro_rules! register_builtin { | |||
39 | _ => return None, | 39 | _ => return None, |
40 | }; | 40 | }; |
41 | 41 | ||
42 | Some(MacroDefId { krate, ast_id, kind: MacroDefKind::BuiltIn(kind) }) | 42 | Some(MacroDefId { krate: Some(krate), ast_id: Some(ast_id), kind: MacroDefKind::BuiltIn(kind) }) |
43 | } | 43 | } |
44 | }; | 44 | }; |
45 | } | 45 | } |
@@ -82,10 +82,9 @@ fn line_expand( | |||
82 | _tt: &tt::Subtree, | 82 | _tt: &tt::Subtree, |
83 | ) -> Result<tt::Subtree, mbe::ExpandError> { | 83 | ) -> Result<tt::Subtree, mbe::ExpandError> { |
84 | let loc = db.lookup_intern_macro(id); | 84 | let loc = db.lookup_intern_macro(id); |
85 | let macro_call = loc.ast_id.to_node(db); | ||
86 | 85 | ||
87 | let arg = macro_call.token_tree().ok_or_else(|| mbe::ExpandError::UnexpectedToken)?; | 86 | let arg = loc.kind.arg(db).ok_or_else(|| mbe::ExpandError::UnexpectedToken)?; |
88 | let arg_start = arg.syntax().text_range().start(); | 87 | let arg_start = arg.text_range().start(); |
89 | 88 | ||
90 | let file = id.as_file(MacroFileKind::Expr); | 89 | let file = id.as_file(MacroFileKind::Expr); |
91 | let line_num = to_line_number(db, file, arg_start); | 90 | let line_num = to_line_number(db, file, arg_start); |
@@ -103,11 +102,10 @@ fn stringify_expand( | |||
103 | _tt: &tt::Subtree, | 102 | _tt: &tt::Subtree, |
104 | ) -> Result<tt::Subtree, mbe::ExpandError> { | 103 | ) -> Result<tt::Subtree, mbe::ExpandError> { |
105 | let loc = db.lookup_intern_macro(id); | 104 | let loc = db.lookup_intern_macro(id); |
106 | let macro_call = loc.ast_id.to_node(db); | ||
107 | 105 | ||
108 | let macro_content = { | 106 | let macro_content = { |
109 | let arg = macro_call.token_tree().ok_or_else(|| mbe::ExpandError::UnexpectedToken)?; | 107 | let arg = loc.kind.arg(db).ok_or_else(|| mbe::ExpandError::UnexpectedToken)?; |
110 | let macro_args = arg.syntax().clone(); | 108 | let macro_args = arg.clone(); |
111 | let text = macro_args.text(); | 109 | let text = macro_args.text(); |
112 | let without_parens = TextUnit::of_char('(')..text.len() - TextUnit::of_char(')'); | 110 | let without_parens = TextUnit::of_char('(')..text.len() - TextUnit::of_char(')'); |
113 | text.slice(without_parens).to_string() | 111 | text.slice(without_parens).to_string() |
@@ -148,7 +146,10 @@ fn column_expand( | |||
148 | _tt: &tt::Subtree, | 146 | _tt: &tt::Subtree, |
149 | ) -> Result<tt::Subtree, mbe::ExpandError> { | 147 | ) -> Result<tt::Subtree, mbe::ExpandError> { |
150 | let loc = db.lookup_intern_macro(id); | 148 | let loc = db.lookup_intern_macro(id); |
151 | let macro_call = loc.ast_id.to_node(db); | 149 | let macro_call = match loc.kind { |
150 | crate::MacroCallKind::FnLike(ast_id) => ast_id.to_node(db), | ||
151 | _ => panic!("column macro called as attr"), | ||
152 | }; | ||
152 | 153 | ||
153 | let _arg = macro_call.token_tree().ok_or_else(|| mbe::ExpandError::UnexpectedToken)?; | 154 | let _arg = macro_call.token_tree().ok_or_else(|| mbe::ExpandError::UnexpectedToken)?; |
154 | let col_start = macro_call.syntax().text_range().start(); | 155 | let col_start = macro_call.syntax().text_range().start(); |
@@ -164,15 +165,10 @@ fn column_expand( | |||
164 | } | 165 | } |
165 | 166 | ||
166 | fn file_expand( | 167 | fn file_expand( |
167 | db: &dyn AstDatabase, | 168 | _db: &dyn AstDatabase, |
168 | id: MacroCallId, | 169 | _id: MacroCallId, |
169 | _tt: &tt::Subtree, | 170 | _tt: &tt::Subtree, |
170 | ) -> Result<tt::Subtree, mbe::ExpandError> { | 171 | ) -> Result<tt::Subtree, mbe::ExpandError> { |
171 | let loc = db.lookup_intern_macro(id); | ||
172 | let macro_call = loc.ast_id.to_node(db); | ||
173 | |||
174 | let _ = macro_call.token_tree().ok_or_else(|| mbe::ExpandError::UnexpectedToken)?; | ||
175 | |||
176 | // FIXME: RA purposefully lacks knowledge of absolute file names | 172 | // FIXME: RA purposefully lacks knowledge of absolute file names |
177 | // so just return "". | 173 | // so just return "". |
178 | let file_name = ""; | 174 | let file_name = ""; |
@@ -207,7 +203,7 @@ fn compile_error_expand( | |||
207 | #[cfg(test)] | 203 | #[cfg(test)] |
208 | mod tests { | 204 | mod tests { |
209 | use super::*; | 205 | use super::*; |
210 | use crate::{test_db::TestDB, MacroCallLoc}; | 206 | use crate::{test_db::TestDB, MacroCallKind, MacroCallLoc}; |
211 | use ra_db::{fixture::WithFixture, SourceDatabase}; | 207 | use ra_db::{fixture::WithFixture, SourceDatabase}; |
212 | 208 | ||
213 | fn expand_builtin_macro(s: &str, expander: BuiltinFnLikeExpander) -> String { | 209 | fn expand_builtin_macro(s: &str, expander: BuiltinFnLikeExpander) -> String { |
@@ -220,14 +216,17 @@ mod tests { | |||
220 | 216 | ||
221 | // the first one should be a macro_rules | 217 | // the first one should be a macro_rules |
222 | let def = MacroDefId { | 218 | let def = MacroDefId { |
223 | krate: CrateId(0), | 219 | krate: Some(CrateId(0)), |
224 | ast_id: AstId::new(file_id.into(), ast_id_map.ast_id(¯o_calls[0])), | 220 | ast_id: Some(AstId::new(file_id.into(), ast_id_map.ast_id(¯o_calls[0]))), |
225 | kind: MacroDefKind::BuiltIn(expander), | 221 | kind: MacroDefKind::BuiltIn(expander), |
226 | }; | 222 | }; |
227 | 223 | ||
228 | let loc = MacroCallLoc { | 224 | let loc = MacroCallLoc { |
229 | def, | 225 | def, |
230 | ast_id: AstId::new(file_id.into(), ast_id_map.ast_id(¯o_calls[1])), | 226 | kind: MacroCallKind::FnLike(AstId::new( |
227 | file_id.into(), | ||
228 | ast_id_map.ast_id(¯o_calls[1]), | ||
229 | )), | ||
231 | }; | 230 | }; |
232 | 231 | ||
233 | let id = db.intern_macro(loc); | 232 | let id = db.intern_macro(loc); |
diff --git a/crates/ra_hir_expand/src/db.rs b/crates/ra_hir_expand/src/db.rs index 8e46fa177..99dabf3fb 100644 --- a/crates/ra_hir_expand/src/db.rs +++ b/crates/ra_hir_expand/src/db.rs | |||
@@ -9,14 +9,15 @@ use ra_prof::profile; | |||
9 | use ra_syntax::{AstNode, Parse, SyntaxNode}; | 9 | use ra_syntax::{AstNode, Parse, SyntaxNode}; |
10 | 10 | ||
11 | use crate::{ | 11 | use crate::{ |
12 | ast_id_map::AstIdMap, BuiltinFnLikeExpander, HirFileId, HirFileIdRepr, MacroCallId, | 12 | ast_id_map::AstIdMap, BuiltinDeriveExpander, BuiltinFnLikeExpander, HirFileId, HirFileIdRepr, |
13 | MacroCallLoc, MacroDefId, MacroDefKind, MacroFile, MacroFileKind, | 13 | MacroCallId, MacroCallLoc, MacroDefId, MacroDefKind, MacroFile, MacroFileKind, |
14 | }; | 14 | }; |
15 | 15 | ||
16 | #[derive(Debug, Clone, Eq, PartialEq)] | 16 | #[derive(Debug, Clone, Eq, PartialEq)] |
17 | pub enum TokenExpander { | 17 | pub enum TokenExpander { |
18 | MacroRules(mbe::MacroRules), | 18 | MacroRules(mbe::MacroRules), |
19 | Builtin(BuiltinFnLikeExpander), | 19 | Builtin(BuiltinFnLikeExpander), |
20 | BuiltinDerive(BuiltinDeriveExpander), | ||
20 | } | 21 | } |
21 | 22 | ||
22 | impl TokenExpander { | 23 | impl TokenExpander { |
@@ -29,6 +30,7 @@ impl TokenExpander { | |||
29 | match self { | 30 | match self { |
30 | TokenExpander::MacroRules(it) => it.expand(tt), | 31 | TokenExpander::MacroRules(it) => it.expand(tt), |
31 | TokenExpander::Builtin(it) => it.expand(db, id, tt), | 32 | TokenExpander::Builtin(it) => it.expand(db, id, tt), |
33 | TokenExpander::BuiltinDerive(it) => it.expand(db, id, tt), | ||
32 | } | 34 | } |
33 | } | 35 | } |
34 | 36 | ||
@@ -36,6 +38,7 @@ impl TokenExpander { | |||
36 | match self { | 38 | match self { |
37 | TokenExpander::MacroRules(it) => it.map_id_down(id), | 39 | TokenExpander::MacroRules(it) => it.map_id_down(id), |
38 | TokenExpander::Builtin(..) => id, | 40 | TokenExpander::Builtin(..) => id, |
41 | TokenExpander::BuiltinDerive(..) => id, | ||
39 | } | 42 | } |
40 | } | 43 | } |
41 | 44 | ||
@@ -43,6 +46,7 @@ impl TokenExpander { | |||
43 | match self { | 46 | match self { |
44 | TokenExpander::MacroRules(it) => it.map_id_up(id), | 47 | TokenExpander::MacroRules(it) => it.map_id_up(id), |
45 | TokenExpander::Builtin(..) => (id, mbe::Origin::Def), | 48 | TokenExpander::Builtin(..) => (id, mbe::Origin::Def), |
49 | TokenExpander::BuiltinDerive(..) => (id, mbe::Origin::Def), | ||
46 | } | 50 | } |
47 | } | 51 | } |
48 | } | 52 | } |
@@ -76,7 +80,7 @@ pub(crate) fn macro_def( | |||
76 | ) -> Option<Arc<(TokenExpander, mbe::TokenMap)>> { | 80 | ) -> Option<Arc<(TokenExpander, mbe::TokenMap)>> { |
77 | match id.kind { | 81 | match id.kind { |
78 | MacroDefKind::Declarative => { | 82 | MacroDefKind::Declarative => { |
79 | let macro_call = id.ast_id.to_node(db); | 83 | let macro_call = id.ast_id?.to_node(db); |
80 | let arg = macro_call.token_tree()?; | 84 | let arg = macro_call.token_tree()?; |
81 | let (tt, tmap) = mbe::ast_to_token_tree(&arg).or_else(|| { | 85 | let (tt, tmap) = mbe::ast_to_token_tree(&arg).or_else(|| { |
82 | log::warn!("fail on macro_def to token tree: {:#?}", arg); | 86 | log::warn!("fail on macro_def to token tree: {:#?}", arg); |
@@ -91,6 +95,10 @@ pub(crate) fn macro_def( | |||
91 | MacroDefKind::BuiltIn(expander) => { | 95 | MacroDefKind::BuiltIn(expander) => { |
92 | Some(Arc::new((TokenExpander::Builtin(expander.clone()), mbe::TokenMap::default()))) | 96 | Some(Arc::new((TokenExpander::Builtin(expander.clone()), mbe::TokenMap::default()))) |
93 | } | 97 | } |
98 | MacroDefKind::BuiltInDerive(expander) => Some(Arc::new(( | ||
99 | TokenExpander::BuiltinDerive(expander.clone()), | ||
100 | mbe::TokenMap::default(), | ||
101 | ))), | ||
94 | } | 102 | } |
95 | } | 103 | } |
96 | 104 | ||
@@ -99,9 +107,8 @@ pub(crate) fn macro_arg( | |||
99 | id: MacroCallId, | 107 | id: MacroCallId, |
100 | ) -> Option<Arc<(tt::Subtree, mbe::TokenMap)>> { | 108 | ) -> Option<Arc<(tt::Subtree, mbe::TokenMap)>> { |
101 | let loc = db.lookup_intern_macro(id); | 109 | let loc = db.lookup_intern_macro(id); |
102 | let macro_call = loc.ast_id.to_node(db); | 110 | let arg = loc.kind.arg(db)?; |
103 | let arg = macro_call.token_tree()?; | 111 | let (tt, tmap) = mbe::syntax_node_to_token_tree(&arg)?; |
104 | let (tt, tmap) = mbe::ast_to_token_tree(&arg)?; | ||
105 | Some(Arc::new((tt, tmap))) | 112 | Some(Arc::new((tt, tmap))) |
106 | } | 113 | } |
107 | 114 | ||
diff --git a/crates/ra_hir_expand/src/hygiene.rs b/crates/ra_hir_expand/src/hygiene.rs index 64c8b06c6..2e8a533f7 100644 --- a/crates/ra_hir_expand/src/hygiene.rs +++ b/crates/ra_hir_expand/src/hygiene.rs | |||
@@ -25,8 +25,9 @@ impl Hygiene { | |||
25 | HirFileIdRepr::MacroFile(macro_file) => { | 25 | HirFileIdRepr::MacroFile(macro_file) => { |
26 | let loc = db.lookup_intern_macro(macro_file.macro_call_id); | 26 | let loc = db.lookup_intern_macro(macro_file.macro_call_id); |
27 | match loc.def.kind { | 27 | match loc.def.kind { |
28 | MacroDefKind::Declarative => Some(loc.def.krate), | 28 | MacroDefKind::Declarative => loc.def.krate, |
29 | MacroDefKind::BuiltIn(_) => None, | 29 | MacroDefKind::BuiltIn(_) => None, |
30 | MacroDefKind::BuiltInDerive(_) => None, | ||
30 | } | 31 | } |
31 | } | 32 | } |
32 | }; | 33 | }; |
diff --git a/crates/ra_hir_expand/src/lib.rs b/crates/ra_hir_expand/src/lib.rs index 3be9bdf86..59c69b91b 100644 --- a/crates/ra_hir_expand/src/lib.rs +++ b/crates/ra_hir_expand/src/lib.rs | |||
@@ -9,6 +9,7 @@ pub mod ast_id_map; | |||
9 | pub mod name; | 9 | pub mod name; |
10 | pub mod hygiene; | 10 | pub mod hygiene; |
11 | pub mod diagnostics; | 11 | pub mod diagnostics; |
12 | pub mod builtin_derive; | ||
12 | pub mod builtin_macro; | 13 | pub mod builtin_macro; |
13 | pub mod quote; | 14 | pub mod quote; |
14 | 15 | ||
@@ -23,6 +24,7 @@ use ra_syntax::{ | |||
23 | }; | 24 | }; |
24 | 25 | ||
25 | use crate::ast_id_map::FileAstId; | 26 | use crate::ast_id_map::FileAstId; |
27 | use crate::builtin_derive::BuiltinDeriveExpander; | ||
26 | use crate::builtin_macro::BuiltinFnLikeExpander; | 28 | use crate::builtin_macro::BuiltinFnLikeExpander; |
27 | 29 | ||
28 | #[cfg(test)] | 30 | #[cfg(test)] |
@@ -69,7 +71,7 @@ impl HirFileId { | |||
69 | HirFileIdRepr::FileId(file_id) => file_id, | 71 | HirFileIdRepr::FileId(file_id) => file_id, |
70 | HirFileIdRepr::MacroFile(macro_file) => { | 72 | HirFileIdRepr::MacroFile(macro_file) => { |
71 | let loc = db.lookup_intern_macro(macro_file.macro_call_id); | 73 | let loc = db.lookup_intern_macro(macro_file.macro_call_id); |
72 | loc.ast_id.file_id.original_file(db) | 74 | loc.kind.file_id().original_file(db) |
73 | } | 75 | } |
74 | } | 76 | } |
75 | } | 77 | } |
@@ -81,8 +83,8 @@ impl HirFileId { | |||
81 | HirFileIdRepr::MacroFile(macro_file) => { | 83 | HirFileIdRepr::MacroFile(macro_file) => { |
82 | let loc: MacroCallLoc = db.lookup_intern_macro(macro_file.macro_call_id); | 84 | let loc: MacroCallLoc = db.lookup_intern_macro(macro_file.macro_call_id); |
83 | 85 | ||
84 | let arg_tt = loc.ast_id.to_node(db).token_tree()?; | 86 | let arg_tt = loc.kind.arg(db)?; |
85 | let def_tt = loc.def.ast_id.to_node(db).token_tree()?; | 87 | let def_tt = loc.def.ast_id?.to_node(db).token_tree()?; |
86 | 88 | ||
87 | let macro_def = db.macro_def(loc.def)?; | 89 | let macro_def = db.macro_def(loc.def)?; |
88 | let (parse, exp_map) = db.parse_macro(macro_file)?; | 90 | let (parse, exp_map) = db.parse_macro(macro_file)?; |
@@ -90,8 +92,8 @@ impl HirFileId { | |||
90 | 92 | ||
91 | Some(ExpansionInfo { | 93 | Some(ExpansionInfo { |
92 | expanded: InFile::new(self, parse.syntax_node()), | 94 | expanded: InFile::new(self, parse.syntax_node()), |
93 | arg: InFile::new(loc.ast_id.file_id, arg_tt), | 95 | arg: InFile::new(loc.kind.file_id(), arg_tt), |
94 | def: InFile::new(loc.ast_id.file_id, def_tt), | 96 | def: InFile::new(loc.def.ast_id?.file_id, def_tt), |
95 | macro_arg, | 97 | macro_arg, |
96 | macro_def, | 98 | macro_def, |
97 | exp_map, | 99 | exp_map, |
@@ -129,18 +131,20 @@ impl salsa::InternKey for MacroCallId { | |||
129 | 131 | ||
130 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 132 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
131 | pub struct MacroDefId { | 133 | pub struct MacroDefId { |
132 | pub krate: CrateId, | 134 | // FIXME: krate and ast_id are currently optional because we don't have a |
133 | pub ast_id: AstId<ast::MacroCall>, | 135 | // definition location for built-in derives. There is one, though: the |
136 | // standard library defines them. The problem is that it uses the new | ||
137 | // `macro` syntax for this, which we don't support yet. As soon as we do | ||
138 | // (which will probably require touching this code), we can instead use | ||
139 | // that (and also remove the hacks for resolving built-in derives). | ||
140 | pub krate: Option<CrateId>, | ||
141 | pub ast_id: Option<AstId<ast::MacroCall>>, | ||
134 | pub kind: MacroDefKind, | 142 | pub kind: MacroDefKind, |
135 | } | 143 | } |
136 | 144 | ||
137 | impl MacroDefId { | 145 | impl MacroDefId { |
138 | pub fn as_call_id( | 146 | pub fn as_call_id(self, db: &dyn db::AstDatabase, kind: MacroCallKind) -> MacroCallId { |
139 | self, | 147 | db.intern_macro(MacroCallLoc { def: self, kind }) |
140 | db: &dyn db::AstDatabase, | ||
141 | ast_id: AstId<ast::MacroCall>, | ||
142 | ) -> MacroCallId { | ||
143 | db.intern_macro(MacroCallLoc { def: self, ast_id }) | ||
144 | } | 148 | } |
145 | } | 149 | } |
146 | 150 | ||
@@ -148,12 +152,38 @@ impl MacroDefId { | |||
148 | pub enum MacroDefKind { | 152 | pub enum MacroDefKind { |
149 | Declarative, | 153 | Declarative, |
150 | BuiltIn(BuiltinFnLikeExpander), | 154 | BuiltIn(BuiltinFnLikeExpander), |
155 | // FIXME: maybe just Builtin and rename BuiltinFnLikeExpander to BuiltinExpander | ||
156 | BuiltInDerive(BuiltinDeriveExpander), | ||
151 | } | 157 | } |
152 | 158 | ||
153 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | 159 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] |
154 | pub struct MacroCallLoc { | 160 | pub struct MacroCallLoc { |
155 | pub(crate) def: MacroDefId, | 161 | pub(crate) def: MacroDefId, |
156 | pub(crate) ast_id: AstId<ast::MacroCall>, | 162 | pub(crate) kind: MacroCallKind, |
163 | } | ||
164 | |||
165 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | ||
166 | pub enum MacroCallKind { | ||
167 | FnLike(AstId<ast::MacroCall>), | ||
168 | Attr(AstId<ast::ModuleItem>), | ||
169 | } | ||
170 | |||
171 | impl MacroCallKind { | ||
172 | pub fn file_id(&self) -> HirFileId { | ||
173 | match self { | ||
174 | MacroCallKind::FnLike(ast_id) => ast_id.file_id, | ||
175 | MacroCallKind::Attr(ast_id) => ast_id.file_id, | ||
176 | } | ||
177 | } | ||
178 | |||
179 | pub fn arg(&self, db: &dyn db::AstDatabase) -> Option<SyntaxNode> { | ||
180 | match self { | ||
181 | MacroCallKind::FnLike(ast_id) => { | ||
182 | Some(ast_id.to_node(db).token_tree()?.syntax().clone()) | ||
183 | } | ||
184 | MacroCallKind::Attr(ast_id) => Some(ast_id.to_node(db).syntax().clone()), | ||
185 | } | ||
186 | } | ||
157 | } | 187 | } |
158 | 188 | ||
159 | impl MacroCallId { | 189 | impl MacroCallId { |
@@ -167,7 +197,7 @@ impl MacroCallId { | |||
167 | #[derive(Debug, Clone, PartialEq, Eq)] | 197 | #[derive(Debug, Clone, PartialEq, Eq)] |
168 | pub struct ExpansionInfo { | 198 | pub struct ExpansionInfo { |
169 | expanded: InFile<SyntaxNode>, | 199 | expanded: InFile<SyntaxNode>, |
170 | arg: InFile<ast::TokenTree>, | 200 | arg: InFile<SyntaxNode>, |
171 | def: InFile<ast::TokenTree>, | 201 | def: InFile<ast::TokenTree>, |
172 | 202 | ||
173 | macro_def: Arc<(db::TokenExpander, mbe::TokenMap)>, | 203 | macro_def: Arc<(db::TokenExpander, mbe::TokenMap)>, |
@@ -178,8 +208,7 @@ pub struct ExpansionInfo { | |||
178 | impl ExpansionInfo { | 208 | impl ExpansionInfo { |
179 | pub fn map_token_down(&self, token: InFile<&SyntaxToken>) -> Option<InFile<SyntaxToken>> { | 209 | pub fn map_token_down(&self, token: InFile<&SyntaxToken>) -> Option<InFile<SyntaxToken>> { |
180 | assert_eq!(token.file_id, self.arg.file_id); | 210 | assert_eq!(token.file_id, self.arg.file_id); |
181 | let range = | 211 | let range = token.value.text_range().checked_sub(self.arg.value.text_range().start())?; |
182 | token.value.text_range().checked_sub(self.arg.value.syntax().text_range().start())?; | ||
183 | let token_id = self.macro_arg.1.token_by_range(range)?; | 212 | let token_id = self.macro_arg.1.token_by_range(range)?; |
184 | let token_id = self.macro_def.0.map_id_down(token_id); | 213 | let token_id = self.macro_def.0.map_id_down(token_id); |
185 | 214 | ||
@@ -195,16 +224,15 @@ impl ExpansionInfo { | |||
195 | 224 | ||
196 | let (token_id, origin) = self.macro_def.0.map_id_up(token_id); | 225 | let (token_id, origin) = self.macro_def.0.map_id_up(token_id); |
197 | let (token_map, tt) = match origin { | 226 | let (token_map, tt) = match origin { |
198 | mbe::Origin::Call => (&self.macro_arg.1, &self.arg), | 227 | mbe::Origin::Call => (&self.macro_arg.1, self.arg.clone()), |
199 | mbe::Origin::Def => (&self.macro_def.1, &self.def), | 228 | mbe::Origin::Def => { |
229 | (&self.macro_def.1, self.def.as_ref().map(|tt| tt.syntax().clone())) | ||
230 | } | ||
200 | }; | 231 | }; |
201 | 232 | ||
202 | let range = token_map.range_by_token(token_id)?; | 233 | let range = token_map.range_by_token(token_id)?; |
203 | let token = algo::find_covering_element( | 234 | let token = algo::find_covering_element(&tt.value, range + tt.value.text_range().start()) |
204 | tt.value.syntax(), | 235 | .into_token()?; |
205 | range + tt.value.syntax().text_range().start(), | ||
206 | ) | ||
207 | .into_token()?; | ||
208 | Some(tt.with_value(token)) | 236 | Some(tt.with_value(token)) |
209 | } | 237 | } |
210 | } | 238 | } |
diff --git a/crates/ra_hir_expand/src/name.rs b/crates/ra_hir_expand/src/name.rs index 05ba37070..86709b5cf 100644 --- a/crates/ra_hir_expand/src/name.rs +++ b/crates/ra_hir_expand/src/name.rs | |||
@@ -83,6 +83,12 @@ impl AsName for ast::Name { | |||
83 | } | 83 | } |
84 | } | 84 | } |
85 | 85 | ||
86 | impl AsName for tt::Ident { | ||
87 | fn as_name(&self) -> Name { | ||
88 | Name::resolve(&self.text) | ||
89 | } | ||
90 | } | ||
91 | |||
86 | impl AsName for ast::FieldKind { | 92 | impl AsName for ast::FieldKind { |
87 | fn as_name(&self) -> Name { | 93 | fn as_name(&self) -> Name { |
88 | match self { | 94 | match self { |
@@ -153,3 +159,7 @@ pub const COLUMN_MACRO: Name = Name::new_inline_ascii(6, b"column"); | |||
153 | pub const COMPILE_ERROR_MACRO: Name = Name::new_inline_ascii(13, b"compile_error"); | 159 | pub const COMPILE_ERROR_MACRO: Name = Name::new_inline_ascii(13, b"compile_error"); |
154 | pub const LINE_MACRO: Name = Name::new_inline_ascii(4, b"line"); | 160 | pub const LINE_MACRO: Name = Name::new_inline_ascii(4, b"line"); |
155 | pub const STRINGIFY_MACRO: Name = Name::new_inline_ascii(9, b"stringify"); | 161 | pub const STRINGIFY_MACRO: Name = Name::new_inline_ascii(9, b"stringify"); |
162 | |||
163 | // Builtin derives | ||
164 | pub const COPY_TRAIT: Name = Name::new_inline_ascii(4, b"Copy"); | ||
165 | pub const CLONE_TRAIT: Name = Name::new_inline_ascii(5, b"Clone"); | ||