diff options
-rw-r--r-- | crates/ra_analysis/src/completion/reference_completion.rs | 68 |
1 files changed, 30 insertions, 38 deletions
diff --git a/crates/ra_analysis/src/completion/reference_completion.rs b/crates/ra_analysis/src/completion/reference_completion.rs index 13d4de9d5..f708f07a0 100644 --- a/crates/ra_analysis/src/completion/reference_completion.rs +++ b/crates/ra_analysis/src/completion/reference_completion.rs | |||
@@ -11,7 +11,7 @@ use crate::{ | |||
11 | db::RootDatabase, | 11 | db::RootDatabase, |
12 | input::{SourceRootId}, | 12 | input::{SourceRootId}, |
13 | completion::CompletionItem, | 13 | completion::CompletionItem, |
14 | descriptors::module::{ModuleId, ModuleScope, ModuleTree}, | 14 | descriptors::module::{ModuleId, ModuleTree}, |
15 | descriptors::function::FnScopes, | 15 | descriptors::function::FnScopes, |
16 | descriptors::DescriptorDatabase, | 16 | descriptors::DescriptorDatabase, |
17 | Cancelable | 17 | Cancelable |
@@ -32,12 +32,29 @@ pub(super) fn completions( | |||
32 | }; | 32 | }; |
33 | 33 | ||
34 | match kind { | 34 | match kind { |
35 | NameRefKind::LocalRef => { | 35 | NameRefKind::LocalRef { enclosing_fn } => { |
36 | let module_scope = db.module_scope(source_root_id, module_id)?; | 36 | if let Some(fn_def) = enclosing_fn { |
37 | if let Some(fn_def) = complete_local_name(acc, &module_scope, name_ref) { | 37 | let scopes = FnScopes::new(fn_def); |
38 | complete_fn(name_ref, &scopes, acc); | ||
38 | complete_expr_keywords(&file, fn_def, name_ref, acc); | 39 | complete_expr_keywords(&file, fn_def, name_ref, acc); |
39 | complete_expr_snippets(acc); | 40 | complete_expr_snippets(acc); |
40 | } | 41 | } |
42 | |||
43 | let module_scope = db.module_scope(source_root_id, module_id)?; | ||
44 | acc.extend( | ||
45 | module_scope | ||
46 | .entries() | ||
47 | .iter() | ||
48 | .filter(|entry| { | ||
49 | // Don't expose this item | ||
50 | !entry.ptr().range().is_subrange(&name_ref.syntax().range()) | ||
51 | }) | ||
52 | .map(|entry| CompletionItem { | ||
53 | label: entry.name().to_string(), | ||
54 | lookup: None, | ||
55 | snippet: None, | ||
56 | }), | ||
57 | ); | ||
41 | } | 58 | } |
42 | NameRefKind::CratePath(path) => { | 59 | NameRefKind::CratePath(path) => { |
43 | complete_path(acc, db, source_root_id, module_tree, module_id, path)? | 60 | complete_path(acc, db, source_root_id, module_tree, module_id, path)? |
@@ -62,7 +79,9 @@ pub(super) fn completions( | |||
62 | enum NameRefKind<'a> { | 79 | enum NameRefKind<'a> { |
63 | /// NameRef is a part of single-segment path, for example, a refernece to a | 80 | /// NameRef is a part of single-segment path, for example, a refernece to a |
64 | /// local variable. | 81 | /// local variable. |
65 | LocalRef, | 82 | LocalRef { |
83 | enclosing_fn: Option<ast::FnDef<'a>>, | ||
84 | }, | ||
66 | /// NameRef is the last segment in crate:: path | 85 | /// NameRef is the last segment in crate:: path |
67 | CratePath(Vec<ast::NameRef<'a>>), | 86 | CratePath(Vec<ast::NameRef<'a>>), |
68 | /// NameRef is bare identifier at the module's root. | 87 | /// NameRef is bare identifier at the module's root. |
@@ -87,7 +106,12 @@ fn classify_name_ref(name_ref: ast::NameRef) -> Option<NameRefKind> { | |||
87 | if let Some(segment) = ast::PathSegment::cast(parent) { | 106 | if let Some(segment) = ast::PathSegment::cast(parent) { |
88 | let path = segment.parent_path(); | 107 | let path = segment.parent_path(); |
89 | if path.qualifier().is_none() { | 108 | if path.qualifier().is_none() { |
90 | return Some(NameRefKind::LocalRef); | 109 | let enclosing_fn = name_ref |
110 | .syntax() | ||
111 | .ancestors() | ||
112 | .take_while(|it| it.kind() != SOURCE_FILE && it.kind() != MODULE) | ||
113 | .find_map(ast::FnDef::cast); | ||
114 | return Some(NameRefKind::LocalRef { enclosing_fn }); | ||
91 | } | 115 | } |
92 | if let Some(crate_path) = crate_path(path) { | 116 | if let Some(crate_path) = crate_path(path) { |
93 | return Some(NameRefKind::CratePath(crate_path)); | 117 | return Some(NameRefKind::CratePath(crate_path)); |
@@ -111,38 +135,6 @@ fn crate_path(mut path: ast::Path) -> Option<Vec<ast::NameRef>> { | |||
111 | Some(res) | 135 | Some(res) |
112 | } | 136 | } |
113 | 137 | ||
114 | fn complete_local_name<'a>( | ||
115 | acc: &mut Vec<CompletionItem>, | ||
116 | module_scope: &ModuleScope, | ||
117 | name_ref: ast::NameRef<'a>, | ||
118 | ) -> Option<ast::FnDef<'a>> { | ||
119 | let enclosing_fn = name_ref | ||
120 | .syntax() | ||
121 | .ancestors() | ||
122 | .take_while(|it| it.kind() != SOURCE_FILE && it.kind() != MODULE) | ||
123 | .find_map(ast::FnDef::cast); | ||
124 | if let Some(fn_def) = enclosing_fn { | ||
125 | let scopes = FnScopes::new(fn_def); | ||
126 | complete_fn(name_ref, &scopes, acc); | ||
127 | } | ||
128 | |||
129 | acc.extend( | ||
130 | module_scope | ||
131 | .entries() | ||
132 | .iter() | ||
133 | .filter(|entry| { | ||
134 | // Don't expose this item | ||
135 | !entry.ptr().range().is_subrange(&name_ref.syntax().range()) | ||
136 | }) | ||
137 | .map(|entry| CompletionItem { | ||
138 | label: entry.name().to_string(), | ||
139 | lookup: None, | ||
140 | snippet: None, | ||
141 | }), | ||
142 | ); | ||
143 | enclosing_fn | ||
144 | } | ||
145 | |||
146 | fn complete_fn(name_ref: ast::NameRef, scopes: &FnScopes, acc: &mut Vec<CompletionItem>) { | 138 | fn complete_fn(name_ref: ast::NameRef, scopes: &FnScopes, acc: &mut Vec<CompletionItem>) { |
147 | let mut shadowed = FxHashSet::default(); | 139 | let mut shadowed = FxHashSet::default(); |
148 | acc.extend( | 140 | acc.extend( |