//! Name resolution algorithm use rustc_hash::FxHashMap; use ra_syntax::{ SmolStr, SyntaxKind, ast::{self, NameOwner} }; use crate::{ descriptors::module::ModuleId, syntax_ptr::LocalSyntaxPtr, }; /// A set of items and imports declared inside a module, without relation to /// other modules. /// /// This stands in-between raw syntax and name resolution and alow us to avoid /// recomputing name res: if `InputModuleItems` are the same, we can avoid /// running name resolution. #[derive(Debug, Default)] struct InputModuleItems { items: Vec, glob_imports: Vec, imports: Vec, } #[derive(Debug, Clone)] struct Path { kind: PathKind, segments: Vec, } #[derive(Debug, Clone, Copy)] enum PathKind { Abs, Self_, Super, Crate, } #[derive(Debug)] struct ItemMap { per_module: FxHashMap, } #[derive(Debug)] struct ModuleItems { items: FxHashMap>, } #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] enum Namespace { Types, Values, } #[derive(Debug)] struct PerNs { types: Option, values: Option, } #[derive(Debug)] struct ModuleItem { ptr: LocalSyntaxPtr, name: SmolStr, kind: SyntaxKind, vis: Vis, } #[derive(Debug)] enum Vis { Priv, Other, } impl InputModuleItems { fn new<'a>(items: impl Iterator>) -> InputModuleItems { let mut res = InputModuleItems::default(); for item in items { res.add_item(item); } res } fn add_item(&mut self, item: ast::ModuleItem) -> Option<()> { match item { ast::ModuleItem::StructDef(it) => self.items.push(ModuleItem::new(it)?), ast::ModuleItem::EnumDef(it) => self.items.push(ModuleItem::new(it)?), ast::ModuleItem::FnDef(it) => self.items.push(ModuleItem::new(it)?), ast::ModuleItem::TraitDef(it) => self.items.push(ModuleItem::new(it)?), ast::ModuleItem::TypeDef(it) => self.items.push(ModuleItem::new(it)?), ast::ModuleItem::ImplItem(it) => { // impls don't define items } ast::ModuleItem::UseItem(it) => self.add_use_item(it), ast::ModuleItem::ExternCrateItem(it) => (), ast::ModuleItem::ConstDef(it) => self.items.push(ModuleItem::new(it)?), ast::ModuleItem::StaticDef(it) => self.items.push(ModuleItem::new(it)?), ast::ModuleItem::Module(it) => self.items.push(ModuleItem::new(it)?), } Some(()) } fn add_use_item(&mut self, item: ast::UseItem) { if let Some(tree) = item.use_tree() { self.add_use_tree(None, tree); } } fn add_use_tree(&mut self, prefix: Option, tree: ast::UseTree) { if let Some(use_tree_list) = tree.use_tree_list() { let prefix = match tree.path() { None => prefix, Some(path) => match convert_path(prefix, path) { Some(it) => Some(it), None => return, // TODO: report errors somewhere }, }; for tree in use_tree_list.use_trees() { self.add_use_tree(prefix.clone(), tree); } } else { if let Some(path) = tree.path() { if let Some(path) = convert_path(prefix, path) { if tree.has_star() { &mut self.glob_imports } else { &mut self.imports } .push(path); } } } } } fn convert_path(prefix: Option, path: ast::Path) -> Option { prefix } impl ModuleItem { fn new<'a>(item: impl ast::NameOwner<'a>) -> Option { let name = item.name()?.text(); let ptr = LocalSyntaxPtr::new(item.syntax()); let kind = item.syntax().kind(); let vis = Vis::Other; let res = ModuleItem { ptr, name, kind, vis, }; Some(res) } }