From 0dd26a2f5b7dab38ee0813e314e2bde269dd5883 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 20 Nov 2018 17:08:40 +0300 Subject: [PATCH] Use OO module API in completion --- crates/ra_analysis/src/completion/mod.rs | 25 +++-------- .../src/completion/reference_completion.rs | 31 +++++-------- .../ra_analysis/src/descriptors/module/mod.rs | 43 +++++++------------ 3 files changed, 31 insertions(+), 68 deletions(-) diff --git a/crates/ra_analysis/src/completion/mod.rs b/crates/ra_analysis/src/completion/mod.rs index 2e082705ea..5e3ee79dd8 100644 --- a/crates/ra_analysis/src/completion/mod.rs +++ b/crates/ra_analysis/src/completion/mod.rs @@ -2,7 +2,6 @@ mod reference_completion; use ra_editor::find_node_at_offset; use ra_syntax::{ - algo::find_leaf_at_offset, algo::visit::{visitor_ctx, VisitorCtx}, ast, AstNode, AtomEdit, @@ -12,8 +11,9 @@ use rustc_hash::{FxHashMap}; use crate::{ db::{self, SyntaxDatabase}, - descriptors::{DescriptorDatabase, module::ModuleSource}, - input::{FilesDatabase}, + descriptors::{ + module::{ModuleDescriptor} + }, Cancelable, FilePosition }; @@ -38,14 +38,7 @@ pub(crate) fn completions( original_file.reparse(&edit) }; - let leaf = match find_leaf_at_offset(original_file.syntax(), position.offset).left_biased() { - None => return Ok(None), - Some(it) => it, - }; - let source_root_id = db.file_source_root(position.file_id); - let module_tree = db.module_tree(source_root_id)?; - let module_source = ModuleSource::for_node(position.file_id, leaf); - let module_id = match module_tree.any_module_for_source(module_source) { + let module = match ModuleDescriptor::guess_from_position(db, position)? { None => return Ok(None), Some(it) => it, }; @@ -55,15 +48,7 @@ pub(crate) fn completions( // First, let's try to complete a reference to some declaration. if let Some(name_ref) = find_node_at_offset::(file.syntax(), position.offset) { has_completions = true; - reference_completion::completions( - &mut res, - db, - source_root_id, - &module_tree, - module_id, - &file, - name_ref, - )?; + reference_completion::completions(&mut res, db, &module, &file, name_ref)?; // special case, `trait T { fn foo(i_am_a_name_ref) {} }` if is_node::(name_ref.syntax()) { param_completions(name_ref.syntax(), &mut res); diff --git a/crates/ra_analysis/src/completion/reference_completion.rs b/crates/ra_analysis/src/completion/reference_completion.rs index 6c5fd0be6c..c94d9af75a 100644 --- a/crates/ra_analysis/src/completion/reference_completion.rs +++ b/crates/ra_analysis/src/completion/reference_completion.rs @@ -9,20 +9,16 @@ use ra_syntax::{ use crate::{ db::RootDatabase, - input::{SourceRootId}, completion::CompletionItem, - descriptors::module::{ModuleId, ModuleTree}, + descriptors::module::{ModuleDescriptor}, descriptors::function::FnScopes, - descriptors::DescriptorDatabase, Cancelable }; pub(super) fn completions( acc: &mut Vec, db: &RootDatabase, - source_root_id: SourceRootId, - module_tree: &ModuleTree, - module_id: ModuleId, + module: &ModuleDescriptor, file: &SourceFileNode, name_ref: ast::NameRef, ) -> Cancelable<()> { @@ -40,7 +36,7 @@ pub(super) fn completions( complete_expr_snippets(acc); } - let module_scope = db.module_scope(source_root_id, module_id)?; + let module_scope = module.scope(db)?; acc.extend( module_scope .entries() @@ -56,9 +52,7 @@ pub(super) fn completions( }), ); } - NameRefKind::CratePath(path) => { - complete_path(acc, db, source_root_id, module_tree, module_id, path)? - } + NameRefKind::CratePath(path) => complete_path(acc, db, module, path)?, NameRefKind::BareIdentInMod => { let name_range = name_ref.syntax().range(); let top_node = name_ref @@ -171,16 +165,14 @@ fn complete_fn(name_ref: ast::NameRef, scopes: &FnScopes, acc: &mut Vec, db: &RootDatabase, - source_root_id: SourceRootId, - module_tree: &ModuleTree, - module_id: ModuleId, + module: &ModuleDescriptor, crate_path: Vec, ) -> Cancelable<()> { - let target_module_id = match find_target_module(module_tree, module_id, crate_path) { + let target_module = match find_target_module(module, crate_path) { None => return Ok(()), Some(it) => it, }; - let module_scope = db.module_scope(source_root_id, target_module_id)?; + let module_scope = target_module.scope(db)?; let completions = module_scope.entries().iter().map(|entry| CompletionItem { label: entry.name().to_string(), lookup: None, @@ -191,14 +183,13 @@ fn complete_path( } fn find_target_module( - module_tree: &ModuleTree, - module_id: ModuleId, + module: &ModuleDescriptor, mut crate_path: Vec, -) -> Option { +) -> Option { crate_path.pop(); - let mut target_module = module_id.root(&module_tree); + let mut target_module = module.crate_root(); for name in crate_path { - target_module = target_module.child(module_tree, name.text().as_str())?; + target_module = target_module.child(name.text().as_str())?; } Some(target_module) } diff --git a/crates/ra_analysis/src/descriptors/module/mod.rs b/crates/ra_analysis/src/descriptors/module/mod.rs index d0560244a1..a894025eda 100644 --- a/crates/ra_analysis/src/descriptors/module/mod.rs +++ b/crates/ra_analysis/src/descriptors/module/mod.rs @@ -15,6 +15,7 @@ use relative_path::RelativePathBuf; use crate::{ db::SyntaxDatabase, syntax_ptr::SyntaxPtr, FileId, FilePosition, Cancelable, descriptors::DescriptorDatabase, + input::SourceRootId }; pub(crate) use self::scope::ModuleScope; @@ -24,6 +25,7 @@ pub(crate) use self::scope::ModuleScope; #[derive(Debug, Clone)] pub(crate) struct ModuleDescriptor { tree: Arc, + source_root_id: SourceRootId, module_id: ModuleId, } @@ -59,13 +61,14 @@ impl ModuleDescriptor { file_id: FileId, module_source: ModuleSource, ) -> Cancelable> { - let source_root = db.file_source_root(file_id); - let module_tree = db.module_tree(source_root)?; + let source_root_id = db.file_source_root(file_id); + let module_tree = db.module_tree(source_root_id)?; let res = match module_tree.any_module_for_source(module_source) { None => None, Some(module_id) => Some(ModuleDescriptor { tree: module_tree, + source_root_id, module_id, }), }; @@ -92,8 +95,8 @@ impl ModuleDescriptor { pub fn parent(&self) -> Option { let parent_id = self.module_id.parent(&self.tree)?; Some(ModuleDescriptor { - tree: Arc::clone(&self.tree), module_id: parent_id, + ..self.clone() }) } @@ -109,13 +112,20 @@ impl ModuleDescriptor { let link = self.module_id.parent_link(&self.tree)?; Some(link.name(&self.tree)) } + + /// Finds a child module with the specified name. pub fn child(&self, name: &str) -> Option { let child_id = self.module_id.child(&self.tree, name)?; Some(ModuleDescriptor { - tree: Arc::clone(&self.tree), module_id: child_id, + ..self.clone() }) } + + /// 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) + } } /// Phisically, rust source is organized as a set of files, but logically it is @@ -190,20 +200,7 @@ impl ModuleId { let link = self.parent_link(tree)?; Some(tree.link(link).owner) } - pub(crate) fn root(self, tree: &ModuleTree) -> ModuleId { - let mut curr = self; - let mut i = 0; - while let Some(next) = curr.parent(tree) { - curr = next; - i += 1; - // simplistic cycle detection - if i > 100 { - return self; - } - } - curr - } - pub(crate) fn child(self, tree: &ModuleTree, name: &str) -> Option { + fn child(self, tree: &ModuleTree, name: &str) -> Option { let link = tree .module(self) .children @@ -260,16 +257,6 @@ struct ModuleData { } impl ModuleSource { - pub(crate) fn for_node(file_id: FileId, node: SyntaxNodeRef) -> ModuleSource { - for node in node.ancestors() { - if let Some(m) = ast::Module::cast(node) { - if !m.has_semi() { - return ModuleSource::new_inline(file_id, m); - } - } - } - ModuleSource::SourceFile(file_id) - } pub(crate) fn new_inline(file_id: FileId, module: ast::Module) -> ModuleSource { assert!(!module.has_semi()); let ptr = SyntaxPtr::new(file_id, module.syntax());