aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src/source_id.rs
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2019-10-29 08:20:02 +0000
committerGitHub <[email protected]>2019-10-29 08:20:02 +0000
commit4f22d2f3b0852f32c0ba5e4545ec8cc2d986cfcc (patch)
tree09667ecbdcc8b84916c509d3a3d09ab56b5d4aed /crates/ra_hir/src/source_id.rs
parent120000609ab0a0e6a946404d0477f5a0a7107800 (diff)
parent77f90caf2deeb6a2d2c8196399fbba61bf0c461d (diff)
Merge #2112
2112: start ra_hir_def crate r=matklad a=matklad Co-authored-by: Aleksey Kladov <[email protected]>
Diffstat (limited to 'crates/ra_hir/src/source_id.rs')
-rw-r--r--crates/ra_hir/src/source_id.rs132
1 files changed, 22 insertions, 110 deletions
diff --git a/crates/ra_hir/src/source_id.rs b/crates/ra_hir/src/source_id.rs
index a4dd99598..260b79661 100644
--- a/crates/ra_hir/src/source_id.rs
+++ b/crates/ra_hir/src/source_id.rs
@@ -2,18 +2,18 @@
2 2
3use std::{ 3use std::{
4 hash::{Hash, Hasher}, 4 hash::{Hash, Hasher},
5 marker::PhantomData,
6 sync::Arc, 5 sync::Arc,
7}; 6};
8 7
9use ra_arena::{impl_arena_id, Arena, RawId}; 8pub use hir_def::ast_id_map::{AstIdMap, ErasedFileAstId, FileAstId};
10use ra_syntax::{ast, AstNode, SyntaxNode, SyntaxNodePtr}; 9use ra_syntax::{AstNode, SyntaxNode};
11 10
12use crate::{db::AstDatabase, HirFileId}; 11use crate::{db::AstDatabase, HirFileId};
13 12
14/// `AstId` points to an AST node in any file. 13/// `AstId` points to an AST node in any file.
15/// 14///
16/// It is stable across reparses, and can be used as salsa key/value. 15/// It is stable across reparses, and can be used as salsa key/value.
16// FIXME: isn't this just a `Source<FileAstId<N>>` ?
17#[derive(Debug)] 17#[derive(Debug)]
18pub(crate) struct AstId<N: AstNode> { 18pub(crate) struct AstId<N: AstNode> {
19 file_id: HirFileId, 19 file_id: HirFileId,
@@ -40,122 +40,34 @@ impl<N: AstNode> Hash for AstId<N> {
40} 40}
41 41
42impl<N: AstNode> AstId<N> { 42impl<N: AstNode> AstId<N> {
43 pub fn new(file_id: HirFileId, file_ast_id: FileAstId<N>) -> AstId<N> {
44 AstId { file_id, file_ast_id }
45 }
46
43 pub(crate) fn file_id(&self) -> HirFileId { 47 pub(crate) fn file_id(&self) -> HirFileId {
44 self.file_id 48 self.file_id
45 } 49 }
46 50
47 pub(crate) fn to_node(&self, db: &impl AstDatabase) -> N { 51 pub(crate) fn to_node(&self, db: &impl AstDatabase) -> N {
48 let syntax_node = db.ast_id_to_node(self.file_id, self.file_ast_id.raw); 52 let syntax_node = db.ast_id_to_node(self.file_id, self.file_ast_id.into());
49 N::cast(syntax_node).unwrap() 53 N::cast(syntax_node).unwrap()
50 } 54 }
51} 55}
52 56
53/// `AstId` points to an AST node in a specific file. 57pub(crate) fn ast_id_map_query(db: &impl AstDatabase, file_id: HirFileId) -> Arc<AstIdMap> {
54#[derive(Debug)] 58 let map = if let Some(node) = db.parse_or_expand(file_id) {
55pub(crate) struct FileAstId<N: AstNode> { 59 AstIdMap::from_source(&node)
56 raw: ErasedFileAstId, 60 } else {
57 _ty: PhantomData<fn() -> N>, 61 AstIdMap::default()
58} 62 };
59 63 Arc::new(map)
60impl<N: AstNode> Clone for FileAstId<N> {
61 fn clone(&self) -> FileAstId<N> {
62 *self
63 }
64}
65impl<N: AstNode> Copy for FileAstId<N> {}
66
67impl<N: AstNode> PartialEq for FileAstId<N> {
68 fn eq(&self, other: &Self) -> bool {
69 self.raw == other.raw
70 }
71}
72impl<N: AstNode> Eq for FileAstId<N> {}
73impl<N: AstNode> Hash for FileAstId<N> {
74 fn hash<H: Hasher>(&self, hasher: &mut H) {
75 self.raw.hash(hasher);
76 }
77}
78
79impl<N: AstNode> FileAstId<N> {
80 pub(crate) fn with_file_id(self, file_id: HirFileId) -> AstId<N> {
81 AstId { file_id, file_ast_id: self }
82 }
83}
84
85#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
86pub struct ErasedFileAstId(RawId);
87impl_arena_id!(ErasedFileAstId);
88
89/// Maps items' `SyntaxNode`s to `ErasedFileAstId`s and back.
90#[derive(Debug, PartialEq, Eq, Default)]
91pub struct AstIdMap {
92 arena: Arena<ErasedFileAstId, SyntaxNodePtr>,
93} 64}
94 65
95impl AstIdMap { 66pub(crate) fn file_item_query(
96 pub(crate) fn ast_id_map_query(db: &impl AstDatabase, file_id: HirFileId) -> Arc<AstIdMap> { 67 db: &impl AstDatabase,
97 let map = if let Some(node) = db.parse_or_expand(file_id) { 68 file_id: HirFileId,
98 AstIdMap::from_source(&node) 69 ast_id: ErasedFileAstId,
99 } else { 70) -> SyntaxNode {
100 AstIdMap::default() 71 let node = db.parse_or_expand(file_id).unwrap();
101 }; 72 db.ast_id_map(file_id)[ast_id].to_node(&node)
102 Arc::new(map)
103 }
104
105 pub(crate) fn file_item_query(
106 db: &impl AstDatabase,
107 file_id: HirFileId,
108 ast_id: ErasedFileAstId,
109 ) -> SyntaxNode {
110 let node = db.parse_or_expand(file_id).unwrap();
111 db.ast_id_map(file_id).arena[ast_id].to_node(&node)
112 }
113
114 pub(crate) fn ast_id<N: AstNode>(&self, item: &N) -> FileAstId<N> {
115 let ptr = SyntaxNodePtr::new(item.syntax());
116 let raw = match self.arena.iter().find(|(_id, i)| **i == ptr) {
117 Some((it, _)) => it,
118 None => panic!(
119 "Can't find {:?} in AstIdMap:\n{:?}",
120 item.syntax(),
121 self.arena.iter().map(|(_id, i)| i).collect::<Vec<_>>(),
122 ),
123 };
124
125 FileAstId { raw, _ty: PhantomData }
126 }
127
128 fn from_source(node: &SyntaxNode) -> AstIdMap {
129 assert!(node.parent().is_none());
130 let mut res = AstIdMap { arena: Arena::default() };
131 // By walking the tree in bread-first order we make sure that parents
132 // get lower ids then children. That is, adding a new child does not
133 // change parent's id. This means that, say, adding a new function to a
134 // trait does not change ids of top-level items, which helps caching.
135 bfs(node, |it| {
136 if let Some(module_item) = ast::ModuleItem::cast(it.clone()) {
137 res.alloc(module_item.syntax());
138 } else if let Some(macro_call) = ast::MacroCall::cast(it) {
139 res.alloc(macro_call.syntax());
140 }
141 });
142 res
143 }
144
145 fn alloc(&mut self, item: &SyntaxNode) -> ErasedFileAstId {
146 self.arena.alloc(SyntaxNodePtr::new(item))
147 }
148}
149
150/// Walks the subtree in bfs order, calling `f` for each node.
151fn bfs(node: &SyntaxNode, mut f: impl FnMut(SyntaxNode)) {
152 let mut curr_layer = vec![node.clone()];
153 let mut next_layer = vec![];
154 while !curr_layer.is_empty() {
155 curr_layer.drain(..).for_each(|node| {
156 next_layer.extend(node.children());
157 f(node);
158 });
159 std::mem::swap(&mut curr_layer, &mut next_layer);
160 }
161} 73}