diff options
Diffstat (limited to 'crates/ra_hir/src/from_source.rs')
-rw-r--r-- | crates/ra_hir/src/from_source.rs | 362 |
1 files changed, 150 insertions, 212 deletions
diff --git a/crates/ra_hir/src/from_source.rs b/crates/ra_hir/src/from_source.rs index 9f7c22b21..6314be8d4 100644 --- a/crates/ra_hir/src/from_source.rs +++ b/crates/ra_hir/src/from_source.rs | |||
@@ -1,219 +1,140 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! Finds a corresponding hir data structure for a syntax node in a specific |
2 | //! file. | ||
2 | 3 | ||
3 | use hir_def::{AstItemDef, LocationCtx, ModuleId}; | 4 | use hir_def::{ |
5 | child_by_source::ChildBySource, dyn_map::DynMap, keys, keys::Key, nameres::ModuleSource, | ||
6 | ConstId, DefWithBodyId, EnumId, EnumVariantId, FunctionId, GenericDefId, ImplId, ModuleId, | ||
7 | StaticId, StructId, TraitId, TypeAliasId, UnionId, VariantId, | ||
8 | }; | ||
4 | use hir_expand::{name::AsName, AstId, MacroDefId, MacroDefKind}; | 9 | use hir_expand::{name::AsName, AstId, MacroDefId, MacroDefKind}; |
10 | use ra_db::FileId; | ||
11 | use ra_prof::profile; | ||
5 | use ra_syntax::{ | 12 | use ra_syntax::{ |
6 | ast::{self, AstNode, NameOwner}, | 13 | ast::{self, AstNode, NameOwner}, |
7 | match_ast, AstPtr, SyntaxNode, | 14 | match_ast, SyntaxNode, |
8 | }; | 15 | }; |
9 | 16 | ||
10 | use crate::{ | 17 | use crate::{ |
11 | db::{AstDatabase, DefDatabase, HirDatabase}, | 18 | db::{DefDatabase, HirDatabase}, |
12 | AssocItem, Const, DefWithBody, Enum, EnumVariant, FieldSource, Function, HasSource, ImplBlock, | 19 | Const, DefWithBody, Enum, EnumVariant, FieldSource, Function, ImplBlock, InFile, Local, |
13 | Local, MacroDef, Module, ModuleDef, ModuleSource, Source, Static, Struct, StructField, Trait, | 20 | MacroDef, Module, Static, Struct, StructField, Trait, TypeAlias, TypeParam, Union, |
14 | TypeAlias, Union, VariantDef, | ||
15 | }; | 21 | }; |
16 | 22 | ||
17 | pub trait FromSource: Sized { | 23 | pub trait FromSource: Sized { |
18 | type Ast; | 24 | type Ast; |
19 | fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self>; | 25 | fn from_source(db: &impl DefDatabase, src: InFile<Self::Ast>) -> Option<Self>; |
20 | } | 26 | } |
21 | 27 | ||
22 | impl FromSource for Struct { | 28 | pub trait FromSourceByContainer: Sized { |
23 | type Ast = ast::StructDef; | 29 | type Ast: AstNode + 'static; |
24 | fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self> { | 30 | type Id: Copy + 'static; |
25 | let id = from_source(db, src)?; | 31 | const KEY: Key<Self::Ast, Self::Id>; |
26 | Some(Struct { id }) | ||
27 | } | ||
28 | } | ||
29 | impl FromSource for Union { | ||
30 | type Ast = ast::UnionDef; | ||
31 | fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self> { | ||
32 | let id = from_source(db, src)?; | ||
33 | Some(Union { id }) | ||
34 | } | ||
35 | } | ||
36 | impl FromSource for Enum { | ||
37 | type Ast = ast::EnumDef; | ||
38 | fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self> { | ||
39 | let id = from_source(db, src)?; | ||
40 | Some(Enum { id }) | ||
41 | } | ||
42 | } | ||
43 | impl FromSource for Trait { | ||
44 | type Ast = ast::TraitDef; | ||
45 | fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self> { | ||
46 | let id = from_source(db, src)?; | ||
47 | Some(Trait { id }) | ||
48 | } | ||
49 | } | ||
50 | impl FromSource for Function { | ||
51 | type Ast = ast::FnDef; | ||
52 | fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self> { | ||
53 | let items = match Container::find(db, src.as_ref().map(|it| it.syntax()))? { | ||
54 | Container::Trait(it) => it.items(db), | ||
55 | Container::ImplBlock(it) => it.items(db), | ||
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 | } | ||
75 | } | 32 | } |
76 | 33 | ||
77 | impl FromSource for Const { | 34 | impl<T: FromSourceByContainer> FromSource for T |
78 | type Ast = ast::ConstDef; | 35 | where |
79 | fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self> { | 36 | T: From<<T as FromSourceByContainer>::Id>, |
80 | let items = match Container::find(db, src.as_ref().map(|it| it.syntax()))? { | 37 | { |
81 | Container::Trait(it) => it.items(db), | 38 | type Ast = <T as FromSourceByContainer>::Ast; |
82 | Container::ImplBlock(it) => it.items(db), | 39 | fn from_source(db: &impl DefDatabase, src: InFile<Self::Ast>) -> Option<Self> { |
83 | Container::Module(m) => { | 40 | analyze_container(db, src.as_ref().map(|it| it.syntax()))[T::KEY] |
84 | return m | 41 | .get(&src) |
85 | .declarations(db) | 42 | .copied() |
86 | .into_iter() | 43 | .map(Self::from) |
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 | } | ||
102 | } | ||
103 | impl FromSource for Static { | ||
104 | type Ast = ast::StaticDef; | ||
105 | fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self> { | ||
106 | let module = match Container::find(db, src.as_ref().map(|it| it.syntax()))? { | ||
107 | Container::Module(it) => it, | ||
108 | Container::Trait(_) | Container::ImplBlock(_) => return None, | ||
109 | }; | ||
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 | } | 44 | } |
119 | } | 45 | } |
120 | 46 | ||
121 | impl FromSource for TypeAlias { | 47 | macro_rules! from_source_by_container_impls { |
122 | type Ast = ast::TypeAliasDef; | 48 | ($(($hir:ident, $id:ident, $ast:path, $key:path)),* ,) => {$( |
123 | fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self> { | 49 | impl FromSourceByContainer for $hir { |
124 | let items = match Container::find(db, src.as_ref().map(|it| it.syntax()))? { | 50 | type Ast = $ast; |
125 | Container::Trait(it) => it.items(db), | 51 | type Id = $id; |
126 | Container::ImplBlock(it) => it.items(db), | 52 | const KEY: Key<Self::Ast, Self::Id> = $key; |
127 | Container::Module(m) => { | 53 | } |
128 | return m | 54 | )*} |
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 | } | ||
146 | } | 55 | } |
147 | 56 | ||
57 | from_source_by_container_impls![ | ||
58 | (Struct, StructId, ast::StructDef, keys::STRUCT), | ||
59 | (Union, UnionId, ast::UnionDef, keys::UNION), | ||
60 | (Enum, EnumId, ast::EnumDef, keys::ENUM), | ||
61 | (Trait, TraitId, ast::TraitDef, keys::TRAIT), | ||
62 | (Function, FunctionId, ast::FnDef, keys::FUNCTION), | ||
63 | (Static, StaticId, ast::StaticDef, keys::STATIC), | ||
64 | (Const, ConstId, ast::ConstDef, keys::CONST), | ||
65 | (TypeAlias, TypeAliasId, ast::TypeAliasDef, keys::TYPE_ALIAS), | ||
66 | (ImplBlock, ImplId, ast::ImplBlock, keys::IMPL), | ||
67 | ]; | ||
68 | |||
148 | impl FromSource for MacroDef { | 69 | impl FromSource for MacroDef { |
149 | type Ast = ast::MacroCall; | 70 | type Ast = ast::MacroCall; |
150 | fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self> { | 71 | fn from_source(db: &impl DefDatabase, src: InFile<Self::Ast>) -> Option<Self> { |
151 | let kind = MacroDefKind::Declarative; | 72 | let kind = MacroDefKind::Declarative; |
152 | 73 | ||
153 | let module_src = ModuleSource::from_child_node(db, src.as_ref().map(|it| it.syntax())); | 74 | let module_src = ModuleSource::from_child_node(db, src.as_ref().map(|it| it.syntax())); |
154 | let module = Module::from_definition(db, Source::new(src.file_id, module_src))?; | 75 | let module = Module::from_definition(db, InFile::new(src.file_id, module_src))?; |
155 | let krate = module.krate().crate_id(); | 76 | let krate = Some(module.krate().id); |
156 | 77 | ||
157 | let ast_id = AstId::new(src.file_id, db.ast_id_map(src.file_id).ast_id(&src.value)); | 78 | let ast_id = Some(AstId::new(src.file_id, db.ast_id_map(src.file_id).ast_id(&src.value))); |
158 | 79 | ||
159 | let id: MacroDefId = MacroDefId { krate, ast_id, kind }; | 80 | let id: MacroDefId = MacroDefId { krate, ast_id, kind }; |
160 | Some(MacroDef { id }) | 81 | Some(MacroDef { id }) |
161 | } | 82 | } |
162 | } | 83 | } |
163 | 84 | ||
164 | impl FromSource for ImplBlock { | ||
165 | type Ast = ast::ImplBlock; | ||
166 | fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self> { | ||
167 | let id = from_source(db, src)?; | ||
168 | Some(ImplBlock { id }) | ||
169 | } | ||
170 | } | ||
171 | |||
172 | impl FromSource for EnumVariant { | 85 | impl FromSource for EnumVariant { |
173 | type Ast = ast::EnumVariant; | 86 | type Ast = ast::EnumVariant; |
174 | fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self> { | 87 | fn from_source(db: &impl DefDatabase, src: InFile<Self::Ast>) -> Option<Self> { |
175 | let parent_enum = src.value.parent_enum(); | 88 | let parent_enum = src.value.parent_enum(); |
176 | let src_enum = Source { file_id: src.file_id, value: parent_enum }; | 89 | let src_enum = InFile { file_id: src.file_id, value: parent_enum }; |
177 | let variants = Enum::from_source(db, src_enum)?.variants(db); | 90 | let parent_enum = Enum::from_source(db, src_enum)?; |
178 | variants.into_iter().find(|v| same_source(&v.source(db), &src)) | 91 | parent_enum.id.child_by_source(db)[keys::ENUM_VARIANT] |
92 | .get(&src) | ||
93 | .copied() | ||
94 | .map(EnumVariant::from) | ||
179 | } | 95 | } |
180 | } | 96 | } |
181 | 97 | ||
182 | impl FromSource for StructField { | 98 | impl FromSource for StructField { |
183 | type Ast = FieldSource; | 99 | type Ast = FieldSource; |
184 | fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self> { | 100 | fn from_source(db: &impl DefDatabase, src: InFile<Self::Ast>) -> Option<Self> { |
185 | let variant_def: VariantDef = match src.value { | 101 | let src = src.as_ref(); |
186 | FieldSource::Named(ref field) => { | 102 | |
103 | // FIXME this is buggy | ||
104 | let variant_id: VariantId = match src.value { | ||
105 | FieldSource::Named(field) => { | ||
187 | let value = field.syntax().ancestors().find_map(ast::StructDef::cast)?; | 106 | let value = field.syntax().ancestors().find_map(ast::StructDef::cast)?; |
188 | let src = Source { file_id: src.file_id, value }; | 107 | let src = InFile { file_id: src.file_id, value }; |
189 | let def = Struct::from_source(db, src)?; | 108 | let def = Struct::from_source(db, src)?; |
190 | VariantDef::from(def) | 109 | def.id.into() |
191 | } | 110 | } |
192 | FieldSource::Pos(ref field) => { | 111 | FieldSource::Pos(field) => { |
193 | let value = field.syntax().ancestors().find_map(ast::EnumVariant::cast)?; | 112 | let value = field.syntax().ancestors().find_map(ast::EnumVariant::cast)?; |
194 | let src = Source { file_id: src.file_id, value }; | 113 | let src = InFile { file_id: src.file_id, value }; |
195 | let def = EnumVariant::from_source(db, src)?; | 114 | let def = EnumVariant::from_source(db, src)?; |
196 | VariantDef::from(def) | 115 | EnumVariantId::from(def).into() |
197 | } | 116 | } |
198 | }; | 117 | }; |
199 | variant_def | 118 | |
200 | .variant_data(db) | 119 | let dyn_map = variant_id.child_by_source(db); |
201 | .fields() | 120 | match src.value { |
202 | .iter() | 121 | FieldSource::Pos(it) => dyn_map[keys::TUPLE_FIELD].get(&src.with_value(it.clone())), |
203 | .map(|(id, _)| StructField { parent: variant_def, id }) | 122 | FieldSource::Named(it) => dyn_map[keys::RECORD_FIELD].get(&src.with_value(it.clone())), |
204 | .find(|f| f.source(db) == src) | 123 | } |
124 | .copied() | ||
125 | .map(StructField::from) | ||
205 | } | 126 | } |
206 | } | 127 | } |
207 | 128 | ||
208 | impl Local { | 129 | impl Local { |
209 | pub fn from_source(db: &impl HirDatabase, src: Source<ast::BindPat>) -> Option<Self> { | 130 | pub fn from_source(db: &impl HirDatabase, src: InFile<ast::BindPat>) -> Option<Self> { |
210 | let file_id = src.file_id; | 131 | let file_id = src.file_id; |
211 | let parent: DefWithBody = src.value.syntax().ancestors().find_map(|it| { | 132 | let parent: DefWithBody = src.value.syntax().ancestors().find_map(|it| { |
212 | let res = match_ast! { | 133 | let res = match_ast! { |
213 | match it { | 134 | match it { |
214 | ast::ConstDef(value) => { Const::from_source(db, Source { value, file_id})?.into() }, | 135 | ast::ConstDef(value) => { Const::from_source(db, InFile { value, file_id})?.into() }, |
215 | ast::StaticDef(value) => { Static::from_source(db, Source { value, file_id})?.into() }, | 136 | ast::StaticDef(value) => { Static::from_source(db, InFile { value, file_id})?.into() }, |
216 | ast::FnDef(value) => { Function::from_source(db, Source { value, file_id})?.into() }, | 137 | ast::FnDef(value) => { Function::from_source(db, InFile { value, file_id})?.into() }, |
217 | _ => return None, | 138 | _ => return None, |
218 | } | 139 | } |
219 | }; | 140 | }; |
@@ -226,84 +147,111 @@ impl Local { | |||
226 | } | 147 | } |
227 | } | 148 | } |
228 | 149 | ||
150 | impl TypeParam { | ||
151 | pub fn from_source(db: &impl HirDatabase, src: InFile<ast::TypeParam>) -> Option<Self> { | ||
152 | let file_id = src.file_id; | ||
153 | let parent: GenericDefId = src.value.syntax().ancestors().find_map(|it| { | ||
154 | let res = match_ast! { | ||
155 | match it { | ||
156 | ast::FnDef(value) => { Function::from_source(db, InFile { value, file_id})?.id.into() }, | ||
157 | ast::StructDef(value) => { Struct::from_source(db, InFile { value, file_id})?.id.into() }, | ||
158 | ast::EnumDef(value) => { Enum::from_source(db, InFile { value, file_id})?.id.into() }, | ||
159 | ast::TraitDef(value) => { Trait::from_source(db, InFile { value, file_id})?.id.into() }, | ||
160 | ast::TypeAliasDef(value) => { TypeAlias::from_source(db, InFile { value, file_id})?.id.into() }, | ||
161 | ast::ImplBlock(value) => { ImplBlock::from_source(db, InFile { value, file_id})?.id.into() }, | ||
162 | _ => return None, | ||
163 | } | ||
164 | }; | ||
165 | Some(res) | ||
166 | })?; | ||
167 | let &id = parent.child_by_source(db)[keys::TYPE_PARAM].get(&src)?; | ||
168 | Some(TypeParam { id }) | ||
169 | } | ||
170 | } | ||
171 | |||
229 | impl Module { | 172 | impl Module { |
230 | pub fn from_declaration(db: &impl DefDatabase, src: Source<ast::Module>) -> Option<Self> { | 173 | pub fn from_declaration(db: &impl DefDatabase, src: InFile<ast::Module>) -> Option<Self> { |
174 | let _p = profile("Module::from_declaration"); | ||
231 | let parent_declaration = src.value.syntax().ancestors().skip(1).find_map(ast::Module::cast); | 175 | let parent_declaration = src.value.syntax().ancestors().skip(1).find_map(ast::Module::cast); |
232 | 176 | ||
233 | let parent_module = match parent_declaration { | 177 | let parent_module = match parent_declaration { |
234 | Some(parent_declaration) => { | 178 | Some(parent_declaration) => { |
235 | let src_parent = Source { file_id: src.file_id, value: parent_declaration }; | 179 | let src_parent = InFile { file_id: src.file_id, value: parent_declaration }; |
236 | Module::from_declaration(db, src_parent) | 180 | Module::from_declaration(db, src_parent) |
237 | } | 181 | } |
238 | _ => { | 182 | None => { |
239 | let src_parent = Source { | 183 | let source_file = db.parse(src.file_id.original_file(db)).tree(); |
240 | file_id: src.file_id, | 184 | let src_parent = |
241 | value: ModuleSource::new(db, Some(src.file_id.original_file(db)), None), | 185 | InFile { file_id: src.file_id, value: ModuleSource::SourceFile(source_file) }; |
242 | }; | ||
243 | Module::from_definition(db, src_parent) | 186 | Module::from_definition(db, src_parent) |
244 | } | 187 | } |
245 | }?; | 188 | }?; |
246 | 189 | ||
247 | let child_name = src.value.name()?; | 190 | let child_name = src.value.name()?.as_name(); |
248 | parent_module.child(db, &child_name.as_name()) | 191 | let def_map = db.crate_def_map(parent_module.id.krate); |
192 | let child_id = def_map[parent_module.id.local_id].children.get(&child_name)?; | ||
193 | Some(parent_module.with_module_id(*child_id)) | ||
249 | } | 194 | } |
250 | 195 | ||
251 | pub fn from_definition(db: &impl DefDatabase, src: Source<ModuleSource>) -> Option<Self> { | 196 | pub fn from_definition(db: &impl DefDatabase, src: InFile<ModuleSource>) -> Option<Self> { |
197 | let _p = profile("Module::from_definition"); | ||
252 | match src.value { | 198 | match src.value { |
253 | ModuleSource::Module(ref module) => { | 199 | ModuleSource::Module(ref module) => { |
254 | assert!(!module.has_semi()); | 200 | assert!(!module.has_semi()); |
255 | return Module::from_declaration( | 201 | return Module::from_declaration( |
256 | db, | 202 | db, |
257 | Source { file_id: src.file_id, value: module.clone() }, | 203 | InFile { file_id: src.file_id, value: module.clone() }, |
258 | ); | 204 | ); |
259 | } | 205 | } |
260 | ModuleSource::SourceFile(_) => (), | 206 | ModuleSource::SourceFile(_) => (), |
261 | }; | 207 | }; |
262 | 208 | ||
263 | let original_file = src.file_id.original_file(db); | 209 | let original_file = src.file_id.original_file(db); |
210 | Module::from_file(db, original_file) | ||
211 | } | ||
264 | 212 | ||
265 | let (krate, local_id) = db.relevant_crates(original_file).iter().find_map(|&crate_id| { | 213 | fn from_file(db: &impl DefDatabase, file: FileId) -> Option<Self> { |
214 | let _p = profile("Module::from_file"); | ||
215 | let (krate, local_id) = db.relevant_crates(file).iter().find_map(|&crate_id| { | ||
266 | let crate_def_map = db.crate_def_map(crate_id); | 216 | let crate_def_map = db.crate_def_map(crate_id); |
267 | let local_id = crate_def_map.modules_for_file(original_file).next()?; | 217 | let local_id = crate_def_map.modules_for_file(file).next()?; |
268 | Some((crate_id, local_id)) | 218 | Some((crate_id, local_id)) |
269 | })?; | 219 | })?; |
270 | Some(Module { id: ModuleId { krate, local_id } }) | 220 | Some(Module { id: ModuleId { krate, local_id } }) |
271 | } | 221 | } |
272 | } | 222 | } |
273 | 223 | ||
274 | fn from_source<N, DEF>(db: &(impl DefDatabase + AstDatabase), src: Source<N>) -> Option<DEF> | 224 | fn analyze_container(db: &impl DefDatabase, src: InFile<&SyntaxNode>) -> DynMap { |
275 | where | 225 | let _p = profile("analyze_container"); |
276 | N: AstNode, | 226 | return child_by_source(db, src).unwrap_or_default(); |
277 | DEF: AstItemDef<N>, | ||
278 | { | ||
279 | let module_src = ModuleSource::from_child_node(db, src.as_ref().map(|it| it.syntax())); | ||
280 | let module = Module::from_definition(db, Source::new(src.file_id, module_src))?; | ||
281 | let ctx = LocationCtx::new(db, module.id, src.file_id); | ||
282 | let items = db.ast_id_map(src.file_id); | ||
283 | let item_id = items.ast_id(&src.value); | ||
284 | Some(DEF::from_ast_id(ctx, item_id)) | ||
285 | } | ||
286 | |||
287 | enum Container { | ||
288 | Trait(Trait), | ||
289 | ImplBlock(ImplBlock), | ||
290 | Module(Module), | ||
291 | } | ||
292 | 227 | ||
293 | impl Container { | 228 | fn child_by_source(db: &impl DefDatabase, src: InFile<&SyntaxNode>) -> Option<DynMap> { |
294 | fn find(db: &impl DefDatabase, src: Source<&SyntaxNode>) -> Option<Container> { | 229 | for container in src.value.ancestors().skip(1) { |
295 | // FIXME: this doesn't try to handle nested declarations | ||
296 | for container in src.value.ancestors() { | ||
297 | let res = match_ast! { | 230 | let res = match_ast! { |
298 | match container { | 231 | match container { |
299 | ast::TraitDef(it) => { | 232 | ast::TraitDef(it) => { |
300 | let c = Trait::from_source(db, src.with_value(it))?; | 233 | let def = Trait::from_source(db, src.with_value(it))?; |
301 | Container::Trait(c) | 234 | def.id.child_by_source(db) |
302 | }, | 235 | }, |
303 | ast::ImplBlock(it) => { | 236 | ast::ImplBlock(it) => { |
304 | let c = ImplBlock::from_source(db, src.with_value(it))?; | 237 | let def = ImplBlock::from_source(db, src.with_value(it))?; |
305 | Container::ImplBlock(c) | 238 | def.id.child_by_source(db) |
306 | }, | 239 | }, |
240 | ast::FnDef(it) => { | ||
241 | let def = Function::from_source(db, src.with_value(it))?; | ||
242 | DefWithBodyId::from(def.id) | ||
243 | .child_by_source(db) | ||
244 | }, | ||
245 | ast::StaticDef(it) => { | ||
246 | let def = Static::from_source(db, src.with_value(it))?; | ||
247 | DefWithBodyId::from(def.id) | ||
248 | .child_by_source(db) | ||
249 | }, | ||
250 | ast::ConstDef(it) => { | ||
251 | let def = Const::from_source(db, src.with_value(it))?; | ||
252 | DefWithBodyId::from(def.id) | ||
253 | .child_by_source(db) | ||
254 | }, | ||
307 | _ => { continue }, | 255 | _ => { continue }, |
308 | } | 256 | } |
309 | }; | 257 | }; |
@@ -312,16 +260,6 @@ impl Container { | |||
312 | 260 | ||
313 | let module_source = ModuleSource::from_child_node(db, src); | 261 | let module_source = ModuleSource::from_child_node(db, src); |
314 | let c = Module::from_definition(db, src.with_value(module_source))?; | 262 | let c = Module::from_definition(db, src.with_value(module_source))?; |
315 | Some(Container::Module(c)) | 263 | Some(c.id.child_by_source(db)) |
316 | } | 264 | } |
317 | } | 265 | } |
318 | |||
319 | /// XXX: AST Nodes and SyntaxNodes have identity equality semantics: nodes are | ||
320 | /// equal if they point to exactly the same object. | ||
321 | /// | ||
322 | /// In general, we do not guarantee that we have exactly one instance of a | ||
323 | /// syntax tree for each file. We probably should add such guarantee, but, for | ||
324 | /// the time being, we will use identity-less AstPtr comparison. | ||
325 | fn same_source<N: AstNode>(s1: &Source<N>, s2: &Source<N>) -> bool { | ||
326 | s1.as_ref().map(AstPtr::new) == s2.as_ref().map(AstPtr::new) | ||
327 | } | ||