aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_def
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2019-12-05 14:16:59 +0000
committerAleksey Kladov <[email protected]>2019-12-05 15:55:54 +0000
commit0c0ce1ae418a2f3f4fc125bd701cdb327f607002 (patch)
tree596e533284a136297c8443094434c9738d24c435 /crates/ra_hir_def
parent4c0bd068da39e74c66104206e27c270454e3562e (diff)
Introduce ChildFromSource
Diffstat (limited to 'crates/ra_hir_def')
-rw-r--r--crates/ra_hir_def/src/child_from_source.rs276
-rw-r--r--crates/ra_hir_def/src/lib.rs1
2 files changed, 277 insertions, 0 deletions
diff --git a/crates/ra_hir_def/src/child_from_source.rs b/crates/ra_hir_def/src/child_from_source.rs
new file mode 100644
index 000000000..37d4b7870
--- /dev/null
+++ b/crates/ra_hir_def/src/child_from_source.rs
@@ -0,0 +1,276 @@
1//! When *constructing* `hir`, we start at some parent syntax node and recursively
2//! lower the children.
3//!
4//! This modules allows one to go in the opposite direction: start with a syntax
5//! node for a *child*, and get its hir.
6
7use either::Either;
8use hir_expand::InFile;
9use ra_syntax::{ast, AstNode, AstPtr};
10
11use crate::{
12 db::DefDatabase,
13 src::{HasChildSource, HasSource},
14 AssocItemId, ConstId, EnumId, EnumVariantId, FunctionId, ImplId, Lookup, ModuleDefId, ModuleId,
15 StaticId, StructFieldId, TraitId, TypeAliasId, VariantId,
16};
17
18pub trait ChildFromSource<CHILD, SOURCE> {
19 fn child_from_source(
20 &self,
21 db: &impl DefDatabase,
22 child_source: InFile<SOURCE>,
23 ) -> Option<CHILD>;
24}
25
26impl ChildFromSource<FunctionId, ast::FnDef> for TraitId {
27 fn child_from_source(
28 &self,
29 db: &impl DefDatabase,
30 child_source: InFile<ast::FnDef>,
31 ) -> Option<FunctionId> {
32 let data = db.trait_data(*self);
33 data.items
34 .iter()
35 .filter_map(|(_, item)| match item {
36 AssocItemId::FunctionId(it) => Some(*it),
37 _ => None,
38 })
39 .find(|func| {
40 let source = func.lookup(db).source(db);
41 same_source(&source, &child_source)
42 })
43 }
44}
45
46impl ChildFromSource<FunctionId, ast::FnDef> for ImplId {
47 fn child_from_source(
48 &self,
49 db: &impl DefDatabase,
50 child_source: InFile<ast::FnDef>,
51 ) -> Option<FunctionId> {
52 let data = db.impl_data(*self);
53 data.items
54 .iter()
55 .filter_map(|item| match item {
56 AssocItemId::FunctionId(it) => Some(*it),
57 _ => None,
58 })
59 .find(|func| {
60 let source = func.lookup(db).source(db);
61 same_source(&source, &child_source)
62 })
63 }
64}
65
66impl ChildFromSource<FunctionId, ast::FnDef> for ModuleId {
67 fn child_from_source(
68 &self,
69 db: &impl DefDatabase,
70 child_source: InFile<ast::FnDef>,
71 ) -> Option<FunctionId> {
72 let crate_def_map = db.crate_def_map(self.krate);
73 let res = crate_def_map[self.local_id]
74 .scope
75 .declarations()
76 .filter_map(|item| match item {
77 ModuleDefId::FunctionId(it) => Some(it),
78 _ => None,
79 })
80 .find(|func| {
81 let source = func.lookup(db).source(db);
82 same_source(&source, &child_source)
83 });
84 res
85 }
86}
87
88impl ChildFromSource<ConstId, ast::ConstDef> for TraitId {
89 fn child_from_source(
90 &self,
91 db: &impl DefDatabase,
92 child_source: InFile<ast::ConstDef>,
93 ) -> Option<ConstId> {
94 let data = db.trait_data(*self);
95 data.items
96 .iter()
97 .filter_map(|(_, item)| match item {
98 AssocItemId::ConstId(it) => Some(*it),
99 _ => None,
100 })
101 .find(|func| {
102 let source = func.lookup(db).source(db);
103 same_source(&source, &child_source)
104 })
105 }
106}
107
108impl ChildFromSource<ConstId, ast::ConstDef> for ImplId {
109 fn child_from_source(
110 &self,
111 db: &impl DefDatabase,
112 child_source: InFile<ast::ConstDef>,
113 ) -> Option<ConstId> {
114 let data = db.impl_data(*self);
115 data.items
116 .iter()
117 .filter_map(|item| match item {
118 AssocItemId::ConstId(it) => Some(*it),
119 _ => None,
120 })
121 .find(|func| {
122 let source = func.lookup(db).source(db);
123 same_source(&source, &child_source)
124 })
125 }
126}
127
128impl ChildFromSource<ConstId, ast::ConstDef> for ModuleId {
129 fn child_from_source(
130 &self,
131 db: &impl DefDatabase,
132 child_source: InFile<ast::ConstDef>,
133 ) -> Option<ConstId> {
134 let crate_def_map = db.crate_def_map(self.krate);
135 let res = crate_def_map[self.local_id]
136 .scope
137 .declarations()
138 .filter_map(|item| match item {
139 ModuleDefId::ConstId(it) => Some(it),
140 _ => None,
141 })
142 .find(|func| {
143 let source = func.lookup(db).source(db);
144 same_source(&source, &child_source)
145 });
146 res
147 }
148}
149
150impl ChildFromSource<TypeAliasId, ast::TypeAliasDef> for TraitId {
151 fn child_from_source(
152 &self,
153 db: &impl DefDatabase,
154 child_source: InFile<ast::TypeAliasDef>,
155 ) -> Option<TypeAliasId> {
156 let data = db.trait_data(*self);
157 data.items
158 .iter()
159 .filter_map(|(_, item)| match item {
160 AssocItemId::TypeAliasId(it) => Some(*it),
161 _ => None,
162 })
163 .find(|func| {
164 let source = func.lookup(db).source(db);
165 same_source(&source, &child_source)
166 })
167 }
168}
169
170impl ChildFromSource<TypeAliasId, ast::TypeAliasDef> for ImplId {
171 fn child_from_source(
172 &self,
173 db: &impl DefDatabase,
174 child_source: InFile<ast::TypeAliasDef>,
175 ) -> Option<TypeAliasId> {
176 let data = db.impl_data(*self);
177 data.items
178 .iter()
179 .filter_map(|item| match item {
180 AssocItemId::TypeAliasId(it) => Some(*it),
181 _ => None,
182 })
183 .find(|func| {
184 let source = func.lookup(db).source(db);
185 same_source(&source, &child_source)
186 })
187 }
188}
189
190impl ChildFromSource<TypeAliasId, ast::TypeAliasDef> for ModuleId {
191 fn child_from_source(
192 &self,
193 db: &impl DefDatabase,
194 child_source: InFile<ast::TypeAliasDef>,
195 ) -> Option<TypeAliasId> {
196 let crate_def_map = db.crate_def_map(self.krate);
197 let res = crate_def_map[self.local_id]
198 .scope
199 .declarations()
200 .filter_map(|item| match item {
201 ModuleDefId::TypeAliasId(it) => Some(it),
202 _ => None,
203 })
204 .find(|func| {
205 let source = func.lookup(db).source(db);
206 same_source(&source, &child_source)
207 });
208 res
209 }
210}
211
212impl ChildFromSource<StaticId, ast::StaticDef> for ModuleId {
213 fn child_from_source(
214 &self,
215 db: &impl DefDatabase,
216 child_source: InFile<ast::StaticDef>,
217 ) -> Option<StaticId> {
218 let crate_def_map = db.crate_def_map(self.krate);
219 let res = crate_def_map[self.local_id]
220 .scope
221 .declarations()
222 .filter_map(|item| match item {
223 ModuleDefId::StaticId(it) => Some(it),
224 _ => None,
225 })
226 .find(|func| {
227 let source = func.lookup(db).source(db);
228 same_source(&source, &child_source)
229 });
230 res
231 }
232}
233
234impl ChildFromSource<StructFieldId, Either<ast::TupleFieldDef, ast::RecordFieldDef>> for VariantId {
235 fn child_from_source(
236 &self,
237 db: &impl DefDatabase,
238 child_source: InFile<Either<ast::TupleFieldDef, ast::RecordFieldDef>>,
239 ) -> Option<StructFieldId> {
240 let arena_map = self.child_source(db);
241 let (local_id, _) = arena_map.as_ref().value.iter().find(|(_local_id, source)| {
242 child_source.file_id == arena_map.file_id
243 && match (source, &child_source.value) {
244 (Either::Left(a), Either::Left(b)) => AstPtr::new(a) == AstPtr::new(b),
245 (Either::Right(a), Either::Right(b)) => AstPtr::new(a) == AstPtr::new(b),
246 _ => false,
247 }
248 })?;
249 Some(StructFieldId { parent: *self, local_id })
250 }
251}
252
253impl ChildFromSource<EnumVariantId, ast::EnumVariant> for EnumId {
254 fn child_from_source(
255 &self,
256 db: &impl DefDatabase,
257 child_source: InFile<ast::EnumVariant>,
258 ) -> Option<EnumVariantId> {
259 let arena_map = self.child_source(db);
260 let (local_id, _) = arena_map.as_ref().value.iter().find(|(_local_id, source)| {
261 child_source.file_id == arena_map.file_id
262 && AstPtr::new(*source) == AstPtr::new(&child_source.value)
263 })?;
264 Some(EnumVariantId { parent: *self, local_id })
265 }
266}
267
268/// XXX: AST Nodes and SyntaxNodes have identity equality semantics: nodes are
269/// equal if they point to exactly the same object.
270///
271/// In general, we do not guarantee that we have exactly one instance of a
272/// syntax tree for each file. We probably should add such guarantee, but, for
273/// the time being, we will use identity-less AstPtr comparison.
274fn same_source<N: AstNode>(s1: &InFile<N>, s2: &InFile<N>) -> bool {
275 s1.as_ref().map(AstPtr::new) == s2.as_ref().map(AstPtr::new)
276}
diff --git a/crates/ra_hir_def/src/lib.rs b/crates/ra_hir_def/src/lib.rs
index cfeacfded..e02622f62 100644
--- a/crates/ra_hir_def/src/lib.rs
+++ b/crates/ra_hir_def/src/lib.rs
@@ -30,6 +30,7 @@ mod trace;
30pub mod nameres; 30pub mod nameres;
31 31
32pub mod src; 32pub mod src;
33pub mod child_from_source;
33 34
34#[cfg(test)] 35#[cfg(test)]
35mod test_db; 36mod test_db;