aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide_api/src/completion/presentation.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide_api/src/completion/presentation.rs')
-rw-r--r--crates/ra_ide_api/src/completion/presentation.rs136
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
3use hir::{Docs, HasSource, HirDisplay, ScopeDef, Ty, TypeWalk}; 3use hir::{db::HirDatabase, Docs, HasSource, HirDisplay, ScopeDef, Ty, TypeWalk};
4use join_to_string::join; 4use join_to_string::join;
5use ra_syntax::ast::NameOwner; 5use ra_syntax::ast::NameOwner;
6use test_utils::tested_by; 6use test_utils::tested_by;
7 7
8use crate::completion::{ 8use crate::completion::{
9 CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions, 9 db, CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions,
10}; 10};
11 11
12use crate::display::{const_label, function_label, macro_label, type_label}; 12use 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
246fn 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)]
226mod tests { 252mod 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}