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