aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_analysis
diff options
context:
space:
mode:
authorFlorian Diebold <[email protected]>2018-12-25 16:43:58 +0000
committerFlorian Diebold <[email protected]>2018-12-25 16:43:58 +0000
commit3e4d41d1e409315ce42cb3c3479236b5e73d0643 (patch)
tree0ae517904e3324d7a9779fb83e11574e1427ee29 /crates/ra_analysis
parent3befd1a9e82809fef5bc68950d3265dbcbbd5527 (diff)
Determine receiver for completion in a more robust way
Also rename a parameter.
Diffstat (limited to 'crates/ra_analysis')
-rw-r--r--crates/ra_analysis/src/completion/complete_dot.rs4
-rw-r--r--crates/ra_analysis/src/completion/completion_context.rs48
2 files changed, 31 insertions, 21 deletions
diff --git a/crates/ra_analysis/src/completion/complete_dot.rs b/crates/ra_analysis/src/completion/complete_dot.rs
index fa62da210..93d657576 100644
--- a/crates/ra_analysis/src/completion/complete_dot.rs
+++ b/crates/ra_analysis/src/completion/complete_dot.rs
@@ -33,9 +33,9 @@ pub(super) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) -> Ca
33 Ok(()) 33 Ok(())
34} 34}
35 35
36fn complete_fields(acc: &mut Completions, ctx: &CompletionContext, ty: Ty) -> Cancelable<()> { 36fn complete_fields(acc: &mut Completions, ctx: &CompletionContext, receiver: Ty) -> Cancelable<()> {
37 // TODO: autoderef etc. 37 // TODO: autoderef etc.
38 match ty { 38 match receiver {
39 Ty::Adt { def_id, .. } => { 39 Ty::Adt { def_id, .. } => {
40 match def_id.resolve(ctx.db)? { 40 match def_id.resolve(ctx.db)? {
41 Def::Struct(s) => { 41 Def::Struct(s) => {
diff --git a/crates/ra_analysis/src/completion/completion_context.rs b/crates/ra_analysis/src/completion/completion_context.rs
index 12e98e870..978772fd4 100644
--- a/crates/ra_analysis/src/completion/completion_context.rs
+++ b/crates/ra_analysis/src/completion/completion_context.rs
@@ -1,12 +1,13 @@
1use ra_editor::find_node_at_offset; 1use ra_editor::find_node_at_offset;
2use ra_text_edit::AtomTextEdit; 2use ra_text_edit::AtomTextEdit;
3use ra_syntax::{ 3use ra_syntax::{
4 algo::find_leaf_at_offset, 4 algo::{find_leaf_at_offset, find_covering_node},
5 ast, 5 ast,
6 AstNode, 6 AstNode,
7 SyntaxNodeRef, 7 SyntaxNodeRef,
8 SourceFileNode, 8 SourceFileNode,
9 TextUnit, 9 TextUnit,
10 TextRange,
10 SyntaxKind::*, 11 SyntaxKind::*,
11}; 12};
12use hir::source_binder; 13use hir::source_binder;
@@ -65,7 +66,7 @@ impl<'a> CompletionContext<'a> {
65 Ok(Some(ctx)) 66 Ok(Some(ctx))
66 } 67 }
67 68
68 fn fill(&mut self, original_file: &SourceFileNode, offset: TextUnit) { 69 fn fill(&mut self, original_file: &'a SourceFileNode, offset: TextUnit) {
69 // Insert a fake ident to get a valid parse tree. We will use this file 70 // Insert a fake ident to get a valid parse tree. We will use this file
70 // to determine context, though the original_file will be used for 71 // to determine context, though the original_file will be used for
71 // actual completion. 72 // actual completion.
@@ -82,7 +83,7 @@ impl<'a> CompletionContext<'a> {
82 self.is_param = true; 83 self.is_param = true;
83 return; 84 return;
84 } 85 }
85 self.classify_name_ref(&file, name_ref); 86 self.classify_name_ref(original_file, name_ref);
86 } 87 }
87 88
88 // Otherwise, see if this is a declaration. We can use heuristics to 89 // Otherwise, see if this is a declaration. We can use heuristics to
@@ -94,7 +95,7 @@ impl<'a> CompletionContext<'a> {
94 } 95 }
95 } 96 }
96 } 97 }
97 fn classify_name_ref(&mut self, file: &SourceFileNode, name_ref: ast::NameRef) { 98 fn classify_name_ref(&mut self, original_file: &'a SourceFileNode, name_ref: ast::NameRef) {
98 let name_range = name_ref.syntax().range(); 99 let name_range = name_ref.syntax().range();
99 let top_node = name_ref 100 let top_node = name_ref
100 .syntax() 101 .syntax()
@@ -144,7 +145,9 @@ impl<'a> CompletionContext<'a> {
144 }; 145 };
145 146
146 if let Some(off) = name_ref.syntax().range().start().checked_sub(2.into()) { 147 if let Some(off) = name_ref.syntax().range().start().checked_sub(2.into()) {
147 if let Some(if_expr) = find_node_at_offset::<ast::IfExpr>(file.syntax(), off) { 148 if let Some(if_expr) =
149 find_node_at_offset::<ast::IfExpr>(original_file.syntax(), off)
150 {
148 if if_expr.syntax().range().end() < name_ref.syntax().range().start() { 151 if if_expr.syntax().range().end() < name_ref.syntax().range().start() {
149 self.after_if = true; 152 self.after_if = true;
150 } 153 }
@@ -152,26 +155,33 @@ impl<'a> CompletionContext<'a> {
152 } 155 }
153 } 156 }
154 } 157 }
155 if let Some(_field_expr) = ast::FieldExpr::cast(parent) { 158 if let Some(field_expr) = ast::FieldExpr::cast(parent) {
156 self.dot_receiver = self 159 // The receiver comes before the point of insertion of the fake
157 .leaf 160 // ident, so it should have the same range in the non-modified file
158 .ancestors() 161 self.dot_receiver = field_expr
159 .take_while(|it| it.kind() != SOURCE_FILE && it.kind() != MODULE) 162 .expr()
160 .find_map(ast::FieldExpr::cast) 163 .map(|e| e.syntax().range())
161 .and_then(ast::FieldExpr::expr); 164 .and_then(|r| find_node_with_range(original_file.syntax(), r));
162 } 165 }
163 if let Some(_method_call_expr) = ast::MethodCallExpr::cast(parent) { 166 if let Some(method_call_expr) = ast::MethodCallExpr::cast(parent) {
164 self.dot_receiver = self 167 // As above
165 .leaf 168 self.dot_receiver = method_call_expr
166 .ancestors() 169 .expr()
167 .take_while(|it| it.kind() != SOURCE_FILE && it.kind() != MODULE) 170 .map(|e| e.syntax().range())
168 .find_map(ast::MethodCallExpr::cast) 171 .and_then(|r| find_node_with_range(original_file.syntax(), r));
169 .and_then(ast::MethodCallExpr::expr);
170 self.is_method_call = true; 172 self.is_method_call = true;
171 } 173 }
172 } 174 }
173} 175}
174 176
177fn find_node_with_range<'a, N: AstNode<'a>>(
178 syntax: SyntaxNodeRef<'a>,
179 range: TextRange,
180) -> Option<N> {
181 let node = find_covering_node(syntax, range);
182 node.ancestors().find_map(N::cast)
183}
184
175fn is_node<'a, N: AstNode<'a>>(node: SyntaxNodeRef<'a>) -> bool { 185fn is_node<'a, N: AstNode<'a>>(node: SyntaxNodeRef<'a>) -> bool {
176 match node.ancestors().filter_map(N::cast).next() { 186 match node.ancestors().filter_map(N::cast).next() {
177 None => false, 187 None => false,