aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2018-11-07 18:08:11 +0000
committerAleksey Kladov <[email protected]>2018-11-07 18:08:11 +0000
commit397c235086cfaf5247d971c1867a38640895e014 (patch)
treeb5cc87077735886edc078cd9747fe9bbe3f28768
parent9b88ec488b3f83ab718c8cb4d7dff95aff0113ed (diff)
Use cached module scopes for completion
-rw-r--r--crates/ra_analysis/src/completion/mod.rs25
-rw-r--r--crates/ra_analysis/src/completion/reference_completion.rs78
-rw-r--r--crates/ra_analysis/src/descriptors/module/mod.rs12
-rw-r--r--crates/ra_analysis/src/descriptors/module/scope.rs2
-rw-r--r--crates/ra_analysis/src/syntax_ptr.rs5
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;
2 2
3use ra_editor::find_node_at_offset; 3use ra_editor::find_node_at_offset;
4use ra_syntax::{ 4use ra_syntax::{
5 algo::find_leaf_at_offset,
5 algo::visit::{visitor_ctx, VisitorCtx}, 6 algo::visit::{visitor_ctx, VisitorCtx},
6 ast, 7 ast,
7 AstNode, AtomEdit, 8 AstNode, AtomEdit,
@@ -11,6 +12,8 @@ use rustc_hash::{FxHashMap};
11 12
12use crate::{ 13use crate::{
13 db::{self, SyntaxDatabase}, 14 db::{self, SyntaxDatabase},
15 descriptors::{DescriptorDatabase, module::ModuleSource},
16 input::{FilesDatabase},
14 Cancelable, FilePosition 17 Cancelable, FilePosition
15}; 18};
16 19
@@ -35,12 +38,32 @@ pub(crate) fn completions(
35 original_file.reparse(&edit) 38 original_file.reparse(&edit)
36 }; 39 };
37 40
41 let leaf = match find_leaf_at_offset(original_file.syntax(), position.offset).left_biased() {
42 None => return Ok(None),
43 Some(it) => it,
44 };
45 let source_root_id = db.file_source_root(position.file_id);
46 let module_tree = db.module_tree(source_root_id)?;
47 let module_source = ModuleSource::for_node(position.file_id, leaf);
48 let module_id = match module_tree.any_module_for_source(module_source) {
49 None => return Ok(None),
50 Some(it) => it,
51 };
52
38 let mut res = Vec::new(); 53 let mut res = Vec::new();
39 let mut has_completions = false; 54 let mut has_completions = false;
40 // First, let's try to complete a reference to some declaration. 55 // First, let's try to complete a reference to some declaration.
41 if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(file.syntax(), position.offset) { 56 if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(file.syntax(), position.offset) {
42 has_completions = true; 57 has_completions = true;
43 reference_completion::completions(&mut res, db, position.file_id, &file, name_ref)?; 58 reference_completion::completions(
59 &mut res,
60 db,
61 source_root_id,
62 &module_tree,
63 module_id,
64 &file,
65 name_ref,
66 )?;
44 // special case, `trait T { fn foo(i_am_a_name_ref) {} }` 67 // special case, `trait T { fn foo(i_am_a_name_ref) {} }`
45 if is_node::<ast::Param>(name_ref.syntax()) { 68 if is_node::<ast::Param>(name_ref.syntax()) {
46 param_completions(name_ref.syntax(), &mut res); 69 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;
3use ra_syntax::{ 3use ra_syntax::{
4 algo::visit::{visitor, Visitor}, 4 algo::visit::{visitor, Visitor},
5 SourceFileNode, AstNode, 5 SourceFileNode, AstNode,
6 ast::{self, AstChildren, ModuleItemOwner, LoopBodyOwner}, 6 ast::{self, LoopBodyOwner},
7 SyntaxKind::*, 7 SyntaxKind::*,
8}; 8};
9 9
10use crate::{ 10use crate::{
11 db::RootDatabase, 11 db::RootDatabase,
12 input::FilesDatabase, 12 input::{SourceRootId},
13 completion::CompletionItem, 13 completion::CompletionItem,
14 descriptors::module::{ModuleId, ModuleScope, ModuleTree, ModuleSource}, 14 descriptors::module::{ModuleId, ModuleScope, ModuleTree},
15 descriptors::function::FnScopes, 15 descriptors::function::FnScopes,
16 descriptors::DescriptorDatabase, 16 descriptors::DescriptorDatabase,
17 FileId, Cancelable 17 Cancelable
18}; 18};
19 19
20pub(super) fn completions( 20pub(super) fn completions(
21 acc: &mut Vec<CompletionItem>, 21 acc: &mut Vec<CompletionItem>,
22 db: &RootDatabase, 22 db: &RootDatabase,
23 file_id: FileId, 23 source_root_id: SourceRootId,
24 module_tree: &ModuleTree,
25 module_id: ModuleId,
24 file: &SourceFileNode, 26 file: &SourceFileNode,
25 name_ref: ast::NameRef, 27 name_ref: ast::NameRef,
26) -> Cancelable<()> { 28) -> Cancelable<()> {
@@ -28,14 +30,18 @@ pub(super) fn completions(
28 Some(it) => it, 30 Some(it) => it,
29 None => return Ok(()), 31 None => return Ok(()),
30 }; 32 };
33
31 match kind { 34 match kind {
32 NameRefKind::LocalRef => { 35 NameRefKind::LocalRef => {
33 if let Some(fn_def) = complete_local_name(acc, &file, name_ref) { 36 let module_scope = db.module_scope(source_root_id, module_id)?;
37 if let Some(fn_def) = complete_local_name(acc, &module_scope, name_ref) {
34 complete_expr_keywords(&file, fn_def, name_ref, acc); 38 complete_expr_keywords(&file, fn_def, name_ref, acc);
35 complete_expr_snippets(acc); 39 complete_expr_snippets(acc);
36 } 40 }
37 } 41 }
38 NameRefKind::CratePath(path) => complete_path(acc, db, file_id, path)?, 42 NameRefKind::CratePath(path) => {
43 complete_path(acc, db, source_root_id, module_tree, module_id, path)?
44 }
39 NameRefKind::BareIdentInMod => { 45 NameRefKind::BareIdentInMod => {
40 let name_range = name_ref.syntax().range(); 46 let name_range = name_ref.syntax().range();
41 let top_node = name_ref 47 let top_node = name_ref
@@ -107,45 +113,26 @@ fn crate_path(mut path: ast::Path) -> Option<Vec<ast::NameRef>> {
107 113
108fn complete_local_name<'a>( 114fn complete_local_name<'a>(
109 acc: &mut Vec<CompletionItem>, 115 acc: &mut Vec<CompletionItem>,
110 file: &SourceFileNode, 116 module_scope: &ModuleScope,
111 name_ref: ast::NameRef<'a>, 117 name_ref: ast::NameRef<'a>,
112) -> Option<ast::FnDef<'a>> { 118) -> Option<ast::FnDef<'a>> {
113 let mut enclosing_fn = None; 119 let enclosing_fn = name_ref
114 for node in name_ref.syntax().ancestors() { 120 .syntax()
115 if let Some(items) = visitor() 121 .ancestors()
116 .visit::<ast::SourceFile, _>(|it| Some(it.items())) 122 .take_while(|it| it.kind() != SOURCE_FILE && it.kind() != MODULE)
117 .visit::<ast::Module, _>(|it| Some(it.item_list()?.items())) 123 .find_map(ast::FnDef::cast);
118 .accept(node) 124 if let Some(fn_def) = enclosing_fn {
119 { 125 let scopes = FnScopes::new(fn_def);
120 if let Some(items) = items { 126 complete_fn(name_ref, &scopes, acc);
121 complete_module_items(file, items, Some(name_ref), acc);
122 }
123 break;
124 } else if enclosing_fn.is_none() {
125 if let Some(fn_def) = ast::FnDef::cast(node) {
126 enclosing_fn = Some(fn_def);
127 let scopes = FnScopes::new(fn_def);
128 complete_fn(name_ref, &scopes, acc);
129 }
130 }
131 } 127 }
132 enclosing_fn
133}
134 128
135fn complete_module_items(
136 file: &SourceFileNode,
137 items: AstChildren<ast::ModuleItem>,
138 this_item: Option<ast::NameRef>,
139 acc: &mut Vec<CompletionItem>,
140) {
141 let scope = ModuleScope::new(items); // FIXME
142 acc.extend( 129 acc.extend(
143 scope 130 module_scope
144 .entries() 131 .entries()
145 .iter() 132 .iter()
146 .filter(|entry| { 133 .filter(|entry| {
147 let syntax = entry.ptr().resolve(file); 134 // Don't expose this item
148 Some(syntax.borrowed()) != this_item.map(|it| it.syntax()) 135 !entry.ptr().range().is_subrange(&name_ref.syntax().range())
149 }) 136 })
150 .map(|entry| CompletionItem { 137 .map(|entry| CompletionItem {
151 label: entry.name().to_string(), 138 label: entry.name().to_string(),
@@ -153,6 +140,7 @@ fn complete_module_items(
153 snippet: None, 140 snippet: None,
154 }), 141 }),
155 ); 142 );
143 enclosing_fn
156} 144}
157 145
158fn complete_fn(name_ref: ast::NameRef, scopes: &FnScopes, acc: &mut Vec<CompletionItem>) { 146fn complete_fn(name_ref: ast::NameRef, scopes: &FnScopes, acc: &mut Vec<CompletionItem>) {
@@ -180,16 +168,12 @@ fn complete_fn(name_ref: ast::NameRef, scopes: &FnScopes, acc: &mut Vec<Completi
180fn complete_path( 168fn complete_path(
181 acc: &mut Vec<CompletionItem>, 169 acc: &mut Vec<CompletionItem>,
182 db: &RootDatabase, 170 db: &RootDatabase,
183 file_id: FileId, 171 source_root_id: SourceRootId,
172 module_tree: &ModuleTree,
173 module_id: ModuleId,
184 crate_path: Vec<ast::NameRef>, 174 crate_path: Vec<ast::NameRef>,
185) -> Cancelable<()> { 175) -> Cancelable<()> {
186 let source_root_id = db.file_source_root(file_id); 176 let target_module_id = match find_target_module(module_tree, module_id, crate_path) {
187 let module_tree = db.module_tree(source_root_id)?;
188 let module_id = match module_tree.any_module_for_source(ModuleSource::SourceFile(file_id)) {
189 None => return Ok(()),
190 Some(it) => it,
191 };
192 let target_module_id = match find_target_module(&module_tree, module_id, crate_path) {
193 None => return Ok(()), 177 None => return Ok(()),
194 Some(it) => it, 178 Some(it) => it,
195 }; 179 };
@@ -327,5 +311,3 @@ fn complete_expr_snippets(acc: &mut Vec<CompletionItem>) {
327 snippet: Some("eprintln!(\"$0 = {:#?}\", $0);".to_string()), 311 snippet: Some("eprintln!(\"$0 = {:#?}\", $0);".to_string()),
328 }); 312 });
329} 313}
330
331
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;
3 3
4use ra_syntax::{ 4use ra_syntax::{
5 ast::{self, AstNode, NameOwner}, 5 ast::{self, AstNode, NameOwner},
6 SmolStr, SyntaxNode, 6 SmolStr, SyntaxNode, SyntaxNodeRef,
7}; 7};
8use relative_path::RelativePathBuf; 8use relative_path::RelativePathBuf;
9 9
@@ -154,6 +154,16 @@ struct ModuleData {
154} 154}
155 155
156impl ModuleSource { 156impl ModuleSource {
157 pub(crate) fn for_node(file_id: FileId, node: SyntaxNodeRef) -> ModuleSource {
158 for node in node.ancestors() {
159 if let Some(m) = ast::Module::cast(node) {
160 if !m.has_semi() {
161 return ModuleSource::new_inline(file_id, m);
162 }
163 }
164 }
165 ModuleSource::SourceFile(file_id)
166 }
157 pub(crate) fn new_inline(file_id: FileId, module: ast::Module) -> ModuleSource { 167 pub(crate) fn new_inline(file_id: FileId, module: ast::Module) -> ModuleSource {
158 assert!(!module.has_semi()); 168 assert!(!module.has_semi());
159 let ptr = SyntaxPtr::new(file_id, module.syntax()); 169 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 {
25} 25}
26 26
27impl ModuleScope { 27impl ModuleScope {
28 pub(crate) fn new<'a>(items: impl Iterator<Item = ast::ModuleItem<'a>>) -> ModuleScope { 28 pub(super) fn new<'a>(items: impl Iterator<Item = ast::ModuleItem<'a>>) -> ModuleScope {
29 let mut entries = Vec::new(); 29 let mut entries = Vec::new();
30 for item in items { 30 for item in items {
31 let entry = match item { 31 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 {
62 local: self, 62 local: self,
63 } 63 }
64 } 64 }
65
66 // Seems unfortunate to expose
67 pub(crate) fn range(self) -> TextRange {
68 self.range
69 }
65} 70}
66 71
67#[test] 72#[test]