aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_expand
diff options
context:
space:
mode:
authorFlorian Diebold <[email protected]>2019-12-05 14:10:33 +0000
committerFlorian Diebold <[email protected]>2019-12-05 16:23:09 +0000
commit18f6a995d0fc1f45099f3cc810a5d55d5401b41b (patch)
tree808cb0f025b488f59935007802d1bb85f1cf0044 /crates/ra_hir_expand
parent4c0bd068da39e74c66104206e27c270454e3562e (diff)
Add expansion infrastructure for derive macros
Diffstat (limited to 'crates/ra_hir_expand')
-rw-r--r--crates/ra_hir_expand/src/ast_id_map.rs12
-rw-r--r--crates/ra_hir_expand/src/builtin_derive.rs64
-rw-r--r--crates/ra_hir_expand/src/builtin_macro.rs37
-rw-r--r--crates/ra_hir_expand/src/db.rs19
-rw-r--r--crates/ra_hir_expand/src/hygiene.rs3
-rw-r--r--crates/ra_hir_expand/src/lib.rs76
-rw-r--r--crates/ra_hir_expand/src/name.rs10
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
42impl<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)]
43struct ErasedFileAstId(RawId); 53struct ErasedFileAstId(RawId);
44impl_arena_id!(ErasedFileAstId); 54impl_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.
2use crate::db::AstDatabase;
3use crate::{name, MacroCallId, MacroDefId, MacroDefKind};
4
5use crate::quote;
6
7macro_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
39register_builtin! {
40 (COPY_TRAIT, Copy) => copy_expand,
41 (CLONE_TRAIT, Clone) => clone_expand
42}
43
44fn 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
55fn 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
166fn file_expand( 167fn 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)]
208mod tests { 204mod 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(&macro_calls[0])), 220 ast_id: Some(AstId::new(file_id.into(), ast_id_map.ast_id(&macro_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(&macro_calls[1])), 226 kind: MacroCallKind::FnLike(AstId::new(
227 file_id.into(),
228 ast_id_map.ast_id(&macro_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;
9use ra_syntax::{AstNode, Parse, SyntaxNode}; 9use ra_syntax::{AstNode, Parse, SyntaxNode};
10 10
11use crate::{ 11use 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)]
17pub enum TokenExpander { 17pub enum TokenExpander {
18 MacroRules(mbe::MacroRules), 18 MacroRules(mbe::MacroRules),
19 Builtin(BuiltinFnLikeExpander), 19 Builtin(BuiltinFnLikeExpander),
20 BuiltinDerive(BuiltinDeriveExpander),
20} 21}
21 22
22impl TokenExpander { 23impl 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;
9pub mod name; 9pub mod name;
10pub mod hygiene; 10pub mod hygiene;
11pub mod diagnostics; 11pub mod diagnostics;
12pub mod builtin_derive;
12pub mod builtin_macro; 13pub mod builtin_macro;
13pub mod quote; 14pub mod quote;
14 15
@@ -23,6 +24,7 @@ use ra_syntax::{
23}; 24};
24 25
25use crate::ast_id_map::FileAstId; 26use crate::ast_id_map::FileAstId;
27use crate::builtin_derive::BuiltinDeriveExpander;
26use crate::builtin_macro::BuiltinFnLikeExpander; 28use 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)]
131pub struct MacroDefId { 133pub 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
137impl MacroDefId { 145impl 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 {
148pub enum MacroDefKind { 152pub 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)]
154pub struct MacroCallLoc { 160pub 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)]
166pub enum MacroCallKind {
167 FnLike(AstId<ast::MacroCall>),
168 Attr(AstId<ast::ModuleItem>),
169}
170
171impl 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
159impl MacroCallId { 189impl MacroCallId {
@@ -167,7 +197,7 @@ impl MacroCallId {
167#[derive(Debug, Clone, PartialEq, Eq)] 197#[derive(Debug, Clone, PartialEq, Eq)]
168pub struct ExpansionInfo { 198pub 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 {
178impl ExpansionInfo { 208impl 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
86impl AsName for tt::Ident {
87 fn as_name(&self) -> Name {
88 Name::resolve(&self.text)
89 }
90}
91
86impl AsName for ast::FieldKind { 92impl 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");
153pub const COMPILE_ERROR_MACRO: Name = Name::new_inline_ascii(13, b"compile_error"); 159pub const COMPILE_ERROR_MACRO: Name = Name::new_inline_ascii(13, b"compile_error");
154pub const LINE_MACRO: Name = Name::new_inline_ascii(4, b"line"); 160pub const LINE_MACRO: Name = Name::new_inline_ascii(4, b"line");
155pub const STRINGIFY_MACRO: Name = Name::new_inline_ascii(9, b"stringify"); 161pub const STRINGIFY_MACRO: Name = Name::new_inline_ascii(9, b"stringify");
162
163// Builtin derives
164pub const COPY_TRAIT: Name = Name::new_inline_ascii(4, b"Copy");
165pub const CLONE_TRAIT: Name = Name::new_inline_ascii(5, b"Clone");