diff options
Diffstat (limited to 'crates/ra_hir/src/ids.rs')
-rw-r--r-- | crates/ra_hir/src/ids.rs | 114 |
1 files changed, 3 insertions, 111 deletions
diff --git a/crates/ra_hir/src/ids.rs b/crates/ra_hir/src/ids.rs index bac7b9e46..e73dd5d21 100644 --- a/crates/ra_hir/src/ids.rs +++ b/crates/ra_hir/src/ids.rs | |||
@@ -5,13 +5,12 @@ use std::{ | |||
5 | }; | 5 | }; |
6 | 6 | ||
7 | use ra_db::{LocationInterner, FileId}; | 7 | use ra_db::{LocationInterner, FileId}; |
8 | use ra_syntax::{TreeArc, SyntaxNode, SourceFile, AstNode, SyntaxNodePtr, ast}; | 8 | use ra_syntax::{TreeArc, SourceFile, AstNode, ast}; |
9 | use ra_arena::{Arena, RawId, ArenaId, impl_arena_id}; | 9 | use ra_arena::{RawId, ArenaId, impl_arena_id}; |
10 | use mbe::MacroRules; | 10 | use mbe::MacroRules; |
11 | 11 | ||
12 | use crate::{ | 12 | use crate::{ |
13 | Module, | 13 | Module, DefDatabase, SourceItemId, SourceFileItemId, |
14 | DefDatabase, | ||
15 | }; | 14 | }; |
16 | 15 | ||
17 | #[derive(Debug, Default)] | 16 | #[derive(Debug, Default)] |
@@ -304,110 +303,3 @@ impl AstItemDef<ast::TypeAliasDef> for TypeId { | |||
304 | &interner.types | 303 | &interner.types |
305 | } | 304 | } |
306 | } | 305 | } |
307 | |||
308 | /// Identifier of item within a specific file. This is stable over reparses, so | ||
309 | /// it's OK to use it as a salsa key/value. | ||
310 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] | ||
311 | pub struct SourceFileItemId(RawId); | ||
312 | impl_arena_id!(SourceFileItemId); | ||
313 | |||
314 | impl SourceFileItemId { | ||
315 | pub(crate) fn with_file_id(self, file_id: HirFileId) -> SourceItemId { | ||
316 | SourceItemId { file_id, item_id: self } | ||
317 | } | ||
318 | } | ||
319 | |||
320 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
321 | pub struct SourceItemId { | ||
322 | pub(crate) file_id: HirFileId, | ||
323 | pub(crate) item_id: SourceFileItemId, | ||
324 | } | ||
325 | |||
326 | /// Maps items' `SyntaxNode`s to `SourceFileItemId`s and back. | ||
327 | #[derive(Debug, PartialEq, Eq)] | ||
328 | pub struct SourceFileItems { | ||
329 | file_id: HirFileId, | ||
330 | arena: Arena<SourceFileItemId, SyntaxNodePtr>, | ||
331 | } | ||
332 | |||
333 | impl SourceFileItems { | ||
334 | pub(crate) fn file_items_query( | ||
335 | db: &impl DefDatabase, | ||
336 | file_id: HirFileId, | ||
337 | ) -> Arc<SourceFileItems> { | ||
338 | let source_file = db.hir_parse(file_id); | ||
339 | Arc::new(SourceFileItems::from_source_file(&source_file, file_id)) | ||
340 | } | ||
341 | |||
342 | pub(crate) fn file_item_query( | ||
343 | db: &impl DefDatabase, | ||
344 | source_item_id: SourceItemId, | ||
345 | ) -> TreeArc<SyntaxNode> { | ||
346 | let source_file = db.hir_parse(source_item_id.file_id); | ||
347 | db.file_items(source_item_id.file_id)[source_item_id.item_id] | ||
348 | .to_node(&source_file) | ||
349 | .to_owned() | ||
350 | } | ||
351 | |||
352 | pub(crate) fn from_source_file( | ||
353 | source_file: &SourceFile, | ||
354 | file_id: HirFileId, | ||
355 | ) -> SourceFileItems { | ||
356 | let mut res = SourceFileItems { file_id, arena: Arena::default() }; | ||
357 | // By walking the tree in bread-first order we make sure that parents | ||
358 | // get lower ids then children. That is, adding a new child does not | ||
359 | // change parent's id. This means that, say, adding a new function to a | ||
360 | // trait does not change ids of top-level items, which helps caching. | ||
361 | bfs(source_file.syntax(), |it| { | ||
362 | if let Some(module_item) = ast::ModuleItem::cast(it) { | ||
363 | res.alloc(module_item.syntax()); | ||
364 | } else if let Some(macro_call) = ast::MacroCall::cast(it) { | ||
365 | res.alloc(macro_call.syntax()); | ||
366 | } | ||
367 | }); | ||
368 | res | ||
369 | } | ||
370 | |||
371 | fn alloc(&mut self, item: &SyntaxNode) -> SourceFileItemId { | ||
372 | self.arena.alloc(SyntaxNodePtr::new(item)) | ||
373 | } | ||
374 | pub(crate) fn id_of(&self, file_id: HirFileId, item: &SyntaxNode) -> SourceFileItemId { | ||
375 | assert_eq!( | ||
376 | self.file_id, file_id, | ||
377 | "SourceFileItems: wrong file, expected {:?}, got {:?}", | ||
378 | self.file_id, file_id | ||
379 | ); | ||
380 | self.id_of_unchecked(item) | ||
381 | } | ||
382 | pub(crate) fn id_of_unchecked(&self, item: &SyntaxNode) -> SourceFileItemId { | ||
383 | let ptr = SyntaxNodePtr::new(item); | ||
384 | if let Some((id, _)) = self.arena.iter().find(|(_id, i)| **i == ptr) { | ||
385 | return id; | ||
386 | } | ||
387 | panic!( | ||
388 | "Can't find {:?} in SourceFileItems:\n{:?}", | ||
389 | item, | ||
390 | self.arena.iter().map(|(_id, i)| i).collect::<Vec<_>>(), | ||
391 | ); | ||
392 | } | ||
393 | } | ||
394 | |||
395 | impl std::ops::Index<SourceFileItemId> for SourceFileItems { | ||
396 | type Output = SyntaxNodePtr; | ||
397 | fn index(&self, idx: SourceFileItemId) -> &SyntaxNodePtr { | ||
398 | &self.arena[idx] | ||
399 | } | ||
400 | } | ||
401 | |||
402 | /// Walks the subtree in bfs order, calling `f` for each node. | ||
403 | fn bfs(node: &SyntaxNode, mut f: impl FnMut(&SyntaxNode)) { | ||
404 | let mut curr_layer = vec![node]; | ||
405 | let mut next_layer = vec![]; | ||
406 | while !curr_layer.is_empty() { | ||
407 | curr_layer.drain(..).for_each(|node| { | ||
408 | next_layer.extend(node.children()); | ||
409 | f(node); | ||
410 | }); | ||
411 | std::mem::swap(&mut curr_layer, &mut next_layer); | ||
412 | } | ||
413 | } | ||