diff options
Diffstat (limited to 'crates/completion/src')
-rw-r--r-- | crates/completion/src/completions/postfix.rs | 86 | ||||
-rw-r--r-- | crates/completion/src/completions/qualified_path.rs | 40 | ||||
-rw-r--r-- | crates/completion/src/completions/trait_impl.rs | 2 | ||||
-rw-r--r-- | crates/completion/src/lib.rs | 2 | ||||
-rw-r--r-- | crates/completion/src/render/builder_ext.rs | 5 | ||||
-rw-r--r-- | crates/completion/src/render/function.rs | 69 |
6 files changed, 164 insertions, 40 deletions
diff --git a/crates/completion/src/completions/postfix.rs b/crates/completion/src/completions/postfix.rs index 7fbda7a6b..c8ba63cd3 100644 --- a/crates/completion/src/completions/postfix.rs +++ b/crates/completion/src/completions/postfix.rs | |||
@@ -5,6 +5,7 @@ mod format_like; | |||
5 | use ide_db::ty_filter::TryEnum; | 5 | use ide_db::ty_filter::TryEnum; |
6 | use syntax::{ | 6 | use syntax::{ |
7 | ast::{self, AstNode, AstToken}, | 7 | ast::{self, AstNode, AstToken}, |
8 | SyntaxKind::{BLOCK_EXPR, EXPR_STMT}, | ||
8 | TextRange, TextSize, | 9 | TextRange, TextSize, |
9 | }; | 10 | }; |
10 | use text_edit::TextEdit; | 11 | use text_edit::TextEdit; |
@@ -220,6 +221,29 @@ pub(crate) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) { | |||
220 | ) | 221 | ) |
221 | .add_to(acc); | 222 | .add_to(acc); |
222 | 223 | ||
224 | if let Some(parent) = dot_receiver.syntax().parent().and_then(|p| p.parent()) { | ||
225 | if matches!(parent.kind(), BLOCK_EXPR | EXPR_STMT) { | ||
226 | postfix_snippet( | ||
227 | ctx, | ||
228 | cap, | ||
229 | &dot_receiver, | ||
230 | "let", | ||
231 | "let", | ||
232 | &format!("let $0 = {};", receiver_text), | ||
233 | ) | ||
234 | .add_to(acc); | ||
235 | postfix_snippet( | ||
236 | ctx, | ||
237 | cap, | ||
238 | &dot_receiver, | ||
239 | "letm", | ||
240 | "let mut", | ||
241 | &format!("let mut $0 = {};", receiver_text), | ||
242 | ) | ||
243 | .add_to(acc); | ||
244 | } | ||
245 | } | ||
246 | |||
223 | if let ast::Expr::Literal(literal) = dot_receiver.clone() { | 247 | if let ast::Expr::Literal(literal) = dot_receiver.clone() { |
224 | if let Some(literal_text) = ast::String::cast(literal.token()) { | 248 | if let Some(literal_text) = ast::String::cast(literal.token()) { |
225 | add_format_like_completions(acc, ctx, &dot_receiver, cap, &literal_text); | 249 | add_format_like_completions(acc, ctx, &dot_receiver, cap, &literal_text); |
@@ -296,6 +320,38 @@ fn main() { | |||
296 | sn dbg dbg!(expr) | 320 | sn dbg dbg!(expr) |
297 | sn dbgr dbg!(&expr) | 321 | sn dbgr dbg!(&expr) |
298 | sn if if expr {} | 322 | sn if if expr {} |
323 | sn let let | ||
324 | sn letm let mut | ||
325 | sn match match expr {} | ||
326 | sn not !expr | ||
327 | sn ok Ok(expr) | ||
328 | sn ref &expr | ||
329 | sn refm &mut expr | ||
330 | sn some Some(expr) | ||
331 | sn while while expr {} | ||
332 | "#]], | ||
333 | ); | ||
334 | } | ||
335 | |||
336 | #[test] | ||
337 | fn postfix_completion_works_for_function_calln() { | ||
338 | check( | ||
339 | r#" | ||
340 | fn foo(elt: bool) -> bool { | ||
341 | !elt | ||
342 | } | ||
343 | |||
344 | fn main() { | ||
345 | let bar = true; | ||
346 | foo(bar.<|>) | ||
347 | } | ||
348 | "#, | ||
349 | expect![[r#" | ||
350 | sn box Box::new(expr) | ||
351 | sn call function(expr) | ||
352 | sn dbg dbg!(expr) | ||
353 | sn dbgr dbg!(&expr) | ||
354 | sn if if expr {} | ||
299 | sn match match expr {} | 355 | sn match match expr {} |
300 | sn not !expr | 356 | sn not !expr |
301 | sn ok Ok(expr) | 357 | sn ok Ok(expr) |
@@ -321,6 +377,8 @@ fn main() { | |||
321 | sn call function(expr) | 377 | sn call function(expr) |
322 | sn dbg dbg!(expr) | 378 | sn dbg dbg!(expr) |
323 | sn dbgr dbg!(&expr) | 379 | sn dbgr dbg!(&expr) |
380 | sn let let | ||
381 | sn letm let mut | ||
324 | sn match match expr {} | 382 | sn match match expr {} |
325 | sn ok Ok(expr) | 383 | sn ok Ok(expr) |
326 | sn ref &expr | 384 | sn ref &expr |
@@ -331,6 +389,34 @@ fn main() { | |||
331 | } | 389 | } |
332 | 390 | ||
333 | #[test] | 391 | #[test] |
392 | fn let_middle_block() { | ||
393 | check( | ||
394 | r#" | ||
395 | fn main() { | ||
396 | baz.l<|> | ||
397 | res | ||
398 | } | ||
399 | "#, | ||
400 | expect![[r#" | ||
401 | sn box Box::new(expr) | ||
402 | sn call function(expr) | ||
403 | sn dbg dbg!(expr) | ||
404 | sn dbgr dbg!(&expr) | ||
405 | sn if if expr {} | ||
406 | sn let let | ||
407 | sn letm let mut | ||
408 | sn match match expr {} | ||
409 | sn not !expr | ||
410 | sn ok Ok(expr) | ||
411 | sn ref &expr | ||
412 | sn refm &mut expr | ||
413 | sn some Some(expr) | ||
414 | sn while while expr {} | ||
415 | "#]], | ||
416 | ); | ||
417 | } | ||
418 | |||
419 | #[test] | ||
334 | fn option_iflet() { | 420 | fn option_iflet() { |
335 | check_edit( | 421 | check_edit( |
336 | "ifl", | 422 | "ifl", |
diff --git a/crates/completion/src/completions/qualified_path.rs b/crates/completion/src/completions/qualified_path.rs index d9387054d..bc23bea3f 100644 --- a/crates/completion/src/completions/qualified_path.rs +++ b/crates/completion/src/completions/qualified_path.rs | |||
@@ -353,10 +353,10 @@ impl S { | |||
353 | fn foo() { let _ = S::<|> } | 353 | fn foo() { let _ = S::<|> } |
354 | "#, | 354 | "#, |
355 | expect![[r#" | 355 | expect![[r#" |
356 | ct C const C: i32 = 42; | 356 | ct C const C: i32 = 42; |
357 | ta T type T = i32; | 357 | ta T type T = i32; |
358 | fn a() fn a() | 358 | fn a() fn a() |
359 | me b() fn b(&self) | 359 | me b(…) fn b(&self) |
360 | "#]], | 360 | "#]], |
361 | ); | 361 | ); |
362 | } | 362 | } |
@@ -503,14 +503,14 @@ trait Sub: Super { | |||
503 | fn foo<T: Sub>() { T::<|> } | 503 | fn foo<T: Sub>() { T::<|> } |
504 | "#, | 504 | "#, |
505 | expect![[r#" | 505 | expect![[r#" |
506 | ct C2 const C2: (); | 506 | ct C2 const C2: (); |
507 | ct CONST const CONST: u8; | 507 | ct CONST const CONST: u8; |
508 | ta SubTy type SubTy; | 508 | ta SubTy type SubTy; |
509 | ta Ty type Ty; | 509 | ta Ty type Ty; |
510 | fn func() fn func() | 510 | fn func() fn func() |
511 | me method() fn method(&self) | 511 | me method(…) fn method(&self) |
512 | fn subfunc() fn subfunc() | 512 | fn subfunc() fn subfunc() |
513 | me submethod() fn submethod(&self) | 513 | me submethod(…) fn submethod(&self) |
514 | "#]], | 514 | "#]], |
515 | ); | 515 | ); |
516 | } | 516 | } |
@@ -543,14 +543,14 @@ impl<T> Sub for Wrap<T> { | |||
543 | } | 543 | } |
544 | "#, | 544 | "#, |
545 | expect![[r#" | 545 | expect![[r#" |
546 | ct C2 const C2: () = (); | 546 | ct C2 const C2: () = (); |
547 | ct CONST const CONST: u8 = 0; | 547 | ct CONST const CONST: u8 = 0; |
548 | ta SubTy type SubTy; | 548 | ta SubTy type SubTy; |
549 | ta Ty type Ty; | 549 | ta Ty type Ty; |
550 | fn func() fn func() | 550 | fn func() fn func() |
551 | me method() fn method(&self) | 551 | me method(…) fn method(&self) |
552 | fn subfunc() fn subfunc() | 552 | fn subfunc() fn subfunc() |
553 | me submethod() fn submethod(&self) | 553 | me submethod(…) fn submethod(&self) |
554 | "#]], | 554 | "#]], |
555 | ); | 555 | ); |
556 | } | 556 | } |
diff --git a/crates/completion/src/completions/trait_impl.rs b/crates/completion/src/completions/trait_impl.rs index a14be9c73..e2fe44aff 100644 --- a/crates/completion/src/completions/trait_impl.rs +++ b/crates/completion/src/completions/trait_impl.rs | |||
@@ -139,7 +139,7 @@ fn add_function_impl( | |||
139 | ) { | 139 | ) { |
140 | let fn_name = func.name(ctx.db).to_string(); | 140 | let fn_name = func.name(ctx.db).to_string(); |
141 | 141 | ||
142 | let label = if func.params(ctx.db).is_empty() { | 142 | let label = if func.assoc_fn_params(ctx.db).is_empty() { |
143 | format!("fn {}()", fn_name) | 143 | format!("fn {}()", fn_name) |
144 | } else { | 144 | } else { |
145 | format!("fn {}(..)", fn_name) | 145 | format!("fn {}(..)", fn_name) |
diff --git a/crates/completion/src/lib.rs b/crates/completion/src/lib.rs index aecc1378b..1ec2e9be7 100644 --- a/crates/completion/src/lib.rs +++ b/crates/completion/src/lib.rs | |||
@@ -44,6 +44,8 @@ pub use crate::{ | |||
44 | // - `expr.while` -> `while expr {}` or `while let ... {}` for `Option` or `Result` | 44 | // - `expr.while` -> `while expr {}` or `while let ... {}` for `Option` or `Result` |
45 | // - `expr.ref` -> `&expr` | 45 | // - `expr.ref` -> `&expr` |
46 | // - `expr.refm` -> `&mut expr` | 46 | // - `expr.refm` -> `&mut expr` |
47 | // - `expr.let` -> `let <|> = expr;` | ||
48 | // - `expr.letm` -> `let mut <|> = expr;` | ||
47 | // - `expr.not` -> `!expr` | 49 | // - `expr.not` -> `!expr` |
48 | // - `expr.dbg` -> `dbg!(expr)` | 50 | // - `expr.dbg` -> `dbg!(expr)` |
49 | // - `expr.dbgr` -> `dbg!(&expr)` | 51 | // - `expr.dbgr` -> `dbg!(&expr)` |
diff --git a/crates/completion/src/render/builder_ext.rs b/crates/completion/src/render/builder_ext.rs index 37b0d0459..ce8718bd5 100644 --- a/crates/completion/src/render/builder_ext.rs +++ b/crates/completion/src/render/builder_ext.rs | |||
@@ -5,6 +5,7 @@ use test_utils::mark; | |||
5 | 5 | ||
6 | use crate::{item::Builder, CompletionContext}; | 6 | use crate::{item::Builder, CompletionContext}; |
7 | 7 | ||
8 | #[derive(Debug)] | ||
8 | pub(super) enum Params { | 9 | pub(super) enum Params { |
9 | Named(Vec<String>), | 10 | Named(Vec<String>), |
10 | Anonymous(usize), | 11 | Anonymous(usize), |
@@ -24,7 +25,7 @@ impl Params { | |||
24 | } | 25 | } |
25 | 26 | ||
26 | impl Builder { | 27 | impl Builder { |
27 | pub(super) fn should_add_parems(&self, ctx: &CompletionContext) -> bool { | 28 | fn should_add_parens(&self, ctx: &CompletionContext) -> bool { |
28 | if !ctx.config.add_call_parenthesis { | 29 | if !ctx.config.add_call_parenthesis { |
29 | return false; | 30 | return false; |
30 | } | 31 | } |
@@ -58,7 +59,7 @@ impl Builder { | |||
58 | name: String, | 59 | name: String, |
59 | params: Params, | 60 | params: Params, |
60 | ) -> Builder { | 61 | ) -> Builder { |
61 | if !self.should_add_parems(ctx) { | 62 | if !self.should_add_parens(ctx) { |
62 | return self; | 63 | return self; |
63 | } | 64 | } |
64 | 65 | ||
diff --git a/crates/completion/src/render/function.rs b/crates/completion/src/render/function.rs index 542383d7e..00e3eb203 100644 --- a/crates/completion/src/render/function.rs +++ b/crates/completion/src/render/function.rs | |||
@@ -2,6 +2,7 @@ | |||
2 | 2 | ||
3 | use hir::{HasSource, Type}; | 3 | use hir::{HasSource, Type}; |
4 | use syntax::{ast::Fn, display::function_declaration}; | 4 | use syntax::{ast::Fn, display::function_declaration}; |
5 | use test_utils::mark; | ||
5 | 6 | ||
6 | use crate::{ | 7 | use crate::{ |
7 | item::{CompletionItem, CompletionItemKind, CompletionKind, ImportToAdd}, | 8 | item::{CompletionItem, CompletionItemKind, CompletionKind, ImportToAdd}, |
@@ -22,7 +23,7 @@ pub(crate) fn render_fn<'a>( | |||
22 | struct FunctionRender<'a> { | 23 | struct FunctionRender<'a> { |
23 | ctx: RenderContext<'a>, | 24 | ctx: RenderContext<'a>, |
24 | name: String, | 25 | name: String, |
25 | fn_: hir::Function, | 26 | func: hir::Function, |
26 | ast_node: Fn, | 27 | ast_node: Fn, |
27 | } | 28 | } |
28 | 29 | ||
@@ -35,15 +36,15 @@ impl<'a> FunctionRender<'a> { | |||
35 | let name = local_name.unwrap_or_else(|| fn_.name(ctx.db()).to_string()); | 36 | let name = local_name.unwrap_or_else(|| fn_.name(ctx.db()).to_string()); |
36 | let ast_node = fn_.source(ctx.db()).value; | 37 | let ast_node = fn_.source(ctx.db()).value; |
37 | 38 | ||
38 | FunctionRender { ctx, name, fn_, ast_node } | 39 | FunctionRender { ctx, name, func: fn_, ast_node } |
39 | } | 40 | } |
40 | 41 | ||
41 | fn render(self, import_to_add: Option<ImportToAdd>) -> CompletionItem { | 42 | fn render(self, import_to_add: Option<ImportToAdd>) -> CompletionItem { |
42 | let params = self.params(); | 43 | let params = self.params(); |
43 | CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), self.name.clone()) | 44 | CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), self.name.clone()) |
44 | .kind(self.kind()) | 45 | .kind(self.kind()) |
45 | .set_documentation(self.ctx.docs(self.fn_)) | 46 | .set_documentation(self.ctx.docs(self.func)) |
46 | .set_deprecated(self.ctx.is_deprecated(self.fn_)) | 47 | .set_deprecated(self.ctx.is_deprecated(self.func)) |
47 | .detail(self.detail()) | 48 | .detail(self.detail()) |
48 | .add_call_parens(self.ctx.completion, self.name, params) | 49 | .add_call_parens(self.ctx.completion, self.name, params) |
49 | .add_import(import_to_add) | 50 | .add_import(import_to_add) |
@@ -67,27 +68,39 @@ impl<'a> FunctionRender<'a> { | |||
67 | } | 68 | } |
68 | 69 | ||
69 | fn params(&self) -> Params { | 70 | fn params(&self) -> Params { |
70 | let params_ty = self.fn_.params(self.ctx.db()); | 71 | let ast_params = match self.ast_node.param_list() { |
71 | let params = self | 72 | Some(it) => it, |
72 | .ast_node | 73 | None => return Params::Named(Vec::new()), |
73 | .param_list() | 74 | }; |
75 | |||
76 | let mut params_pats = Vec::new(); | ||
77 | let params_ty = if self.ctx.completion.dot_receiver.is_some() { | ||
78 | self.func.method_params(self.ctx.db()).unwrap_or_default() | ||
79 | } else { | ||
80 | if let Some(s) = ast_params.self_param() { | ||
81 | mark::hit!(parens_for_method_call_as_assoc_fn); | ||
82 | params_pats.push(Some(s.to_string())); | ||
83 | } | ||
84 | self.func.assoc_fn_params(self.ctx.db()) | ||
85 | }; | ||
86 | params_pats | ||
87 | .extend(ast_params.params().into_iter().map(|it| it.pat().map(|it| it.to_string()))); | ||
88 | |||
89 | let params = params_pats | ||
74 | .into_iter() | 90 | .into_iter() |
75 | .flat_map(|it| it.params()) | ||
76 | .zip(params_ty) | 91 | .zip(params_ty) |
77 | .flat_map(|(it, param_ty)| { | 92 | .flat_map(|(pat, param_ty)| { |
78 | if let Some(pat) = it.pat() { | 93 | let pat = pat?; |
79 | let name = pat.to_string(); | 94 | let name = pat.to_string(); |
80 | let arg = name.trim_start_matches("mut ").trim_start_matches('_'); | 95 | let arg = name.trim_start_matches("mut ").trim_start_matches('_'); |
81 | return Some(self.add_arg(arg, param_ty.ty())); | 96 | Some(self.add_arg(arg, param_ty.ty())) |
82 | } | ||
83 | None | ||
84 | }) | 97 | }) |
85 | .collect(); | 98 | .collect(); |
86 | Params::Named(params) | 99 | Params::Named(params) |
87 | } | 100 | } |
88 | 101 | ||
89 | fn kind(&self) -> CompletionItemKind { | 102 | fn kind(&self) -> CompletionItemKind { |
90 | if self.fn_.self_param(self.ctx.db()).is_some() { | 103 | if self.func.self_param(self.ctx.db()).is_some() { |
91 | CompletionItemKind::Method | 104 | CompletionItemKind::Method |
92 | } else { | 105 | } else { |
93 | CompletionItemKind::Function | 106 | CompletionItemKind::Function |
@@ -173,6 +186,28 @@ fn bar(s: &S) { | |||
173 | } | 186 | } |
174 | 187 | ||
175 | #[test] | 188 | #[test] |
189 | fn parens_for_method_call_as_assoc_fn() { | ||
190 | mark::check!(parens_for_method_call_as_assoc_fn); | ||
191 | check_edit( | ||
192 | "foo", | ||
193 | r#" | ||
194 | struct S; | ||
195 | impl S { | ||
196 | fn foo(&self) {} | ||
197 | } | ||
198 | fn main() { S::f<|> } | ||
199 | "#, | ||
200 | r#" | ||
201 | struct S; | ||
202 | impl S { | ||
203 | fn foo(&self) {} | ||
204 | } | ||
205 | fn main() { S::foo(${1:&self})$0 } | ||
206 | "#, | ||
207 | ); | ||
208 | } | ||
209 | |||
210 | #[test] | ||
176 | fn suppress_arg_snippets() { | 211 | fn suppress_arg_snippets() { |
177 | mark::check!(suppress_arg_snippets); | 212 | mark::check!(suppress_arg_snippets); |
178 | check_edit_with_config( | 213 | check_edit_with_config( |