From 5f8068cea83b4f74ca3a9afb033a405d79727140 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 20 Nov 2018 18:34:10 +0300 Subject: make mod private --- crates/ra_analysis/src/descriptors/module/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'crates/ra_analysis/src/descriptors') diff --git a/crates/ra_analysis/src/descriptors/module/mod.rs b/crates/ra_analysis/src/descriptors/module/mod.rs index 047454cff..091c150e5 100644 --- a/crates/ra_analysis/src/descriptors/module/mod.rs +++ b/crates/ra_analysis/src/descriptors/module/mod.rs @@ -1,5 +1,5 @@ pub(super) mod imp; -pub(crate) mod scope; +mod scope; use std::sync::Arc; -- cgit v1.2.3 From bcdcfa9df222667e6bfcbb1a8923bdc55bd57dc0 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 20 Nov 2018 19:24:58 +0300 Subject: Some import resolution boilerplate --- crates/ra_analysis/src/descriptors/module/mod.rs | 1 + .../ra_analysis/src/descriptors/module/nameres.rs | 156 +++++++++++++++++++++ 2 files changed, 157 insertions(+) create mode 100644 crates/ra_analysis/src/descriptors/module/nameres.rs (limited to 'crates/ra_analysis/src/descriptors') diff --git a/crates/ra_analysis/src/descriptors/module/mod.rs b/crates/ra_analysis/src/descriptors/module/mod.rs index 091c150e5..958487541 100644 --- a/crates/ra_analysis/src/descriptors/module/mod.rs +++ b/crates/ra_analysis/src/descriptors/module/mod.rs @@ -1,5 +1,6 @@ pub(super) mod imp; mod scope; +mod nameres; use std::sync::Arc; diff --git a/crates/ra_analysis/src/descriptors/module/nameres.rs b/crates/ra_analysis/src/descriptors/module/nameres.rs new file mode 100644 index 000000000..137aa8b17 --- /dev/null +++ b/crates/ra_analysis/src/descriptors/module/nameres.rs @@ -0,0 +1,156 @@ +//! 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) + } +} -- cgit v1.2.3 From 8086107b6ac8555a226ceb294e2c633dfe36c6e1 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 20 Nov 2018 19:40:37 +0300 Subject: implement path conversion --- .../ra_analysis/src/descriptors/module/nameres.rs | 45 +++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) (limited to 'crates/ra_analysis/src/descriptors') diff --git a/crates/ra_analysis/src/descriptors/module/nameres.rs b/crates/ra_analysis/src/descriptors/module/nameres.rs index 137aa8b17..b65b6adb7 100644 --- a/crates/ra_analysis/src/descriptors/module/nameres.rs +++ b/crates/ra_analysis/src/descriptors/module/nameres.rs @@ -136,7 +136,50 @@ impl InputModuleItems { } fn convert_path(prefix: Option, path: ast::Path) -> Option { - prefix + let prefix = if let Some(qual) = path.qualifier() { + Some(convert_path(prefix, qual)?) + } else { + None + }; + let segment = path.segment()?; + let res = match segment.kind()? { + ast::PathSegmentKind::Name(name) => { + let mut res = prefix.unwrap_or_else(|| Path { + kind: PathKind::Abs, + segments: Vec::with_capacity(1), + }); + res.segments.push(name.text()); + res + } + ast::PathSegmentKind::CrateKw => { + if prefix.is_some() { + return None; + } + Path { + kind: PathKind::Crate, + segments: Vec::new(), + } + } + ast::PathSegmentKind::SelfKw => { + if prefix.is_some() { + return None; + } + Path { + kind: PathKind::Self_, + segments: Vec::new(), + } + } + ast::PathSegmentKind::SuperKw => { + if prefix.is_some() { + return None; + } + Path { + kind: PathKind::Super, + segments: Vec::new(), + } + } + }; + Some(res) } impl ModuleItem { -- cgit v1.2.3 From c54b51fdedd21b0367af7cb3fac3bc16d21b8cc1 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 20 Nov 2018 21:12:15 +0300 Subject: add DefId --- crates/ra_analysis/src/descriptors/module/nameres.rs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) (limited to 'crates/ra_analysis/src/descriptors') diff --git a/crates/ra_analysis/src/descriptors/module/nameres.rs b/crates/ra_analysis/src/descriptors/module/nameres.rs index b65b6adb7..8002656d6 100644 --- a/crates/ra_analysis/src/descriptors/module/nameres.rs +++ b/crates/ra_analysis/src/descriptors/module/nameres.rs @@ -7,6 +7,7 @@ use ra_syntax::{ }; use crate::{ + loc2id::DefId, descriptors::module::ModuleId, syntax_ptr::LocalSyntaxPtr, }; @@ -45,7 +46,8 @@ struct ItemMap { #[derive(Debug)] struct ModuleItems { - items: FxHashMap>, + items: FxHashMap>, + import_resolutions: FxHashMap, } #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] @@ -197,3 +199,14 @@ impl ModuleItem { Some(res) } } + +struct Resolver { + input: FxHashMap, + result: ModuleItems, +} + +impl Resolver { + fn resolve(&mut self){ + + } +} -- cgit v1.2.3 From 1cf92c3e286232be7e0d1370b88547ca0cb6f636 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 20 Nov 2018 21:17:14 +0300 Subject: remember spans with paths --- crates/ra_analysis/src/descriptors/module/nameres.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'crates/ra_analysis/src/descriptors') diff --git a/crates/ra_analysis/src/descriptors/module/nameres.rs b/crates/ra_analysis/src/descriptors/module/nameres.rs index 8002656d6..18e8342b3 100644 --- a/crates/ra_analysis/src/descriptors/module/nameres.rs +++ b/crates/ra_analysis/src/descriptors/module/nameres.rs @@ -3,7 +3,7 @@ use rustc_hash::FxHashMap; use ra_syntax::{ SmolStr, SyntaxKind, - ast::{self, NameOwner} + ast::{self, NameOwner, AstNode} }; use crate::{ @@ -28,7 +28,7 @@ struct InputModuleItems { #[derive(Debug, Clone)] struct Path { kind: PathKind, - segments: Vec, + segments: Vec<(LocalSyntaxPtr, SmolStr)>, } #[derive(Debug, Clone, Copy)] @@ -150,7 +150,8 @@ fn convert_path(prefix: Option, path: ast::Path) -> Option { kind: PathKind::Abs, segments: Vec::with_capacity(1), }); - res.segments.push(name.text()); + let ptr = LocalSyntaxPtr::new(name.syntax()); + res.segments.push((ptr, name.text())); res } ast::PathSegmentKind::CrateKw => { -- cgit v1.2.3 From cc8163439f65138c0945c37d6bddc64ced2d2143 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 20 Nov 2018 21:50:22 +0300 Subject: populate modules --- crates/ra_analysis/src/descriptors/module/mod.rs | 7 ++ .../ra_analysis/src/descriptors/module/nameres.rs | 74 +++++++++++++++++++--- 2 files changed, 71 insertions(+), 10 deletions(-) (limited to 'crates/ra_analysis/src/descriptors') diff --git a/crates/ra_analysis/src/descriptors/module/mod.rs b/crates/ra_analysis/src/descriptors/module/mod.rs index 958487541..f49e7f909 100644 --- a/crates/ra_analysis/src/descriptors/module/mod.rs +++ b/crates/ra_analysis/src/descriptors/module/mod.rs @@ -214,6 +214,13 @@ impl ModuleId { .find(|it| it.name == name)?; Some(*link.points_to.first()?) } + fn children<'a>(self, tree: &'a ModuleTree) -> impl Iterator + 'a { + tree.module(self).children.iter().filter_map(move |&it| { + let link = tree.link(it); + let module = *link.points_to.first()?; + Some((link.name.clone(), module)) + }) + } fn problems(self, tree: &ModuleTree, db: &impl SyntaxDatabase) -> Vec<(SyntaxNode, Problem)> { tree.module(self) .children diff --git a/crates/ra_analysis/src/descriptors/module/nameres.rs b/crates/ra_analysis/src/descriptors/module/nameres.rs index 18e8342b3..6ff8e61f5 100644 --- a/crates/ra_analysis/src/descriptors/module/nameres.rs +++ b/crates/ra_analysis/src/descriptors/module/nameres.rs @@ -1,15 +1,21 @@ //! Name resolution algorithm +use std::sync::Arc; + use rustc_hash::FxHashMap; use ra_syntax::{ - SmolStr, SyntaxKind, + SmolStr, SyntaxKind::{self, *}, ast::{self, NameOwner, AstNode} }; use crate::{ - loc2id::DefId, - descriptors::module::ModuleId, - syntax_ptr::LocalSyntaxPtr, + loc2id::{DefId, DefLoc}, + descriptors::{ + DescriptorDatabase, + module::{ModuleId, ModuleTree}, + }, + syntax_ptr::{LocalSyntaxPtr, SyntaxPtr}, + input::SourceRootId, }; /// A set of items and imports declared inside a module, without relation to @@ -44,9 +50,9 @@ struct ItemMap { per_module: FxHashMap, } -#[derive(Debug)] +#[derive(Debug, Default)] struct ModuleItems { - items: FxHashMap>, + items: FxHashMap, import_resolutions: FxHashMap, } @@ -201,13 +207,61 @@ impl ModuleItem { } } -struct Resolver { +struct Resolver<'a, DB> { + db: &'a DB, + source_root: SourceRootId, + module_tree: Arc, input: FxHashMap, - result: ModuleItems, + result: ItemMap, +} + +impl<'a, DB> Resolver<'a, DB> +where + DB: DescriptorDatabase, +{ + fn resolve(&mut self) { + for (&module_id, items) in self.input.iter() { + populate_module( + self.db, + self.source_root, + &*self.module_tree, + &mut self.result, + module_id, + items, + ) + } + } } -impl Resolver { - fn resolve(&mut self){ +fn populate_module( + db: &impl DescriptorDatabase, + source_root: SourceRootId, + module_tree: &ModuleTree, + item_map: &mut ItemMap, + module_id: ModuleId, + input: &InputModuleItems, +) { + let file_id = module_id.source(module_tree).file_id(); + let mut module_items = ModuleItems::default(); + + for item in input.items.iter() { + if item.kind == MODULE { + // handle submodules separatelly + continue; + } + let ptr = item.ptr.into_global(file_id); + let def_loc = DefLoc::Item { ptr }; + let def_id = db.id_maps().def_id(def_loc); + module_items.items.insert(item.name.clone(), def_id); + } + + for (name, mod_id) in module_id.children(module_tree) { + let def_loc = DefLoc::Module { + id: mod_id, + source_root, + }; } + + item_map.per_module.insert(module_id, module_items); } -- cgit v1.2.3 From aab71bff8eb89fb65f4aba8e90df2ae586ecb0a6 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 20 Nov 2018 23:36:53 +0300 Subject: move to method --- .../ra_analysis/src/descriptors/module/nameres.rs | 63 +++++++++++----------- 1 file changed, 30 insertions(+), 33 deletions(-) (limited to 'crates/ra_analysis/src/descriptors') diff --git a/crates/ra_analysis/src/descriptors/module/nameres.rs b/crates/ra_analysis/src/descriptors/module/nameres.rs index 6ff8e61f5..44059e5c3 100644 --- a/crates/ra_analysis/src/descriptors/module/nameres.rs +++ b/crates/ra_analysis/src/descriptors/module/nameres.rs @@ -209,9 +209,9 @@ impl ModuleItem { struct Resolver<'a, DB> { db: &'a DB, + input: &'a FxHashMap, source_root: SourceRootId, module_tree: Arc, - input: FxHashMap, result: ItemMap, } @@ -221,47 +221,44 @@ where { fn resolve(&mut self) { for (&module_id, items) in self.input.iter() { - populate_module( - self.db, - self.source_root, - &*self.module_tree, - &mut self.result, + self.populate_module( module_id, items, ) } } -} -fn populate_module( - db: &impl DescriptorDatabase, - source_root: SourceRootId, - module_tree: &ModuleTree, - item_map: &mut ItemMap, - module_id: ModuleId, - input: &InputModuleItems, -) { - let file_id = module_id.source(module_tree).file_id(); + fn populate_module( + &mut self, + module_id: ModuleId, + input: &InputModuleItems, + ) { + let file_id = module_id.source(&self.module_tree).file_id(); - let mut module_items = ModuleItems::default(); + let mut module_items = ModuleItems::default(); - for item in input.items.iter() { - if item.kind == MODULE { - // handle submodules separatelly - continue; + for item in input.items.iter() { + if item.kind == MODULE { + // handle submodules separatelly + continue; + } + let ptr = item.ptr.into_global(file_id); + let def_loc = DefLoc::Item { ptr }; + let def_id = self.db.id_maps().def_id(def_loc); + module_items.items.insert(item.name.clone(), def_id); } - let ptr = item.ptr.into_global(file_id); - let def_loc = DefLoc::Item { ptr }; - let def_id = db.id_maps().def_id(def_loc); - module_items.items.insert(item.name.clone(), def_id); - } - for (name, mod_id) in module_id.children(module_tree) { - let def_loc = DefLoc::Module { - id: mod_id, - source_root, - }; - } + for (name, mod_id) in module_id.children(&self.module_tree) { + let def_loc = DefLoc::Module { + id: mod_id, + source_root: self.source_root, + }; + let def_id = self.db.id_maps().def_id(def_loc); + module_items.items.insert(name, def_id); + } - item_map.per_module.insert(module_id, module_items); + self.result.per_module.insert(module_id, module_items); + } } + + -- cgit v1.2.3 From 9bb11aee44f377fdf2ce7bed5c09ccbcf30f9b57 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 21 Nov 2018 00:31:12 +0300 Subject: populate resolve from unresolved imports --- crates/ra_analysis/src/descriptors/module/mod.rs | 13 ++- .../ra_analysis/src/descriptors/module/nameres.rs | 100 ++++++++++++++++++--- 2 files changed, 97 insertions(+), 16 deletions(-) (limited to 'crates/ra_analysis/src/descriptors') diff --git a/crates/ra_analysis/src/descriptors/module/mod.rs b/crates/ra_analysis/src/descriptors/module/mod.rs index f49e7f909..2d0bfa64c 100644 --- a/crates/ra_analysis/src/descriptors/module/mod.rs +++ b/crates/ra_analysis/src/descriptors/module/mod.rs @@ -103,9 +103,11 @@ impl ModuleDescriptor { /// The root of the tree this module is part of pub fn crate_root(&self) -> ModuleDescriptor { - generate(Some(self.clone()), |it| it.parent()) - .last() - .unwrap() + let root_id = self.module_id.crate_root(&self.tree); + ModuleDescriptor { + module_id: root_id, + ..self.clone() + } } /// `name` is `None` for the crate's root module @@ -205,6 +207,11 @@ impl ModuleId { let link = self.parent_link(tree)?; Some(tree.link(link).owner) } + fn crate_root(self, tree: &ModuleTree) -> ModuleId { + generate(Some(self), move |it| it.parent(tree)) + .last() + .unwrap() + } fn child(self, tree: &ModuleTree, name: &str) -> Option { let link = tree .module(self) diff --git a/crates/ra_analysis/src/descriptors/module/nameres.rs b/crates/ra_analysis/src/descriptors/module/nameres.rs index 44059e5c3..058e64ad1 100644 --- a/crates/ra_analysis/src/descriptors/module/nameres.rs +++ b/crates/ra_analysis/src/descriptors/module/nameres.rs @@ -52,10 +52,18 @@ struct ItemMap { #[derive(Debug, Default)] struct ModuleItems { - items: FxHashMap, + items: FxHashMap, import_resolutions: FxHashMap, } +/// Resolution is basically `DefId` atm, but it should account for stuff like +/// multiple namespaces, ambiguity and errors. +#[derive(Debug, Clone)] +struct Resolution { + /// None for unresolved + def_id: Option, +} + #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] enum Namespace { Types, @@ -221,22 +229,27 @@ where { fn resolve(&mut self) { for (&module_id, items) in self.input.iter() { - self.populate_module( - module_id, - items, - ) + self.populate_module(module_id, items) + } + + for &module_id in self.input.keys() { + self.resolve_imports(module_id); } } - fn populate_module( - &mut self, - module_id: ModuleId, - input: &InputModuleItems, - ) { + fn populate_module(&mut self, module_id: ModuleId, input: &InputModuleItems) { let file_id = module_id.source(&self.module_tree).file_id(); let mut module_items = ModuleItems::default(); + for import in input.imports.iter() { + if let Some((_, name)) = import.segments.last() { + module_items + .items + .insert(name.clone(), Resolution { def_id: None }); + } + } + for item in input.items.iter() { if item.kind == MODULE { // handle submodules separatelly @@ -245,7 +258,10 @@ where let ptr = item.ptr.into_global(file_id); let def_loc = DefLoc::Item { ptr }; let def_id = self.db.id_maps().def_id(def_loc); - module_items.items.insert(item.name.clone(), def_id); + let resolution = Resolution { + def_id: Some(def_id), + }; + module_items.items.insert(item.name.clone(), resolution); } for (name, mod_id) in module_id.children(&self.module_tree) { @@ -254,11 +270,69 @@ where source_root: self.source_root, }; let def_id = self.db.id_maps().def_id(def_loc); - module_items.items.insert(name, def_id); + let resolution = Resolution { + def_id: Some(def_id), + }; + module_items.items.insert(name, resolution); } self.result.per_module.insert(module_id, module_items); } -} + fn resolve_imports(&mut self, module_id: ModuleId) { + for import in self.input[&module_id].imports.iter() { + self.resolve_import(module_id, import); + } + } + + fn resolve_import(&mut self, module_id: ModuleId, import: &Path) { + let mut curr = match import.kind { + // TODO: handle extern crates + PathKind::Abs => return, + PathKind::Self_ => module_id, + PathKind::Super => { + match module_id.parent(&self.module_tree) { + Some(it) => it, + // TODO: error + None => return, + } + } + PathKind::Crate => module_id.crate_root(&self.module_tree), + }; + + for (i, (ptr, name)) in import.segments.iter().enumerate() { + let is_last = i == import.segments.len() - 1; + + let def_id = match self.result.per_module[&curr].items.get(name) { + None => return, + Some(res) => match res.def_id { + Some(it) => it, + None => return, + }, + }; + + self.update(module_id, |items| { + items.import_resolutions.insert(*ptr, def_id); + }); + if !is_last { + curr = match self.db.id_maps().def_loc(def_id) { + DefLoc::Module { id, .. } => id, + _ => return, + } + } else { + self.update(module_id, |items| { + let res = Resolution { + def_id: Some(def_id), + }; + items.items.insert(name.clone(), res); + }) + } + } + } + + fn update(&mut self, module_id: ModuleId, f: impl FnOnce(&mut ModuleItems)) { + let module_items = self.result.per_module.get_mut(&module_id).unwrap(); + f(module_items) + } +} -- cgit v1.2.3 From 36aad851383c7fd1ca5ffaa99ba8cc96b85378c1 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 21 Nov 2018 00:39:50 +0300 Subject: add item map query --- crates/ra_analysis/src/descriptors/mod.rs | 6 +++++- crates/ra_analysis/src/descriptors/module/mod.rs | 2 +- crates/ra_analysis/src/descriptors/module/nameres.rs | 18 ++++++++++++++---- 3 files changed, 20 insertions(+), 6 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 a8489f89c..30bc5eca2 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}, + descriptors::module::{ModuleId, ModuleScope, ModuleTree, ModuleSource, nameres::ItemMap}, input::SourceRootId, loc2id::IdDatabase, syntax_ptr::LocalSyntaxPtr, @@ -25,6 +25,10 @@ salsa::query_group! { use fn function::imp::fn_scopes; } + fn _item_map(source_root_id: SourceRootId) -> Cancelable> { + type ItemMapQuery; + use fn module::nameres::item_map; + } fn _module_tree(source_root_id: SourceRootId) -> Cancelable> { type ModuleTreeQuery; use fn module::imp::module_tree; diff --git a/crates/ra_analysis/src/descriptors/module/mod.rs b/crates/ra_analysis/src/descriptors/module/mod.rs index 2d0bfa64c..124926a40 100644 --- a/crates/ra_analysis/src/descriptors/module/mod.rs +++ b/crates/ra_analysis/src/descriptors/module/mod.rs @@ -1,6 +1,6 @@ pub(super) mod imp; mod scope; -mod nameres; +pub(super) mod nameres; use std::sync::Arc; diff --git a/crates/ra_analysis/src/descriptors/module/nameres.rs b/crates/ra_analysis/src/descriptors/module/nameres.rs index 058e64ad1..657e5bd1c 100644 --- a/crates/ra_analysis/src/descriptors/module/nameres.rs +++ b/crates/ra_analysis/src/descriptors/module/nameres.rs @@ -9,6 +9,7 @@ use ra_syntax::{ }; use crate::{ + Cancelable, loc2id::{DefId, DefLoc}, descriptors::{ DescriptorDatabase, @@ -45,12 +46,21 @@ enum PathKind { Crate, } -#[derive(Debug)] -struct ItemMap { +pub(crate) fn item_map( + db: &impl DescriptorDatabase, + source_root: SourceRootId, +) -> Cancelable> { + unimplemented!() +} + +/// Item map is the result of the name resolution. Item map contains, for each +/// module, the set of visible items. +#[derive(Debug, PartialEq, Eq)] +pub(crate) struct ItemMap { per_module: FxHashMap, } -#[derive(Debug, Default)] +#[derive(Debug, Default, PartialEq, Eq)] struct ModuleItems { items: FxHashMap, import_resolutions: FxHashMap, @@ -58,7 +68,7 @@ struct ModuleItems { /// Resolution is basically `DefId` atm, but it should account for stuff like /// multiple namespaces, ambiguity and errors. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq, Eq)] struct Resolution { /// None for unresolved def_id: Option, -- cgit v1.2.3 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 From ff75ad13a45dc603d445b1491d65e17c4db9addb Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 21 Nov 2018 11:18:43 +0300 Subject: Measure time --- crates/ra_analysis/src/descriptors/module/nameres.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'crates/ra_analysis/src/descriptors') diff --git a/crates/ra_analysis/src/descriptors/module/nameres.rs b/crates/ra_analysis/src/descriptors/module/nameres.rs index 2fae93c9d..a354fa54c 100644 --- a/crates/ra_analysis/src/descriptors/module/nameres.rs +++ b/crates/ra_analysis/src/descriptors/module/nameres.rs @@ -1,5 +1,8 @@ //! Name resolution algorithm -use std::sync::Arc; +use std::{ + sync::Arc, + time::Instant, +}; use rustc_hash::FxHashMap; @@ -74,6 +77,7 @@ pub(crate) fn item_map( db: &impl DescriptorDatabase, source_root: SourceRootId, ) -> Cancelable> { + let start = Instant::now(); let module_tree = db._module_tree(source_root)?; let input = module_tree .modules() @@ -92,6 +96,8 @@ pub(crate) fn item_map( }; resolver.resolve()?; let res = resolver.result; + let elapsed = start.elapsed(); + log::info!("item_map: {:?}", elapsed); Ok(Arc::new(res)) } -- cgit v1.2.3 From b70b6bce19981df5d0cda6a0193fb9b07da6ea51 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 21 Nov 2018 11:35:25 +0300 Subject: Move to top --- .../ra_analysis/src/descriptors/module/nameres.rs | 26 +++++++++++----------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'crates/ra_analysis/src/descriptors') diff --git a/crates/ra_analysis/src/descriptors/module/nameres.rs b/crates/ra_analysis/src/descriptors/module/nameres.rs index a354fa54c..34127e78f 100644 --- a/crates/ra_analysis/src/descriptors/module/nameres.rs +++ b/crates/ra_analysis/src/descriptors/module/nameres.rs @@ -22,6 +22,19 @@ use crate::{ input::SourceRootId, }; +/// Item map is the result of the name resolution. Item map contains, for each +/// module, the set of visible items. +#[derive(Default, Debug, PartialEq, Eq)] +pub(crate) struct ItemMap { + per_module: FxHashMap, +} + +#[derive(Debug, Default, PartialEq, Eq)] +struct ModuleItems { + items: FxHashMap, + import_resolutions: FxHashMap, +} + /// A set of items and imports declared inside a module, without relation to /// other modules. /// @@ -101,19 +114,6 @@ pub(crate) fn item_map( 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(Default, Debug, PartialEq, Eq)] -pub(crate) struct ItemMap { - per_module: FxHashMap, -} - -#[derive(Debug, Default, PartialEq, Eq)] -struct ModuleItems { - items: FxHashMap, - import_resolutions: FxHashMap, -} - /// Resolution is basically `DefId` atm, but it should account for stuff like /// multiple namespaces, ambiguity and errors. #[derive(Debug, Clone, PartialEq, Eq)] -- cgit v1.2.3 From 049f8df93cca05af395ce873738dc85d5a25f3fc Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 21 Nov 2018 12:57:05 +0300 Subject: switch completion to new scope --- crates/ra_analysis/src/descriptors/mod.rs | 6 +- crates/ra_analysis/src/descriptors/module/imp.rs | 21 +--- crates/ra_analysis/src/descriptors/module/mod.rs | 9 +- .../ra_analysis/src/descriptors/module/nameres.rs | 60 +++++----- crates/ra_analysis/src/descriptors/module/scope.rs | 124 --------------------- 5 files changed, 43 insertions(+), 177 deletions(-) delete mode 100644 crates/ra_analysis/src/descriptors/module/scope.rs (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 a32042b84..6b56d92e1 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, InputModuleItems}}, + descriptors::module::{ModuleId, ModuleTree, ModuleSource, nameres::{ItemMap, InputModuleItems}}, input::SourceRootId, loc2id::IdDatabase, syntax_ptr::LocalSyntaxPtr, @@ -37,10 +37,6 @@ salsa::query_group! { type ModuleTreeQuery; use fn module::imp::module_tree; } - fn _module_scope(source_root_id: SourceRootId, module_id: ModuleId) -> Cancelable> { - type ModuleScopeQuery; - use fn module::imp::module_scope; - } fn _fn_syntax(fn_id: FnId) -> FnDefNode { type FnSyntaxQuery; // Don't retain syntax trees in memory diff --git a/crates/ra_analysis/src/descriptors/module/imp.rs b/crates/ra_analysis/src/descriptors/module/imp.rs index defe87216..d4dce861f 100644 --- a/crates/ra_analysis/src/descriptors/module/imp.rs +++ b/crates/ra_analysis/src/descriptors/module/imp.rs @@ -1,7 +1,7 @@ use std::sync::Arc; use ra_syntax::{ - ast::{self, ModuleItemOwner, NameOwner}, + ast::{self, NameOwner}, SmolStr, }; use relative_path::RelativePathBuf; @@ -15,7 +15,7 @@ use crate::{ }; use super::{ - LinkData, LinkId, ModuleData, ModuleId, ModuleScope, ModuleSource, ModuleSourceNode, + LinkData, LinkId, ModuleData, ModuleId, ModuleSource, ModuleSourceNode, ModuleTree, Problem, }; @@ -81,23 +81,6 @@ pub(crate) fn modules<'a>( }) } -pub(crate) fn module_scope( - db: &impl DescriptorDatabase, - source_root_id: SourceRootId, - module_id: ModuleId, -) -> Cancelable> { - let tree = db._module_tree(source_root_id)?; - let source = module_id.source(&tree).resolve(db); - let res = match source { - ModuleSourceNode::SourceFile(it) => ModuleScope::new(it.borrowed().items()), - ModuleSourceNode::Module(it) => match it.borrowed().item_list() { - Some(items) => ModuleScope::new(items.items()), - None => ModuleScope::new(std::iter::empty()), - }, - }; - Ok(Arc::new(res)) -} - pub(crate) fn module_tree( db: &impl DescriptorDatabase, source_root: SourceRootId, diff --git a/crates/ra_analysis/src/descriptors/module/mod.rs b/crates/ra_analysis/src/descriptors/module/mod.rs index 95d9bcc27..cfdffcdbc 100644 --- a/crates/ra_analysis/src/descriptors/module/mod.rs +++ b/crates/ra_analysis/src/descriptors/module/mod.rs @@ -1,5 +1,4 @@ pub(super) mod imp; -mod scope; pub(super) mod nameres; use std::sync::Arc; @@ -19,7 +18,7 @@ use crate::{ input::SourceRootId }; -pub(crate) use self::scope::ModuleScope; +pub(crate) use self::{nameres::ModuleScope}; /// `ModuleDescriptor` is API entry point to get all the information /// about a particular module. @@ -126,8 +125,10 @@ impl ModuleDescriptor { } /// Returns a `ModuleScope`: a set of items, visible in this module. - pub fn scope(&self, db: &impl DescriptorDatabase) -> Cancelable> { - db._module_scope(self.source_root_id, self.module_id) + pub(crate) fn scope(&self, db: &impl DescriptorDatabase) -> Cancelable { + let item_map = db._item_map(self.source_root_id)?; + let res = item_map.per_module[&self.module_id].clone(); + Ok(res) } pub fn problems(&self, db: &impl DescriptorDatabase) -> Vec<(SyntaxNode, Problem)> { diff --git a/crates/ra_analysis/src/descriptors/module/nameres.rs b/crates/ra_analysis/src/descriptors/module/nameres.rs index 34127e78f..c5bf467ca 100644 --- a/crates/ra_analysis/src/descriptors/module/nameres.rs +++ b/crates/ra_analysis/src/descriptors/module/nameres.rs @@ -8,7 +8,7 @@ use rustc_hash::FxHashMap; use ra_syntax::{ SmolStr, SyntaxKind::{self, *}, - ast::{self, NameOwner, AstNode, ModuleItemOwner} + ast::{self, AstNode, ModuleItemOwner} }; use crate::{ @@ -26,13 +26,13 @@ use crate::{ /// module, the set of visible items. #[derive(Default, Debug, PartialEq, Eq)] pub(crate) struct ItemMap { - per_module: FxHashMap, + pub(crate) per_module: FxHashMap, } -#[derive(Debug, Default, PartialEq, Eq)] -struct ModuleItems { - items: FxHashMap, - import_resolutions: FxHashMap, +#[derive(Debug, Default, PartialEq, Eq, Clone)] +pub(crate) struct ModuleScope { + pub(crate) items: FxHashMap, + pub(crate) import_resolutions: FxHashMap, } /// A set of items and imports declared inside a module, without relation to @@ -117,22 +117,25 @@ pub(crate) fn item_map( /// Resolution is basically `DefId` atm, but it should account for stuff like /// multiple namespaces, ambiguity and errors. #[derive(Debug, Clone, PartialEq, Eq)] -struct Resolution { +pub(crate) struct Resolution { /// None for unresolved - def_id: Option, + pub(crate) def_id: Option, + /// ident by whitch this is imported into local scope. + /// TODO: make this offset-independent. + pub(crate) import_name: Option, } -#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] -enum Namespace { - Types, - Values, -} +// #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +// enum Namespace { +// Types, +// Values, +// } -#[derive(Debug)] -struct PerNs { - types: Option, - values: Option, -} +// #[derive(Debug)] +// struct PerNs { +// types: Option, +// values: Option, +// } #[derive(Debug, PartialEq, Eq)] struct ModuleItem { @@ -144,7 +147,7 @@ struct ModuleItem { #[derive(Debug, PartialEq, Eq)] enum Vis { - Priv, + // Priv, Other, } @@ -302,13 +305,17 @@ where fn populate_module(&mut self, module_id: ModuleId, input: &InputModuleItems) { let file_id = module_id.source(&self.module_tree).file_id(); - let mut module_items = ModuleItems::default(); + let mut module_items = ModuleScope::default(); for import in input.imports.iter() { - if let Some((_, name)) = import.segments.last() { - module_items - .items - .insert(name.clone(), Resolution { def_id: None }); + if let Some((ptr, name)) = import.segments.last() { + module_items.items.insert( + name.clone(), + Resolution { + def_id: None, + import_name: Some(*ptr), + }, + ); } } @@ -322,6 +329,7 @@ where let def_id = self.db.id_maps().def_id(def_loc); let resolution = Resolution { def_id: Some(def_id), + import_name: None, }; module_items.items.insert(item.name.clone(), resolution); } @@ -334,6 +342,7 @@ where let def_id = self.db.id_maps().def_id(def_loc); let resolution = Resolution { def_id: Some(def_id), + import_name: None, }; module_items.items.insert(name, resolution); } @@ -386,6 +395,7 @@ where self.update(module_id, |items| { let res = Resolution { def_id: Some(def_id), + import_name: Some(*ptr), }; items.items.insert(name.clone(), res); }) @@ -393,7 +403,7 @@ where } } - fn update(&mut self, module_id: ModuleId, f: impl FnOnce(&mut ModuleItems)) { + fn update(&mut self, module_id: ModuleId, f: impl FnOnce(&mut ModuleScope)) { let module_items = self.result.per_module.get_mut(&module_id).unwrap(); f(module_items) } diff --git a/crates/ra_analysis/src/descriptors/module/scope.rs b/crates/ra_analysis/src/descriptors/module/scope.rs deleted file mode 100644 index 4490228e4..000000000 --- a/crates/ra_analysis/src/descriptors/module/scope.rs +++ /dev/null @@ -1,124 +0,0 @@ -//! Backend for module-level scope resolution & completion - -use ra_syntax::{ast, AstNode, SmolStr}; - -use crate::syntax_ptr::LocalSyntaxPtr; - -/// `ModuleScope` contains all named items declared in the scope. -#[derive(Debug, PartialEq, Eq)] -pub(crate) struct ModuleScope { - entries: Vec, -} - -/// `Entry` is a single named declaration iside a module. -#[derive(Debug, PartialEq, Eq)] -pub(crate) struct Entry { - ptr: LocalSyntaxPtr, - kind: EntryKind, - name: SmolStr, -} - -#[derive(Debug, PartialEq, Eq)] -enum EntryKind { - Item, - Import, -} - -impl ModuleScope { - pub(super) fn new<'a>(items: impl Iterator>) -> ModuleScope { - let mut entries = Vec::new(); - for item in items { - let entry = match item { - ast::ModuleItem::StructDef(item) => Entry::new(item), - ast::ModuleItem::EnumDef(item) => Entry::new(item), - ast::ModuleItem::FnDef(item) => Entry::new(item), - ast::ModuleItem::ConstDef(item) => Entry::new(item), - ast::ModuleItem::StaticDef(item) => Entry::new(item), - ast::ModuleItem::TraitDef(item) => Entry::new(item), - ast::ModuleItem::TypeDef(item) => Entry::new(item), - ast::ModuleItem::Module(item) => Entry::new(item), - ast::ModuleItem::UseItem(item) => { - if let Some(tree) = item.use_tree() { - collect_imports(tree, &mut entries); - } - continue; - } - ast::ModuleItem::ExternCrateItem(_) | ast::ModuleItem::ImplItem(_) => continue, - }; - entries.extend(entry) - } - - ModuleScope { entries } - } - - pub fn entries(&self) -> &[Entry] { - self.entries.as_slice() - } -} - -impl Entry { - fn new<'a>(item: impl ast::NameOwner<'a>) -> Option { - let name = item.name()?; - Some(Entry { - name: name.text(), - ptr: LocalSyntaxPtr::new(name.syntax()), - kind: EntryKind::Item, - }) - } - fn new_import(path: ast::Path) -> Option { - let name_ref = path.segment()?.name_ref()?; - Some(Entry { - name: name_ref.text(), - ptr: LocalSyntaxPtr::new(name_ref.syntax()), - kind: EntryKind::Import, - }) - } - pub fn name(&self) -> &SmolStr { - &self.name - } - pub fn ptr(&self) -> LocalSyntaxPtr { - self.ptr - } -} - -fn collect_imports(tree: ast::UseTree, acc: &mut Vec) { - if let Some(use_tree_list) = tree.use_tree_list() { - return use_tree_list - .use_trees() - .for_each(|it| collect_imports(it, acc)); - } - if let Some(path) = tree.path() { - acc.extend(Entry::new_import(path)); - } -} - -#[cfg(test)] -mod tests { - use super::*; - use ra_syntax::{ast::ModuleItemOwner, SourceFileNode}; - - fn do_check(code: &str, expected: &[&str]) { - let file = SourceFileNode::parse(&code); - let scope = ModuleScope::new(file.ast().items()); - let actual = scope.entries.iter().map(|it| it.name()).collect::>(); - assert_eq!(expected, actual.as_slice()); - } - - #[test] - fn test_module_scope() { - do_check( - " - struct Foo; - enum Bar {} - mod baz {} - fn quux() {} - use x::{ - y::z, - t, - }; - type T = (); - ", - &["Foo", "Bar", "baz", "quux", "z", "t", "T"], - ) - } -} -- cgit v1.2.3