diff options
-rw-r--r-- | crates/ide_assists/src/handlers/extract_type_alias.rs | 28 | ||||
-rw-r--r-- | crates/ide_completion/src/completions/dot.rs | 7 | ||||
-rw-r--r-- | crates/ide_completion/src/completions/flyimport.rs | 6 | ||||
-rw-r--r-- | crates/ide_completion/src/completions/keyword.rs | 2 | ||||
-rw-r--r-- | crates/ide_completion/src/completions/macro_in_item_position.rs | 2 | ||||
-rw-r--r-- | crates/ide_completion/src/completions/postfix.rs | 17 | ||||
-rw-r--r-- | crates/ide_completion/src/completions/snippet.rs | 2 | ||||
-rw-r--r-- | crates/ide_completion/src/context.rs | 65 | ||||
-rw-r--r-- | crates/ide_completion/src/patterns.rs | 49 | ||||
-rw-r--r-- | crates/ide_completion/src/render/function.rs | 2 |
10 files changed, 113 insertions, 67 deletions
diff --git a/crates/ide_assists/src/handlers/extract_type_alias.rs b/crates/ide_assists/src/handlers/extract_type_alias.rs index 442a209b9..998e0de7b 100644 --- a/crates/ide_assists/src/handlers/extract_type_alias.rs +++ b/crates/ide_assists/src/handlers/extract_type_alias.rs | |||
@@ -25,7 +25,12 @@ pub(crate) fn extract_type_alias(acc: &mut Assists, ctx: &AssistContext) -> Opti | |||
25 | } | 25 | } |
26 | 26 | ||
27 | let node = ctx.find_node_at_range::<ast::Type>()?; | 27 | let node = ctx.find_node_at_range::<ast::Type>()?; |
28 | let insert = ctx.find_node_at_offset::<ast::Item>()?.syntax().text_range().start(); | 28 | let insert = ctx |
29 | .find_node_at_offset::<ast::Impl>() | ||
30 | .map(|imp| imp.syntax().clone()) | ||
31 | .or_else(|| ctx.find_node_at_offset::<ast::Item>().map(|item| item.syntax().clone()))? | ||
32 | .text_range() | ||
33 | .start(); | ||
29 | let target = node.syntax().text_range(); | 34 | let target = node.syntax().text_range(); |
30 | 35 | ||
31 | acc.add( | 36 | acc.add( |
@@ -146,4 +151,25 @@ struct S { | |||
146 | "#, | 151 | "#, |
147 | ); | 152 | ); |
148 | } | 153 | } |
154 | |||
155 | #[test] | ||
156 | fn extract_from_impl() { | ||
157 | // When invoked in an impl, extracted type alias should be placed next to the impl, not | ||
158 | // inside. | ||
159 | check_assist( | ||
160 | extract_type_alias, | ||
161 | r#" | ||
162 | impl S { | ||
163 | fn f() -> $0(u8, u8)$0 {} | ||
164 | } | ||
165 | "#, | ||
166 | r#" | ||
167 | type $0Type = (u8, u8); | ||
168 | |||
169 | impl S { | ||
170 | fn f() -> Type {} | ||
171 | } | ||
172 | "#, | ||
173 | ); | ||
174 | } | ||
149 | } | 175 | } |
diff --git a/crates/ide_completion/src/completions/dot.rs b/crates/ide_completion/src/completions/dot.rs index 302c9ccbd..e0a7021fd 100644 --- a/crates/ide_completion/src/completions/dot.rs +++ b/crates/ide_completion/src/completions/dot.rs | |||
@@ -8,7 +8,7 @@ use crate::{context::CompletionContext, Completions}; | |||
8 | 8 | ||
9 | /// Complete dot accesses, i.e. fields or methods. | 9 | /// Complete dot accesses, i.e. fields or methods. |
10 | pub(crate) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) { | 10 | pub(crate) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) { |
11 | let dot_receiver = match &ctx.dot_receiver { | 11 | let dot_receiver = match ctx.dot_receiver() { |
12 | Some(expr) => expr, | 12 | Some(expr) => expr, |
13 | _ => return complete_undotted_self(acc, ctx), | 13 | _ => return complete_undotted_self(acc, ctx), |
14 | }; | 14 | }; |
@@ -30,7 +30,10 @@ pub(crate) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) { | |||
30 | } | 30 | } |
31 | 31 | ||
32 | fn complete_undotted_self(acc: &mut Completions, ctx: &CompletionContext) { | 32 | fn complete_undotted_self(acc: &mut Completions, ctx: &CompletionContext) { |
33 | if !ctx.is_trivial_path || !ctx.config.enable_self_on_the_fly { | 33 | if !ctx.config.enable_self_on_the_fly { |
34 | return; | ||
35 | } | ||
36 | if !ctx.is_trivial_path || ctx.is_path_disallowed() { | ||
34 | return; | 37 | return; |
35 | } | 38 | } |
36 | ctx.scope.process_all_names(&mut |name, def| { | 39 | ctx.scope.process_all_names(&mut |name, def| { |
diff --git a/crates/ide_completion/src/completions/flyimport.rs b/crates/ide_completion/src/completions/flyimport.rs index df27e7a84..d72bf13d3 100644 --- a/crates/ide_completion/src/completions/flyimport.rs +++ b/crates/ide_completion/src/completions/flyimport.rs | |||
@@ -162,19 +162,19 @@ pub(crate) fn position_for_import<'a>( | |||
162 | Some(match import_candidate { | 162 | Some(match import_candidate { |
163 | Some(ImportCandidate::Path(_)) => ctx.name_ref_syntax.as_ref()?.syntax(), | 163 | Some(ImportCandidate::Path(_)) => ctx.name_ref_syntax.as_ref()?.syntax(), |
164 | Some(ImportCandidate::TraitAssocItem(_)) => ctx.path_qual.as_ref()?.syntax(), | 164 | Some(ImportCandidate::TraitAssocItem(_)) => ctx.path_qual.as_ref()?.syntax(), |
165 | Some(ImportCandidate::TraitMethod(_)) => ctx.dot_receiver.as_ref()?.syntax(), | 165 | Some(ImportCandidate::TraitMethod(_)) => ctx.dot_receiver()?.syntax(), |
166 | None => ctx | 166 | None => ctx |
167 | .name_ref_syntax | 167 | .name_ref_syntax |
168 | .as_ref() | 168 | .as_ref() |
169 | .map(|name_ref| name_ref.syntax()) | 169 | .map(|name_ref| name_ref.syntax()) |
170 | .or_else(|| ctx.path_qual.as_ref().map(|path| path.syntax())) | 170 | .or_else(|| ctx.path_qual.as_ref().map(|path| path.syntax())) |
171 | .or_else(|| ctx.dot_receiver.as_ref().map(|expr| expr.syntax()))?, | 171 | .or_else(|| ctx.dot_receiver().map(|expr| expr.syntax()))?, |
172 | }) | 172 | }) |
173 | } | 173 | } |
174 | 174 | ||
175 | fn import_assets(ctx: &CompletionContext, fuzzy_name: String) -> Option<ImportAssets> { | 175 | fn import_assets(ctx: &CompletionContext, fuzzy_name: String) -> Option<ImportAssets> { |
176 | let current_module = ctx.scope.module()?; | 176 | let current_module = ctx.scope.module()?; |
177 | if let Some(dot_receiver) = &ctx.dot_receiver { | 177 | if let Some(dot_receiver) = ctx.dot_receiver() { |
178 | ImportAssets::for_fuzzy_method_call( | 178 | ImportAssets::for_fuzzy_method_call( |
179 | current_module, | 179 | current_module, |
180 | ctx.sema.type_of_expr(dot_receiver)?, | 180 | ctx.sema.type_of_expr(dot_receiver)?, |
diff --git a/crates/ide_completion/src/completions/keyword.rs b/crates/ide_completion/src/completions/keyword.rs index 0d035c611..1a7a484a4 100644 --- a/crates/ide_completion/src/completions/keyword.rs +++ b/crates/ide_completion/src/completions/keyword.rs | |||
@@ -31,7 +31,7 @@ pub(crate) fn complete_use_tree_keyword(acc: &mut Completions, ctx: &CompletionC | |||
31 | } | 31 | } |
32 | 32 | ||
33 | // Suggest .await syntax for types that implement Future trait | 33 | // Suggest .await syntax for types that implement Future trait |
34 | if let Some(receiver) = &ctx.dot_receiver { | 34 | if let Some(receiver) = ctx.dot_receiver() { |
35 | if let Some(ty) = ctx.sema.type_of_expr(receiver) { | 35 | if let Some(ty) = ctx.sema.type_of_expr(receiver) { |
36 | if ty.impls_future(ctx.db) { | 36 | if ty.impls_future(ctx.db) { |
37 | let mut item = kw_completion("await"); | 37 | let mut item = kw_completion("await"); |
diff --git a/crates/ide_completion/src/completions/macro_in_item_position.rs b/crates/ide_completion/src/completions/macro_in_item_position.rs index 202e71215..781b96ff1 100644 --- a/crates/ide_completion/src/completions/macro_in_item_position.rs +++ b/crates/ide_completion/src/completions/macro_in_item_position.rs | |||
@@ -5,7 +5,7 @@ use crate::{CompletionContext, Completions}; | |||
5 | // Ideally this should be removed and moved into `(un)qualified_path` respectively | 5 | // Ideally this should be removed and moved into `(un)qualified_path` respectively |
6 | pub(crate) fn complete_macro_in_item_position(acc: &mut Completions, ctx: &CompletionContext) { | 6 | pub(crate) fn complete_macro_in_item_position(acc: &mut Completions, ctx: &CompletionContext) { |
7 | // Show only macros in top level. | 7 | // Show only macros in top level. |
8 | if !ctx.is_new_item { | 8 | if !ctx.expects_item() { |
9 | return; | 9 | return; |
10 | } | 10 | } |
11 | 11 | ||
diff --git a/crates/ide_completion/src/completions/postfix.rs b/crates/ide_completion/src/completions/postfix.rs index 962aaf0df..86bbb58e2 100644 --- a/crates/ide_completion/src/completions/postfix.rs +++ b/crates/ide_completion/src/completions/postfix.rs | |||
@@ -14,6 +14,7 @@ use crate::{ | |||
14 | completions::postfix::format_like::add_format_like_completions, | 14 | completions::postfix::format_like::add_format_like_completions, |
15 | context::CompletionContext, | 15 | context::CompletionContext, |
16 | item::{Builder, CompletionKind}, | 16 | item::{Builder, CompletionKind}, |
17 | patterns::ImmediateLocation, | ||
17 | CompletionItem, CompletionItemKind, Completions, | 18 | CompletionItem, CompletionItemKind, Completions, |
18 | }; | 19 | }; |
19 | 20 | ||
@@ -22,13 +23,16 @@ pub(crate) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) { | |||
22 | return; | 23 | return; |
23 | } | 24 | } |
24 | 25 | ||
25 | let dot_receiver = match &ctx.dot_receiver { | 26 | let (dot_receiver, receiver_is_ambiguous_float_literal) = match &ctx.completion_location { |
26 | Some(it) => it, | 27 | Some(ImmediateLocation::MethodCall { receiver: Some(it) }) => (it, false), |
27 | None => return, | 28 | Some(ImmediateLocation::FieldAccess { |
29 | receiver: Some(it), | ||
30 | receiver_is_ambiguous_float_literal, | ||
31 | }) => (it, *receiver_is_ambiguous_float_literal), | ||
32 | _ => return, | ||
28 | }; | 33 | }; |
29 | 34 | ||
30 | let receiver_text = | 35 | let receiver_text = get_receiver_text(dot_receiver, receiver_is_ambiguous_float_literal); |
31 | get_receiver_text(dot_receiver, ctx.dot_receiver_is_ambiguous_float_literal); | ||
32 | 36 | ||
33 | let receiver_ty = match ctx.sema.type_of_expr(&dot_receiver) { | 37 | let receiver_ty = match ctx.sema.type_of_expr(&dot_receiver) { |
34 | Some(it) => it, | 38 | Some(it) => it, |
@@ -123,8 +127,7 @@ pub(crate) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) { | |||
123 | // The rest of the postfix completions create an expression that moves an argument, | 127 | // The rest of the postfix completions create an expression that moves an argument, |
124 | // so it's better to consider references now to avoid breaking the compilation | 128 | // so it's better to consider references now to avoid breaking the compilation |
125 | let dot_receiver = include_references(dot_receiver); | 129 | let dot_receiver = include_references(dot_receiver); |
126 | let receiver_text = | 130 | let receiver_text = get_receiver_text(&dot_receiver, receiver_is_ambiguous_float_literal); |
127 | get_receiver_text(&dot_receiver, ctx.dot_receiver_is_ambiguous_float_literal); | ||
128 | 131 | ||
129 | match try_enum { | 132 | match try_enum { |
130 | Some(try_enum) => match try_enum { | 133 | Some(try_enum) => match try_enum { |
diff --git a/crates/ide_completion/src/completions/snippet.rs b/crates/ide_completion/src/completions/snippet.rs index defc25b00..6e6a6eb92 100644 --- a/crates/ide_completion/src/completions/snippet.rs +++ b/crates/ide_completion/src/completions/snippet.rs | |||
@@ -29,7 +29,7 @@ pub(crate) fn complete_expr_snippet(acc: &mut Completions, ctx: &CompletionConte | |||
29 | } | 29 | } |
30 | 30 | ||
31 | pub(crate) fn complete_item_snippet(acc: &mut Completions, ctx: &CompletionContext) { | 31 | pub(crate) fn complete_item_snippet(acc: &mut Completions, ctx: &CompletionContext) { |
32 | if !ctx.is_new_item { | 32 | if !ctx.expects_item() { |
33 | return; | 33 | return; |
34 | } | 34 | } |
35 | let cap = match ctx.config.snippet_cap { | 35 | let cap = match ctx.config.snippet_cap { |
diff --git a/crates/ide_completion/src/context.rs b/crates/ide_completion/src/context.rs index 7c46c815d..6f685c02f 100644 --- a/crates/ide_completion/src/context.rs +++ b/crates/ide_completion/src/context.rs | |||
@@ -78,11 +78,6 @@ pub(crate) struct CompletionContext<'a> { | |||
78 | pub(super) can_be_stmt: bool, | 78 | pub(super) can_be_stmt: bool, |
79 | /// `true` if we expect an expression at the cursor position. | 79 | /// `true` if we expect an expression at the cursor position. |
80 | pub(super) is_expr: bool, | 80 | pub(super) is_expr: bool, |
81 | /// Something is typed at the "top" level, in module or impl/trait. | ||
82 | pub(super) is_new_item: bool, | ||
83 | /// The receiver if this is a field or method access, i.e. writing something.$0 | ||
84 | pub(super) dot_receiver: Option<ast::Expr>, | ||
85 | pub(super) dot_receiver_is_ambiguous_float_literal: bool, | ||
86 | /// If this is a call (method or function) in particular, i.e. the () are already there. | 81 | /// If this is a call (method or function) in particular, i.e. the () are already there. |
87 | pub(super) is_call: bool, | 82 | pub(super) is_call: bool, |
88 | /// Like `is_call`, but for tuple patterns. | 83 | /// Like `is_call`, but for tuple patterns. |
@@ -158,9 +153,6 @@ impl<'a> CompletionContext<'a> { | |||
158 | path_qual: None, | 153 | path_qual: None, |
159 | can_be_stmt: false, | 154 | can_be_stmt: false, |
160 | is_expr: false, | 155 | is_expr: false, |
161 | is_new_item: false, | ||
162 | dot_receiver: None, | ||
163 | dot_receiver_is_ambiguous_float_literal: false, | ||
164 | is_call: false, | 156 | is_call: false, |
165 | is_pattern_call: false, | 157 | is_pattern_call: false, |
166 | is_macro_call: false, | 158 | is_macro_call: false, |
@@ -255,6 +247,22 @@ impl<'a> CompletionContext<'a> { | |||
255 | ) | 247 | ) |
256 | } | 248 | } |
257 | 249 | ||
250 | pub(crate) fn has_dot_receiver(&self) -> bool { | ||
251 | matches!( | ||
252 | &self.completion_location, | ||
253 | Some(ImmediateLocation::FieldAccess { receiver, .. }) | Some(ImmediateLocation::MethodCall { receiver }) | ||
254 | if receiver.is_some() | ||
255 | ) | ||
256 | } | ||
257 | |||
258 | pub(crate) fn dot_receiver(&self) -> Option<&ast::Expr> { | ||
259 | match &self.completion_location { | ||
260 | Some(ImmediateLocation::MethodCall { receiver }) | ||
261 | | Some(ImmediateLocation::FieldAccess { receiver, .. }) => receiver.as_ref(), | ||
262 | _ => None, | ||
263 | } | ||
264 | } | ||
265 | |||
258 | pub(crate) fn expects_use_tree(&self) -> bool { | 266 | pub(crate) fn expects_use_tree(&self) -> bool { |
259 | matches!(self.completion_location, Some(ImmediateLocation::Use)) | 267 | matches!(self.completion_location, Some(ImmediateLocation::Use)) |
260 | } | 268 | } |
@@ -267,6 +275,7 @@ impl<'a> CompletionContext<'a> { | |||
267 | matches!(self.completion_location, Some(ImmediateLocation::ItemList)) | 275 | matches!(self.completion_location, Some(ImmediateLocation::ItemList)) |
268 | } | 276 | } |
269 | 277 | ||
278 | // fn expects_value(&self) -> bool { | ||
270 | pub(crate) fn expects_expression(&self) -> bool { | 279 | pub(crate) fn expects_expression(&self) -> bool { |
271 | self.is_expr | 280 | self.is_expr |
272 | } | 281 | } |
@@ -540,16 +549,7 @@ impl<'a> CompletionContext<'a> { | |||
540 | self.name_ref_syntax = | 549 | self.name_ref_syntax = |
541 | find_node_at_offset(original_file, name_ref.syntax().text_range().start()); | 550 | find_node_at_offset(original_file, name_ref.syntax().text_range().start()); |
542 | 551 | ||
543 | let name_range = name_ref.syntax().text_range(); | 552 | if matches!(self.completion_location, Some(ImmediateLocation::ItemList)) { |
544 | let top_node = name_ref | ||
545 | .syntax() | ||
546 | .ancestors() | ||
547 | .take_while(|it| it.text_range() == name_range) | ||
548 | .last() | ||
549 | .unwrap(); | ||
550 | |||
551 | if matches!(top_node.parent().map(|it| it.kind()), Some(SOURCE_FILE) | Some(ITEM_LIST)) { | ||
552 | self.is_new_item = true; | ||
553 | return; | 553 | return; |
554 | } | 554 | } |
555 | 555 | ||
@@ -623,33 +623,8 @@ impl<'a> CompletionContext<'a> { | |||
623 | .unwrap_or(false); | 623 | .unwrap_or(false); |
624 | self.is_expr = path.syntax().parent().and_then(ast::PathExpr::cast).is_some(); | 624 | self.is_expr = path.syntax().parent().and_then(ast::PathExpr::cast).is_some(); |
625 | } | 625 | } |
626 | 626 | self.is_call |= | |
627 | if let Some(field_expr) = ast::FieldExpr::cast(parent.clone()) { | 627 | matches!(self.completion_location, Some(ImmediateLocation::MethodCall { .. })); |
628 | // The receiver comes before the point of insertion of the fake | ||
629 | // ident, so it should have the same range in the non-modified file | ||
630 | self.dot_receiver = field_expr | ||
631 | .expr() | ||
632 | .map(|e| e.syntax().text_range()) | ||
633 | .and_then(|r| find_node_with_range(original_file, r)); | ||
634 | self.dot_receiver_is_ambiguous_float_literal = | ||
635 | if let Some(ast::Expr::Literal(l)) = &self.dot_receiver { | ||
636 | match l.kind() { | ||
637 | ast::LiteralKind::FloatNumber { .. } => l.token().text().ends_with('.'), | ||
638 | _ => false, | ||
639 | } | ||
640 | } else { | ||
641 | false | ||
642 | }; | ||
643 | } | ||
644 | |||
645 | if let Some(method_call_expr) = ast::MethodCallExpr::cast(parent) { | ||
646 | // As above | ||
647 | self.dot_receiver = method_call_expr | ||
648 | .receiver() | ||
649 | .map(|e| e.syntax().text_range()) | ||
650 | .and_then(|r| find_node_with_range(original_file, r)); | ||
651 | self.is_call = true; | ||
652 | } | ||
653 | } | 628 | } |
654 | } | 629 | } |
655 | 630 | ||
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. |
diff --git a/crates/ide_completion/src/render/function.rs b/crates/ide_completion/src/render/function.rs index 3ec77ca0f..1abeed96d 100644 --- a/crates/ide_completion/src/render/function.rs +++ b/crates/ide_completion/src/render/function.rs | |||
@@ -154,7 +154,7 @@ impl<'a> FunctionRender<'a> { | |||
154 | }; | 154 | }; |
155 | 155 | ||
156 | let mut params_pats = Vec::new(); | 156 | let mut params_pats = Vec::new(); |
157 | let params_ty = if self.ctx.completion.dot_receiver.is_some() || self.receiver.is_some() { | 157 | let params_ty = if self.ctx.completion.has_dot_receiver() || self.receiver.is_some() { |
158 | self.func.method_params(self.ctx.db()).unwrap_or_default() | 158 | self.func.method_params(self.ctx.db()).unwrap_or_default() |
159 | } else { | 159 | } else { |
160 | if let Some(s) = ast_params.self_param() { | 160 | if let Some(s) = ast_params.self_param() { |