diff options
-rw-r--r-- | crates/ra_hir/src/from_source.rs | 147 | ||||
-rw-r--r-- | crates/ra_hir_def/src/child_from_source.rs | 276 | ||||
-rw-r--r-- | crates/ra_hir_def/src/lib.rs | 1 |
3 files changed, 325 insertions, 99 deletions
diff --git a/crates/ra_hir/src/from_source.rs b/crates/ra_hir/src/from_source.rs index 18d87f6d7..6fa947759 100644 --- a/crates/ra_hir/src/from_source.rs +++ b/crates/ra_hir/src/from_source.rs | |||
@@ -1,17 +1,20 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | use either::Either; | ||
2 | 3 | ||
3 | use hir_def::{nameres::ModuleSource, AstItemDef, LocationCtx, ModuleId}; | 4 | use hir_def::{ |
5 | child_from_source::ChildFromSource, nameres::ModuleSource, AstItemDef, EnumVariantId, ImplId, | ||
6 | LocationCtx, ModuleId, TraitId, VariantId, | ||
7 | }; | ||
4 | use hir_expand::{name::AsName, AstId, MacroDefId, MacroDefKind}; | 8 | use hir_expand::{name::AsName, AstId, MacroDefId, MacroDefKind}; |
5 | use ra_syntax::{ | 9 | use ra_syntax::{ |
6 | ast::{self, AstNode, NameOwner}, | 10 | ast::{self, AstNode, NameOwner}, |
7 | match_ast, AstPtr, SyntaxNode, | 11 | match_ast, SyntaxNode, |
8 | }; | 12 | }; |
9 | 13 | ||
10 | use crate::{ | 14 | use crate::{ |
11 | db::{AstDatabase, DefDatabase, HirDatabase}, | 15 | db::{AstDatabase, DefDatabase, HirDatabase}, |
12 | AssocItem, Const, DefWithBody, Enum, EnumVariant, FieldSource, Function, HasSource, ImplBlock, | 16 | Const, DefWithBody, Enum, EnumVariant, FieldSource, Function, ImplBlock, InFile, Local, |
13 | InFile, Local, MacroDef, Module, ModuleDef, Static, Struct, StructField, Trait, TypeAlias, | 17 | MacroDef, Module, Static, Struct, StructField, Trait, TypeAlias, Union, |
14 | Union, VariantDef, | ||
15 | }; | 18 | }; |
16 | 19 | ||
17 | pub trait FromSource: Sized { | 20 | pub trait FromSource: Sized { |
@@ -50,98 +53,36 @@ impl FromSource for Trait { | |||
50 | impl FromSource for Function { | 53 | impl FromSource for Function { |
51 | type Ast = ast::FnDef; | 54 | type Ast = ast::FnDef; |
52 | fn from_source(db: &(impl DefDatabase + AstDatabase), src: InFile<Self::Ast>) -> Option<Self> { | 55 | fn from_source(db: &(impl DefDatabase + AstDatabase), src: InFile<Self::Ast>) -> Option<Self> { |
53 | let items = match Container::find(db, src.as_ref().map(|it| it.syntax()))? { | 56 | Container::find(db, src.as_ref().map(|it| it.syntax()))? |
54 | Container::Trait(it) => it.items(db), | 57 | .child_from_source(db, src) |
55 | Container::ImplBlock(it) => it.items(db), | 58 | .map(Function::from) |
56 | Container::Module(m) => { | ||
57 | return m | ||
58 | .declarations(db) | ||
59 | .into_iter() | ||
60 | .filter_map(|it| match it { | ||
61 | ModuleDef::Function(it) => Some(it), | ||
62 | _ => None, | ||
63 | }) | ||
64 | .find(|it| same_source(&it.source(db), &src)) | ||
65 | } | ||
66 | }; | ||
67 | items | ||
68 | .into_iter() | ||
69 | .filter_map(|it| match it { | ||
70 | AssocItem::Function(it) => Some(it), | ||
71 | _ => None, | ||
72 | }) | ||
73 | .find(|it| same_source(&it.source(db), &src)) | ||
74 | } | 59 | } |
75 | } | 60 | } |
76 | 61 | ||
77 | impl FromSource for Const { | 62 | impl FromSource for Const { |
78 | type Ast = ast::ConstDef; | 63 | type Ast = ast::ConstDef; |
79 | fn from_source(db: &(impl DefDatabase + AstDatabase), src: InFile<Self::Ast>) -> Option<Self> { | 64 | fn from_source(db: &(impl DefDatabase + AstDatabase), src: InFile<Self::Ast>) -> Option<Self> { |
80 | let items = match Container::find(db, src.as_ref().map(|it| it.syntax()))? { | 65 | Container::find(db, src.as_ref().map(|it| it.syntax()))? |
81 | Container::Trait(it) => it.items(db), | 66 | .child_from_source(db, src) |
82 | Container::ImplBlock(it) => it.items(db), | 67 | .map(Const::from) |
83 | Container::Module(m) => { | ||
84 | return m | ||
85 | .declarations(db) | ||
86 | .into_iter() | ||
87 | .filter_map(|it| match it { | ||
88 | ModuleDef::Const(it) => Some(it), | ||
89 | _ => None, | ||
90 | }) | ||
91 | .find(|it| same_source(&it.source(db), &src)) | ||
92 | } | ||
93 | }; | ||
94 | items | ||
95 | .into_iter() | ||
96 | .filter_map(|it| match it { | ||
97 | AssocItem::Const(it) => Some(it), | ||
98 | _ => None, | ||
99 | }) | ||
100 | .find(|it| same_source(&it.source(db), &src)) | ||
101 | } | 68 | } |
102 | } | 69 | } |
103 | impl FromSource for Static { | 70 | impl FromSource for Static { |
104 | type Ast = ast::StaticDef; | 71 | type Ast = ast::StaticDef; |
105 | fn from_source(db: &(impl DefDatabase + AstDatabase), src: InFile<Self::Ast>) -> Option<Self> { | 72 | fn from_source(db: &(impl DefDatabase + AstDatabase), src: InFile<Self::Ast>) -> Option<Self> { |
106 | let module = match Container::find(db, src.as_ref().map(|it| it.syntax()))? { | 73 | match Container::find(db, src.as_ref().map(|it| it.syntax()))? { |
107 | Container::Module(it) => it, | 74 | Container::Module(it) => it.id.child_from_source(db, src).map(Static::from), |
108 | Container::Trait(_) | Container::ImplBlock(_) => return None, | 75 | Container::Trait(_) | Container::ImplBlock(_) => None, |
109 | }; | 76 | } |
110 | module | ||
111 | .declarations(db) | ||
112 | .into_iter() | ||
113 | .filter_map(|it| match it { | ||
114 | ModuleDef::Static(it) => Some(it), | ||
115 | _ => None, | ||
116 | }) | ||
117 | .find(|it| same_source(&it.source(db), &src)) | ||
118 | } | 77 | } |
119 | } | 78 | } |
120 | 79 | ||
121 | impl FromSource for TypeAlias { | 80 | impl FromSource for TypeAlias { |
122 | type Ast = ast::TypeAliasDef; | 81 | type Ast = ast::TypeAliasDef; |
123 | fn from_source(db: &(impl DefDatabase + AstDatabase), src: InFile<Self::Ast>) -> Option<Self> { | 82 | fn from_source(db: &(impl DefDatabase + AstDatabase), src: InFile<Self::Ast>) -> Option<Self> { |
124 | let items = match Container::find(db, src.as_ref().map(|it| it.syntax()))? { | 83 | Container::find(db, src.as_ref().map(|it| it.syntax()))? |
125 | Container::Trait(it) => it.items(db), | 84 | .child_from_source(db, src) |
126 | Container::ImplBlock(it) => it.items(db), | 85 | .map(TypeAlias::from) |
127 | Container::Module(m) => { | ||
128 | return m | ||
129 | .declarations(db) | ||
130 | .into_iter() | ||
131 | .filter_map(|it| match it { | ||
132 | ModuleDef::TypeAlias(it) => Some(it), | ||
133 | _ => None, | ||
134 | }) | ||
135 | .find(|it| same_source(&it.source(db), &src)) | ||
136 | } | ||
137 | }; | ||
138 | items | ||
139 | .into_iter() | ||
140 | .filter_map(|it| match it { | ||
141 | AssocItem::TypeAlias(it) => Some(it), | ||
142 | _ => None, | ||
143 | }) | ||
144 | .find(|it| same_source(&it.source(db), &src)) | ||
145 | } | 86 | } |
146 | } | 87 | } |
147 | 88 | ||
@@ -174,34 +115,33 @@ impl FromSource for EnumVariant { | |||
174 | fn from_source(db: &(impl DefDatabase + AstDatabase), src: InFile<Self::Ast>) -> Option<Self> { | 115 | fn from_source(db: &(impl DefDatabase + AstDatabase), src: InFile<Self::Ast>) -> Option<Self> { |
175 | let parent_enum = src.value.parent_enum(); | 116 | let parent_enum = src.value.parent_enum(); |
176 | let src_enum = InFile { file_id: src.file_id, value: parent_enum }; | 117 | let src_enum = InFile { file_id: src.file_id, value: parent_enum }; |
177 | let variants = Enum::from_source(db, src_enum)?.variants(db); | 118 | let parent_enum = Enum::from_source(db, src_enum)?; |
178 | variants.into_iter().find(|v| same_source(&v.source(db), &src)) | 119 | parent_enum.id.child_from_source(db, src).map(EnumVariant::from) |
179 | } | 120 | } |
180 | } | 121 | } |
181 | 122 | ||
182 | impl FromSource for StructField { | 123 | impl FromSource for StructField { |
183 | type Ast = FieldSource; | 124 | type Ast = FieldSource; |
184 | fn from_source(db: &(impl DefDatabase + AstDatabase), src: InFile<Self::Ast>) -> Option<Self> { | 125 | fn from_source(db: &(impl DefDatabase + AstDatabase), src: InFile<Self::Ast>) -> Option<Self> { |
185 | let variant_def: VariantDef = match src.value { | 126 | let variant_id: VariantId = match src.value { |
186 | FieldSource::Named(ref field) => { | 127 | FieldSource::Named(ref field) => { |
187 | let value = field.syntax().ancestors().find_map(ast::StructDef::cast)?; | 128 | let value = field.syntax().ancestors().find_map(ast::StructDef::cast)?; |
188 | let src = InFile { file_id: src.file_id, value }; | 129 | let src = InFile { file_id: src.file_id, value }; |
189 | let def = Struct::from_source(db, src)?; | 130 | let def = Struct::from_source(db, src)?; |
190 | VariantDef::from(def) | 131 | def.id.into() |
191 | } | 132 | } |
192 | FieldSource::Pos(ref field) => { | 133 | FieldSource::Pos(ref field) => { |
193 | let value = field.syntax().ancestors().find_map(ast::EnumVariant::cast)?; | 134 | let value = field.syntax().ancestors().find_map(ast::EnumVariant::cast)?; |
194 | let src = InFile { file_id: src.file_id, value }; | 135 | let src = InFile { file_id: src.file_id, value }; |
195 | let def = EnumVariant::from_source(db, src)?; | 136 | let def = EnumVariant::from_source(db, src)?; |
196 | VariantDef::from(def) | 137 | EnumVariantId::from(def).into() |
197 | } | 138 | } |
198 | }; | 139 | }; |
199 | variant_def | 140 | let src = src.map(|field_source| match field_source { |
200 | .variant_data(db) | 141 | FieldSource::Pos(it) => Either::Left(it), |
201 | .fields() | 142 | FieldSource::Named(it) => Either::Right(it), |
202 | .iter() | 143 | }); |
203 | .map(|(id, _)| StructField { parent: variant_def, id }) | 144 | variant_id.child_from_source(db, src).map(StructField::from) |
204 | .find(|f| f.source(db) == src) | ||
205 | } | 145 | } |
206 | } | 146 | } |
207 | 147 | ||
@@ -315,12 +255,21 @@ impl Container { | |||
315 | } | 255 | } |
316 | } | 256 | } |
317 | 257 | ||
318 | /// XXX: AST Nodes and SyntaxNodes have identity equality semantics: nodes are | 258 | impl<CHILD, SOURCE> ChildFromSource<CHILD, SOURCE> for Container |
319 | /// equal if they point to exactly the same object. | 259 | where |
320 | /// | 260 | TraitId: ChildFromSource<CHILD, SOURCE>, |
321 | /// In general, we do not guarantee that we have exactly one instance of a | 261 | ImplId: ChildFromSource<CHILD, SOURCE>, |
322 | /// syntax tree for each file. We probably should add such guarantee, but, for | 262 | ModuleId: ChildFromSource<CHILD, SOURCE>, |
323 | /// the time being, we will use identity-less AstPtr comparison. | 263 | { |
324 | fn same_source<N: AstNode>(s1: &InFile<N>, s2: &InFile<N>) -> bool { | 264 | fn child_from_source( |
325 | s1.as_ref().map(AstPtr::new) == s2.as_ref().map(AstPtr::new) | 265 | &self, |
266 | db: &impl DefDatabase, | ||
267 | child_source: InFile<SOURCE>, | ||
268 | ) -> Option<CHILD> { | ||
269 | match self { | ||
270 | Container::Trait(it) => it.id.child_from_source(db, child_source), | ||
271 | Container::ImplBlock(it) => it.id.child_from_source(db, child_source), | ||
272 | Container::Module(it) => it.id.child_from_source(db, child_source), | ||
273 | } | ||
274 | } | ||
326 | } | 275 | } |
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 | |||
7 | use either::Either; | ||
8 | use hir_expand::InFile; | ||
9 | use ra_syntax::{ast, AstNode, AstPtr}; | ||
10 | |||
11 | use 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 | |||
18 | pub 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 | |||
26 | impl 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 | |||
46 | impl 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 | |||
66 | impl 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 | |||
88 | impl 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 | |||
108 | impl 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 | |||
128 | impl 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 | |||
150 | impl 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 | |||
170 | impl 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 | |||
190 | impl 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 | |||
212 | impl 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 | |||
234 | impl 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 | |||
253 | impl 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. | ||
274 | fn 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; | |||
30 | pub mod nameres; | 30 | pub mod nameres; |
31 | 31 | ||
32 | pub mod src; | 32 | pub mod src; |
33 | pub mod child_from_source; | ||
33 | 34 | ||
34 | #[cfg(test)] | 35 | #[cfg(test)] |
35 | mod test_db; | 36 | mod test_db; |