diff options
Diffstat (limited to 'crates/ra_hir_expand/src/lib.rs')
-rw-r--r-- | crates/ra_hir_expand/src/lib.rs | 76 |
1 files changed, 52 insertions, 24 deletions
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 | } |