aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src/source_id.rs
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2019-03-26 11:40:34 +0000
committerAleksey Kladov <[email protected]>2019-03-26 11:42:28 +0000
commit0b820cacab020993b6e1667f491289122f03de04 (patch)
tree51bca0fffff48bc0124b35f4091738f03e651688 /crates/ra_hir/src/source_id.rs
parent8254244e4970b085809d42a34282649b4a4e16a2 (diff)
move source_id to a separate file
Diffstat (limited to 'crates/ra_hir/src/source_id.rs')
-rw-r--r--crates/ra_hir/src/source_id.rs113
1 files changed, 113 insertions, 0 deletions
diff --git a/crates/ra_hir/src/source_id.rs b/crates/ra_hir/src/source_id.rs
new file mode 100644
index 000000000..f961adf8b
--- /dev/null
+++ b/crates/ra_hir/src/source_id.rs
@@ -0,0 +1,113 @@
1use std::sync::Arc;
2
3use ra_arena::{Arena, RawId, impl_arena_id};
4use ra_syntax::{SyntaxNodePtr, TreeArc, SyntaxNode, SourceFile, AstNode, ast};
5
6use crate::{HirFileId, DefDatabase};
7
8/// Identifier of item within a specific file. This is stable over reparses, so
9/// it's OK to use it as a salsa key/value.
10#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
11pub struct SourceFileItemId(RawId);
12impl_arena_id!(SourceFileItemId);
13
14impl SourceFileItemId {
15 pub(crate) fn with_file_id(self, file_id: HirFileId) -> SourceItemId {
16 SourceItemId { file_id, item_id: self }
17 }
18}
19
20#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
21pub struct SourceItemId {
22 pub(crate) file_id: HirFileId,
23 pub(crate) item_id: SourceFileItemId,
24}
25
26/// Maps items' `SyntaxNode`s to `SourceFileItemId`s and back.
27#[derive(Debug, PartialEq, Eq)]
28pub struct SourceFileItems {
29 file_id: HirFileId,
30 arena: Arena<SourceFileItemId, SyntaxNodePtr>,
31}
32
33impl SourceFileItems {
34 pub(crate) fn file_items_query(
35 db: &impl DefDatabase,
36 file_id: HirFileId,
37 ) -> Arc<SourceFileItems> {
38 let source_file = db.hir_parse(file_id);
39 Arc::new(SourceFileItems::from_source_file(&source_file, file_id))
40 }
41
42 pub(crate) fn file_item_query(
43 db: &impl DefDatabase,
44 source_item_id: SourceItemId,
45 ) -> TreeArc<SyntaxNode> {
46 let source_file = db.hir_parse(source_item_id.file_id);
47 db.file_items(source_item_id.file_id)[source_item_id.item_id]
48 .to_node(&source_file)
49 .to_owned()
50 }
51
52 pub(crate) fn from_source_file(
53 source_file: &SourceFile,
54 file_id: HirFileId,
55 ) -> SourceFileItems {
56 let mut res = SourceFileItems { file_id, arena: Arena::default() };
57 // By walking the tree in bread-first order we make sure that parents
58 // get lower ids then children. That is, adding a new child does not
59 // change parent's id. This means that, say, adding a new function to a
60 // trait does not change ids of top-level items, which helps caching.
61 bfs(source_file.syntax(), |it| {
62 if let Some(module_item) = ast::ModuleItem::cast(it) {
63 res.alloc(module_item.syntax());
64 } else if let Some(macro_call) = ast::MacroCall::cast(it) {
65 res.alloc(macro_call.syntax());
66 }
67 });
68 res
69 }
70
71 fn alloc(&mut self, item: &SyntaxNode) -> SourceFileItemId {
72 self.arena.alloc(SyntaxNodePtr::new(item))
73 }
74 pub(crate) fn id_of(&self, file_id: HirFileId, item: &SyntaxNode) -> SourceFileItemId {
75 assert_eq!(
76 self.file_id, file_id,
77 "SourceFileItems: wrong file, expected {:?}, got {:?}",
78 self.file_id, file_id
79 );
80 self.id_of_unchecked(item)
81 }
82 pub(crate) fn id_of_unchecked(&self, item: &SyntaxNode) -> SourceFileItemId {
83 let ptr = SyntaxNodePtr::new(item);
84 if let Some((id, _)) = self.arena.iter().find(|(_id, i)| **i == ptr) {
85 return id;
86 }
87 panic!(
88 "Can't find {:?} in SourceFileItems:\n{:?}",
89 item,
90 self.arena.iter().map(|(_id, i)| i).collect::<Vec<_>>(),
91 );
92 }
93}
94
95impl std::ops::Index<SourceFileItemId> for SourceFileItems {
96 type Output = SyntaxNodePtr;
97 fn index(&self, idx: SourceFileItemId) -> &SyntaxNodePtr {
98 &self.arena[idx]
99 }
100}
101
102/// Walks the subtree in bfs order, calling `f` for each node.
103fn bfs(node: &SyntaxNode, mut f: impl FnMut(&SyntaxNode)) {
104 let mut curr_layer = vec![node];
105 let mut next_layer = vec![];
106 while !curr_layer.is_empty() {
107 curr_layer.drain(..).for_each(|node| {
108 next_layer.extend(node.children());
109 f(node);
110 });
111 std::mem::swap(&mut curr_layer, &mut next_layer);
112 }
113}