diff --git a/crates/ide_completion/src/completions/fn_param.rs b/crates/ide_completion/src/completions/fn_param.rs index 80ad3b9c8f..1488436df3 100644 --- a/crates/ide_completion/src/completions/fn_param.rs +++ b/crates/ide_completion/src/completions/fn_param.rs @@ -6,14 +6,17 @@ use syntax::{ match_ast, AstNode, }; -use crate::{CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions}; +use crate::{ + context::ParamKind, CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, + Completions, +}; /// Complete repeated parameters, both name and type. For example, if all /// functions in a file have a `spam: &mut Spam` parameter, a completion with /// `spam: &mut Spam` insert text/label and `spam` lookup string will be /// suggested. pub(crate) fn complete_fn_param(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> { - if !ctx.is_param { + if ctx.is_param != Some(ParamKind::Function) { return None; } diff --git a/crates/ide_completion/src/context.rs b/crates/ide_completion/src/context.rs index e38234a8a5..f4637c401b 100644 --- a/crates/ide_completion/src/context.rs +++ b/crates/ide_completion/src/context.rs @@ -60,6 +60,12 @@ pub(crate) enum CallKind { Mac, Expr, } + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub(crate) enum ParamKind { + Function, + Closure, +} /// `CompletionContext` is created early during completion to figure out, where /// exactly is the cursor, syntax-wise. #[derive(Debug)] @@ -91,7 +97,7 @@ pub(crate) struct CompletionContext<'a> { // potentially set if we are completing a name pub(super) is_pat_or_const: Option, - pub(super) is_param: bool, + pub(super) is_param: Option, pub(super) completion_location: Option, pub(super) prev_sibling: Option, @@ -158,7 +164,7 @@ impl<'a> CompletionContext<'a> { lifetime_allowed: false, is_label_ref: false, is_pat_or_const: None, - is_param: false, + is_param: None, completion_location: None, prev_sibling: None, attribute_under_caret: None, @@ -670,7 +676,17 @@ impl<'a> CompletionContext<'a> { self.fill_impl_def(); } - self.is_param |= is_node::(name.syntax()); + if let Some(param) = name + .syntax() + .ancestors() + .find_map(ast::Param::cast) + .filter(|it| it.syntax().text_range() == name.syntax().text_range()) + { + let is_closure_param = + param.syntax().ancestors().nth(2).and_then(ast::ClosureExpr::cast).is_some(); + self.is_param = + Some(if is_closure_param { ParamKind::Closure } else { ParamKind::Function }); + } } fn classify_name_ref(&mut self, original_file: &SyntaxNode, name_ref: ast::NameRef) { @@ -774,13 +790,6 @@ fn find_node_with_range(syntax: &SyntaxNode, range: TextRange) -> Op syntax.covering_element(range).ancestors().find_map(N::cast) } -fn is_node(node: &SyntaxNode) -> bool { - match node.ancestors().find_map(N::cast) { - None => false, - Some(n) => n.syntax().text_range() == node.text_range(), - } -} - fn path_or_use_tree_qualifier(path: &ast::Path) -> Option<(ast::Path, bool)> { if let Some(qual) = path.qualifier() { return Some((qual, false)); diff --git a/crates/ide_completion/src/render/pattern.rs b/crates/ide_completion/src/render/pattern.rs index 17dd6662f5..67961a602f 100644 --- a/crates/ide_completion/src/render/pattern.rs +++ b/crates/ide_completion/src/render/pattern.rs @@ -4,7 +4,10 @@ use hir::{db::HirDatabase, HasAttrs, HasVisibility, Name, StructKind}; use ide_db::helpers::SnippetCap; use itertools::Itertools; -use crate::{item::CompletionKind, render::RenderContext, CompletionItem, CompletionItemKind}; +use crate::{ + context::ParamKind, item::CompletionKind, render::RenderContext, CompletionItem, + CompletionItemKind, +}; pub(crate) fn render_struct_pat( ctx: RenderContext<'_>, @@ -83,7 +86,7 @@ fn render_pat( _ => return None, }; - if ctx.completion.is_param { + if ctx.completion.is_param == Some(ParamKind::Function) { pat.push(':'); pat.push(' '); pat.push_str(name); diff --git a/crates/ide_completion/src/render/struct_literal.rs b/crates/ide_completion/src/render/struct_literal.rs index a6571eb022..68871a4671 100644 --- a/crates/ide_completion/src/render/struct_literal.rs +++ b/crates/ide_completion/src/render/struct_literal.rs @@ -58,11 +58,6 @@ fn render_literal( _ => return None, }; - if ctx.completion.is_param { - literal.push(':'); - literal.push(' '); - literal.push_str(name); - } if ctx.snippet_cap().is_some() { literal.push_str("$0"); } diff --git a/crates/ide_completion/src/tests/pattern.rs b/crates/ide_completion/src/tests/pattern.rs index 10647e490e..3e10575b19 100644 --- a/crates/ide_completion/src/tests/pattern.rs +++ b/crates/ide_completion/src/tests/pattern.rs @@ -309,3 +309,41 @@ fn outer(Foo { bar$0 }: Foo) {} expect![[r#""#]], ) } + +#[test] +fn completes_in_fn_param() { + check_empty( + r#" +struct Foo { bar: Bar } +struct Bar(u32); +fn foo($0) {} +"#, + expect![[r#" + kw mut + bn Foo Foo { bar$1 }: Foo$0 + st Foo + bn Bar Bar($1): Bar$0 + st Bar + "#]], + ) +} + +#[test] +fn completes_in_closure_param() { + check_empty( + r#" +struct Foo { bar: Bar } +struct Bar(u32); +fn foo() { + |$0| {}; +} +"#, + expect![[r#" + kw mut + bn Foo Foo { bar$1 }$0 + st Foo + bn Bar Bar($1)$0 + st Bar + "#]], + ) +}