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.rs114
1 files changed, 109 insertions, 5 deletions
diff --git a/crates/ra_ide_api/src/completion/presentation.rs b/crates/ra_ide_api/src/completion/presentation.rs
index 2d670372e..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};
@@ -150,7 +150,8 @@ impl Completions {
150 }) 150 })
151 .set_documentation(func.docs(ctx.db)) 151 .set_documentation(func.docs(ctx.db))
152 .detail(detail); 152 .detail(detail);
153 // If not an import, add parenthesis automatically. 153
154 // Add `<>` for generic types
154 if ctx.use_item_syntax.is_none() 155 if ctx.use_item_syntax.is_none()
155 && !ctx.is_call 156 && !ctx.is_call
156 && ctx.db.feature_flags.get("completion.insertion.add-call-parenthesis") 157 && ctx.db.feature_flags.get("completion.insertion.add-call-parenthesis")
@@ -164,11 +165,13 @@ impl Completions {
164 }; 165 };
165 builder = builder.insert_snippet(snippet); 166 builder = builder.insert_snippet(snippet);
166 } 167 }
168
167 self.add(builder) 169 self.add(builder)
168 } 170 }
169 171
170 fn add_adt_with_name(&mut self, ctx: &CompletionContext, name: String, adt: hir::Adt) { 172 fn add_adt_with_name(&mut self, ctx: &CompletionContext, name: String, adt: hir::Adt) {
171 let builder = CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name); 173 let mut builder =
174 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.clone());
172 175
173 let kind = match adt { 176 let kind = match adt {
174 hir::Adt::Struct(_) => CompletionItemKind::Struct, 177 hir::Adt::Struct(_) => CompletionItemKind::Struct,
@@ -178,6 +181,17 @@ impl Completions {
178 }; 181 };
179 let docs = adt.docs(ctx.db); 182 let docs = adt.docs(ctx.db);
180 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
181 builder.kind(kind).set_documentation(docs).add_to(self) 195 builder.kind(kind).set_documentation(docs).add_to(self)
182 } 196 }
183 197
@@ -221,7 +235,6 @@ impl Completions {
221 .separator(", ") 235 .separator(", ")
222 .surround_with("(", ")") 236 .surround_with("(", ")")
223 .to_string(); 237 .to_string();
224
225 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.to_string()) 238 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.to_string())
226 .kind(CompletionItemKind::EnumVariant) 239 .kind(CompletionItemKind::EnumVariant)
227 .set_documentation(variant.docs(ctx.db)) 240 .set_documentation(variant.docs(ctx.db))
@@ -230,6 +243,11 @@ impl Completions {
230 } 243 }
231} 244}
232 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
233#[cfg(test)] 251#[cfg(test)]
234mod tests { 252mod tests {
235 use crate::completion::{do_completion, CompletionItem, CompletionKind}; 253 use crate::completion::{do_completion, CompletionItem, CompletionKind};
@@ -397,4 +415,90 @@ mod tests {
397]"# 415]"#
398 ); 416 );
399 } 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 }
400} 504}