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.rs114
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
7use ra_db::{LocationInterner, FileId}; 7use ra_db::{LocationInterner, FileId};
8use ra_syntax::{TreeArc, SyntaxNode, SourceFile, AstNode, SyntaxNodePtr, ast}; 8use ra_syntax::{TreeArc, SourceFile, AstNode, ast};
9use ra_arena::{Arena, RawId, ArenaId, impl_arena_id}; 9use ra_arena::{RawId, ArenaId, impl_arena_id};
10use mbe::MacroRules; 10use mbe::MacroRules;
11 11
12use crate::{ 12use 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)]
311pub struct SourceFileItemId(RawId);
312impl_arena_id!(SourceFileItemId);
313
314impl 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)]
321pub 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)]
328pub struct SourceFileItems {
329 file_id: HirFileId,
330 arena: Arena<SourceFileItemId, SyntaxNodePtr>,
331}
332
333impl 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
395impl 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.
403fn 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}