diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2019-10-09 09:16:18 +0100 |
---|---|---|
committer | GitHub <[email protected]> | 2019-10-09 09:16:18 +0100 |
commit | d5a6cac3357f22dea2e630e17d0f091988cdd558 (patch) | |
tree | 416648fde13020d33d62068a5d52221c66c210b5 /crates/ra_ide_api/src/completion/presentation.rs | |
parent | 06a8deae4a29949f438d66c54eed4e016ac35432 (diff) | |
parent | e0b1c17dcb367a3edfd9df4b1d7cfbcd059cd207 (diff) |
Merge #1970
1970: Add <> when completing generics r=matklad a=matklad
@flodiebold wdyt? Is it correct that we always need to add `<>` in generic types?
Co-authored-by: Aleksey Kladov <[email protected]>
Diffstat (limited to 'crates/ra_ide_api/src/completion/presentation.rs')
-rw-r--r-- | crates/ra_ide_api/src/completion/presentation.rs | 136 |
1 files changed, 124 insertions, 12 deletions
diff --git a/crates/ra_ide_api/src/completion/presentation.rs b/crates/ra_ide_api/src/completion/presentation.rs index eb480a775..400a266a2 100644 --- a/crates/ra_ide_api/src/completion/presentation.rs +++ b/crates/ra_ide_api/src/completion/presentation.rs | |||
@@ -1,12 +1,12 @@ | |||
1 | //! This modules takes care of rendering various definitions as completion items. | 1 | //! This modules takes care of rendering various definitions as completion items. |
2 | 2 | ||
3 | use hir::{Docs, HasSource, HirDisplay, ScopeDef, Ty, TypeWalk}; | 3 | use hir::{db::HirDatabase, Docs, HasSource, HirDisplay, ScopeDef, Ty, TypeWalk}; |
4 | use join_to_string::join; | 4 | use join_to_string::join; |
5 | use ra_syntax::ast::NameOwner; | 5 | use ra_syntax::ast::NameOwner; |
6 | use test_utils::tested_by; | 6 | use test_utils::tested_by; |
7 | 7 | ||
8 | use crate::completion::{ | 8 | use crate::completion::{ |
9 | CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions, | 9 | db, CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions, |
10 | }; | 10 | }; |
11 | 11 | ||
12 | use crate::display::{const_label, function_label, macro_label, type_label}; | 12 | use crate::display::{const_label, function_label, macro_label, type_label}; |
@@ -50,14 +50,8 @@ impl Completions { | |||
50 | ScopeDef::ModuleDef(Function(func)) => { | 50 | ScopeDef::ModuleDef(Function(func)) => { |
51 | return self.add_function_with_name(ctx, Some(local_name), *func); | 51 | return self.add_function_with_name(ctx, Some(local_name), *func); |
52 | } | 52 | } |
53 | ScopeDef::ModuleDef(Adt(hir::Adt::Struct(it))) => { | 53 | ScopeDef::ModuleDef(Adt(adt)) => { |
54 | (CompletionItemKind::Struct, it.docs(ctx.db)) | 54 | return self.add_adt_with_name(ctx, local_name, *adt); |
55 | } | ||
56 | ScopeDef::ModuleDef(Adt(hir::Adt::Union(it))) => { | ||
57 | (CompletionItemKind::Struct, it.docs(ctx.db)) | ||
58 | } | ||
59 | ScopeDef::ModuleDef(Adt(hir::Adt::Enum(it))) => { | ||
60 | (CompletionItemKind::Enum, it.docs(ctx.db)) | ||
61 | } | 55 | } |
62 | ScopeDef::ModuleDef(EnumVariant(it)) => { | 56 | ScopeDef::ModuleDef(EnumVariant(it)) => { |
63 | (CompletionItemKind::EnumVariant, it.docs(ctx.db)) | 57 | (CompletionItemKind::EnumVariant, it.docs(ctx.db)) |
@@ -156,7 +150,8 @@ impl Completions { | |||
156 | }) | 150 | }) |
157 | .set_documentation(func.docs(ctx.db)) | 151 | .set_documentation(func.docs(ctx.db)) |
158 | .detail(detail); | 152 | .detail(detail); |
159 | // If not an import, add parenthesis automatically. | 153 | |
154 | // Add `<>` for generic types | ||
160 | if ctx.use_item_syntax.is_none() | 155 | if ctx.use_item_syntax.is_none() |
161 | && !ctx.is_call | 156 | && !ctx.is_call |
162 | && ctx.db.feature_flags.get("completion.insertion.add-call-parenthesis") | 157 | && ctx.db.feature_flags.get("completion.insertion.add-call-parenthesis") |
@@ -170,9 +165,36 @@ impl Completions { | |||
170 | }; | 165 | }; |
171 | builder = builder.insert_snippet(snippet); | 166 | builder = builder.insert_snippet(snippet); |
172 | } | 167 | } |
168 | |||
173 | self.add(builder) | 169 | self.add(builder) |
174 | } | 170 | } |
175 | 171 | ||
172 | fn add_adt_with_name(&mut self, ctx: &CompletionContext, name: String, adt: hir::Adt) { | ||
173 | let mut builder = | ||
174 | CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.clone()); | ||
175 | |||
176 | let kind = match adt { | ||
177 | hir::Adt::Struct(_) => CompletionItemKind::Struct, | ||
178 | // FIXME: add CompletionItemKind::Union | ||
179 | hir::Adt::Union(_) => CompletionItemKind::Struct, | ||
180 | hir::Adt::Enum(_) => CompletionItemKind::Enum, | ||
181 | }; | ||
182 | let docs = adt.docs(ctx.db); | ||
183 | |||
184 | // If not an import, add parenthesis automatically. | ||
185 | if ctx.is_path_type | ||
186 | && !ctx.has_type_args | ||
187 | && ctx.db.feature_flags.get("completion.insertion.add-call-parenthesis") | ||
188 | { | ||
189 | if has_non_default_type_params(adt, ctx.db) { | ||
190 | tested_by!(inserts_angle_brackets_for_generics); | ||
191 | builder = builder.insert_snippet(format!("{}<$0>", name)); | ||
192 | } | ||
193 | } | ||
194 | |||
195 | builder.kind(kind).set_documentation(docs).add_to(self) | ||
196 | } | ||
197 | |||
176 | pub(crate) fn add_const(&mut self, ctx: &CompletionContext, constant: hir::Const) { | 198 | pub(crate) fn add_const(&mut self, ctx: &CompletionContext, constant: hir::Const) { |
177 | let ast_node = constant.source(ctx.db).ast; | 199 | let ast_node = constant.source(ctx.db).ast; |
178 | let name = match ast_node.name() { | 200 | let name = match ast_node.name() { |
@@ -213,7 +235,6 @@ impl Completions { | |||
213 | .separator(", ") | 235 | .separator(", ") |
214 | .surround_with("(", ")") | 236 | .surround_with("(", ")") |
215 | .to_string(); | 237 | .to_string(); |
216 | |||
217 | CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.to_string()) | 238 | CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.to_string()) |
218 | .kind(CompletionItemKind::EnumVariant) | 239 | .kind(CompletionItemKind::EnumVariant) |
219 | .set_documentation(variant.docs(ctx.db)) | 240 | .set_documentation(variant.docs(ctx.db)) |
@@ -222,6 +243,11 @@ impl Completions { | |||
222 | } | 243 | } |
223 | } | 244 | } |
224 | 245 | ||
246 | fn has_non_default_type_params(adt: hir::Adt, db: &db::RootDatabase) -> bool { | ||
247 | let subst = db.generic_defaults(adt.into()); | ||
248 | subst.iter().any(|ty| ty == &Ty::Unknown) | ||
249 | } | ||
250 | |||
225 | #[cfg(test)] | 251 | #[cfg(test)] |
226 | mod tests { | 252 | mod tests { |
227 | use crate::completion::{do_completion, CompletionItem, CompletionKind}; | 253 | use crate::completion::{do_completion, CompletionItem, CompletionKind}; |
@@ -389,4 +415,90 @@ mod tests { | |||
389 | ]"# | 415 | ]"# |
390 | ); | 416 | ); |
391 | } | 417 | } |
418 | |||
419 | #[test] | ||
420 | fn inserts_angle_brackets_for_generics() { | ||
421 | covers!(inserts_angle_brackets_for_generics); | ||
422 | assert_debug_snapshot!( | ||
423 | do_reference_completion( | ||
424 | r" | ||
425 | struct Vec<T> {} | ||
426 | fn foo(xs: Ve<|>) | ||
427 | " | ||
428 | ), | ||
429 | @r###" | ||
430 | [ | ||
431 | CompletionItem { | ||
432 | label: "Vec", | ||
433 | source_range: [61; 63), | ||
434 | delete: [61; 63), | ||
435 | insert: "Vec<$0>", | ||
436 | kind: Struct, | ||
437 | }, | ||
438 | CompletionItem { | ||
439 | label: "foo", | ||
440 | source_range: [61; 63), | ||
441 | delete: [61; 63), | ||
442 | insert: "foo($0)", | ||
443 | kind: Function, | ||
444 | detail: "fn foo(xs: Ve)", | ||
445 | }, | ||
446 | ] | ||
447 | "### | ||
448 | ); | ||
449 | assert_debug_snapshot!( | ||
450 | do_reference_completion( | ||
451 | r" | ||
452 | struct Vec<T = i128> {} | ||
453 | fn foo(xs: Ve<|>) | ||
454 | " | ||
455 | ), | ||
456 | @r###" | ||
457 | [ | ||
458 | CompletionItem { | ||
459 | label: "Vec", | ||
460 | source_range: [68; 70), | ||
461 | delete: [68; 70), | ||
462 | insert: "Vec", | ||
463 | kind: Struct, | ||
464 | }, | ||
465 | CompletionItem { | ||
466 | label: "foo", | ||
467 | source_range: [68; 70), | ||
468 | delete: [68; 70), | ||
469 | insert: "foo($0)", | ||
470 | kind: Function, | ||
471 | detail: "fn foo(xs: Ve)", | ||
472 | }, | ||
473 | ] | ||
474 | "### | ||
475 | ); | ||
476 | assert_debug_snapshot!( | ||
477 | do_reference_completion( | ||
478 | r" | ||
479 | struct Vec<T> {} | ||
480 | fn foo(xs: Ve<|><i128>) | ||
481 | " | ||
482 | ), | ||
483 | @r###" | ||
484 | [ | ||
485 | CompletionItem { | ||
486 | label: "Vec", | ||
487 | source_range: [61; 63), | ||
488 | delete: [61; 63), | ||
489 | insert: "Vec", | ||
490 | kind: Struct, | ||
491 | }, | ||
492 | CompletionItem { | ||
493 | label: "foo", | ||
494 | source_range: [61; 63), | ||
495 | delete: [61; 63), | ||
496 | insert: "foo($0)", | ||
497 | kind: Function, | ||
498 | detail: "fn foo(xs: Ve<i128>)", | ||
499 | }, | ||
500 | ] | ||
501 | "### | ||
502 | ); | ||
503 | } | ||
392 | } | 504 | } |