diff options
author | Aleksey Kladov <[email protected]> | 2018-11-07 18:08:11 +0000 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2018-11-07 18:08:11 +0000 |
commit | 397c235086cfaf5247d971c1867a38640895e014 (patch) | |
tree | b5cc87077735886edc078cd9747fe9bbe3f28768 | |
parent | 9b88ec488b3f83ab718c8cb4d7dff95aff0113ed (diff) |
Use cached module scopes for completion
-rw-r--r-- | crates/ra_analysis/src/completion/mod.rs | 25 | ||||
-rw-r--r-- | crates/ra_analysis/src/completion/reference_completion.rs | 78 | ||||
-rw-r--r-- | crates/ra_analysis/src/descriptors/module/mod.rs | 12 | ||||
-rw-r--r-- | crates/ra_analysis/src/descriptors/module/scope.rs | 2 | ||||
-rw-r--r-- | 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; | |||
2 | 2 | ||
3 | use ra_editor::find_node_at_offset; | 3 | use ra_editor::find_node_at_offset; |
4 | use ra_syntax::{ | 4 | use 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 | ||
12 | use crate::{ | 13 | use 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; | |||
3 | use ra_syntax::{ | 3 | use 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 | ||
10 | use crate::{ | 10 | use 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 | ||
20 | pub(super) fn completions( | 20 | pub(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 | ||
108 | fn complete_local_name<'a>( | 114 | fn 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 | ||
135 | fn 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 | ||
158 | fn complete_fn(name_ref: ast::NameRef, scopes: &FnScopes, acc: &mut Vec<CompletionItem>) { | 146 | fn 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 | |||
180 | fn complete_path( | 168 | fn 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 | ||
4 | use ra_syntax::{ | 4 | use ra_syntax::{ |
5 | ast::{self, AstNode, NameOwner}, | 5 | ast::{self, AstNode, NameOwner}, |
6 | SmolStr, SyntaxNode, | 6 | SmolStr, SyntaxNode, SyntaxNodeRef, |
7 | }; | 7 | }; |
8 | use relative_path::RelativePathBuf; | 8 | use relative_path::RelativePathBuf; |
9 | 9 | ||
@@ -154,6 +154,16 @@ struct ModuleData { | |||
154 | } | 154 | } |
155 | 155 | ||
156 | impl ModuleSource { | 156 | impl 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 | ||
27 | impl ModuleScope { | 27 | impl 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] |