aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src/source_binder.rs
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2020-02-29 17:32:18 +0000
committerAleksey Kladov <[email protected]>2020-02-29 17:32:18 +0000
commit28332d9b63ed58ecc33604d04488f07ff75a553d (patch)
tree9d3c5dcbffffe51481b148d8cd143efc4f19ec84 /crates/ra_hir/src/source_binder.rs
parenta6a623dfbb40b79cac7857165114fa11a25e4e1f (diff)
Simplify SourceBinder
Diffstat (limited to 'crates/ra_hir/src/source_binder.rs')
-rw-r--r--crates/ra_hir/src/source_binder.rs284
1 files changed, 0 insertions, 284 deletions
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs
deleted file mode 100644
index 439a4d5db..000000000
--- a/crates/ra_hir/src/source_binder.rs
+++ /dev/null
@@ -1,284 +0,0 @@
1//! `SourceBinder` is the main entry point for getting info about source code.
2//! It's main task is to map source syntax trees to hir-level IDs.
3
4use hir_def::{
5 child_by_source::ChildBySource,
6 dyn_map::DynMap,
7 keys::{self, Key},
8 ConstId, DefWithBodyId, EnumId, EnumVariantId, FunctionId, GenericDefId, ImplId, ModuleId,
9 StaticId, StructFieldId, StructId, TraitId, TypeAliasId, TypeParamId, UnionId, VariantId,
10};
11use hir_expand::{name::AsName, AstId, InFile, MacroDefId, MacroDefKind};
12use ra_db::FileId;
13use ra_prof::profile;
14use ra_syntax::{
15 ast::{self, NameOwner},
16 match_ast, AstNode, SyntaxNode,
17};
18use rustc_hash::FxHashMap;
19
20use crate::{db::HirDatabase, Module};
21
22pub(crate) struct SourceBinder {
23 child_by_source_cache: FxHashMap<ChildContainer, DynMap>,
24}
25
26impl SourceBinder {
27 pub(crate) fn new() -> SourceBinder {
28 SourceBinder { child_by_source_cache: FxHashMap::default() }
29 }
30
31 pub(crate) fn to_module_def(&mut self, db: &impl HirDatabase, file: FileId) -> Option<Module> {
32 let _p = profile("SourceBinder::to_module_def");
33 let (krate, local_id) = db.relevant_crates(file).iter().find_map(|&crate_id| {
34 let crate_def_map = db.crate_def_map(crate_id);
35 let local_id = crate_def_map.modules_for_file(file).next()?;
36 Some((crate_id, local_id))
37 })?;
38 Some(Module { id: ModuleId { krate, local_id } })
39 }
40
41 pub(crate) fn to_id<T: ToId>(
42 &mut self,
43 db: &impl HirDatabase,
44 src: InFile<T>,
45 ) -> Option<T::ID> {
46 T::to_id(db, self, src)
47 }
48
49 pub(crate) fn find_container(
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) {
55 let res: ChildContainer = match_ast! {
56 match (container.value) {
57 ast::TraitDef(it) => {
58 let def: TraitId = self.to_id(db, container.with_value(it))?;
59 def.into()
60 },
61 ast::ImplBlock(it) => {
62 let def: ImplId = self.to_id(db, container.with_value(it))?;
63 def.into()
64 },
65 ast::FnDef(it) => {
66 let def: FunctionId = self.to_id(db, container.with_value(it))?;
67 DefWithBodyId::from(def).into()
68 },
69 ast::StaticDef(it) => {
70 let def: StaticId = self.to_id(db, container.with_value(it))?;
71 DefWithBodyId::from(def).into()
72 },
73 ast::ConstDef(it) => {
74 let def: ConstId = self.to_id(db, container.with_value(it))?;
75 DefWithBodyId::from(def).into()
76 },
77 ast::EnumDef(it) => {
78 let def: EnumId = self.to_id(db, container.with_value(it))?;
79 def.into()
80 },
81 ast::StructDef(it) => {
82 let def: StructId = self.to_id(db, container.with_value(it))?;
83 VariantId::from(def).into()
84 },
85 ast::UnionDef(it) => {
86 let def: UnionId = self.to_id(db, container.with_value(it))?;
87 VariantId::from(def).into()
88 },
89 ast::Module(it) => {
90 let def: ModuleId = self.to_id(db, container.with_value(it))?;
91 def.into()
92 },
93 _ => { continue },
94 }
95 };
96 return Some(res);
97 }
98
99 let c = self.to_module_def(db, src.file_id.original_file(db))?;
100 Some(c.id.into())
101 }
102
103 fn child_by_source(&mut self, db: &impl HirDatabase, container: ChildContainer) -> &DynMap {
104 self.child_by_source_cache.entry(container).or_insert_with(|| container.child_by_source(db))
105 }
106}
107
108pub(crate) trait ToId: Sized {
109 type ID: Sized + Copy + 'static;
110 fn to_id<DB: HirDatabase>(
111 db: &DB,
112 sb: &mut SourceBinder,
113 src: InFile<Self>,
114 ) -> Option<Self::ID>;
115}
116
117#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
118pub(crate) enum ChildContainer {
119 DefWithBodyId(DefWithBodyId),
120 ModuleId(ModuleId),
121 TraitId(TraitId),
122 ImplId(ImplId),
123 EnumId(EnumId),
124 VariantId(VariantId),
125 /// XXX: this might be the same def as, for example an `EnumId`. However,
126 /// here the children generic parameters, and not, eg enum variants.
127 GenericDefId(GenericDefId),
128}
129impl_froms! {
130 ChildContainer:
131 DefWithBodyId,
132 ModuleId,
133 TraitId,
134 ImplId,
135 EnumId,
136 VariantId,
137 GenericDefId
138}
139
140impl ChildContainer {
141 fn child_by_source(self, db: &impl HirDatabase) -> DynMap {
142 match self {
143 ChildContainer::DefWithBodyId(it) => it.child_by_source(db),
144 ChildContainer::ModuleId(it) => it.child_by_source(db),
145 ChildContainer::TraitId(it) => it.child_by_source(db),
146 ChildContainer::ImplId(it) => it.child_by_source(db),
147 ChildContainer::EnumId(it) => it.child_by_source(db),
148 ChildContainer::VariantId(it) => it.child_by_source(db),
149 ChildContainer::GenericDefId(it) => it.child_by_source(db),
150 }
151 }
152}
153
154pub(crate) trait ToIdByKey: Sized + AstNode + 'static {
155 type ID: Sized + Copy + 'static;
156 const KEY: Key<Self, Self::ID>;
157}
158
159impl<T: ToIdByKey> ToId for T {
160 type ID = <T as ToIdByKey>::ID;
161 fn to_id<DB: HirDatabase>(
162 db: &DB,
163 sb: &mut SourceBinder,
164 src: InFile<Self>,
165 ) -> Option<Self::ID> {
166 let container = sb.find_container(db, src.as_ref().map(|it| it.syntax()))?;
167 let dyn_map =
168 &*sb.child_by_source_cache.entry(container).or_insert_with(|| match container {
169 ChildContainer::DefWithBodyId(it) => it.child_by_source(db),
170 ChildContainer::ModuleId(it) => it.child_by_source(db),
171 ChildContainer::TraitId(it) => it.child_by_source(db),
172 ChildContainer::ImplId(it) => it.child_by_source(db),
173 ChildContainer::EnumId(it) => it.child_by_source(db),
174 ChildContainer::VariantId(it) => it.child_by_source(db),
175 ChildContainer::GenericDefId(it) => it.child_by_source(db),
176 });
177 dyn_map[T::KEY].get(&src).copied()
178 }
179}
180
181macro_rules! to_id_key_impls {
182 ($(($id:ident, $ast:path, $key:path)),* ,) => {$(
183 impl ToIdByKey for $ast {
184 type ID = $id;
185 const KEY: Key<Self, Self::ID> = $key;
186 }
187 )*}
188}
189
190to_id_key_impls![
191 (StructId, ast::StructDef, keys::STRUCT),
192 (UnionId, ast::UnionDef, keys::UNION),
193 (EnumId, ast::EnumDef, keys::ENUM),
194 (TraitId, ast::TraitDef, keys::TRAIT),
195 (FunctionId, ast::FnDef, keys::FUNCTION),
196 (StaticId, ast::StaticDef, keys::STATIC),
197 (ConstId, ast::ConstDef, keys::CONST),
198 (TypeAliasId, ast::TypeAliasDef, keys::TYPE_ALIAS),
199 (ImplId, ast::ImplBlock, keys::IMPL),
200 (StructFieldId, ast::RecordFieldDef, keys::RECORD_FIELD),
201 (EnumVariantId, ast::EnumVariant, keys::ENUM_VARIANT),
202];
203
204// FIXME: use DynMap as well?
205impl ToId for ast::MacroCall {
206 type ID = MacroDefId;
207 fn to_id<DB: HirDatabase>(
208 db: &DB,
209 sb: &mut SourceBinder,
210 src: InFile<Self>,
211 ) -> Option<Self::ID> {
212 let kind = MacroDefKind::Declarative;
213
214 let krate = sb.to_module_def(db, src.file_id.original_file(db))?.id.krate;
215
216 let ast_id = Some(AstId::new(src.file_id, db.ast_id_map(src.file_id).ast_id(&src.value)));
217
218 Some(MacroDefId { krate: Some(krate), ast_id, kind })
219 }
220}
221
222impl ToId for ast::TypeParam {
223 type ID = TypeParamId;
224
225 fn to_id<DB: HirDatabase>(
226 db: &DB,
227 sb: &mut SourceBinder,
228 src: InFile<Self>,
229 ) -> Option<Self::ID> {
230 let file_id = src.file_id;
231 let parent: GenericDefId = src.value.syntax().ancestors().find_map(|it| {
232 let res = match_ast! {
233 match it {
234 ast::FnDef(value) => { sb.to_id(db, InFile { value, file_id})?.into() },
235 ast::StructDef(value) => { sb.to_id(db, InFile { value, file_id})?.into() },
236 ast::EnumDef(value) => { sb.to_id(db, InFile { value, file_id})?.into() },
237 ast::TraitDef(value) => { sb.to_id(db, InFile { value, file_id})?.into() },
238 ast::TypeAliasDef(value) => { sb.to_id(db, InFile { value, file_id})?.into() },
239 ast::ImplBlock(value) => { sb.to_id(db, InFile { value, file_id})?.into() },
240 _ => return None,
241 }
242 };
243 Some(res)
244 })?;
245 sb.child_by_source(db, parent.into())[keys::TYPE_PARAM].get(&src).copied()
246 }
247}
248
249impl ToId for ast::Module {
250 type ID = ModuleId;
251
252 fn to_id<DB: HirDatabase>(
253 db: &DB,
254 sb: &mut SourceBinder,
255 src: InFile<ast::Module>,
256 ) -> Option<ModuleId> {
257 {
258 let _p = profile("ast::Module::to_def");
259 let parent_declaration = src
260 .as_ref()
261 .map(|it| it.syntax())
262 .cloned()
263 .ancestors_with_macros(db)
264 .skip(1)
265 .find_map(|it| {
266 let m = ast::Module::cast(it.value.clone())?;
267 Some(it.with_value(m))
268 });
269
270 let parent_module = match parent_declaration {
271 Some(parent_declaration) => sb.to_id(db, parent_declaration)?,
272 None => {
273 let file_id = src.file_id.original_file(db);
274 sb.to_module_def(db, file_id)?.id
275 }
276 };
277
278 let child_name = src.value.name()?.as_name();
279 let def_map = db.crate_def_map(parent_module.krate);
280 let child_id = *def_map[parent_module.local_id].children.get(&child_name)?;
281 Some(ModuleId { krate: parent_module.krate, local_id: child_id })
282 }
283 }
284}