aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src/ids.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir/src/ids.rs')
-rw-r--r--crates/ra_hir/src/ids.rs64
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
100fn 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(&macro_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)]
111enum HirFileIdRepr { 118enum 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 {
290pub struct SourceFileItemId(RawId); 303pub struct SourceFileItemId(RawId);
291impl_arena_id!(SourceFileItemId); 304impl_arena_id!(SourceFileItemId);
292 305
306impl 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)]
294pub struct SourceItemId { 313pub 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 {