From 789772e8e5137c3769aa36b2a3c85ffec949e40e Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Fri, 18 Jan 2019 14:34:13 +0300 Subject: move input module items to the lower module --- crates/ra_hir/src/nameres/lower.rs | 200 +++++++++++++++++++++++++++++++++++++ 1 file changed, 200 insertions(+) create mode 100644 crates/ra_hir/src/nameres/lower.rs (limited to 'crates/ra_hir/src/nameres') diff --git a/crates/ra_hir/src/nameres/lower.rs b/crates/ra_hir/src/nameres/lower.rs new file mode 100644 index 000000000..dd3bf245f --- /dev/null +++ b/crates/ra_hir/src/nameres/lower.rs @@ -0,0 +1,200 @@ +use std::sync::Arc; + +use ra_syntax::{ + TextRange, SyntaxKind, AstNode, + ast::{self, ModuleItemOwner}, +}; +use ra_db::{FileId, SourceRootId}; + +use crate::{ + SourceItemId, SourceFileItemId, Path, ModuleSource, HirDatabase, Name, SourceFileItems, + HirFileId, MacroCallLoc, AsName, + module_tree::ModuleId +}; +/// A set of items and imports declared inside a module, without relation to +/// other modules. +/// +/// This sits in-between raw syntax and name resolution and allows us to avoid +/// recomputing name res: if two instance of `InputModuleItems` are the same, we +/// can avoid redoing name resolution. +#[derive(Debug, Default, PartialEq, Eq)] +pub struct InputModuleItems { + pub(crate) items: Vec, + pub(super) imports: Vec, +} + +impl InputModuleItems { + pub(crate) fn input_module_items_query( + db: &impl HirDatabase, + source_root_id: SourceRootId, + module_id: ModuleId, + ) -> Arc { + let module_tree = db.module_tree(source_root_id); + let source = module_id.source(&module_tree); + let file_id = source.file_id; + let source = ModuleSource::from_source_item_id(db, source); + let file_items = db.file_items(file_id); + let fill = |acc: &mut InputModuleItems, items: &mut Iterator| { + for item in items { + match item { + ast::ItemOrMacro::Item(it) => { + acc.add_item(file_id, &file_items, it); + } + ast::ItemOrMacro::Macro(macro_call) => { + let item_id = file_items.id_of_unchecked(macro_call.syntax()); + let loc = MacroCallLoc { + source_root_id, + module_id, + source_item_id: SourceItemId { + file_id, + item_id: Some(item_id), + }, + }; + let id = loc.id(db); + let file_id = HirFileId::from(id); + let file_items = db.file_items(file_id); + //FIXME: expand recursively + for item in db.hir_source_file(file_id).items() { + acc.add_item(file_id, &file_items, item); + } + } + } + } + }; + + let mut res = InputModuleItems::default(); + match source { + ModuleSource::SourceFile(it) => fill(&mut res, &mut it.items_with_macros()), + ModuleSource::Module(it) => { + if let Some(item_list) = it.item_list() { + fill(&mut res, &mut item_list.items_with_macros()) + } + } + }; + Arc::new(res) + } + + pub(crate) fn add_item( + &mut self, + file_id: HirFileId, + file_items: &SourceFileItems, + item: &ast::ModuleItem, + ) -> Option<()> { + match item.kind() { + ast::ModuleItemKind::StructDef(it) => { + self.items.push(ModuleItem::new(file_id, file_items, it)?) + } + ast::ModuleItemKind::EnumDef(it) => { + self.items.push(ModuleItem::new(file_id, file_items, it)?) + } + ast::ModuleItemKind::FnDef(it) => { + self.items.push(ModuleItem::new(file_id, file_items, it)?) + } + ast::ModuleItemKind::TraitDef(it) => { + self.items.push(ModuleItem::new(file_id, file_items, it)?) + } + ast::ModuleItemKind::TypeDef(it) => { + self.items.push(ModuleItem::new(file_id, file_items, it)?) + } + ast::ModuleItemKind::ImplBlock(_) => { + // impls don't define items + } + ast::ModuleItemKind::UseItem(it) => self.add_use_item(file_items, it), + ast::ModuleItemKind::ExternCrateItem(_) => { + // TODO + } + ast::ModuleItemKind::ConstDef(it) => { + self.items.push(ModuleItem::new(file_id, file_items, it)?) + } + ast::ModuleItemKind::StaticDef(it) => { + self.items.push(ModuleItem::new(file_id, file_items, it)?) + } + ast::ModuleItemKind::Module(it) => { + self.items.push(ModuleItem::new(file_id, file_items, it)?) + } + } + Some(()) + } + + fn add_use_item(&mut self, file_items: &SourceFileItems, item: &ast::UseItem) { + let file_item_id = file_items.id_of_unchecked(item.syntax()); + let start_offset = item.syntax().range().start(); + Path::expand_use_item(item, |path, range| { + let kind = match range { + None => ImportKind::Glob, + Some(range) => ImportKind::Named(NamedImport { + file_item_id, + relative_range: range - start_offset, + }), + }; + self.imports.push(Import { kind, path }) + }) + } +} + +#[derive(Debug, PartialEq, Eq)] +pub(super) enum Vis { + // Priv, + Other, +} + +#[derive(Debug, PartialEq, Eq)] +pub(crate) struct ModuleItem { + pub(crate) id: SourceItemId, + pub(crate) name: Name, + pub(super) kind: SyntaxKind, + pub(super) vis: Vis, +} + +impl ModuleItem { + fn new( + file_id: HirFileId, + file_items: &SourceFileItems, + item: &impl ast::NameOwner, + ) -> Option { + let name = item.name()?.as_name(); + let kind = item.syntax().kind(); + let vis = Vis::Other; + let item_id = Some(file_items.id_of_unchecked(item.syntax())); + let id = SourceItemId { file_id, item_id }; + let res = ModuleItem { + id, + name, + kind, + vis, + }; + Some(res) + } +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub(super) struct Import { + pub(super) path: Path, + pub(super) kind: ImportKind, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct NamedImport { + pub file_item_id: SourceFileItemId, + pub relative_range: TextRange, +} + +impl NamedImport { + // FIXME: this is only here for one use-case in completion. Seems like a + // pretty gross special case. + pub fn range(&self, db: &impl HirDatabase, file_id: FileId) -> TextRange { + let source_item_id = SourceItemId { + file_id: file_id.into(), + item_id: Some(self.file_item_id), + }; + let syntax = db.file_item(source_item_id); + let offset = syntax.range().start(); + self.relative_range + offset + } +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub(super) enum ImportKind { + Glob, + Named(NamedImport), +} -- cgit v1.2.3