From 397c235086cfaf5247d971c1867a38640895e014 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 7 Nov 2018 21:08:11 +0300 Subject: Use cached module scopes for completion --- crates/ra_analysis/src/completion/mod.rs | 25 ++++++- .../src/completion/reference_completion.rs | 78 +++++++++------------- crates/ra_analysis/src/descriptors/module/mod.rs | 12 +++- crates/ra_analysis/src/descriptors/module/scope.rs | 2 +- crates/ra_analysis/src/syntax_ptr.rs | 5 ++ 5 files changed, 71 insertions(+), 51 deletions(-) diff --git a/crates/ra_analysis/src/completion/mod.rs b/crates/ra_analysis/src/completion/mod.rs index 763533012..2e082705e 100644 --- a/crates/ra_analysis/src/completion/mod.rs +++ b/crates/ra_analysis/src/completion/mod.rs @@ -2,6 +2,7 @@ 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, @@ -11,6 +12,8 @@ use rustc_hash::{FxHashMap}; use crate::{ db::{self, SyntaxDatabase}, + descriptors::{DescriptorDatabase, module::ModuleSource}, + input::{FilesDatabase}, Cancelable, FilePosition }; @@ -35,12 +38,32 @@ 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) { + None => return Ok(None), + Some(it) => it, + }; + let mut res = Vec::new(); let mut has_completions = false; // 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, position.file_id, &file, name_ref)?; + reference_completion::completions( + &mut res, + db, + source_root_id, + &module_tree, + module_id, + &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 b08174968..13d4de9d5 100644 --- a/crates/ra_analysis/src/completion/reference_completion.rs +++ b/crates/ra_analysis/src/completion/reference_completion.rs @@ -3,24 +3,26 @@ use ra_editor::find_node_at_offset; use ra_syntax::{ algo::visit::{visitor, Visitor}, SourceFileNode, AstNode, - ast::{self, AstChildren, ModuleItemOwner, LoopBodyOwner}, + ast::{self, LoopBodyOwner}, SyntaxKind::*, }; use crate::{ db::RootDatabase, - input::FilesDatabase, + input::{SourceRootId}, completion::CompletionItem, - descriptors::module::{ModuleId, ModuleScope, ModuleTree, ModuleSource}, + descriptors::module::{ModuleId, ModuleScope, ModuleTree}, descriptors::function::FnScopes, descriptors::DescriptorDatabase, - FileId, Cancelable + Cancelable }; pub(super) fn completions( acc: &mut Vec, db: &RootDatabase, - file_id: FileId, + source_root_id: SourceRootId, + module_tree: &ModuleTree, + module_id: ModuleId, file: &SourceFileNode, name_ref: ast::NameRef, ) -> Cancelable<()> { @@ -28,14 +30,18 @@ pub(super) fn completions( Some(it) => it, None => return Ok(()), }; + match kind { NameRefKind::LocalRef => { - if let Some(fn_def) = complete_local_name(acc, &file, name_ref) { + let module_scope = db.module_scope(source_root_id, module_id)?; + if let Some(fn_def) = complete_local_name(acc, &module_scope, name_ref) { complete_expr_keywords(&file, fn_def, name_ref, acc); complete_expr_snippets(acc); } } - NameRefKind::CratePath(path) => complete_path(acc, db, file_id, path)?, + NameRefKind::CratePath(path) => { + complete_path(acc, db, source_root_id, module_tree, module_id, path)? + } NameRefKind::BareIdentInMod => { let name_range = name_ref.syntax().range(); let top_node = name_ref @@ -107,45 +113,26 @@ fn crate_path(mut path: ast::Path) -> Option> { fn complete_local_name<'a>( acc: &mut Vec, - file: &SourceFileNode, + module_scope: &ModuleScope, name_ref: ast::NameRef<'a>, ) -> Option> { - let mut enclosing_fn = None; - for node in name_ref.syntax().ancestors() { - if let Some(items) = visitor() - .visit::(|it| Some(it.items())) - .visit::(|it| Some(it.item_list()?.items())) - .accept(node) - { - if let Some(items) = items { - complete_module_items(file, items, Some(name_ref), acc); - } - break; - } else if enclosing_fn.is_none() { - if let Some(fn_def) = ast::FnDef::cast(node) { - enclosing_fn = Some(fn_def); - let scopes = FnScopes::new(fn_def); - complete_fn(name_ref, &scopes, acc); - } - } + let enclosing_fn = name_ref + .syntax() + .ancestors() + .take_while(|it| it.kind() != SOURCE_FILE && it.kind() != MODULE) + .find_map(ast::FnDef::cast); + if let Some(fn_def) = enclosing_fn { + let scopes = FnScopes::new(fn_def); + complete_fn(name_ref, &scopes, acc); } - enclosing_fn -} -fn complete_module_items( - file: &SourceFileNode, - items: AstChildren, - this_item: Option, - acc: &mut Vec, -) { - let scope = ModuleScope::new(items); // FIXME acc.extend( - scope + module_scope .entries() .iter() .filter(|entry| { - let syntax = entry.ptr().resolve(file); - Some(syntax.borrowed()) != this_item.map(|it| it.syntax()) + // Don't expose this item + !entry.ptr().range().is_subrange(&name_ref.syntax().range()) }) .map(|entry| CompletionItem { label: entry.name().to_string(), @@ -153,6 +140,7 @@ fn complete_module_items( snippet: None, }), ); + enclosing_fn } fn complete_fn(name_ref: ast::NameRef, scopes: &FnScopes, acc: &mut Vec) { @@ -180,16 +168,12 @@ fn complete_fn(name_ref: ast::NameRef, scopes: &FnScopes, acc: &mut Vec, db: &RootDatabase, - file_id: FileId, + source_root_id: SourceRootId, + module_tree: &ModuleTree, + module_id: ModuleId, crate_path: Vec, ) -> Cancelable<()> { - let source_root_id = db.file_source_root(file_id); - let module_tree = db.module_tree(source_root_id)?; - let module_id = match module_tree.any_module_for_source(ModuleSource::SourceFile(file_id)) { - None => return Ok(()), - Some(it) => it, - }; - let target_module_id = match find_target_module(&module_tree, module_id, crate_path) { + let target_module_id = match find_target_module(module_tree, module_id, crate_path) { None => return Ok(()), Some(it) => it, }; @@ -327,5 +311,3 @@ fn complete_expr_snippets(acc: &mut Vec) { snippet: Some("eprintln!(\"$0 = {:#?}\", $0);".to_string()), }); } - - diff --git a/crates/ra_analysis/src/descriptors/module/mod.rs b/crates/ra_analysis/src/descriptors/module/mod.rs index 58d6abed3..bc1148b22 100644 --- a/crates/ra_analysis/src/descriptors/module/mod.rs +++ b/crates/ra_analysis/src/descriptors/module/mod.rs @@ -3,7 +3,7 @@ pub(crate) mod scope; use ra_syntax::{ ast::{self, AstNode, NameOwner}, - SmolStr, SyntaxNode, + SmolStr, SyntaxNode, SyntaxNodeRef, }; use relative_path::RelativePathBuf; @@ -154,6 +154,16 @@ 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()); diff --git a/crates/ra_analysis/src/descriptors/module/scope.rs b/crates/ra_analysis/src/descriptors/module/scope.rs index 5fcbc3cb0..4490228e4 100644 --- a/crates/ra_analysis/src/descriptors/module/scope.rs +++ b/crates/ra_analysis/src/descriptors/module/scope.rs @@ -25,7 +25,7 @@ enum EntryKind { } impl ModuleScope { - pub(crate) fn new<'a>(items: impl Iterator>) -> ModuleScope { + pub(super) fn new<'a>(items: impl Iterator>) -> ModuleScope { let mut entries = Vec::new(); for item in items { let entry = match item { diff --git a/crates/ra_analysis/src/syntax_ptr.rs b/crates/ra_analysis/src/syntax_ptr.rs index e45934ce0..194b94584 100644 --- a/crates/ra_analysis/src/syntax_ptr.rs +++ b/crates/ra_analysis/src/syntax_ptr.rs @@ -62,6 +62,11 @@ impl LocalSyntaxPtr { local: self, } } + + // Seems unfortunate to expose + pub(crate) fn range(self) -> TextRange { + self.range + } } #[test] -- cgit v1.2.3