diff options
Diffstat (limited to 'crates/ide_completion/src/patterns.rs')
-rw-r--r-- | crates/ide_completion/src/patterns.rs | 49 |
1 files changed, 44 insertions, 5 deletions
diff --git a/crates/ide_completion/src/patterns.rs b/crates/ide_completion/src/patterns.rs index 26516046b..080898aef 100644 --- a/crates/ide_completion/src/patterns.rs +++ b/crates/ide_completion/src/patterns.rs | |||
@@ -7,13 +7,13 @@ use syntax::{ | |||
7 | ast::{self, LoopBodyOwner}, | 7 | ast::{self, LoopBodyOwner}, |
8 | match_ast, AstNode, Direction, SyntaxElement, | 8 | match_ast, AstNode, Direction, SyntaxElement, |
9 | SyntaxKind::*, | 9 | SyntaxKind::*, |
10 | SyntaxNode, SyntaxToken, TextSize, T, | 10 | SyntaxNode, SyntaxToken, TextRange, TextSize, T, |
11 | }; | 11 | }; |
12 | 12 | ||
13 | #[cfg(test)] | 13 | #[cfg(test)] |
14 | use crate::test_utils::{check_pattern_is_applicable, check_pattern_is_not_applicable}; | 14 | use crate::test_utils::{check_pattern_is_applicable, check_pattern_is_not_applicable}; |
15 | 15 | ||
16 | /// Direct parent container of the cursor position | 16 | /// Immediate previous node to what we are completing. |
17 | #[derive(Copy, Clone, Debug, PartialEq, Eq)] | 17 | #[derive(Copy, Clone, Debug, PartialEq, Eq)] |
18 | pub(crate) enum ImmediatePrevSibling { | 18 | pub(crate) enum ImmediatePrevSibling { |
19 | IfExpr, | 19 | IfExpr, |
@@ -21,7 +21,7 @@ pub(crate) enum ImmediatePrevSibling { | |||
21 | ImplDefType, | 21 | ImplDefType, |
22 | } | 22 | } |
23 | 23 | ||
24 | /// Direct parent container of the cursor position | 24 | /// Direct parent "thing" of what we are currently completing. |
25 | #[derive(Clone, Debug, PartialEq, Eq)] | 25 | #[derive(Clone, Debug, PartialEq, Eq)] |
26 | pub(crate) enum ImmediateLocation { | 26 | pub(crate) enum ImmediateLocation { |
27 | Use, | 27 | Use, |
@@ -37,6 +37,15 @@ pub(crate) enum ImmediateLocation { | |||
37 | // Fake file ast node | 37 | // Fake file ast node |
38 | ModDeclaration(ast::Module), | 38 | ModDeclaration(ast::Module), |
39 | // Original file ast node | 39 | // Original file ast node |
40 | MethodCall { | ||
41 | receiver: Option<ast::Expr>, | ||
42 | }, | ||
43 | // Original file ast node | ||
44 | FieldAccess { | ||
45 | receiver: Option<ast::Expr>, | ||
46 | receiver_is_ambiguous_float_literal: bool, | ||
47 | }, | ||
48 | // Original file ast node | ||
40 | /// The record expr of the field name we are completing | 49 | /// The record expr of the field name we are completing |
41 | RecordExpr(ast::RecordExpr), | 50 | RecordExpr(ast::RecordExpr), |
42 | // Original file ast node | 51 | // Original file ast node |
@@ -164,12 +173,38 @@ pub(crate) fn determine_location( | |||
164 | Some(TRAIT) => ImmediateLocation::Trait, | 173 | Some(TRAIT) => ImmediateLocation::Trait, |
165 | _ => return None, | 174 | _ => return None, |
166 | }, | 175 | }, |
167 | ast::Module(it) => if it.item_list().is_none() { | 176 | ast::Module(it) => { |
177 | if it.item_list().is_none() { | ||
168 | ImmediateLocation::ModDeclaration(it) | 178 | ImmediateLocation::ModDeclaration(it) |
169 | } else { | 179 | } else { |
170 | return None | 180 | return None; |
181 | } | ||
171 | }, | 182 | }, |
172 | ast::Attr(it) => ImmediateLocation::Attribute(it), | 183 | ast::Attr(it) => ImmediateLocation::Attribute(it), |
184 | ast::FieldExpr(it) => { | ||
185 | let receiver = it | ||
186 | .expr() | ||
187 | .map(|e| e.syntax().text_range()) | ||
188 | .and_then(|r| find_node_with_range(original_file, r)); | ||
189 | let receiver_is_ambiguous_float_literal = if let Some(ast::Expr::Literal(l)) = &receiver { | ||
190 | match l.kind() { | ||
191 | ast::LiteralKind::FloatNumber { .. } => l.token().text().ends_with('.'), | ||
192 | _ => false, | ||
193 | } | ||
194 | } else { | ||
195 | false | ||
196 | }; | ||
197 | ImmediateLocation::FieldAccess { | ||
198 | receiver, | ||
199 | receiver_is_ambiguous_float_literal, | ||
200 | } | ||
201 | }, | ||
202 | ast::MethodCallExpr(it) => ImmediateLocation::MethodCall { | ||
203 | receiver: it | ||
204 | .receiver() | ||
205 | .map(|e| e.syntax().text_range()) | ||
206 | .and_then(|r| find_node_with_range(original_file, r)), | ||
207 | }, | ||
173 | _ => return None, | 208 | _ => return None, |
174 | } | 209 | } |
175 | }; | 210 | }; |
@@ -194,6 +229,10 @@ fn maximize_name_ref(name_ref: &ast::NameRef) -> SyntaxNode { | |||
194 | name_ref.syntax().clone() | 229 | name_ref.syntax().clone() |
195 | } | 230 | } |
196 | 231 | ||
232 | fn find_node_with_range<N: AstNode>(syntax: &SyntaxNode, range: TextRange) -> Option<N> { | ||
233 | syntax.covering_element(range).ancestors().find_map(N::cast) | ||
234 | } | ||
235 | |||
197 | pub(crate) fn inside_impl_trait_block(element: SyntaxElement) -> bool { | 236 | pub(crate) fn inside_impl_trait_block(element: SyntaxElement) -> bool { |
198 | // Here we search `impl` keyword up through the all ancestors, unlike in `has_impl_parent`, | 237 | // Here we search `impl` keyword up through the all ancestors, unlike in `has_impl_parent`, |
199 | // where we only check the first parent with different text range. | 238 | // where we only check the first parent with different text range. |