diff options
-rw-r--r-- | crates/ra_hir/src/from_source.rs | 181 |
1 files changed, 16 insertions, 165 deletions
diff --git a/crates/ra_hir/src/from_source.rs b/crates/ra_hir/src/from_source.rs index 59722eba3..30e818892 100644 --- a/crates/ra_hir/src/from_source.rs +++ b/crates/ra_hir/src/from_source.rs | |||
@@ -2,139 +2,32 @@ | |||
2 | //! file. | 2 | //! file. |
3 | 3 | ||
4 | use hir_def::{ | 4 | use hir_def::{ |
5 | child_by_source::ChildBySource, dyn_map::DynMap, keys, keys::Key, nameres::ModuleSource, | 5 | child_by_source::ChildBySource, keys, nameres::ModuleSource, GenericDefId, ModuleId, |
6 | ConstId, DefWithBodyId, EnumId, EnumVariantId, FunctionId, GenericDefId, ImplId, ModuleId, | ||
7 | StaticId, StructId, TraitId, TypeAliasId, UnionId, VariantId, | ||
8 | }; | 6 | }; |
9 | use hir_expand::{name::AsName, AstId, MacroDefId, MacroDefKind}; | 7 | use hir_expand::name::AsName; |
10 | use ra_db::FileId; | 8 | use ra_db::FileId; |
11 | use ra_prof::profile; | 9 | use ra_prof::profile; |
12 | use ra_syntax::{ | 10 | use ra_syntax::{ |
13 | ast::{self, AstNode, NameOwner}, | 11 | ast::{self, AstNode, NameOwner}, |
14 | match_ast, SyntaxNode, | 12 | match_ast, |
15 | }; | 13 | }; |
16 | 14 | ||
17 | use crate::{ | 15 | use crate::{ |
18 | db::{DefDatabase, HirDatabase}, | 16 | db::{DefDatabase, HirDatabase}, |
19 | Const, DefWithBody, Enum, EnumVariant, FieldSource, Function, ImplBlock, InFile, Local, | 17 | Const, DefWithBody, Enum, Function, ImplBlock, InFile, Local, Module, SourceBinder, Static, |
20 | MacroDef, Module, Static, Struct, StructField, Trait, TypeAlias, TypeParam, Union, | 18 | Struct, Trait, TypeAlias, TypeParam, |
21 | }; | 19 | }; |
22 | 20 | ||
23 | pub(crate) trait FromSource: Sized { | ||
24 | type Ast; | ||
25 | fn from_source(db: &impl DefDatabase, src: InFile<Self::Ast>) -> Option<Self>; | ||
26 | } | ||
27 | |||
28 | pub trait FromSourceByContainer: Sized { | ||
29 | type Ast: AstNode + 'static; | ||
30 | type Id: Copy + 'static; | ||
31 | const KEY: Key<Self::Ast, Self::Id>; | ||
32 | } | ||
33 | |||
34 | impl<T: FromSourceByContainer> FromSource for T | ||
35 | where | ||
36 | T: From<<T as FromSourceByContainer>::Id>, | ||
37 | { | ||
38 | type Ast = <T as FromSourceByContainer>::Ast; | ||
39 | fn from_source(db: &impl DefDatabase, src: InFile<Self::Ast>) -> Option<Self> { | ||
40 | analyze_container(db, src.as_ref().map(|it| it.syntax()))[T::KEY] | ||
41 | .get(&src) | ||
42 | .copied() | ||
43 | .map(Self::from) | ||
44 | } | ||
45 | } | ||
46 | |||
47 | macro_rules! from_source_by_container_impls { | ||
48 | ($(($hir:ident, $id:ident, $ast:path, $key:path)),* ,) => {$( | ||
49 | impl FromSourceByContainer for $hir { | ||
50 | type Ast = $ast; | ||
51 | type Id = $id; | ||
52 | const KEY: Key<Self::Ast, Self::Id> = $key; | ||
53 | } | ||
54 | )*} | ||
55 | } | ||
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 | |||
69 | impl FromSource for MacroDef { | ||
70 | type Ast = ast::MacroCall; | ||
71 | fn from_source(db: &impl DefDatabase, src: InFile<Self::Ast>) -> Option<Self> { | ||
72 | let kind = MacroDefKind::Declarative; | ||
73 | |||
74 | let module_src = ModuleSource::from_child_node(db, src.as_ref().map(|it| it.syntax())); | ||
75 | let module = Module::from_definition(db, InFile::new(src.file_id, module_src))?; | ||
76 | let krate = Some(module.krate().id); | ||
77 | |||
78 | let ast_id = Some(AstId::new(src.file_id, db.ast_id_map(src.file_id).ast_id(&src.value))); | ||
79 | |||
80 | let id: MacroDefId = MacroDefId { krate, ast_id, kind }; | ||
81 | Some(MacroDef { id }) | ||
82 | } | ||
83 | } | ||
84 | |||
85 | impl FromSource for EnumVariant { | ||
86 | type Ast = ast::EnumVariant; | ||
87 | fn from_source(db: &impl DefDatabase, src: InFile<Self::Ast>) -> Option<Self> { | ||
88 | let parent_enum = src.value.parent_enum(); | ||
89 | let src_enum = InFile { file_id: src.file_id, value: parent_enum }; | ||
90 | let parent_enum = Enum::from_source(db, src_enum)?; | ||
91 | parent_enum.id.child_by_source(db)[keys::ENUM_VARIANT] | ||
92 | .get(&src) | ||
93 | .copied() | ||
94 | .map(EnumVariant::from) | ||
95 | } | ||
96 | } | ||
97 | |||
98 | impl FromSource for StructField { | ||
99 | type Ast = FieldSource; | ||
100 | fn from_source(db: &impl DefDatabase, src: InFile<Self::Ast>) -> Option<Self> { | ||
101 | let src = src.as_ref(); | ||
102 | |||
103 | // FIXME this is buggy | ||
104 | let variant_id: VariantId = match src.value { | ||
105 | FieldSource::Named(field) => { | ||
106 | let value = field.syntax().ancestors().find_map(ast::StructDef::cast)?; | ||
107 | let src = InFile { file_id: src.file_id, value }; | ||
108 | let def = Struct::from_source(db, src)?; | ||
109 | def.id.into() | ||
110 | } | ||
111 | FieldSource::Pos(field) => { | ||
112 | let value = field.syntax().ancestors().find_map(ast::EnumVariant::cast)?; | ||
113 | let src = InFile { file_id: src.file_id, value }; | ||
114 | let def = EnumVariant::from_source(db, src)?; | ||
115 | EnumVariantId::from(def).into() | ||
116 | } | ||
117 | }; | ||
118 | |||
119 | let dyn_map = variant_id.child_by_source(db); | ||
120 | match src.value { | ||
121 | FieldSource::Pos(it) => dyn_map[keys::TUPLE_FIELD].get(&src.with_value(it.clone())), | ||
122 | FieldSource::Named(it) => dyn_map[keys::RECORD_FIELD].get(&src.with_value(it.clone())), | ||
123 | } | ||
124 | .copied() | ||
125 | .map(StructField::from) | ||
126 | } | ||
127 | } | ||
128 | |||
129 | impl Local { | 21 | impl Local { |
130 | pub fn from_source(db: &impl HirDatabase, src: InFile<ast::BindPat>) -> Option<Self> { | 22 | pub fn from_source(db: &impl HirDatabase, src: InFile<ast::BindPat>) -> Option<Self> { |
23 | let mut sb = SourceBinder::new(db); | ||
131 | let file_id = src.file_id; | 24 | let file_id = src.file_id; |
132 | let parent: DefWithBody = src.value.syntax().ancestors().find_map(|it| { | 25 | let parent: DefWithBody = src.value.syntax().ancestors().find_map(|it| { |
133 | let res = match_ast! { | 26 | let res = match_ast! { |
134 | match it { | 27 | match it { |
135 | ast::ConstDef(value) => { Const::from_source(db, InFile { value, file_id})?.into() }, | 28 | ast::ConstDef(value) => { sb.to_def::<Const, _>(InFile { value, file_id})?.into() }, |
136 | ast::StaticDef(value) => { Static::from_source(db, InFile { value, file_id})?.into() }, | 29 | ast::StaticDef(value) => { sb.to_def::<Static, _>(InFile { value, file_id})?.into() }, |
137 | ast::FnDef(value) => { Function::from_source(db, InFile { value, file_id})?.into() }, | 30 | ast::FnDef(value) => { sb.to_def::<Function, _>(InFile { value, file_id})?.into() }, |
138 | _ => return None, | 31 | _ => return None, |
139 | } | 32 | } |
140 | }; | 33 | }; |
@@ -149,16 +42,17 @@ impl Local { | |||
149 | 42 | ||
150 | impl TypeParam { | 43 | impl TypeParam { |
151 | pub fn from_source(db: &impl HirDatabase, src: InFile<ast::TypeParam>) -> Option<Self> { | 44 | pub fn from_source(db: &impl HirDatabase, src: InFile<ast::TypeParam>) -> Option<Self> { |
45 | let mut sb = SourceBinder::new(db); | ||
152 | let file_id = src.file_id; | 46 | let file_id = src.file_id; |
153 | let parent: GenericDefId = src.value.syntax().ancestors().find_map(|it| { | 47 | let parent: GenericDefId = src.value.syntax().ancestors().find_map(|it| { |
154 | let res = match_ast! { | 48 | let res = match_ast! { |
155 | match it { | 49 | match it { |
156 | ast::FnDef(value) => { Function::from_source(db, InFile { value, file_id})?.id.into() }, | 50 | ast::FnDef(value) => { sb.to_def::<Function, _>(InFile { value, file_id})?.id.into() }, |
157 | ast::StructDef(value) => { Struct::from_source(db, InFile { value, file_id})?.id.into() }, | 51 | ast::StructDef(value) => { sb.to_def::<Struct, _>(InFile { value, file_id})?.id.into() }, |
158 | ast::EnumDef(value) => { Enum::from_source(db, InFile { value, file_id})?.id.into() }, | 52 | ast::EnumDef(value) => { sb.to_def::<Enum, _>(InFile { value, file_id})?.id.into() }, |
159 | ast::TraitDef(value) => { Trait::from_source(db, InFile { value, file_id})?.id.into() }, | 53 | ast::TraitDef(value) => { sb.to_def::<Trait, _>(InFile { value, file_id})?.id.into() }, |
160 | ast::TypeAliasDef(value) => { TypeAlias::from_source(db, InFile { value, file_id})?.id.into() }, | 54 | ast::TypeAliasDef(value) => { sb.to_def::<TypeAlias, _>(InFile { value, file_id})?.id.into() }, |
161 | ast::ImplBlock(value) => { ImplBlock::from_source(db, InFile { value, file_id})?.id.into() }, | 55 | ast::ImplBlock(value) => { sb.to_def::<ImplBlock, _>(InFile { value, file_id})?.id.into() }, |
162 | _ => return None, | 56 | _ => return None, |
163 | } | 57 | } |
164 | }; | 58 | }; |
@@ -220,46 +114,3 @@ impl Module { | |||
220 | Some(Module { id: ModuleId { krate, local_id } }) | 114 | Some(Module { id: ModuleId { krate, local_id } }) |
221 | } | 115 | } |
222 | } | 116 | } |
223 | |||
224 | fn analyze_container(db: &impl DefDatabase, src: InFile<&SyntaxNode>) -> DynMap { | ||
225 | let _p = profile("analyze_container"); | ||
226 | return child_by_source(db, src).unwrap_or_default(); | ||
227 | |||
228 | fn child_by_source(db: &impl DefDatabase, src: InFile<&SyntaxNode>) -> Option<DynMap> { | ||
229 | for container in src.value.ancestors().skip(1) { | ||
230 | let res = match_ast! { | ||
231 | match container { | ||
232 | ast::TraitDef(it) => { | ||
233 | let def = Trait::from_source(db, src.with_value(it))?; | ||
234 | def.id.child_by_source(db) | ||
235 | }, | ||
236 | ast::ImplBlock(it) => { | ||
237 | let def = ImplBlock::from_source(db, src.with_value(it))?; | ||
238 | def.id.child_by_source(db) | ||
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 | }, | ||
255 | _ => { continue }, | ||
256 | } | ||
257 | }; | ||
258 | return Some(res); | ||
259 | } | ||
260 | |||
261 | let module_source = ModuleSource::from_child_node(db, src); | ||
262 | let c = Module::from_definition(db, src.with_value(module_source))?; | ||
263 | Some(c.id.child_by_source(db)) | ||
264 | } | ||
265 | } | ||