diff options
Diffstat (limited to 'crates/ra_hir/src/ids.rs')
-rw-r--r-- | crates/ra_hir/src/ids.rs | 64 |
1 files changed, 43 insertions, 21 deletions
diff --git a/crates/ra_hir/src/ids.rs b/crates/ra_hir/src/ids.rs index 5b00330c6..9596488d3 100644 --- a/crates/ra_hir/src/ids.rs +++ b/crates/ra_hir/src/ids.rs | |||
@@ -83,30 +83,37 @@ impl HirFileId { | |||
83 | } | 83 | } |
84 | } | 84 | } |
85 | 85 | ||
86 | pub(crate) fn as_macro_call_id(self) -> Option<MacroCallId> { | ||
87 | match self.0 { | ||
88 | HirFileIdRepr::Macro(it) => Some(it), | ||
89 | _ => None, | ||
90 | } | ||
91 | } | ||
92 | |||
93 | pub(crate) fn hir_parse( | 86 | pub(crate) fn hir_parse( |
94 | db: &impl PersistentHirDatabase, | 87 | db: &impl PersistentHirDatabase, |
95 | file_id: HirFileId, | 88 | file_id: HirFileId, |
96 | ) -> TreeArc<SourceFile> { | 89 | ) -> TreeArc<SourceFile> { |
97 | match file_id.0 { | 90 | match file_id.0 { |
98 | HirFileIdRepr::File(file_id) => db.parse(file_id), | 91 | HirFileIdRepr::File(file_id) => db.parse(file_id), |
99 | HirFileIdRepr::Macro(m) => { | 92 | HirFileIdRepr::Macro(macro_call_id) => { |
100 | if let Some(exp) = db.expand_macro_invocation(m) { | ||
101 | return exp.file(); | ||
102 | } | ||
103 | // returning an empty string looks fishy... | 93 | // returning an empty string looks fishy... |
104 | SourceFile::parse("") | 94 | parse_macro(db, macro_call_id).unwrap_or_else(|| SourceFile::parse("")) |
105 | } | 95 | } |
106 | } | 96 | } |
107 | } | 97 | } |
108 | } | 98 | } |
109 | 99 | ||
100 | fn parse_macro( | ||
101 | db: &impl PersistentHirDatabase, | ||
102 | macro_call_id: MacroCallId, | ||
103 | ) -> Option<TreeArc<SourceFile>> { | ||
104 | let loc = macro_call_id.loc(db); | ||
105 | let syntax = db.file_item(loc.source_item_id); | ||
106 | let macro_call = ast::MacroCall::cast(&syntax).unwrap(); | ||
107 | let (macro_arg, _) = macro_call.token_tree().and_then(mbe::ast_to_token_tree)?; | ||
108 | |||
109 | let def_map = db.crate_def_map(loc.module.krate); | ||
110 | let (krate, macro_id) = def_map.resolve_macro(macro_call_id)?; | ||
111 | let def_map = db.crate_def_map(krate); | ||
112 | let macro_rules = &def_map[macro_id]; | ||
113 | let tt = macro_rules.expand(¯o_arg).ok()?; | ||
114 | Some(mbe::token_tree_to_ast_item_list(&tt)) | ||
115 | } | ||
116 | |||
110 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 117 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
111 | enum HirFileIdRepr { | 118 | enum HirFileIdRepr { |
112 | File(FileId), | 119 | File(FileId), |
@@ -200,8 +207,14 @@ pub(crate) trait AstItemDef<N: AstNode>: ArenaId + Clone { | |||
200 | fn interner(interner: &HirInterner) -> &LocationIntener<ItemLoc<N>, Self>; | 207 | fn interner(interner: &HirInterner) -> &LocationIntener<ItemLoc<N>, Self>; |
201 | fn from_ast(ctx: LocationCtx<&impl PersistentHirDatabase>, ast: &N) -> Self { | 208 | fn from_ast(ctx: LocationCtx<&impl PersistentHirDatabase>, ast: &N) -> Self { |
202 | let items = ctx.db.file_items(ctx.file_id); | 209 | let items = ctx.db.file_items(ctx.file_id); |
203 | let raw = | 210 | let item_id = items.id_of(ctx.file_id, ast.syntax()); |
204 | SourceItemId { file_id: ctx.file_id, item_id: items.id_of(ctx.file_id, ast.syntax()) }; | 211 | Self::from_source_item_id_unchecked(ctx, item_id) |
212 | } | ||
213 | fn from_source_item_id_unchecked( | ||
214 | ctx: LocationCtx<&impl PersistentHirDatabase>, | ||
215 | item_id: SourceFileItemId, | ||
216 | ) -> Self { | ||
217 | let raw = SourceItemId { file_id: ctx.file_id, item_id }; | ||
205 | let loc = ItemLoc { module: ctx.module, raw, _ty: PhantomData }; | 218 | let loc = ItemLoc { module: ctx.module, raw, _ty: PhantomData }; |
206 | 219 | ||
207 | Self::interner(ctx.db.as_ref()).loc2id(&loc) | 220 | Self::interner(ctx.db.as_ref()).loc2id(&loc) |
@@ -290,6 +303,12 @@ impl AstItemDef<ast::TypeAliasDef> for TypeId { | |||
290 | pub struct SourceFileItemId(RawId); | 303 | pub struct SourceFileItemId(RawId); |
291 | impl_arena_id!(SourceFileItemId); | 304 | impl_arena_id!(SourceFileItemId); |
292 | 305 | ||
306 | impl SourceFileItemId { | ||
307 | pub(crate) fn with_file_id(self, file_id: HirFileId) -> SourceItemId { | ||
308 | SourceItemId { file_id, item_id: self } | ||
309 | } | ||
310 | } | ||
311 | |||
293 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 312 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
294 | pub struct SourceItemId { | 313 | pub struct SourceItemId { |
295 | pub(crate) file_id: HirFileId, | 314 | pub(crate) file_id: HirFileId, |
@@ -309,9 +328,7 @@ impl SourceFileItems { | |||
309 | file_id: HirFileId, | 328 | file_id: HirFileId, |
310 | ) -> Arc<SourceFileItems> { | 329 | ) -> Arc<SourceFileItems> { |
311 | let source_file = db.hir_parse(file_id); | 330 | let source_file = db.hir_parse(file_id); |
312 | let mut res = SourceFileItems { file_id, arena: Arena::default() }; | 331 | Arc::new(SourceFileItems::from_source_file(&source_file, file_id)) |
313 | res.init(&source_file); | ||
314 | Arc::new(res) | ||
315 | } | 332 | } |
316 | 333 | ||
317 | pub(crate) fn file_item_query( | 334 | pub(crate) fn file_item_query( |
@@ -324,18 +341,23 @@ impl SourceFileItems { | |||
324 | .to_owned() | 341 | .to_owned() |
325 | } | 342 | } |
326 | 343 | ||
327 | fn init(&mut self, source_file: &SourceFile) { | 344 | pub(crate) fn from_source_file( |
345 | source_file: &SourceFile, | ||
346 | file_id: HirFileId, | ||
347 | ) -> SourceFileItems { | ||
348 | let mut res = SourceFileItems { file_id, arena: Arena::default() }; | ||
328 | // By walking the tree in bread-first order we make sure that parents | 349 | // By walking the tree in bread-first order we make sure that parents |
329 | // get lower ids then children. That is, adding a new child does not | 350 | // get lower ids then children. That is, adding a new child does not |
330 | // change parent's id. This means that, say, adding a new function to a | 351 | // change parent's id. This means that, say, adding a new function to a |
331 | // trait does not change ids of top-level items, which helps caching. | 352 | // trait does not change ids of top-level items, which helps caching. |
332 | bfs(source_file.syntax(), |it| { | 353 | bfs(source_file.syntax(), |it| { |
333 | if let Some(module_item) = ast::ModuleItem::cast(it) { | 354 | if let Some(module_item) = ast::ModuleItem::cast(it) { |
334 | self.alloc(module_item.syntax()); | 355 | res.alloc(module_item.syntax()); |
335 | } else if let Some(macro_call) = ast::MacroCall::cast(it) { | 356 | } else if let Some(macro_call) = ast::MacroCall::cast(it) { |
336 | self.alloc(macro_call.syntax()); | 357 | res.alloc(macro_call.syntax()); |
337 | } | 358 | } |
338 | }) | 359 | }); |
360 | res | ||
339 | } | 361 | } |
340 | 362 | ||
341 | fn alloc(&mut self, item: &SyntaxNode) -> SourceFileItemId { | 363 | fn alloc(&mut self, item: &SyntaxNode) -> SourceFileItemId { |