aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide/src/completion/presentation.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide/src/completion/presentation.rs')
-rw-r--r--crates/ra_ide/src/completion/presentation.rs1230
1 files changed, 0 insertions, 1230 deletions
diff --git a/crates/ra_ide/src/completion/presentation.rs b/crates/ra_ide/src/completion/presentation.rs
deleted file mode 100644
index 9a94ff476..000000000
--- a/crates/ra_ide/src/completion/presentation.rs
+++ /dev/null
@@ -1,1230 +0,0 @@
1//! This modules takes care of rendering various definitions as completion items.
2//! It also handles scoring (sorting) completions.
3
4use hir::{Docs, HasAttrs, HasSource, HirDisplay, ModPath, ScopeDef, StructKind, Type};
5use ra_syntax::ast::NameOwner;
6use stdx::SepBy;
7use test_utils::mark;
8
9use crate::{
10 completion::{
11 completion_item::Builder, CompletionContext, CompletionItem, CompletionItemKind,
12 CompletionKind, Completions,
13 },
14 display::{const_label, function_declaration, macro_label, type_label},
15 CompletionScore, RootDatabase,
16};
17
18impl Completions {
19 pub(crate) fn add_field(&mut self, ctx: &CompletionContext, field: hir::Field, ty: &Type) {
20 let is_deprecated = is_deprecated(field, ctx.db);
21 let name = field.name(ctx.db);
22 let mut completion_item =
23 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.to_string())
24 .kind(CompletionItemKind::Field)
25 .detail(ty.display(ctx.db).to_string())
26 .set_documentation(field.docs(ctx.db))
27 .set_deprecated(is_deprecated);
28
29 if let Some(score) = compute_score(ctx, &ty, &name.to_string()) {
30 completion_item = completion_item.set_score(score);
31 }
32
33 completion_item.add_to(self);
34 }
35
36 pub(crate) fn add_tuple_field(&mut self, ctx: &CompletionContext, field: usize, ty: &Type) {
37 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), field.to_string())
38 .kind(CompletionItemKind::Field)
39 .detail(ty.display(ctx.db).to_string())
40 .add_to(self);
41 }
42
43 pub(crate) fn add_resolution(
44 &mut self,
45 ctx: &CompletionContext,
46 local_name: String,
47 resolution: &ScopeDef,
48 ) {
49 use hir::ModuleDef::*;
50
51 let completion_kind = match resolution {
52 ScopeDef::ModuleDef(BuiltinType(..)) => CompletionKind::BuiltinType,
53 _ => CompletionKind::Reference,
54 };
55
56 let kind = match resolution {
57 ScopeDef::ModuleDef(Module(..)) => CompletionItemKind::Module,
58 ScopeDef::ModuleDef(Function(func)) => {
59 return self.add_function(ctx, *func, Some(local_name));
60 }
61 ScopeDef::ModuleDef(Adt(hir::Adt::Struct(_))) => CompletionItemKind::Struct,
62 // FIXME: add CompletionItemKind::Union
63 ScopeDef::ModuleDef(Adt(hir::Adt::Union(_))) => CompletionItemKind::Struct,
64 ScopeDef::ModuleDef(Adt(hir::Adt::Enum(_))) => CompletionItemKind::Enum,
65
66 ScopeDef::ModuleDef(EnumVariant(var)) => {
67 return self.add_enum_variant(ctx, *var, Some(local_name));
68 }
69 ScopeDef::ModuleDef(Const(..)) => CompletionItemKind::Const,
70 ScopeDef::ModuleDef(Static(..)) => CompletionItemKind::Static,
71 ScopeDef::ModuleDef(Trait(..)) => CompletionItemKind::Trait,
72 ScopeDef::ModuleDef(TypeAlias(..)) => CompletionItemKind::TypeAlias,
73 ScopeDef::ModuleDef(BuiltinType(..)) => CompletionItemKind::BuiltinType,
74 ScopeDef::GenericParam(..) => CompletionItemKind::TypeParam,
75 ScopeDef::Local(..) => CompletionItemKind::Binding,
76 // (does this need its own kind?)
77 ScopeDef::AdtSelfType(..) | ScopeDef::ImplSelfType(..) => CompletionItemKind::TypeParam,
78 ScopeDef::MacroDef(mac) => {
79 return self.add_macro(ctx, Some(local_name), *mac);
80 }
81 ScopeDef::Unknown => {
82 return self.add(
83 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), local_name)
84 .kind(CompletionItemKind::UnresolvedReference),
85 );
86 }
87 };
88
89 let docs = match resolution {
90 ScopeDef::ModuleDef(Module(it)) => it.docs(ctx.db),
91 ScopeDef::ModuleDef(Adt(it)) => it.docs(ctx.db),
92 ScopeDef::ModuleDef(EnumVariant(it)) => it.docs(ctx.db),
93 ScopeDef::ModuleDef(Const(it)) => it.docs(ctx.db),
94 ScopeDef::ModuleDef(Static(it)) => it.docs(ctx.db),
95 ScopeDef::ModuleDef(Trait(it)) => it.docs(ctx.db),
96 ScopeDef::ModuleDef(TypeAlias(it)) => it.docs(ctx.db),
97 _ => None,
98 };
99
100 let mut completion_item =
101 CompletionItem::new(completion_kind, ctx.source_range(), local_name.clone());
102 if let ScopeDef::Local(local) = resolution {
103 let ty = local.ty(ctx.db);
104 if !ty.is_unknown() {
105 completion_item = completion_item.detail(ty.display(ctx.db).to_string());
106 }
107 };
108
109 if let ScopeDef::Local(local) = resolution {
110 if let Some(score) = compute_score(ctx, &local.ty(ctx.db), &local_name) {
111 completion_item = completion_item.set_score(score);
112 }
113 }
114
115 // Add `<>` for generic types
116 if ctx.is_path_type && !ctx.has_type_args && ctx.config.add_call_parenthesis {
117 if let Some(cap) = ctx.config.snippet_cap {
118 let has_non_default_type_params = match resolution {
119 ScopeDef::ModuleDef(Adt(it)) => it.has_non_default_type_params(ctx.db),
120 ScopeDef::ModuleDef(TypeAlias(it)) => it.has_non_default_type_params(ctx.db),
121 _ => false,
122 };
123 if has_non_default_type_params {
124 mark::hit!(inserts_angle_brackets_for_generics);
125 completion_item = completion_item
126 .lookup_by(local_name.clone())
127 .label(format!("{}<…>", local_name))
128 .insert_snippet(cap, format!("{}<$0>", local_name));
129 }
130 }
131 }
132
133 completion_item.kind(kind).set_documentation(docs).add_to(self)
134 }
135
136 pub(crate) fn add_macro(
137 &mut self,
138 ctx: &CompletionContext,
139 name: Option<String>,
140 macro_: hir::MacroDef,
141 ) {
142 // FIXME: Currently proc-macro do not have ast-node,
143 // such that it does not have source
144 if macro_.is_proc_macro() {
145 return;
146 }
147
148 let name = match name {
149 Some(it) => it,
150 None => return,
151 };
152
153 let ast_node = macro_.source(ctx.db).value;
154 let detail = macro_label(&ast_node);
155
156 let docs = macro_.docs(ctx.db);
157
158 let mut builder = CompletionItem::new(
159 CompletionKind::Reference,
160 ctx.source_range(),
161 &format!("{}!", name),
162 )
163 .kind(CompletionItemKind::Macro)
164 .set_documentation(docs.clone())
165 .set_deprecated(is_deprecated(macro_, ctx.db))
166 .detail(detail);
167
168 let needs_bang = ctx.use_item_syntax.is_none() && !ctx.is_macro_call;
169 builder = match ctx.config.snippet_cap {
170 Some(cap) if needs_bang => {
171 let docs = docs.as_ref().map_or("", |s| s.as_str());
172 let (bra, ket) = guess_macro_braces(&name, docs);
173 builder
174 .insert_snippet(cap, format!("{}!{}$0{}", name, bra, ket))
175 .label(format!("{}!{}…{}", name, bra, ket))
176 .lookup_by(format!("{}!", name))
177 }
178 None if needs_bang => builder.insert_text(format!("{}!", name)),
179 _ => {
180 mark::hit!(dont_insert_macro_call_parens_unncessary);
181 builder.insert_text(name)
182 }
183 };
184
185 self.add(builder);
186 }
187
188 pub(crate) fn add_function(
189 &mut self,
190 ctx: &CompletionContext,
191 func: hir::Function,
192 local_name: Option<String>,
193 ) {
194 let has_self_param = func.has_self_param(ctx.db);
195
196 let name = local_name.unwrap_or_else(|| func.name(ctx.db).to_string());
197 let ast_node = func.source(ctx.db).value;
198
199 let mut builder =
200 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.clone())
201 .kind(if has_self_param {
202 CompletionItemKind::Method
203 } else {
204 CompletionItemKind::Function
205 })
206 .set_documentation(func.docs(ctx.db))
207 .set_deprecated(is_deprecated(func, ctx.db))
208 .detail(function_declaration(&ast_node));
209
210 let params = ast_node
211 .param_list()
212 .into_iter()
213 .flat_map(|it| it.params())
214 .flat_map(|it| it.pat())
215 .map(|pat| pat.to_string().trim_start_matches('_').into())
216 .collect();
217
218 builder = builder.add_call_parens(ctx, name, Params::Named(params));
219
220 self.add(builder)
221 }
222
223 pub(crate) fn add_const(&mut self, ctx: &CompletionContext, constant: hir::Const) {
224 let ast_node = constant.source(ctx.db).value;
225 let name = match ast_node.name() {
226 Some(name) => name,
227 _ => return,
228 };
229 let detail = const_label(&ast_node);
230
231 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.text().to_string())
232 .kind(CompletionItemKind::Const)
233 .set_documentation(constant.docs(ctx.db))
234 .set_deprecated(is_deprecated(constant, ctx.db))
235 .detail(detail)
236 .add_to(self);
237 }
238
239 pub(crate) fn add_type_alias(&mut self, ctx: &CompletionContext, type_alias: hir::TypeAlias) {
240 let type_def = type_alias.source(ctx.db).value;
241 let name = match type_def.name() {
242 Some(name) => name,
243 _ => return,
244 };
245 let detail = type_label(&type_def);
246
247 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.text().to_string())
248 .kind(CompletionItemKind::TypeAlias)
249 .set_documentation(type_alias.docs(ctx.db))
250 .set_deprecated(is_deprecated(type_alias, ctx.db))
251 .detail(detail)
252 .add_to(self);
253 }
254
255 pub(crate) fn add_qualified_enum_variant(
256 &mut self,
257 ctx: &CompletionContext,
258 variant: hir::EnumVariant,
259 path: ModPath,
260 ) {
261 self.add_enum_variant_impl(ctx, variant, None, Some(path))
262 }
263
264 pub(crate) fn add_enum_variant(
265 &mut self,
266 ctx: &CompletionContext,
267 variant: hir::EnumVariant,
268 local_name: Option<String>,
269 ) {
270 self.add_enum_variant_impl(ctx, variant, local_name, None)
271 }
272
273 fn add_enum_variant_impl(
274 &mut self,
275 ctx: &CompletionContext,
276 variant: hir::EnumVariant,
277 local_name: Option<String>,
278 path: Option<ModPath>,
279 ) {
280 let is_deprecated = is_deprecated(variant, ctx.db);
281 let name = local_name.unwrap_or_else(|| variant.name(ctx.db).to_string());
282 let qualified_name = match &path {
283 Some(it) => it.to_string(),
284 None => name.to_string(),
285 };
286 let detail_types = variant
287 .fields(ctx.db)
288 .into_iter()
289 .map(|field| (field.name(ctx.db), field.signature_ty(ctx.db)));
290 let variant_kind = variant.kind(ctx.db);
291 let detail = match variant_kind {
292 StructKind::Tuple | StructKind::Unit => detail_types
293 .map(|(_, t)| t.display(ctx.db).to_string())
294 .sep_by(", ")
295 .surround_with("(", ")")
296 .to_string(),
297 StructKind::Record => detail_types
298 .map(|(n, t)| format!("{}: {}", n, t.display(ctx.db).to_string()))
299 .sep_by(", ")
300 .surround_with("{ ", " }")
301 .to_string(),
302 };
303 let mut res = CompletionItem::new(
304 CompletionKind::Reference,
305 ctx.source_range(),
306 qualified_name.clone(),
307 )
308 .kind(CompletionItemKind::EnumVariant)
309 .set_documentation(variant.docs(ctx.db))
310 .set_deprecated(is_deprecated)
311 .detail(detail);
312
313 if path.is_some() {
314 res = res.lookup_by(name);
315 }
316
317 if variant_kind == StructKind::Tuple {
318 mark::hit!(inserts_parens_for_tuple_enums);
319 let params = Params::Anonymous(variant.fields(ctx.db).len());
320 res = res.add_call_parens(ctx, qualified_name, params)
321 }
322
323 res.add_to(self);
324 }
325}
326
327pub(crate) fn compute_score(
328 ctx: &CompletionContext,
329 ty: &Type,
330 name: &str,
331) -> Option<CompletionScore> {
332 let (active_name, active_type) = if let Some(record_field) = &ctx.record_field_syntax {
333 mark::hit!(record_field_type_match);
334 let (struct_field, _local) = ctx.sema.resolve_record_field(record_field)?;
335 (struct_field.name(ctx.db).to_string(), struct_field.signature_ty(ctx.db))
336 } else if let Some(active_parameter) = &ctx.active_parameter {
337 mark::hit!(active_param_type_match);
338 (active_parameter.name.clone(), active_parameter.ty.clone())
339 } else {
340 return None;
341 };
342
343 // Compute score
344 // For the same type
345 if &active_type != ty {
346 return None;
347 }
348
349 let mut res = CompletionScore::TypeMatch;
350
351 // If same type + same name then go top position
352 if active_name == name {
353 res = CompletionScore::TypeAndNameMatch
354 }
355
356 Some(res)
357}
358
359enum Params {
360 Named(Vec<String>),
361 Anonymous(usize),
362}
363
364impl Params {
365 fn len(&self) -> usize {
366 match self {
367 Params::Named(xs) => xs.len(),
368 Params::Anonymous(len) => *len,
369 }
370 }
371
372 fn is_empty(&self) -> bool {
373 self.len() == 0
374 }
375}
376
377impl Builder {
378 fn add_call_parens(mut self, ctx: &CompletionContext, name: String, params: Params) -> Builder {
379 if !ctx.config.add_call_parenthesis {
380 return self;
381 }
382 if ctx.use_item_syntax.is_some() {
383 mark::hit!(no_parens_in_use_item);
384 return self;
385 }
386 if ctx.is_pattern_call {
387 mark::hit!(dont_duplicate_pattern_parens);
388 return self;
389 }
390 if ctx.is_call {
391 return self;
392 }
393
394 // Don't add parentheses if the expected type is some function reference.
395 if let Some(ty) = &ctx.expected_type {
396 if ty.is_fn() {
397 mark::hit!(no_call_parens_if_fn_ptr_needed);
398 return self;
399 }
400 }
401
402 let cap = match ctx.config.snippet_cap {
403 Some(it) => it,
404 None => return self,
405 };
406 // If not an import, add parenthesis automatically.
407 mark::hit!(inserts_parens_for_function_calls);
408
409 let (snippet, label) = if params.is_empty() {
410 (format!("{}()$0", name), format!("{}()", name))
411 } else {
412 self = self.trigger_call_info();
413 let snippet = match (ctx.config.add_call_argument_snippets, params) {
414 (true, Params::Named(params)) => {
415 let function_params_snippet = params
416 .iter()
417 .enumerate()
418 .map(|(index, param_name)| format!("${{{}:{}}}", index + 1, param_name))
419 .sep_by(", ");
420 format!("{}({})$0", name, function_params_snippet)
421 }
422 _ => {
423 mark::hit!(suppress_arg_snippets);
424 format!("{}($0)", name)
425 }
426 };
427
428 (snippet, format!("{}(…)", name))
429 };
430 self.lookup_by(name).label(label).insert_snippet(cap, snippet)
431 }
432}
433
434fn is_deprecated(node: impl HasAttrs, db: &RootDatabase) -> bool {
435 node.attrs(db).by_key("deprecated").exists()
436}
437
438fn guess_macro_braces(macro_name: &str, docs: &str) -> (&'static str, &'static str) {
439 let mut votes = [0, 0, 0];
440 for (idx, s) in docs.match_indices(&macro_name) {
441 let (before, after) = (&docs[..idx], &docs[idx + s.len()..]);
442 // Ensure to match the full word
443 if after.starts_with('!')
444 && !before.ends_with(|c: char| c == '_' || c.is_ascii_alphanumeric())
445 {
446 // It may have spaces before the braces like `foo! {}`
447 match after[1..].chars().find(|&c| !c.is_whitespace()) {
448 Some('{') => votes[0] += 1,
449 Some('[') => votes[1] += 1,
450 Some('(') => votes[2] += 1,
451 _ => {}
452 }
453 }
454 }
455
456 // Insert a space before `{}`.
457 // We prefer the last one when some votes equal.
458 let (_vote, (bra, ket)) = votes
459 .iter()
460 .zip(&[(" {", "}"), ("[", "]"), ("(", ")")])
461 .max_by_key(|&(&vote, _)| vote)
462 .unwrap();
463 (*bra, *ket)
464}
465
466#[cfg(test)]
467mod tests {
468 use std::cmp::Reverse;
469
470 use expect::{expect, Expect};
471 use test_utils::mark;
472
473 use crate::{
474 completion::{
475 test_utils::{
476 check_edit, check_edit_with_config, do_completion, get_all_completion_items,
477 },
478 CompletionConfig, CompletionKind,
479 },
480 CompletionScore,
481 };
482
483 fn check(ra_fixture: &str, expect: Expect) {
484 let actual = do_completion(ra_fixture, CompletionKind::Reference);
485 expect.assert_debug_eq(&actual);
486 }
487
488 fn check_scores(ra_fixture: &str, expect: Expect) {
489 fn display_score(score: Option<CompletionScore>) -> &'static str {
490 match score {
491 Some(CompletionScore::TypeMatch) => "[type]",
492 Some(CompletionScore::TypeAndNameMatch) => "[type+name]",
493 None => "[]".into(),
494 }
495 }
496
497 let mut completions = get_all_completion_items(CompletionConfig::default(), ra_fixture);
498 completions.sort_by_key(|it| (Reverse(it.score()), it.label().to_string()));
499 let actual = completions
500 .into_iter()
501 .filter(|it| it.completion_kind == CompletionKind::Reference)
502 .map(|it| {
503 let tag = it.kind().unwrap().tag();
504 let score = display_score(it.score());
505 format!("{} {} {}\n", tag, it.label(), score)
506 })
507 .collect::<String>();
508 expect.assert_eq(&actual);
509 }
510
511 #[test]
512 fn enum_detail_includes_record_fields() {
513 check(
514 r#"
515enum Foo { Foo { x: i32, y: i32 } }
516
517fn main() { Foo::Fo<|> }
518"#,
519 expect![[r#"
520 [
521 CompletionItem {
522 label: "Foo",
523 source_range: 54..56,
524 delete: 54..56,
525 insert: "Foo",
526 kind: EnumVariant,
527 detail: "{ x: i32, y: i32 }",
528 },
529 ]
530 "#]],
531 );
532 }
533
534 #[test]
535 fn enum_detail_doesnt_include_tuple_fields() {
536 check(
537 r#"
538enum Foo { Foo (i32, i32) }
539
540fn main() { Foo::Fo<|> }
541"#,
542 expect![[r#"
543 [
544 CompletionItem {
545 label: "Foo(…)",
546 source_range: 46..48,
547 delete: 46..48,
548 insert: "Foo($0)",
549 kind: EnumVariant,
550 lookup: "Foo",
551 detail: "(i32, i32)",
552 trigger_call_info: true,
553 },
554 ]
555 "#]],
556 );
557 }
558
559 #[test]
560 fn enum_detail_just_parentheses_for_unit() {
561 check(
562 r#"
563enum Foo { Foo }
564
565fn main() { Foo::Fo<|> }
566"#,
567 expect![[r#"
568 [
569 CompletionItem {
570 label: "Foo",
571 source_range: 35..37,
572 delete: 35..37,
573 insert: "Foo",
574 kind: EnumVariant,
575 detail: "()",
576 },
577 ]
578 "#]],
579 );
580 }
581
582 #[test]
583 fn sets_deprecated_flag_in_completion_items() {
584 check(
585 r#"
586#[deprecated]
587fn something_deprecated() {}
588#[deprecated(since = "1.0.0")]
589fn something_else_deprecated() {}
590
591fn main() { som<|> }
592"#,
593 expect![[r#"
594 [
595 CompletionItem {
596 label: "main()",
597 source_range: 121..124,
598 delete: 121..124,
599 insert: "main()$0",
600 kind: Function,
601 lookup: "main",
602 detail: "fn main()",
603 },
604 CompletionItem {
605 label: "something_deprecated()",
606 source_range: 121..124,
607 delete: 121..124,
608 insert: "something_deprecated()$0",
609 kind: Function,
610 lookup: "something_deprecated",
611 detail: "fn something_deprecated()",
612 deprecated: true,
613 },
614 CompletionItem {
615 label: "something_else_deprecated()",
616 source_range: 121..124,
617 delete: 121..124,
618 insert: "something_else_deprecated()$0",
619 kind: Function,
620 lookup: "something_else_deprecated",
621 detail: "fn something_else_deprecated()",
622 deprecated: true,
623 },
624 ]
625 "#]],
626 );
627
628 check(
629 r#"
630struct A { #[deprecated] the_field: u32 }
631fn foo() { A { the<|> } }
632"#,
633 expect![[r#"
634 [
635 CompletionItem {
636 label: "the_field",
637 source_range: 57..60,
638 delete: 57..60,
639 insert: "the_field",
640 kind: Field,
641 detail: "u32",
642 deprecated: true,
643 },
644 ]
645 "#]],
646 );
647 }
648
649 #[test]
650 fn renders_docs() {
651 check(
652 r#"
653struct S {
654 /// Field docs
655 foo:
656}
657impl S {
658 /// Method docs
659 fn bar(self) { self.<|> }
660}"#,
661 expect![[r#"
662 [
663 CompletionItem {
664 label: "bar()",
665 source_range: 94..94,
666 delete: 94..94,
667 insert: "bar()$0",
668 kind: Method,
669 lookup: "bar",
670 detail: "fn bar(self)",
671 documentation: Documentation(
672 "Method docs",
673 ),
674 },
675 CompletionItem {
676 label: "foo",
677 source_range: 94..94,
678 delete: 94..94,
679 insert: "foo",
680 kind: Field,
681 detail: "{unknown}",
682 documentation: Documentation(
683 "Field docs",
684 ),
685 },
686 ]
687 "#]],
688 );
689
690 check(
691 r#"
692use self::my<|>;
693
694/// mod docs
695mod my { }
696
697/// enum docs
698enum E {
699 /// variant docs
700 V
701}
702use self::E::*;
703"#,
704 expect![[r#"
705 [
706 CompletionItem {
707 label: "E",
708 source_range: 10..12,
709 delete: 10..12,
710 insert: "E",
711 kind: Enum,
712 documentation: Documentation(
713 "enum docs",
714 ),
715 },
716 CompletionItem {
717 label: "V",
718 source_range: 10..12,
719 delete: 10..12,
720 insert: "V",
721 kind: EnumVariant,
722 detail: "()",
723 documentation: Documentation(
724 "variant docs",
725 ),
726 },
727 CompletionItem {
728 label: "my",
729 source_range: 10..12,
730 delete: 10..12,
731 insert: "my",
732 kind: Module,
733 documentation: Documentation(
734 "mod docs",
735 ),
736 },
737 ]
738 "#]],
739 )
740 }
741
742 #[test]
743 fn dont_render_attrs() {
744 check(
745 r#"
746struct S;
747impl S {
748 #[inline]
749 fn the_method(&self) { }
750}
751fn foo(s: S) { s.<|> }
752"#,
753 expect![[r#"
754 [
755 CompletionItem {
756 label: "the_method()",
757 source_range: 81..81,
758 delete: 81..81,
759 insert: "the_method()$0",
760 kind: Method,
761 lookup: "the_method",
762 detail: "fn the_method(&self)",
763 },
764 ]
765 "#]],
766 )
767 }
768
769 #[test]
770 fn inserts_parens_for_function_calls() {
771 mark::check!(inserts_parens_for_function_calls);
772 check_edit(
773 "no_args",
774 r#"
775fn no_args() {}
776fn main() { no_<|> }
777"#,
778 r#"
779fn no_args() {}
780fn main() { no_args()$0 }
781"#,
782 );
783
784 check_edit(
785 "with_args",
786 r#"
787fn with_args(x: i32, y: String) {}
788fn main() { with_<|> }
789"#,
790 r#"
791fn with_args(x: i32, y: String) {}
792fn main() { with_args(${1:x}, ${2:y})$0 }
793"#,
794 );
795
796 check_edit(
797 "foo",
798 r#"
799struct S;
800impl S {
801 fn foo(&self) {}
802}
803fn bar(s: &S) { s.f<|> }
804"#,
805 r#"
806struct S;
807impl S {
808 fn foo(&self) {}
809}
810fn bar(s: &S) { s.foo()$0 }
811"#,
812 );
813
814 check_edit(
815 "foo",
816 r#"
817struct S {}
818impl S {
819 fn foo(&self, x: i32) {}
820}
821fn bar(s: &S) {
822 s.f<|>
823}
824"#,
825 r#"
826struct S {}
827impl S {
828 fn foo(&self, x: i32) {}
829}
830fn bar(s: &S) {
831 s.foo(${1:x})$0
832}
833"#,
834 );
835 }
836
837 #[test]
838 fn suppress_arg_snippets() {
839 mark::check!(suppress_arg_snippets);
840 check_edit_with_config(
841 CompletionConfig { add_call_argument_snippets: false, ..CompletionConfig::default() },
842 "with_args",
843 r#"
844fn with_args(x: i32, y: String) {}
845fn main() { with_<|> }
846"#,
847 r#"
848fn with_args(x: i32, y: String) {}
849fn main() { with_args($0) }
850"#,
851 );
852 }
853
854 #[test]
855 fn strips_underscores_from_args() {
856 check_edit(
857 "foo",
858 r#"
859fn foo(_foo: i32, ___bar: bool, ho_ge_: String) {}
860fn main() { f<|> }
861"#,
862 r#"
863fn foo(_foo: i32, ___bar: bool, ho_ge_: String) {}
864fn main() { foo(${1:foo}, ${2:bar}, ${3:ho_ge_})$0 }
865"#,
866 );
867 }
868
869 #[test]
870 fn inserts_parens_for_tuple_enums() {
871 mark::check!(inserts_parens_for_tuple_enums);
872 check_edit(
873 "Some",
874 r#"
875enum Option<T> { Some(T), None }
876use Option::*;
877fn main() -> Option<i32> {
878 Som<|>
879}
880"#,
881 r#"
882enum Option<T> { Some(T), None }
883use Option::*;
884fn main() -> Option<i32> {
885 Some($0)
886}
887"#,
888 );
889 check_edit(
890 "Some",
891 r#"
892enum Option<T> { Some(T), None }
893use Option::*;
894fn main(value: Option<i32>) {
895 match value {
896 Som<|>
897 }
898}
899"#,
900 r#"
901enum Option<T> { Some(T), None }
902use Option::*;
903fn main(value: Option<i32>) {
904 match value {
905 Some($0)
906 }
907}
908"#,
909 );
910 }
911
912 #[test]
913 fn dont_duplicate_pattern_parens() {
914 mark::check!(dont_duplicate_pattern_parens);
915 check_edit(
916 "Var",
917 r#"
918enum E { Var(i32) }
919fn main() {
920 match E::Var(92) {
921 E::<|>(92) => (),
922 }
923}
924"#,
925 r#"
926enum E { Var(i32) }
927fn main() {
928 match E::Var(92) {
929 E::Var(92) => (),
930 }
931}
932"#,
933 );
934 }
935
936 #[test]
937 fn no_call_parens_if_fn_ptr_needed() {
938 mark::check!(no_call_parens_if_fn_ptr_needed);
939 check_edit(
940 "foo",
941 r#"
942fn foo(foo: u8, bar: u8) {}
943struct ManualVtable { f: fn(u8, u8) }
944
945fn main() -> ManualVtable {
946 ManualVtable { f: f<|> }
947}
948"#,
949 r#"
950fn foo(foo: u8, bar: u8) {}
951struct ManualVtable { f: fn(u8, u8) }
952
953fn main() -> ManualVtable {
954 ManualVtable { f: foo }
955}
956"#,
957 );
958 }
959
960 #[test]
961 fn no_parens_in_use_item() {
962 mark::check!(no_parens_in_use_item);
963 check_edit(
964 "foo",
965 r#"
966mod m { pub fn foo() {} }
967use crate::m::f<|>;
968"#,
969 r#"
970mod m { pub fn foo() {} }
971use crate::m::foo;
972"#,
973 );
974 }
975
976 #[test]
977 fn no_parens_in_call() {
978 check_edit(
979 "foo",
980 r#"
981fn foo(x: i32) {}
982fn main() { f<|>(); }
983"#,
984 r#"
985fn foo(x: i32) {}
986fn main() { foo(); }
987"#,
988 );
989 check_edit(
990 "foo",
991 r#"
992struct Foo;
993impl Foo { fn foo(&self){} }
994fn f(foo: &Foo) { foo.f<|>(); }
995"#,
996 r#"
997struct Foo;
998impl Foo { fn foo(&self){} }
999fn f(foo: &Foo) { foo.foo(); }
1000"#,
1001 );
1002 }
1003
1004 #[test]
1005 fn inserts_angle_brackets_for_generics() {
1006 mark::check!(inserts_angle_brackets_for_generics);
1007 check_edit(
1008 "Vec",
1009 r#"
1010struct Vec<T> {}
1011fn foo(xs: Ve<|>)
1012"#,
1013 r#"
1014struct Vec<T> {}
1015fn foo(xs: Vec<$0>)
1016"#,
1017 );
1018 check_edit(
1019 "Vec",
1020 r#"
1021type Vec<T> = (T,);
1022fn foo(xs: Ve<|>)
1023"#,
1024 r#"
1025type Vec<T> = (T,);
1026fn foo(xs: Vec<$0>)
1027"#,
1028 );
1029 check_edit(
1030 "Vec",
1031 r#"
1032struct Vec<T = i128> {}
1033fn foo(xs: Ve<|>)
1034"#,
1035 r#"
1036struct Vec<T = i128> {}
1037fn foo(xs: Vec)
1038"#,
1039 );
1040 check_edit(
1041 "Vec",
1042 r#"
1043struct Vec<T> {}
1044fn foo(xs: Ve<|><i128>)
1045"#,
1046 r#"
1047struct Vec<T> {}
1048fn foo(xs: Vec<i128>)
1049"#,
1050 );
1051 }
1052
1053 #[test]
1054 fn dont_insert_macro_call_parens_unncessary() {
1055 mark::check!(dont_insert_macro_call_parens_unncessary);
1056 check_edit(
1057 "frobnicate!",
1058 r#"
1059//- /main.rs
1060use foo::<|>;
1061//- /foo/lib.rs
1062#[macro_export]
1063macro_rules frobnicate { () => () }
1064"#,
1065 r#"
1066use foo::frobnicate;
1067"#,
1068 );
1069
1070 check_edit(
1071 "frobnicate!",
1072 r#"
1073macro_rules frobnicate { () => () }
1074fn main() { frob<|>!(); }
1075"#,
1076 r#"
1077macro_rules frobnicate { () => () }
1078fn main() { frobnicate!(); }
1079"#,
1080 );
1081 }
1082
1083 #[test]
1084 fn active_param_score() {
1085 mark::check!(active_param_type_match);
1086 check_scores(
1087 r#"
1088struct S { foo: i64, bar: u32, baz: u32 }
1089fn test(bar: u32) { }
1090fn foo(s: S) { test(s.<|>) }
1091"#,
1092 expect![[r#"
1093 fd bar [type+name]
1094 fd baz [type]
1095 fd foo []
1096 "#]],
1097 );
1098 }
1099
1100 #[test]
1101 fn record_field_scores() {
1102 mark::check!(record_field_type_match);
1103 check_scores(
1104 r#"
1105struct A { foo: i64, bar: u32, baz: u32 }
1106struct B { x: (), y: f32, bar: u32 }
1107fn foo(a: A) { B { bar: a.<|> }; }
1108"#,
1109 expect![[r#"
1110 fd bar [type+name]
1111 fd baz [type]
1112 fd foo []
1113 "#]],
1114 )
1115 }
1116
1117 #[test]
1118 fn record_field_and_call_scores() {
1119 check_scores(
1120 r#"
1121struct A { foo: i64, bar: u32, baz: u32 }
1122struct B { x: (), y: f32, bar: u32 }
1123fn f(foo: i64) { }
1124fn foo(a: A) { B { bar: f(a.<|>) }; }
1125"#,
1126 expect![[r#"
1127 fd foo [type+name]
1128 fd bar []
1129 fd baz []
1130 "#]],
1131 );
1132 check_scores(
1133 r#"
1134struct A { foo: i64, bar: u32, baz: u32 }
1135struct B { x: (), y: f32, bar: u32 }
1136fn f(foo: i64) { }
1137fn foo(a: A) { f(B { bar: a.<|> }); }
1138"#,
1139 expect![[r#"
1140 fd bar [type+name]
1141 fd baz [type]
1142 fd foo []
1143 "#]],
1144 );
1145 }
1146
1147 #[test]
1148 fn prioritize_exact_ref_match() {
1149 check_scores(
1150 r#"
1151struct WorldSnapshot { _f: () };
1152fn go(world: &WorldSnapshot) { go(w<|>) }
1153"#,
1154 expect![[r#"
1155 bn world [type+name]
1156 st WorldSnapshot []
1157 fn go(…) []
1158 "#]],
1159 );
1160 }
1161
1162 #[test]
1163 fn too_many_arguments() {
1164 mark::check!(too_many_arguments);
1165 check_scores(
1166 r#"
1167struct Foo;
1168fn f(foo: &Foo) { f(foo, w<|>) }
1169"#,
1170 expect![[r#"
1171 st Foo []
1172 fn f(…) []
1173 bn foo []
1174 "#]],
1175 );
1176 }
1177
1178 #[test]
1179 fn guesses_macro_braces() {
1180 check_edit(
1181 "vec!",
1182 r#"
1183/// Creates a [`Vec`] containing the arguments.
1184///
1185/// ```
1186/// let v = vec![1, 2, 3];
1187/// assert_eq!(v[0], 1);
1188/// assert_eq!(v[1], 2);
1189/// assert_eq!(v[2], 3);
1190/// ```
1191macro_rules! vec { () => {} }
1192
1193fn fn main() { v<|> }
1194"#,
1195 r#"
1196/// Creates a [`Vec`] containing the arguments.
1197///
1198/// ```
1199/// let v = vec![1, 2, 3];
1200/// assert_eq!(v[0], 1);
1201/// assert_eq!(v[1], 2);
1202/// assert_eq!(v[2], 3);
1203/// ```
1204macro_rules! vec { () => {} }
1205
1206fn fn main() { vec![$0] }
1207"#,
1208 );
1209
1210 check_edit(
1211 "foo!",
1212 r#"
1213/// Foo
1214///
1215/// Don't call `fooo!()` `fooo!()`, or `_foo![]` `_foo![]`,
1216/// call as `let _=foo! { hello world };`
1217macro_rules! foo { () => {} }
1218fn main() { <|> }
1219"#,
1220 r#"
1221/// Foo
1222///
1223/// Don't call `fooo!()` `fooo!()`, or `_foo![]` `_foo![]`,
1224/// call as `let _=foo! { hello world };`
1225macro_rules! foo { () => {} }
1226fn main() { foo! {$0} }
1227"#,
1228 )
1229 }
1230}