diff options
Diffstat (limited to 'crates/ra_hir/src/from_source.rs')
-rw-r--r-- | crates/ra_hir/src/from_source.rs | 265 |
1 files changed, 0 insertions, 265 deletions
diff --git a/crates/ra_hir/src/from_source.rs b/crates/ra_hir/src/from_source.rs deleted file mode 100644 index 6314be8d4..000000000 --- a/crates/ra_hir/src/from_source.rs +++ /dev/null | |||
@@ -1,265 +0,0 @@ | |||
1 | //! Finds a corresponding hir data structure for a syntax node in a specific | ||
2 | //! file. | ||
3 | |||
4 | use hir_def::{ | ||
5 | child_by_source::ChildBySource, dyn_map::DynMap, keys, keys::Key, nameres::ModuleSource, | ||
6 | ConstId, DefWithBodyId, EnumId, EnumVariantId, FunctionId, GenericDefId, ImplId, ModuleId, | ||
7 | StaticId, StructId, TraitId, TypeAliasId, UnionId, VariantId, | ||
8 | }; | ||
9 | use hir_expand::{name::AsName, AstId, MacroDefId, MacroDefKind}; | ||
10 | use ra_db::FileId; | ||
11 | use ra_prof::profile; | ||
12 | use ra_syntax::{ | ||
13 | ast::{self, AstNode, NameOwner}, | ||
14 | match_ast, SyntaxNode, | ||
15 | }; | ||
16 | |||
17 | use crate::{ | ||
18 | db::{DefDatabase, HirDatabase}, | ||
19 | Const, DefWithBody, Enum, EnumVariant, FieldSource, Function, ImplBlock, InFile, Local, | ||
20 | MacroDef, Module, Static, Struct, StructField, Trait, TypeAlias, TypeParam, Union, | ||
21 | }; | ||
22 | |||
23 | pub 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 { | ||
130 | pub fn from_source(db: &impl HirDatabase, src: InFile<ast::BindPat>) -> Option<Self> { | ||
131 | let file_id = src.file_id; | ||
132 | let parent: DefWithBody = src.value.syntax().ancestors().find_map(|it| { | ||
133 | let res = match_ast! { | ||
134 | match it { | ||
135 | ast::ConstDef(value) => { Const::from_source(db, InFile { value, file_id})?.into() }, | ||
136 | ast::StaticDef(value) => { Static::from_source(db, InFile { value, file_id})?.into() }, | ||
137 | ast::FnDef(value) => { Function::from_source(db, InFile { value, file_id})?.into() }, | ||
138 | _ => return None, | ||
139 | } | ||
140 | }; | ||
141 | Some(res) | ||
142 | })?; | ||
143 | let (_body, source_map) = db.body_with_source_map(parent.into()); | ||
144 | let src = src.map(ast::Pat::from); | ||
145 | let pat_id = source_map.node_pat(src.as_ref())?; | ||
146 | Some(Local { parent, pat_id }) | ||
147 | } | ||
148 | } | ||
149 | |||
150 | impl TypeParam { | ||
151 | pub fn from_source(db: &impl HirDatabase, src: InFile<ast::TypeParam>) -> Option<Self> { | ||
152 | let file_id = src.file_id; | ||
153 | let parent: GenericDefId = src.value.syntax().ancestors().find_map(|it| { | ||
154 | let res = match_ast! { | ||
155 | match it { | ||
156 | ast::FnDef(value) => { Function::from_source(db, InFile { value, file_id})?.id.into() }, | ||
157 | ast::StructDef(value) => { Struct::from_source(db, InFile { value, file_id})?.id.into() }, | ||
158 | ast::EnumDef(value) => { Enum::from_source(db, InFile { value, file_id})?.id.into() }, | ||
159 | ast::TraitDef(value) => { Trait::from_source(db, InFile { value, file_id})?.id.into() }, | ||
160 | ast::TypeAliasDef(value) => { TypeAlias::from_source(db, InFile { value, file_id})?.id.into() }, | ||
161 | ast::ImplBlock(value) => { ImplBlock::from_source(db, InFile { value, file_id})?.id.into() }, | ||
162 | _ => return None, | ||
163 | } | ||
164 | }; | ||
165 | Some(res) | ||
166 | })?; | ||
167 | let &id = parent.child_by_source(db)[keys::TYPE_PARAM].get(&src)?; | ||
168 | Some(TypeParam { id }) | ||
169 | } | ||
170 | } | ||
171 | |||
172 | impl Module { | ||
173 | pub fn from_declaration(db: &impl DefDatabase, src: InFile<ast::Module>) -> Option<Self> { | ||
174 | let _p = profile("Module::from_declaration"); | ||
175 | let parent_declaration = src.value.syntax().ancestors().skip(1).find_map(ast::Module::cast); | ||
176 | |||
177 | let parent_module = match parent_declaration { | ||
178 | Some(parent_declaration) => { | ||
179 | let src_parent = InFile { file_id: src.file_id, value: parent_declaration }; | ||
180 | Module::from_declaration(db, src_parent) | ||
181 | } | ||
182 | None => { | ||
183 | let source_file = db.parse(src.file_id.original_file(db)).tree(); | ||
184 | let src_parent = | ||
185 | InFile { file_id: src.file_id, value: ModuleSource::SourceFile(source_file) }; | ||
186 | Module::from_definition(db, src_parent) | ||
187 | } | ||
188 | }?; | ||
189 | |||
190 | let child_name = src.value.name()?.as_name(); | ||
191 | let def_map = db.crate_def_map(parent_module.id.krate); | ||
192 | let child_id = def_map[parent_module.id.local_id].children.get(&child_name)?; | ||
193 | Some(parent_module.with_module_id(*child_id)) | ||
194 | } | ||
195 | |||
196 | pub fn from_definition(db: &impl DefDatabase, src: InFile<ModuleSource>) -> Option<Self> { | ||
197 | let _p = profile("Module::from_definition"); | ||
198 | match src.value { | ||
199 | ModuleSource::Module(ref module) => { | ||
200 | assert!(!module.has_semi()); | ||
201 | return Module::from_declaration( | ||
202 | db, | ||
203 | InFile { file_id: src.file_id, value: module.clone() }, | ||
204 | ); | ||
205 | } | ||
206 | ModuleSource::SourceFile(_) => (), | ||
207 | }; | ||
208 | |||
209 | let original_file = src.file_id.original_file(db); | ||
210 | Module::from_file(db, original_file) | ||
211 | } | ||
212 | |||
213 | fn from_file(db: &impl DefDatabase, file: FileId) -> Option<Self> { | ||
214 | let _p = profile("Module::from_file"); | ||
215 | let (krate, local_id) = db.relevant_crates(file).iter().find_map(|&crate_id| { | ||
216 | let crate_def_map = db.crate_def_map(crate_id); | ||
217 | let local_id = crate_def_map.modules_for_file(file).next()?; | ||
218 | Some((crate_id, local_id)) | ||
219 | })?; | ||
220 | Some(Module { id: ModuleId { krate, local_id } }) | ||
221 | } | ||
222 | } | ||
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 | } | ||