diff options
Diffstat (limited to 'crates/ra_hir/src/source_binder.rs')
-rw-r--r-- | crates/ra_hir/src/source_binder.rs | 217 |
1 files changed, 69 insertions, 148 deletions
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs index f3150f578..4353e25ac 100644 --- a/crates/ra_hir/src/source_binder.rs +++ b/crates/ra_hir/src/source_binder.rs | |||
@@ -5,112 +5,89 @@ use hir_def::{ | |||
5 | child_by_source::ChildBySource, | 5 | child_by_source::ChildBySource, |
6 | dyn_map::DynMap, | 6 | dyn_map::DynMap, |
7 | keys::{self, Key}, | 7 | keys::{self, Key}, |
8 | resolver::{HasResolver, Resolver}, | ||
9 | ConstId, DefWithBodyId, EnumId, EnumVariantId, FunctionId, GenericDefId, ImplId, ModuleId, | 8 | ConstId, DefWithBodyId, EnumId, EnumVariantId, FunctionId, GenericDefId, ImplId, ModuleId, |
10 | StaticId, StructFieldId, StructId, TraitId, TypeAliasId, UnionId, VariantId, | 9 | StaticId, StructFieldId, StructId, TraitId, TypeAliasId, TypeParamId, UnionId, VariantId, |
11 | }; | 10 | }; |
12 | use hir_expand::{name::AsName, AstId, InFile, MacroDefId, MacroDefKind}; | 11 | use hir_expand::{name::AsName, AstId, InFile, MacroDefId, MacroDefKind}; |
12 | use ra_db::FileId; | ||
13 | use ra_prof::profile; | 13 | use ra_prof::profile; |
14 | use ra_syntax::{ | 14 | use ra_syntax::{ |
15 | ast::{self, NameOwner}, | 15 | ast::{self, NameOwner}, |
16 | match_ast, AstNode, SyntaxNode, TextUnit, | 16 | match_ast, AstNode, SyntaxNode, |
17 | }; | 17 | }; |
18 | use rustc_hash::FxHashMap; | 18 | use rustc_hash::FxHashMap; |
19 | 19 | ||
20 | use crate::{db::HirDatabase, Local, Module, SourceAnalyzer, TypeParam}; | 20 | use crate::{db::HirDatabase, Module}; |
21 | use ra_db::FileId; | ||
22 | 21 | ||
23 | pub struct SourceBinder<'a, DB> { | 22 | pub(crate) struct SourceBinder { |
24 | pub db: &'a DB, | ||
25 | child_by_source_cache: FxHashMap<ChildContainer, DynMap>, | 23 | child_by_source_cache: FxHashMap<ChildContainer, DynMap>, |
26 | } | 24 | } |
27 | 25 | ||
28 | impl<DB: HirDatabase> SourceBinder<'_, DB> { | 26 | impl SourceBinder { |
29 | pub fn new(db: &DB) -> SourceBinder<DB> { | 27 | pub(crate) fn new() -> SourceBinder { |
30 | SourceBinder { db, child_by_source_cache: FxHashMap::default() } | 28 | SourceBinder { child_by_source_cache: FxHashMap::default() } |
31 | } | ||
32 | |||
33 | pub fn analyze( | ||
34 | &mut self, | ||
35 | src: InFile<&SyntaxNode>, | ||
36 | offset: Option<TextUnit>, | ||
37 | ) -> SourceAnalyzer { | ||
38 | let _p = profile("SourceBinder::analyzer"); | ||
39 | let container = match self.find_container(src) { | ||
40 | Some(it) => it, | ||
41 | None => return SourceAnalyzer::new_for_resolver(Resolver::default(), src), | ||
42 | }; | ||
43 | |||
44 | let resolver = match container { | ||
45 | ChildContainer::DefWithBodyId(def) => { | ||
46 | return SourceAnalyzer::new_for_body(self.db, def, src, offset) | ||
47 | } | ||
48 | ChildContainer::TraitId(it) => it.resolver(self.db), | ||
49 | ChildContainer::ImplId(it) => it.resolver(self.db), | ||
50 | ChildContainer::ModuleId(it) => it.resolver(self.db), | ||
51 | ChildContainer::EnumId(it) => it.resolver(self.db), | ||
52 | ChildContainer::VariantId(it) => it.resolver(self.db), | ||
53 | ChildContainer::GenericDefId(it) => it.resolver(self.db), | ||
54 | }; | ||
55 | SourceAnalyzer::new_for_resolver(resolver, src) | ||
56 | } | ||
57 | |||
58 | pub fn to_def<T: ToDef>(&mut self, src: InFile<T>) -> Option<T::Def> { | ||
59 | T::to_def(self, src) | ||
60 | } | 29 | } |
61 | 30 | ||
62 | pub fn to_module_def(&mut self, file: FileId) -> Option<Module> { | 31 | pub(crate) fn to_module_def(&mut self, db: &impl HirDatabase, file: FileId) -> Option<Module> { |
63 | let _p = profile("SourceBinder::to_module_def"); | 32 | let _p = profile("SourceBinder::to_module_def"); |
64 | let (krate, local_id) = self.db.relevant_crates(file).iter().find_map(|&crate_id| { | 33 | let (krate, local_id) = db.relevant_crates(file).iter().find_map(|&crate_id| { |
65 | let crate_def_map = self.db.crate_def_map(crate_id); | 34 | let crate_def_map = db.crate_def_map(crate_id); |
66 | let local_id = crate_def_map.modules_for_file(file).next()?; | 35 | let local_id = crate_def_map.modules_for_file(file).next()?; |
67 | Some((crate_id, local_id)) | 36 | Some((crate_id, local_id)) |
68 | })?; | 37 | })?; |
69 | Some(Module { id: ModuleId { krate, local_id } }) | 38 | Some(Module { id: ModuleId { krate, local_id } }) |
70 | } | 39 | } |
71 | 40 | ||
72 | fn to_id<T: ToId>(&mut self, src: InFile<T>) -> Option<T::ID> { | 41 | pub(crate) fn to_id<T: ToId>( |
73 | T::to_id(self, src) | 42 | &mut self, |
43 | db: &impl HirDatabase, | ||
44 | src: InFile<T>, | ||
45 | ) -> Option<T::ID> { | ||
46 | T::to_id(db, self, src) | ||
74 | } | 47 | } |
75 | 48 | ||
76 | fn find_container(&mut self, src: InFile<&SyntaxNode>) -> Option<ChildContainer> { | 49 | pub(crate) fn find_container( |
77 | for container in src.cloned().ancestors_with_macros(self.db).skip(1) { | 50 | &mut self, |
51 | db: &impl HirDatabase, | ||
52 | src: InFile<&SyntaxNode>, | ||
53 | ) -> Option<ChildContainer> { | ||
54 | for container in src.cloned().ancestors_with_macros(db).skip(1) { | ||
78 | let res: ChildContainer = match_ast! { | 55 | let res: ChildContainer = match_ast! { |
79 | match (container.value) { | 56 | match (container.value) { |
80 | ast::TraitDef(it) => { | 57 | ast::TraitDef(it) => { |
81 | let def: TraitId = self.to_id(container.with_value(it))?; | 58 | let def: TraitId = self.to_id(db, container.with_value(it))?; |
82 | def.into() | 59 | def.into() |
83 | }, | 60 | }, |
84 | ast::ImplBlock(it) => { | 61 | ast::ImplBlock(it) => { |
85 | let def: ImplId = self.to_id(container.with_value(it))?; | 62 | let def: ImplId = self.to_id(db, container.with_value(it))?; |
86 | def.into() | 63 | def.into() |
87 | }, | 64 | }, |
88 | ast::FnDef(it) => { | 65 | ast::FnDef(it) => { |
89 | let def: FunctionId = self.to_id(container.with_value(it))?; | 66 | let def: FunctionId = self.to_id(db, container.with_value(it))?; |
90 | DefWithBodyId::from(def).into() | 67 | DefWithBodyId::from(def).into() |
91 | }, | 68 | }, |
92 | ast::StaticDef(it) => { | 69 | ast::StaticDef(it) => { |
93 | let def: StaticId = self.to_id(container.with_value(it))?; | 70 | let def: StaticId = self.to_id(db, container.with_value(it))?; |
94 | DefWithBodyId::from(def).into() | 71 | DefWithBodyId::from(def).into() |
95 | }, | 72 | }, |
96 | ast::ConstDef(it) => { | 73 | ast::ConstDef(it) => { |
97 | let def: ConstId = self.to_id(container.with_value(it))?; | 74 | let def: ConstId = self.to_id(db, container.with_value(it))?; |
98 | DefWithBodyId::from(def).into() | 75 | DefWithBodyId::from(def).into() |
99 | }, | 76 | }, |
100 | ast::EnumDef(it) => { | 77 | ast::EnumDef(it) => { |
101 | let def: EnumId = self.to_id(container.with_value(it))?; | 78 | let def: EnumId = self.to_id(db, container.with_value(it))?; |
102 | def.into() | 79 | def.into() |
103 | }, | 80 | }, |
104 | ast::StructDef(it) => { | 81 | ast::StructDef(it) => { |
105 | let def: StructId = self.to_id(container.with_value(it))?; | 82 | let def: StructId = self.to_id(db, container.with_value(it))?; |
106 | VariantId::from(def).into() | 83 | VariantId::from(def).into() |
107 | }, | 84 | }, |
108 | ast::UnionDef(it) => { | 85 | ast::UnionDef(it) => { |
109 | let def: UnionId = self.to_id(container.with_value(it))?; | 86 | let def: UnionId = self.to_id(db, container.with_value(it))?; |
110 | VariantId::from(def).into() | 87 | VariantId::from(def).into() |
111 | }, | 88 | }, |
112 | ast::Module(it) => { | 89 | ast::Module(it) => { |
113 | let def: ModuleId = self.to_id(container.with_value(it))?; | 90 | let def: ModuleId = self.to_id(db, container.with_value(it))?; |
114 | def.into() | 91 | def.into() |
115 | }, | 92 | }, |
116 | _ => { continue }, | 93 | _ => { continue }, |
@@ -119,12 +96,11 @@ impl<DB: HirDatabase> SourceBinder<'_, DB> { | |||
119 | return Some(res); | 96 | return Some(res); |
120 | } | 97 | } |
121 | 98 | ||
122 | let c = self.to_module_def(src.file_id.original_file(self.db))?; | 99 | let c = self.to_module_def(db, src.file_id.original_file(db))?; |
123 | Some(c.id.into()) | 100 | Some(c.id.into()) |
124 | } | 101 | } |
125 | 102 | ||
126 | fn child_by_source(&mut self, container: ChildContainer) -> &DynMap { | 103 | fn child_by_source(&mut self, db: &impl HirDatabase, container: ChildContainer) -> &DynMap { |
127 | let db = self.db; | ||
128 | self.child_by_source_cache.entry(container).or_insert_with(|| match container { | 104 | self.child_by_source_cache.entry(container).or_insert_with(|| match container { |
129 | ChildContainer::DefWithBodyId(it) => it.child_by_source(db), | 105 | ChildContainer::DefWithBodyId(it) => it.child_by_source(db), |
130 | ChildContainer::ModuleId(it) => it.child_by_source(db), | 106 | ChildContainer::ModuleId(it) => it.child_by_source(db), |
@@ -137,49 +113,17 @@ impl<DB: HirDatabase> SourceBinder<'_, DB> { | |||
137 | } | 113 | } |
138 | } | 114 | } |
139 | 115 | ||
140 | pub trait ToId: Sized { | 116 | pub(crate) trait ToId: Sized { |
141 | type ID: Sized + Copy + 'static; | 117 | type ID: Sized + Copy + 'static; |
142 | fn to_id<DB: HirDatabase>(sb: &mut SourceBinder<'_, DB>, src: InFile<Self>) | 118 | fn to_id<DB: HirDatabase>( |
143 | -> Option<Self::ID>; | 119 | db: &DB, |
144 | } | 120 | sb: &mut SourceBinder, |
145 | |||
146 | pub trait ToDef: Sized + AstNode + 'static { | ||
147 | type Def; | ||
148 | fn to_def<DB: HirDatabase>( | ||
149 | sb: &mut SourceBinder<'_, DB>, | ||
150 | src: InFile<Self>, | 121 | src: InFile<Self>, |
151 | ) -> Option<Self::Def>; | 122 | ) -> Option<Self::ID>; |
152 | } | ||
153 | |||
154 | macro_rules! to_def_impls { | ||
155 | ($(($def:path, $ast:path)),* ,) => {$( | ||
156 | impl ToDef for $ast { | ||
157 | type Def = $def; | ||
158 | fn to_def<DB: HirDatabase>(sb: &mut SourceBinder<'_, DB>, src: InFile<Self>) | ||
159 | -> Option<Self::Def> | ||
160 | { sb.to_id(src).map(Into::into) } | ||
161 | } | ||
162 | )*} | ||
163 | } | 123 | } |
164 | 124 | ||
165 | to_def_impls![ | ||
166 | (crate::Module, ast::Module), | ||
167 | (crate::Struct, ast::StructDef), | ||
168 | (crate::Enum, ast::EnumDef), | ||
169 | (crate::Union, ast::UnionDef), | ||
170 | (crate::Trait, ast::TraitDef), | ||
171 | (crate::ImplBlock, ast::ImplBlock), | ||
172 | (crate::TypeAlias, ast::TypeAliasDef), | ||
173 | (crate::Const, ast::ConstDef), | ||
174 | (crate::Static, ast::StaticDef), | ||
175 | (crate::Function, ast::FnDef), | ||
176 | (crate::StructField, ast::RecordFieldDef), | ||
177 | (crate::EnumVariant, ast::EnumVariant), | ||
178 | (crate::MacroDef, ast::MacroCall), // this one is dubious, not all calls are macros | ||
179 | ]; | ||
180 | |||
181 | #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] | 125 | #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] |
182 | enum ChildContainer { | 126 | pub(crate) enum ChildContainer { |
183 | DefWithBodyId(DefWithBodyId), | 127 | DefWithBodyId(DefWithBodyId), |
184 | ModuleId(ModuleId), | 128 | ModuleId(ModuleId), |
185 | TraitId(TraitId), | 129 | TraitId(TraitId), |
@@ -201,7 +145,7 @@ impl_froms! { | |||
201 | GenericDefId | 145 | GenericDefId |
202 | } | 146 | } |
203 | 147 | ||
204 | pub trait ToIdByKey: Sized + AstNode + 'static { | 148 | pub(crate) trait ToIdByKey: Sized + AstNode + 'static { |
205 | type ID: Sized + Copy + 'static; | 149 | type ID: Sized + Copy + 'static; |
206 | const KEY: Key<Self, Self::ID>; | 150 | const KEY: Key<Self, Self::ID>; |
207 | } | 151 | } |
@@ -209,11 +153,11 @@ pub trait ToIdByKey: Sized + AstNode + 'static { | |||
209 | impl<T: ToIdByKey> ToId for T { | 153 | impl<T: ToIdByKey> ToId for T { |
210 | type ID = <T as ToIdByKey>::ID; | 154 | type ID = <T as ToIdByKey>::ID; |
211 | fn to_id<DB: HirDatabase>( | 155 | fn to_id<DB: HirDatabase>( |
212 | sb: &mut SourceBinder<'_, DB>, | 156 | db: &DB, |
157 | sb: &mut SourceBinder, | ||
213 | src: InFile<Self>, | 158 | src: InFile<Self>, |
214 | ) -> Option<Self::ID> { | 159 | ) -> Option<Self::ID> { |
215 | let container = sb.find_container(src.as_ref().map(|it| it.syntax()))?; | 160 | let container = sb.find_container(db, src.as_ref().map(|it| it.syntax()))?; |
216 | let db = sb.db; | ||
217 | let dyn_map = | 161 | let dyn_map = |
218 | &*sb.child_by_source_cache.entry(container).or_insert_with(|| match container { | 162 | &*sb.child_by_source_cache.entry(container).or_insert_with(|| match container { |
219 | ChildContainer::DefWithBodyId(it) => it.child_by_source(db), | 163 | ChildContainer::DefWithBodyId(it) => it.child_by_source(db), |
@@ -255,68 +199,44 @@ to_id_key_impls![ | |||
255 | impl ToId for ast::MacroCall { | 199 | impl ToId for ast::MacroCall { |
256 | type ID = MacroDefId; | 200 | type ID = MacroDefId; |
257 | fn to_id<DB: HirDatabase>( | 201 | fn to_id<DB: HirDatabase>( |
258 | sb: &mut SourceBinder<'_, DB>, | 202 | db: &DB, |
203 | sb: &mut SourceBinder, | ||
259 | src: InFile<Self>, | 204 | src: InFile<Self>, |
260 | ) -> Option<Self::ID> { | 205 | ) -> Option<Self::ID> { |
261 | let kind = MacroDefKind::Declarative; | 206 | let kind = MacroDefKind::Declarative; |
262 | 207 | ||
263 | let krate = sb.to_module_def(src.file_id.original_file(sb.db))?.id.krate; | 208 | let krate = sb.to_module_def(db, src.file_id.original_file(db))?.id.krate; |
264 | 209 | ||
265 | let ast_id = | 210 | let ast_id = Some(AstId::new(src.file_id, db.ast_id_map(src.file_id).ast_id(&src.value))); |
266 | Some(AstId::new(src.file_id, sb.db.ast_id_map(src.file_id).ast_id(&src.value))); | ||
267 | 211 | ||
268 | Some(MacroDefId { krate: Some(krate), ast_id, kind }) | 212 | Some(MacroDefId { krate: Some(krate), ast_id, kind }) |
269 | } | 213 | } |
270 | } | 214 | } |
271 | 215 | ||
272 | impl ToDef for ast::BindPat { | 216 | impl ToId for ast::TypeParam { |
273 | type Def = Local; | 217 | type ID = TypeParamId; |
274 | |||
275 | fn to_def<DB: HirDatabase>(sb: &mut SourceBinder<'_, DB>, src: InFile<Self>) -> Option<Local> { | ||
276 | let file_id = src.file_id; | ||
277 | let parent: DefWithBodyId = src.value.syntax().ancestors().find_map(|it| { | ||
278 | let res = match_ast! { | ||
279 | match it { | ||
280 | ast::ConstDef(value) => { sb.to_id(InFile { value, file_id})?.into() }, | ||
281 | ast::StaticDef(value) => { sb.to_id(InFile { value, file_id})?.into() }, | ||
282 | ast::FnDef(value) => { sb.to_id(InFile { value, file_id})?.into() }, | ||
283 | _ => return None, | ||
284 | } | ||
285 | }; | ||
286 | Some(res) | ||
287 | })?; | ||
288 | let (_body, source_map) = sb.db.body_with_source_map(parent); | ||
289 | let src = src.map(ast::Pat::from); | ||
290 | let pat_id = source_map.node_pat(src.as_ref())?; | ||
291 | Some(Local { parent: parent.into(), pat_id }) | ||
292 | } | ||
293 | } | ||
294 | |||
295 | impl ToDef for ast::TypeParam { | ||
296 | type Def = TypeParam; | ||
297 | 218 | ||
298 | fn to_def<DB: HirDatabase>( | 219 | fn to_id<DB: HirDatabase>( |
299 | sb: &mut SourceBinder<'_, DB>, | 220 | db: &DB, |
300 | src: InFile<ast::TypeParam>, | 221 | sb: &mut SourceBinder, |
301 | ) -> Option<TypeParam> { | 222 | src: InFile<Self>, |
302 | let mut sb = SourceBinder::new(sb.db); | 223 | ) -> Option<Self::ID> { |
303 | let file_id = src.file_id; | 224 | let file_id = src.file_id; |
304 | let parent: GenericDefId = src.value.syntax().ancestors().find_map(|it| { | 225 | let parent: GenericDefId = src.value.syntax().ancestors().find_map(|it| { |
305 | let res = match_ast! { | 226 | let res = match_ast! { |
306 | match it { | 227 | match it { |
307 | ast::FnDef(value) => { sb.to_id(InFile { value, file_id})?.into() }, | 228 | ast::FnDef(value) => { sb.to_id(db, InFile { value, file_id})?.into() }, |
308 | ast::StructDef(value) => { sb.to_id(InFile { value, file_id})?.into() }, | 229 | ast::StructDef(value) => { sb.to_id(db, InFile { value, file_id})?.into() }, |
309 | ast::EnumDef(value) => { sb.to_id(InFile { value, file_id})?.into() }, | 230 | ast::EnumDef(value) => { sb.to_id(db, InFile { value, file_id})?.into() }, |
310 | ast::TraitDef(value) => { sb.to_id(InFile { value, file_id})?.into() }, | 231 | ast::TraitDef(value) => { sb.to_id(db, InFile { value, file_id})?.into() }, |
311 | ast::TypeAliasDef(value) => { sb.to_id(InFile { value, file_id})?.into() }, | 232 | ast::TypeAliasDef(value) => { sb.to_id(db, InFile { value, file_id})?.into() }, |
312 | ast::ImplBlock(value) => { sb.to_id(InFile { value, file_id})?.into() }, | 233 | ast::ImplBlock(value) => { sb.to_id(db, InFile { value, file_id})?.into() }, |
313 | _ => return None, | 234 | _ => return None, |
314 | } | 235 | } |
315 | }; | 236 | }; |
316 | Some(res) | 237 | Some(res) |
317 | })?; | 238 | })?; |
318 | let &id = sb.child_by_source(parent.into())[keys::TYPE_PARAM].get(&src)?; | 239 | sb.child_by_source(db, parent.into())[keys::TYPE_PARAM].get(&src).copied() |
319 | Some(TypeParam { id }) | ||
320 | } | 240 | } |
321 | } | 241 | } |
322 | 242 | ||
@@ -324,7 +244,8 @@ impl ToId for ast::Module { | |||
324 | type ID = ModuleId; | 244 | type ID = ModuleId; |
325 | 245 | ||
326 | fn to_id<DB: HirDatabase>( | 246 | fn to_id<DB: HirDatabase>( |
327 | sb: &mut SourceBinder<'_, DB>, | 247 | db: &DB, |
248 | sb: &mut SourceBinder, | ||
328 | src: InFile<ast::Module>, | 249 | src: InFile<ast::Module>, |
329 | ) -> Option<ModuleId> { | 250 | ) -> Option<ModuleId> { |
330 | { | 251 | { |
@@ -333,7 +254,7 @@ impl ToId for ast::Module { | |||
333 | .as_ref() | 254 | .as_ref() |
334 | .map(|it| it.syntax()) | 255 | .map(|it| it.syntax()) |
335 | .cloned() | 256 | .cloned() |
336 | .ancestors_with_macros(sb.db) | 257 | .ancestors_with_macros(db) |
337 | .skip(1) | 258 | .skip(1) |
338 | .find_map(|it| { | 259 | .find_map(|it| { |
339 | let m = ast::Module::cast(it.value.clone())?; | 260 | let m = ast::Module::cast(it.value.clone())?; |
@@ -341,15 +262,15 @@ impl ToId for ast::Module { | |||
341 | }); | 262 | }); |
342 | 263 | ||
343 | let parent_module = match parent_declaration { | 264 | let parent_module = match parent_declaration { |
344 | Some(parent_declaration) => sb.to_id(parent_declaration)?, | 265 | Some(parent_declaration) => sb.to_id(db, parent_declaration)?, |
345 | None => { | 266 | None => { |
346 | let file_id = src.file_id.original_file(sb.db); | 267 | let file_id = src.file_id.original_file(db); |
347 | sb.to_module_def(file_id)?.id | 268 | sb.to_module_def(db, file_id)?.id |
348 | } | 269 | } |
349 | }; | 270 | }; |
350 | 271 | ||
351 | let child_name = src.value.name()?.as_name(); | 272 | let child_name = src.value.name()?.as_name(); |
352 | let def_map = sb.db.crate_def_map(parent_module.krate); | 273 | let def_map = db.crate_def_map(parent_module.krate); |
353 | let child_id = *def_map[parent_module.local_id].children.get(&child_name)?; | 274 | let child_id = *def_map[parent_module.local_id].children.get(&child_name)?; |
354 | Some(ModuleId { krate: parent_module.krate, local_id: child_id }) | 275 | Some(ModuleId { krate: parent_module.krate, local_id: child_id }) |
355 | } | 276 | } |