aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src/source_binder.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir/src/source_binder.rs')
-rw-r--r--crates/ra_hir/src/source_binder.rs278
1 files changed, 0 insertions, 278 deletions
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs
deleted file mode 100644
index 4353e25ac..000000000
--- a/crates/ra_hir/src/source_binder.rs
+++ /dev/null
@@ -1,278 +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(|| match container {
105 ChildContainer::DefWithBodyId(it) => it.child_by_source(db),
106 ChildContainer::ModuleId(it) => it.child_by_source(db),
107 ChildContainer::TraitId(it) => it.child_by_source(db),
108 ChildContainer::ImplId(it) => it.child_by_source(db),
109 ChildContainer::EnumId(it) => it.child_by_source(db),
110 ChildContainer::VariantId(it) => it.child_by_source(db),
111 ChildContainer::GenericDefId(it) => it.child_by_source(db),
112 })
113 }
114}
115
116pub(crate) trait ToId: Sized {
117 type ID: Sized + Copy + 'static;
118 fn to_id<DB: HirDatabase>(
119 db: &DB,
120 sb: &mut SourceBinder,
121 src: InFile<Self>,
122 ) -> Option<Self::ID>;
123}
124
125#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
126pub(crate) enum ChildContainer {
127 DefWithBodyId(DefWithBodyId),
128 ModuleId(ModuleId),
129 TraitId(TraitId),
130 ImplId(ImplId),
131 EnumId(EnumId),
132 VariantId(VariantId),
133 /// XXX: this might be the same def as, for example an `EnumId`. However,
134 /// here the children generic parameters, and not, eg enum variants.
135 GenericDefId(GenericDefId),
136}
137impl_froms! {
138 ChildContainer:
139 DefWithBodyId,
140 ModuleId,
141 TraitId,
142 ImplId,
143 EnumId,
144 VariantId,
145 GenericDefId
146}
147
148pub(crate) trait ToIdByKey: Sized + AstNode + 'static {
149 type ID: Sized + Copy + 'static;
150 const KEY: Key<Self, Self::ID>;
151}
152
153impl<T: ToIdByKey> ToId for T {
154 type ID = <T as ToIdByKey>::ID;
155 fn to_id<DB: HirDatabase>(
156 db: &DB,
157 sb: &mut SourceBinder,
158 src: InFile<Self>,
159 ) -> Option<Self::ID> {
160 let container = sb.find_container(db, src.as_ref().map(|it| it.syntax()))?;
161 let dyn_map =
162 &*sb.child_by_source_cache.entry(container).or_insert_with(|| match container {
163 ChildContainer::DefWithBodyId(it) => it.child_by_source(db),
164 ChildContainer::ModuleId(it) => it.child_by_source(db),
165 ChildContainer::TraitId(it) => it.child_by_source(db),
166 ChildContainer::ImplId(it) => it.child_by_source(db),
167 ChildContainer::EnumId(it) => it.child_by_source(db),
168 ChildContainer::VariantId(it) => it.child_by_source(db),
169 ChildContainer::GenericDefId(it) => it.child_by_source(db),
170 });
171 dyn_map[T::KEY].get(&src).copied()
172 }
173}
174
175macro_rules! to_id_key_impls {
176 ($(($id:ident, $ast:path, $key:path)),* ,) => {$(
177 impl ToIdByKey for $ast {
178 type ID = $id;
179 const KEY: Key<Self, Self::ID> = $key;
180 }
181 )*}
182}
183
184to_id_key_impls![
185 (StructId, ast::StructDef, keys::STRUCT),
186 (UnionId, ast::UnionDef, keys::UNION),
187 (EnumId, ast::EnumDef, keys::ENUM),
188 (TraitId, ast::TraitDef, keys::TRAIT),
189 (FunctionId, ast::FnDef, keys::FUNCTION),
190 (StaticId, ast::StaticDef, keys::STATIC),
191 (ConstId, ast::ConstDef, keys::CONST),
192 (TypeAliasId, ast::TypeAliasDef, keys::TYPE_ALIAS),
193 (ImplId, ast::ImplBlock, keys::IMPL),
194 (StructFieldId, ast::RecordFieldDef, keys::RECORD_FIELD),
195 (EnumVariantId, ast::EnumVariant, keys::ENUM_VARIANT),
196];
197
198// FIXME: use DynMap as well?
199impl ToId for ast::MacroCall {
200 type ID = MacroDefId;
201 fn to_id<DB: HirDatabase>(
202 db: &DB,
203 sb: &mut SourceBinder,
204 src: InFile<Self>,
205 ) -> Option<Self::ID> {
206 let kind = MacroDefKind::Declarative;
207
208 let krate = sb.to_module_def(db, src.file_id.original_file(db))?.id.krate;
209
210 let ast_id = Some(AstId::new(src.file_id, db.ast_id_map(src.file_id).ast_id(&src.value)));
211
212 Some(MacroDefId { krate: Some(krate), ast_id, kind })
213 }
214}
215
216impl ToId for ast::TypeParam {
217 type ID = TypeParamId;
218
219 fn to_id<DB: HirDatabase>(
220 db: &DB,
221 sb: &mut SourceBinder,
222 src: InFile<Self>,
223 ) -> Option<Self::ID> {
224 let file_id = src.file_id;
225 let parent: GenericDefId = src.value.syntax().ancestors().find_map(|it| {
226 let res = match_ast! {
227 match it {
228 ast::FnDef(value) => { sb.to_id(db, InFile { value, file_id})?.into() },
229 ast::StructDef(value) => { sb.to_id(db, InFile { value, file_id})?.into() },
230 ast::EnumDef(value) => { sb.to_id(db, InFile { value, file_id})?.into() },
231 ast::TraitDef(value) => { sb.to_id(db, InFile { value, file_id})?.into() },
232 ast::TypeAliasDef(value) => { sb.to_id(db, InFile { value, file_id})?.into() },
233 ast::ImplBlock(value) => { sb.to_id(db, InFile { value, file_id})?.into() },
234 _ => return None,
235 }
236 };
237 Some(res)
238 })?;
239 sb.child_by_source(db, parent.into())[keys::TYPE_PARAM].get(&src).copied()
240 }
241}
242
243impl ToId for ast::Module {
244 type ID = ModuleId;
245
246 fn to_id<DB: HirDatabase>(
247 db: &DB,
248 sb: &mut SourceBinder,
249 src: InFile<ast::Module>,
250 ) -> Option<ModuleId> {
251 {
252 let _p = profile("ast::Module::to_def");
253 let parent_declaration = src
254 .as_ref()
255 .map(|it| it.syntax())
256 .cloned()
257 .ancestors_with_macros(db)
258 .skip(1)
259 .find_map(|it| {
260 let m = ast::Module::cast(it.value.clone())?;
261 Some(it.with_value(m))
262 });
263
264 let parent_module = match parent_declaration {
265 Some(parent_declaration) => sb.to_id(db, parent_declaration)?,
266 None => {
267 let file_id = src.file_id.original_file(db);
268 sb.to_module_def(db, file_id)?.id
269 }
270 };
271
272 let child_name = src.value.name()?.as_name();
273 let def_map = db.crate_def_map(parent_module.krate);
274 let child_id = *def_map[parent_module.local_id].children.get(&child_name)?;
275 Some(ModuleId { krate: parent_module.krate, local_id: child_id })
276 }
277 }
278}