about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--crates/ide_completion/src/completions/fn_param.rs20
-rw-r--r--crates/ide_completion/src/render/function.rs72
-rw-r--r--crates/ide_completion/src/tests/fn_param.rs13
3 files changed, 96 insertions, 9 deletions
diff --git a/crates/ide_completion/src/completions/fn_param.rs b/crates/ide_completion/src/completions/fn_param.rs
index 7e9c1f49dea..5bfd2bc1df1 100644
--- a/crates/ide_completion/src/completions/fn_param.rs
+++ b/crates/ide_completion/src/completions/fn_param.rs
@@ -5,7 +5,7 @@ use rustc_hash::FxHashMap;
 use syntax::{
     algo,
     ast::{self, HasModuleItem},
-    match_ast, AstNode, Direction, SyntaxKind,
+    match_ast, AstNode, Direction, SyntaxKind, TextRange,
 };
 
 use crate::{
@@ -27,12 +27,12 @@ pub(crate) fn complete_fn_param(acc: &mut Completions, ctx: &CompletionContext)
 
     let comma_wrapper = comma_wrapper(ctx);
     let mut add_new_item_to_acc = |label: &str, lookup: String| {
-        let mk_item = |label: &str| {
-            CompletionItem::new(CompletionItemKind::Binding, ctx.source_range(), label)
+        let mk_item = |label: &str, range: TextRange| {
+            CompletionItem::new(CompletionItemKind::Binding, range, label)
         };
         let mut item = match &comma_wrapper {
-            Some(fmt) => mk_item(&fmt(label)),
-            None => mk_item(label),
+            Some((fmt, range)) => mk_item(&fmt(label), *range),
+            None => mk_item(label, ctx.source_range()),
         };
         item.lookup_by(lookup);
         item.add_to(acc)
@@ -162,14 +162,16 @@ fn should_add_self_completions(ctx: &CompletionContext, param_list: &ast::ParamL
     inside_impl && no_params
 }
 
-fn comma_wrapper(ctx: &CompletionContext) -> Option<impl Fn(&str) -> String> {
+fn comma_wrapper(ctx: &CompletionContext) -> Option<(impl Fn(&str) -> String, TextRange)> {
+    let param = ctx.token.ancestors().find(|node| node.kind() == SyntaxKind::PARAM)?;
+
     let next_token_kind = {
-        let t = ctx.token.next_token()?;
+        let t = param.last_token()?.next_token()?;
         let t = algo::skip_whitespace_token(t, Direction::Next)?;
         t.kind()
     };
     let prev_token_kind = {
-        let t = ctx.previous_token.clone()?;
+        let t = param.first_token()?.prev_token()?;
         let t = algo::skip_whitespace_token(t, Direction::Prev)?;
         t.kind()
     };
@@ -182,5 +184,5 @@ fn comma_wrapper(ctx: &CompletionContext) -> Option<impl Fn(&str) -> String> {
         matches!(prev_token_kind, SyntaxKind::COMMA | SyntaxKind::L_PAREN | SyntaxKind::PIPE);
     let leading = if has_leading_comma { "" } else { ", " };
 
-    Some(move |param: &_| format!("{}{}{}", leading, param, trailing))
+    Some((move |label: &_| (format!("{}{}{}", leading, label, trailing)), param.text_range()))
 }
diff --git a/crates/ide_completion/src/render/function.rs b/crates/ide_completion/src/render/function.rs
index 9e5f91db39c..2ae300ab653 100644
--- a/crates/ide_completion/src/render/function.rs
+++ b/crates/ide_completion/src/render/function.rs
@@ -565,4 +565,76 @@ fn main() {
 "#,
         );
     }
+
+    #[test]
+    fn complete_fn_param() {
+        // has mut kw
+        check_edit(
+            "mut bar",
+            r#"
+fn f(foo: (), mut bar: u32) {}
+fn g(foo: (), mut ba$0)
+"#,
+            r#"
+fn f(foo: (), mut bar: u32) {}
+fn g(foo: (), mut bar: u32)
+"#,
+        );
+
+        // has type param
+        check_edit(
+            "mut bar",
+            r#"
+fn g(foo: (), mut ba$0: u32)
+fn f(foo: (), mut bar: u32) {}
+"#,
+            r#"
+fn g(foo: (), mut bar: u32)
+fn f(foo: (), mut bar: u32) {}
+"#,
+        );
+    }
+
+    #[test]
+    fn complete_fn_mut_param_add_comma() {
+        // add leading and trailing comma
+        check_edit(
+            "mut bar",
+            r#"
+fn f(foo: (), mut bar: u32) {}
+fn g(foo: ()mut ba$0 baz: ())
+"#,
+            r#"
+fn f(foo: (), mut bar: u32) {}
+fn g(foo: (), mut bar: u32, baz: ())
+"#,
+        );
+    }
+
+    #[test]
+    fn complete_fn_mut_param_has_attribute() {
+        check_edit(
+            "mut bar",
+            r#"
+fn f(foo: (), #[baz = "qux"] mut bar: u32) {}
+fn g(foo: (), mut ba$0)
+"#,
+            r#"
+fn f(foo: (), #[baz = "qux"] mut bar: u32) {}
+fn g(foo: (), #[baz = "qux"] mut bar: u32)
+"#,
+        );
+
+        check_edit(
+            "mut bar",
+            r#"
+fn f(foo: (), #[baz = "qux"] mut bar: u32) {}
+fn g(foo: (), #[baz = "qux"] mut ba$0)
+"#,
+            r#"
+fn f(foo: (), #[baz = "qux"] mut bar: u32) {}
+fn g(foo: (), #[baz = "qux"] mut bar: u32)
+"#,
+        );
+    }
 }
diff --git a/crates/ide_completion/src/tests/fn_param.rs b/crates/ide_completion/src/tests/fn_param.rs
index 779ec0c3a76..678c99aa7ad 100644
--- a/crates/ide_completion/src/tests/fn_param.rs
+++ b/crates/ide_completion/src/tests/fn_param.rs
@@ -232,3 +232,16 @@ fn bar(bar$0) {}
         "#]],
     )
 }
+
+#[test]
+fn completes_for_params_with_attributes() {
+    check(
+        r#"
+fn f(foo: (), #[baz = "qux"] mut bar: u32) {}
+fn g(foo: (), #[baz = "qux"] mut ba$0)
+"#,
+        expect![[r##"
+            bn #[baz = "qux"] mut bar: u32
+        "##]],
+    )
+}