diff options
author | Aleksey Kladov <[email protected]> | 2019-01-18 13:36:56 +0000 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2019-01-19 12:37:25 +0000 |
commit | c0aeb5204c010a11db2015113a7858b517415de1 (patch) | |
tree | 0a41b5828fde247ce21af57c182235e935d3ffb8 /crates/ra_hir/src/nameres | |
parent | b93c6bc5575db4acc5aa5867b6f0cc0dd37858f4 (diff) |
switched to lowerd module
Diffstat (limited to 'crates/ra_hir/src/nameres')
-rw-r--r-- | crates/ra_hir/src/nameres/lower.rs | 213 |
1 files changed, 193 insertions, 20 deletions
diff --git a/crates/ra_hir/src/nameres/lower.rs b/crates/ra_hir/src/nameres/lower.rs index 35bdbafbf..6bca14444 100644 --- a/crates/ra_hir/src/nameres/lower.rs +++ b/crates/ra_hir/src/nameres/lower.rs | |||
@@ -1,10 +1,11 @@ | |||
1 | use std::sync::Arc; | 1 | use std::sync::Arc; |
2 | 2 | ||
3 | use ra_syntax::{ | 3 | use ra_syntax::{ |
4 | TextRange, SyntaxKind, AstNode, | 4 | TextRange, SyntaxKind, AstNode, SourceFile, TreeArc, |
5 | ast::{self, ModuleItemOwner}, | 5 | ast::{self, ModuleItemOwner}, |
6 | }; | 6 | }; |
7 | use ra_db::{FileId, SourceRootId}; | 7 | use ra_db::{SourceRootId, LocalSyntaxPtr}; |
8 | use ra_arena::{Arena, RawId, impl_arena_id, map::ArenaMap}; | ||
8 | 9 | ||
9 | use crate::{ | 10 | use crate::{ |
10 | SourceItemId, SourceFileItemId, Path, ModuleSource, HirDatabase, Name, SourceFileItems, | 11 | SourceItemId, SourceFileItemId, Path, ModuleSource, HirDatabase, Name, SourceFileItems, |
@@ -139,12 +140,12 @@ impl InputModuleItems { | |||
139 | fn add_use_item(&mut self, file_items: &SourceFileItems, item: &ast::UseItem) { | 140 | fn add_use_item(&mut self, file_items: &SourceFileItems, item: &ast::UseItem) { |
140 | let file_item_id = file_items.id_of_unchecked(item.syntax()); | 141 | let file_item_id = file_items.id_of_unchecked(item.syntax()); |
141 | let start_offset = item.syntax().range().start(); | 142 | let start_offset = item.syntax().range().start(); |
142 | Path::expand_use_item(item, |path, range| { | 143 | Path::expand_use_item(item, |path, segment| { |
143 | let kind = match range { | 144 | let kind = match segment { |
144 | None => ImportKind::Glob, | 145 | None => ImportKind::Glob, |
145 | Some(range) => ImportKind::Named(NamedImport { | 146 | Some(segment) => ImportKind::Named(NamedImport { |
146 | file_item_id, | 147 | file_item_id, |
147 | relative_range: range - start_offset, | 148 | relative_range: segment.syntax().range() - start_offset, |
148 | }), | 149 | }), |
149 | }; | 150 | }; |
150 | self.imports.push(Import { kind, path }) | 151 | self.imports.push(Import { kind, path }) |
@@ -199,22 +200,194 @@ pub struct NamedImport { | |||
199 | pub relative_range: TextRange, | 200 | pub relative_range: TextRange, |
200 | } | 201 | } |
201 | 202 | ||
202 | impl NamedImport { | ||
203 | // FIXME: this is only here for one use-case in completion. Seems like a | ||
204 | // pretty gross special case. | ||
205 | pub fn range(&self, db: &impl HirDatabase, file_id: FileId) -> TextRange { | ||
206 | let source_item_id = SourceItemId { | ||
207 | file_id: file_id.into(), | ||
208 | item_id: Some(self.file_item_id), | ||
209 | }; | ||
210 | let syntax = db.file_item(source_item_id); | ||
211 | let offset = syntax.range().start(); | ||
212 | self.relative_range + offset | ||
213 | } | ||
214 | } | ||
215 | |||
216 | #[derive(Debug, Clone, PartialEq, Eq)] | 203 | #[derive(Debug, Clone, PartialEq, Eq)] |
217 | pub(super) enum ImportKind { | 204 | pub(super) enum ImportKind { |
218 | Glob, | 205 | Glob, |
219 | Named(NamedImport), | 206 | Named(NamedImport), |
220 | } | 207 | } |
208 | |||
209 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
210 | pub struct LoweredImport(RawId); | ||
211 | impl_arena_id!(LoweredImport); | ||
212 | |||
213 | #[derive(Debug, PartialEq, Eq)] | ||
214 | pub(super) struct ImportData { | ||
215 | pub(super) path: Path, | ||
216 | pub(super) is_glob: bool, | ||
217 | } | ||
218 | |||
219 | #[derive(Debug, Default, PartialEq, Eq)] | ||
220 | pub struct LoweredModule { | ||
221 | pub(super) items: Vec<ModuleItem>, | ||
222 | pub(super) imports: Arena<LoweredImport, ImportData>, | ||
223 | } | ||
224 | |||
225 | #[derive(Debug, Default, PartialEq, Eq)] | ||
226 | pub struct ImportSourceMap { | ||
227 | map: ArenaMap<LoweredImport, LocalSyntaxPtr>, | ||
228 | } | ||
229 | |||
230 | impl ImportSourceMap { | ||
231 | fn insert(&mut self, import: LoweredImport, segment: &ast::PathSegment) { | ||
232 | self.map | ||
233 | .insert(import, LocalSyntaxPtr::new(segment.syntax())) | ||
234 | } | ||
235 | |||
236 | pub fn get(&self, source: &ModuleSource, import: LoweredImport) -> TreeArc<ast::PathSegment> { | ||
237 | let file = match source { | ||
238 | ModuleSource::SourceFile(file) => &*file, | ||
239 | ModuleSource::Module(m) => m.syntax().ancestors().find_map(SourceFile::cast).unwrap(), | ||
240 | }; | ||
241 | |||
242 | ast::PathSegment::cast(&self.map[import].resolve(file)) | ||
243 | .unwrap() | ||
244 | .to_owned() | ||
245 | } | ||
246 | } | ||
247 | |||
248 | impl LoweredModule { | ||
249 | pub(crate) fn lower_module_module_query( | ||
250 | db: &impl HirDatabase, | ||
251 | source_root_id: SourceRootId, | ||
252 | module_id: ModuleId, | ||
253 | ) -> Arc<LoweredModule> { | ||
254 | db.lower_module(source_root_id, module_id).0 | ||
255 | } | ||
256 | |||
257 | pub(crate) fn lower_module_source_map_query( | ||
258 | db: &impl HirDatabase, | ||
259 | source_root_id: SourceRootId, | ||
260 | module_id: ModuleId, | ||
261 | ) -> Arc<ImportSourceMap> { | ||
262 | db.lower_module(source_root_id, module_id).1 | ||
263 | } | ||
264 | |||
265 | pub(crate) fn lower_module_query( | ||
266 | db: &impl HirDatabase, | ||
267 | source_root_id: SourceRootId, | ||
268 | module_id: ModuleId, | ||
269 | ) -> (Arc<LoweredModule>, Arc<ImportSourceMap>) { | ||
270 | let module_tree = db.module_tree(source_root_id); | ||
271 | let source = module_id.source(&module_tree); | ||
272 | let file_id = source.file_id; | ||
273 | let source = ModuleSource::from_source_item_id(db, source); | ||
274 | let mut source_map = ImportSourceMap::default(); | ||
275 | let mut res = LoweredModule::default(); | ||
276 | match source { | ||
277 | ModuleSource::SourceFile(it) => res.fill( | ||
278 | &mut source_map, | ||
279 | db, | ||
280 | source_root_id, | ||
281 | module_id, | ||
282 | file_id, | ||
283 | &mut it.items_with_macros(), | ||
284 | ), | ||
285 | ModuleSource::Module(it) => { | ||
286 | if let Some(item_list) = it.item_list() { | ||
287 | res.fill( | ||
288 | &mut source_map, | ||
289 | db, | ||
290 | source_root_id, | ||
291 | module_id, | ||
292 | file_id, | ||
293 | &mut item_list.items_with_macros(), | ||
294 | ) | ||
295 | } | ||
296 | } | ||
297 | }; | ||
298 | (Arc::new(res), Arc::new(source_map)) | ||
299 | } | ||
300 | |||
301 | fn fill( | ||
302 | &mut self, | ||
303 | source_map: &mut ImportSourceMap, | ||
304 | db: &impl HirDatabase, | ||
305 | source_root_id: SourceRootId, | ||
306 | module_id: ModuleId, | ||
307 | file_id: HirFileId, | ||
308 | items: &mut Iterator<Item = ast::ItemOrMacro>, | ||
309 | ) { | ||
310 | let file_items = db.file_items(file_id); | ||
311 | |||
312 | for item in items { | ||
313 | match item { | ||
314 | ast::ItemOrMacro::Item(it) => { | ||
315 | self.add_item(source_map, file_id, &file_items, it); | ||
316 | } | ||
317 | ast::ItemOrMacro::Macro(macro_call) => { | ||
318 | let item_id = file_items.id_of_unchecked(macro_call.syntax()); | ||
319 | let loc = MacroCallLoc { | ||
320 | source_root_id, | ||
321 | module_id, | ||
322 | source_item_id: SourceItemId { | ||
323 | file_id, | ||
324 | item_id: Some(item_id), | ||
325 | }, | ||
326 | }; | ||
327 | let id = loc.id(db); | ||
328 | let file_id = HirFileId::from(id); | ||
329 | let file_items = db.file_items(file_id); | ||
330 | //FIXME: expand recursively | ||
331 | for item in db.hir_source_file(file_id).items() { | ||
332 | self.add_item(source_map, file_id, &file_items, item); | ||
333 | } | ||
334 | } | ||
335 | } | ||
336 | } | ||
337 | } | ||
338 | |||
339 | fn add_item( | ||
340 | &mut self, | ||
341 | source_map: &mut ImportSourceMap, | ||
342 | file_id: HirFileId, | ||
343 | file_items: &SourceFileItems, | ||
344 | item: &ast::ModuleItem, | ||
345 | ) -> Option<()> { | ||
346 | match item.kind() { | ||
347 | ast::ModuleItemKind::StructDef(it) => { | ||
348 | self.items.push(ModuleItem::new(file_id, file_items, it)?) | ||
349 | } | ||
350 | ast::ModuleItemKind::EnumDef(it) => { | ||
351 | self.items.push(ModuleItem::new(file_id, file_items, it)?) | ||
352 | } | ||
353 | ast::ModuleItemKind::FnDef(it) => { | ||
354 | self.items.push(ModuleItem::new(file_id, file_items, it)?) | ||
355 | } | ||
356 | ast::ModuleItemKind::TraitDef(it) => { | ||
357 | self.items.push(ModuleItem::new(file_id, file_items, it)?) | ||
358 | } | ||
359 | ast::ModuleItemKind::TypeDef(it) => { | ||
360 | self.items.push(ModuleItem::new(file_id, file_items, it)?) | ||
361 | } | ||
362 | ast::ModuleItemKind::ImplBlock(_) => { | ||
363 | // impls don't define items | ||
364 | } | ||
365 | ast::ModuleItemKind::UseItem(it) => self.add_use_item(source_map, it), | ||
366 | ast::ModuleItemKind::ExternCrateItem(_) => { | ||
367 | // TODO | ||
368 | } | ||
369 | ast::ModuleItemKind::ConstDef(it) => { | ||
370 | self.items.push(ModuleItem::new(file_id, file_items, it)?) | ||
371 | } | ||
372 | ast::ModuleItemKind::StaticDef(it) => { | ||
373 | self.items.push(ModuleItem::new(file_id, file_items, it)?) | ||
374 | } | ||
375 | ast::ModuleItemKind::Module(it) => { | ||
376 | self.items.push(ModuleItem::new(file_id, file_items, it)?) | ||
377 | } | ||
378 | } | ||
379 | Some(()) | ||
380 | } | ||
381 | |||
382 | fn add_use_item(&mut self, source_map: &mut ImportSourceMap, item: &ast::UseItem) { | ||
383 | Path::expand_use_item(item, |path, segment| { | ||
384 | let import = self.imports.alloc(ImportData { | ||
385 | path, | ||
386 | is_glob: segment.is_none(), | ||
387 | }); | ||
388 | if let Some(segment) = segment { | ||
389 | source_map.insert(import, segment) | ||
390 | } | ||
391 | }) | ||
392 | } | ||
393 | } | ||