From 02c4f823485fb5302b8f8eb6fee84122ca73979c Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 21 Nov 2018 11:16:46 +0300 Subject: simple test for item map --- crates/ra_analysis/src/descriptors/mod.rs | 6 +- crates/ra_analysis/src/descriptors/module/mod.rs | 7 ++ .../ra_analysis/src/descriptors/module/nameres.rs | 119 ++++++++++++++++++--- 3 files changed, 116 insertions(+), 16 deletions(-) (limited to 'crates/ra_analysis/src/descriptors') diff --git a/crates/ra_analysis/src/descriptors/mod.rs b/crates/ra_analysis/src/descriptors/mod.rs index 30bc5eca2..a32042b84 100644 --- a/crates/ra_analysis/src/descriptors/mod.rs +++ b/crates/ra_analysis/src/descriptors/mod.rs @@ -11,7 +11,7 @@ use ra_syntax::{ use crate::{ db::SyntaxDatabase, descriptors::function::{resolve_local_name, FnId, FnScopes}, - descriptors::module::{ModuleId, ModuleScope, ModuleTree, ModuleSource, nameres::ItemMap}, + descriptors::module::{ModuleId, ModuleScope, ModuleTree, ModuleSource, nameres::{ItemMap, InputModuleItems}}, input::SourceRootId, loc2id::IdDatabase, syntax_ptr::LocalSyntaxPtr, @@ -25,6 +25,10 @@ salsa::query_group! { use fn function::imp::fn_scopes; } + fn _input_module_items(source_root_id: SourceRootId, module_id: ModuleId) -> Cancelable> { + type InputModuleItemsQuery; + use fn module::nameres::input_module_items; + } fn _item_map(source_root_id: SourceRootId) -> Cancelable> { type ItemMapQuery; use fn module::nameres::item_map; diff --git a/crates/ra_analysis/src/descriptors/module/mod.rs b/crates/ra_analysis/src/descriptors/module/mod.rs index 124926a40..95d9bcc27 100644 --- a/crates/ra_analysis/src/descriptors/module/mod.rs +++ b/crates/ra_analysis/src/descriptors/module/mod.rs @@ -149,6 +149,13 @@ pub(crate) struct ModuleTree { } impl ModuleTree { + fn modules<'a>(&'a self) -> impl Iterator + 'a { + self.mods + .iter() + .enumerate() + .map(|(idx, _)| ModuleId(idx as u32)) + } + fn modules_for_source(&self, source: ModuleSource) -> Vec { self.mods .iter() diff --git a/crates/ra_analysis/src/descriptors/module/nameres.rs b/crates/ra_analysis/src/descriptors/module/nameres.rs index 657e5bd1c..2fae93c9d 100644 --- a/crates/ra_analysis/src/descriptors/module/nameres.rs +++ b/crates/ra_analysis/src/descriptors/module/nameres.rs @@ -5,7 +5,7 @@ use rustc_hash::FxHashMap; use ra_syntax::{ SmolStr, SyntaxKind::{self, *}, - ast::{self, NameOwner, AstNode} + ast::{self, NameOwner, AstNode, ModuleItemOwner} }; use crate::{ @@ -13,9 +13,9 @@ use crate::{ loc2id::{DefId, DefLoc}, descriptors::{ DescriptorDatabase, - module::{ModuleId, ModuleTree}, + module::{ModuleId, ModuleTree, ModuleSourceNode}, }, - syntax_ptr::{LocalSyntaxPtr, SyntaxPtr}, + syntax_ptr::{LocalSyntaxPtr}, input::SourceRootId, }; @@ -25,20 +25,20 @@ use crate::{ /// 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 { +#[derive(Debug, Default, PartialEq, Eq)] +pub(crate) struct InputModuleItems { items: Vec, glob_imports: Vec, imports: Vec, } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq, Eq)] struct Path { kind: PathKind, segments: Vec<(LocalSyntaxPtr, SmolStr)>, } -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] enum PathKind { Abs, Self_, @@ -46,16 +46,58 @@ enum PathKind { Crate, } +pub(crate) fn input_module_items( + db: &impl DescriptorDatabase, + source_root: SourceRootId, + module_id: ModuleId, +) -> Cancelable> { + let module_tree = db._module_tree(source_root)?; + let source = module_id.source(&module_tree); + let res = match source.resolve(db) { + ModuleSourceNode::SourceFile(it) => { + let items = it.borrowed().items(); + InputModuleItems::new(items) + } + ModuleSourceNode::Module(it) => { + let items = it + .borrowed() + .item_list() + .into_iter() + .flat_map(|it| it.items()); + InputModuleItems::new(items) + } + }; + Ok(Arc::new(res)) +} + pub(crate) fn item_map( db: &impl DescriptorDatabase, source_root: SourceRootId, ) -> Cancelable> { - unimplemented!() + let module_tree = db._module_tree(source_root)?; + let input = module_tree + .modules() + .map(|id| { + let items = db._input_module_items(source_root, id)?; + Ok((id, items)) + }) + .collect::>>()?; + + let mut resolver = Resolver { + db: db, + input: &input, + source_root, + module_tree, + result: ItemMap::default(), + }; + resolver.resolve()?; + let res = resolver.result; + Ok(Arc::new(res)) } /// Item map is the result of the name resolution. Item map contains, for each /// module, the set of visible items. -#[derive(Debug, PartialEq, Eq)] +#[derive(Default, Debug, PartialEq, Eq)] pub(crate) struct ItemMap { per_module: FxHashMap, } @@ -86,7 +128,7 @@ struct PerNs { values: Option, } -#[derive(Debug)] +#[derive(Debug, PartialEq, Eq)] struct ModuleItem { ptr: LocalSyntaxPtr, name: SmolStr, @@ -94,7 +136,7 @@ struct ModuleItem { vis: Vis, } -#[derive(Debug)] +#[derive(Debug, PartialEq, Eq)] enum Vis { Priv, Other, @@ -116,11 +158,13 @@ impl InputModuleItems { 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) => { + ast::ModuleItem::ImplItem(_) => { // impls don't define items } ast::ModuleItem::UseItem(it) => self.add_use_item(it), - ast::ModuleItem::ExternCrateItem(it) => (), + ast::ModuleItem::ExternCrateItem(_) => { + // TODO + } 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)?), @@ -227,7 +271,7 @@ impl ModuleItem { struct Resolver<'a, DB> { db: &'a DB, - input: &'a FxHashMap, + input: &'a FxHashMap>, source_root: SourceRootId, module_tree: Arc, result: ItemMap, @@ -237,14 +281,16 @@ impl<'a, DB> Resolver<'a, DB> where DB: DescriptorDatabase, { - fn resolve(&mut self) { + fn resolve(&mut self) -> Cancelable<()> { for (&module_id, items) in self.input.iter() { self.populate_module(module_id, items) } for &module_id in self.input.keys() { + crate::db::check_canceled(self.db)?; self.resolve_imports(module_id); } + Ok(()) } fn populate_module(&mut self, module_id: ModuleId, input: &InputModuleItems) { @@ -346,3 +392,46 @@ where f(module_items) } } + +#[cfg(test)] +mod tests { + use crate::{ + mock_analysis::analysis_and_position, + descriptors::{DescriptorDatabase, module::ModuleDescriptor}, + input::FilesDatabase, +}; + use super::*; + + fn item_map(fixture: &str) -> (Arc, ModuleId) { + let (analysis, pos) = analysis_and_position(fixture); + let db = analysis.imp.db; + let source_root = db.file_source_root(pos.file_id); + let descr = ModuleDescriptor::guess_from_position(&*db, pos) + .unwrap() + .unwrap(); + let module_id = descr.module_id; + (db._item_map(source_root).unwrap(), module_id) + } + + #[test] + fn test_item_map() { + let (item_map, module_id) = item_map( + " + //- /lib.rs + mod foo; + + use crate::foo::bar::Baz; + <|> + + //- /foo/mod.rs + pub mod bar; + + //- /foo/bar.rs + pub struct Baz; + ", + ); + let name = SmolStr::from("Baz"); + let resolution = &item_map.per_module[&module_id].items[&name]; + assert!(resolution.def_id.is_some()); + } +} -- cgit v1.2.3