diff options
Diffstat (limited to 'crates/ra_hir/src/source_binder.rs')
-rw-r--r-- | crates/ra_hir/src/source_binder.rs | 73 |
1 files changed, 65 insertions, 8 deletions
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs index c02175c06..97e3aef34 100644 --- a/crates/ra_hir/src/source_binder.rs +++ b/crates/ra_hir/src/source_binder.rs | |||
@@ -8,15 +8,15 @@ use hir_def::{ | |||
8 | dyn_map::DynMap, | 8 | dyn_map::DynMap, |
9 | keys::{self, Key}, | 9 | keys::{self, Key}, |
10 | resolver::{HasResolver, Resolver}, | 10 | resolver::{HasResolver, Resolver}, |
11 | ConstId, DefWithBodyId, EnumId, EnumVariantId, FunctionId, ImplId, ModuleId, StaticId, | 11 | ConstId, DefWithBodyId, EnumId, EnumVariantId, FunctionId, GenericDefId, ImplId, ModuleId, |
12 | StructFieldId, StructId, TraitId, TypeAliasId, UnionId, VariantId, | 12 | StaticId, StructFieldId, StructId, TraitId, TypeAliasId, UnionId, VariantId, |
13 | }; | 13 | }; |
14 | use hir_expand::{AstId, InFile, MacroDefId, MacroDefKind}; | 14 | use hir_expand::{AstId, InFile, MacroDefId, MacroDefKind}; |
15 | use ra_prof::profile; | 15 | use ra_prof::profile; |
16 | use ra_syntax::{ast, match_ast, AstNode, SyntaxNode, TextUnit}; | 16 | use ra_syntax::{ast, match_ast, AstNode, SyntaxNode, TextUnit}; |
17 | use rustc_hash::FxHashMap; | 17 | use rustc_hash::FxHashMap; |
18 | 18 | ||
19 | use crate::{db::HirDatabase, ModuleSource, SourceAnalyzer}; | 19 | use crate::{db::HirDatabase, Local, ModuleSource, SourceAnalyzer, TypeParam}; |
20 | 20 | ||
21 | pub struct SourceBinder<'a, DB> { | 21 | pub struct SourceBinder<'a, DB> { |
22 | pub db: &'a DB, | 22 | pub db: &'a DB, |
@@ -53,8 +53,7 @@ impl<DB: HirDatabase> SourceBinder<'_, DB> { | |||
53 | } | 53 | } |
54 | 54 | ||
55 | pub fn to_def<T: ToDef>(&mut self, src: InFile<T>) -> Option<T::Def> { | 55 | pub fn to_def<T: ToDef>(&mut self, src: InFile<T>) -> Option<T::Def> { |
56 | let id: T::ID = self.to_id(src)?; | 56 | T::to_def(self, src) |
57 | Some(id.into()) | ||
58 | } | 57 | } |
59 | 58 | ||
60 | fn to_id<T: ToId>(&mut self, src: InFile<T>) -> Option<T::ID> { | 59 | fn to_id<T: ToId>(&mut self, src: InFile<T>) -> Option<T::ID> { |
@@ -110,20 +109,27 @@ impl<DB: HirDatabase> SourceBinder<'_, DB> { | |||
110 | } | 109 | } |
111 | } | 110 | } |
112 | 111 | ||
113 | pub trait ToId: Sized + AstNode + 'static { | 112 | pub trait ToId: Sized { |
114 | type ID: Sized + Copy + 'static; | 113 | type ID: Sized + Copy + 'static; |
115 | fn to_id<DB: HirDatabase>(sb: &mut SourceBinder<'_, DB>, src: InFile<Self>) | 114 | fn to_id<DB: HirDatabase>(sb: &mut SourceBinder<'_, DB>, src: InFile<Self>) |
116 | -> Option<Self::ID>; | 115 | -> Option<Self::ID>; |
117 | } | 116 | } |
118 | 117 | ||
119 | pub trait ToDef: ToId { | 118 | pub trait ToDef: Sized + AstNode + 'static { |
120 | type Def: From<Self::ID>; | 119 | type Def; |
120 | fn to_def<DB: HirDatabase>( | ||
121 | sb: &mut SourceBinder<'_, DB>, | ||
122 | src: InFile<Self>, | ||
123 | ) -> Option<Self::Def>; | ||
121 | } | 124 | } |
122 | 125 | ||
123 | macro_rules! to_def_impls { | 126 | macro_rules! to_def_impls { |
124 | ($(($def:path, $ast:path)),* ,) => {$( | 127 | ($(($def:path, $ast:path)),* ,) => {$( |
125 | impl ToDef for $ast { | 128 | impl ToDef for $ast { |
126 | type Def = $def; | 129 | type Def = $def; |
130 | fn to_def<DB: HirDatabase>(sb: &mut SourceBinder<'_, DB>, src: InFile<Self>) | ||
131 | -> Option<Self::Def> | ||
132 | { sb.to_id(src).map(Into::into) } | ||
127 | } | 133 | } |
128 | )*} | 134 | )*} |
129 | } | 135 | } |
@@ -230,3 +236,54 @@ impl ToId for ast::MacroCall { | |||
230 | Some(MacroDefId { krate, ast_id, kind }) | 236 | Some(MacroDefId { krate, ast_id, kind }) |
231 | } | 237 | } |
232 | } | 238 | } |
239 | |||
240 | impl ToDef for ast::BindPat { | ||
241 | type Def = Local; | ||
242 | |||
243 | fn to_def<DB: HirDatabase>(sb: &mut SourceBinder<'_, DB>, src: InFile<Self>) -> Option<Local> { | ||
244 | let file_id = src.file_id; | ||
245 | let parent: DefWithBodyId = src.value.syntax().ancestors().find_map(|it| { | ||
246 | let res = match_ast! { | ||
247 | match it { | ||
248 | ast::ConstDef(value) => { sb.to_id(InFile { value, file_id})?.into() }, | ||
249 | ast::StaticDef(value) => { sb.to_id(InFile { value, file_id})?.into() }, | ||
250 | ast::FnDef(value) => { sb.to_id(InFile { value, file_id})?.into() }, | ||
251 | _ => return None, | ||
252 | } | ||
253 | }; | ||
254 | Some(res) | ||
255 | })?; | ||
256 | let (_body, source_map) = sb.db.body_with_source_map(parent); | ||
257 | let src = src.map(ast::Pat::from); | ||
258 | let pat_id = source_map.node_pat(src.as_ref())?; | ||
259 | Some(Local { parent: parent.into(), pat_id }) | ||
260 | } | ||
261 | } | ||
262 | |||
263 | impl ToDef for ast::TypeParam { | ||
264 | type Def = TypeParam; | ||
265 | |||
266 | fn to_def<DB: HirDatabase>( | ||
267 | sb: &mut SourceBinder<'_, DB>, | ||
268 | src: InFile<ast::TypeParam>, | ||
269 | ) -> Option<TypeParam> { | ||
270 | let mut sb = SourceBinder::new(sb.db); | ||
271 | let file_id = src.file_id; | ||
272 | let parent: GenericDefId = src.value.syntax().ancestors().find_map(|it| { | ||
273 | let res = match_ast! { | ||
274 | match it { | ||
275 | ast::FnDef(value) => { sb.to_id(InFile { value, file_id})?.into() }, | ||
276 | ast::StructDef(value) => { sb.to_id(InFile { value, file_id})?.into() }, | ||
277 | ast::EnumDef(value) => { sb.to_id(InFile { value, file_id})?.into() }, | ||
278 | ast::TraitDef(value) => { sb.to_id(InFile { value, file_id})?.into() }, | ||
279 | ast::TypeAliasDef(value) => { sb.to_id(InFile { value, file_id})?.into() }, | ||
280 | ast::ImplBlock(value) => { sb.to_id(InFile { value, file_id})?.into() }, | ||
281 | _ => return None, | ||
282 | } | ||
283 | }; | ||
284 | Some(res) | ||
285 | })?; | ||
286 | let &id = parent.child_by_source(sb.db)[keys::TYPE_PARAM].get(&src)?; | ||
287 | Some(TypeParam { id }) | ||
288 | } | ||
289 | } | ||