aboutsummaryrefslogtreecommitdiff
path: root/crates/ide/src/inlay_hints.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ide/src/inlay_hints.rs')
-rw-r--r--crates/ide/src/inlay_hints.rs1015
1 files changed, 493 insertions, 522 deletions
diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs
index d6dfa0183..9f2f6c80a 100644
--- a/crates/ide/src/inlay_hints.rs
+++ b/crates/ide/src/inlay_hints.rs
@@ -299,9 +299,8 @@ fn should_not_display_type_hint(
299 // Type of expr should be iterable. 299 // Type of expr should be iterable.
300 return it.in_token().is_none() || 300 return it.in_token().is_none() ||
301 it.iterable() 301 it.iterable()
302 .and_then(|iterable_expr|sema.type_of_expr(&iterable_expr)) 302 .and_then(|iterable_expr| sema.type_of_expr(&iterable_expr))
303 .map(|iterable_ty| iterable_ty.is_unknown() || iterable_ty.is_unit()) 303 .map_or(true, |iterable_ty| iterable_ty.is_unknown() || iterable_ty.is_unit())
304 .unwrap_or(true)
305 }, 304 },
306 _ => (), 305 _ => (),
307 } 306 }
@@ -319,8 +318,8 @@ fn should_hide_param_name_hint(
319 // hide when: 318 // hide when:
320 // - the parameter name is a suffix of the function's name 319 // - the parameter name is a suffix of the function's name
321 // - the argument is an enum whose name is equal to the parameter 320 // - the argument is an enum whose name is equal to the parameter
322 // - exact argument<->parameter match(ignoring leading underscore) or argument is a prefix/suffix 321 // - exact argument<->parameter match(ignoring leading underscore) or parameter is a prefix/suffix
323 // of parameter with _ splitting it off 322 // of argument with _ splitting it off
324 // - param starts with `ra_fixture` 323 // - param starts with `ra_fixture`
325 // - param is a well known name in an unary function 324 // - param is a well known name in an unary function
326 325
@@ -342,23 +341,22 @@ fn should_hide_param_name_hint(
342} 341}
343 342
344fn is_argument_similar_to_param_name(argument: &ast::Expr, param_name: &str) -> bool { 343fn is_argument_similar_to_param_name(argument: &ast::Expr, param_name: &str) -> bool {
345 match get_string_representation(argument) { 344 // check whether param_name and argument are the same or
346 None => false, 345 // whether param_name is a prefix/suffix of argument(split at `_`)
347 Some(argument) => { 346 let argument = match get_string_representation(argument) {
348 let mut res = false; 347 Some(argument) => argument,
349 if let Some(first) = argument.bytes().skip_while(|&c| c == b'_').position(|c| c == b'_') 348 None => return false,
350 { 349 };
351 res |= param_name == argument[..first].trim_start_matches('_'); 350
352 } 351 let param_name = param_name.trim_start_matches('_');
353 if let Some(last) = 352 let argument = argument.trim_start_matches('_');
354 argument.bytes().rev().skip_while(|&c| c == b'_').position(|c| c == b'_') 353 if argument.strip_prefix(param_name).map_or(false, |s| s.starts_with('_')) {
355 { 354 return true;
356 res |= param_name == argument[last..].trim_end_matches('_');
357 }
358 res |= argument == param_name;
359 res
360 }
361 } 355 }
356 if argument.strip_suffix(param_name).map_or(false, |s| s.ends_with('_')) {
357 return true;
358 }
359 argument == param_name
362} 360}
363 361
364/// Hide the parameter name of an unary function if it is a `_` - prefixed suffix of the function's name, or equal. 362/// Hide the parameter name of an unary function if it is a `_` - prefixed suffix of the function's name, or equal.
@@ -451,6 +449,42 @@ mod tests {
451 check_with_config(TEST_CONFIG, ra_fixture); 449 check_with_config(TEST_CONFIG, ra_fixture);
452 } 450 }
453 451
452 fn check_params(ra_fixture: &str) {
453 check_with_config(
454 InlayHintsConfig {
455 parameter_hints: true,
456 type_hints: false,
457 chaining_hints: false,
458 max_length: None,
459 },
460 ra_fixture,
461 );
462 }
463
464 fn check_types(ra_fixture: &str) {
465 check_with_config(
466 InlayHintsConfig {
467 parameter_hints: false,
468 type_hints: true,
469 chaining_hints: false,
470 max_length: None,
471 },
472 ra_fixture,
473 );
474 }
475
476 fn check_chains(ra_fixture: &str) {
477 check_with_config(
478 InlayHintsConfig {
479 parameter_hints: false,
480 type_hints: false,
481 chaining_hints: true,
482 max_length: None,
483 },
484 ra_fixture,
485 );
486 }
487
454 fn check_with_config(config: InlayHintsConfig, ra_fixture: &str) { 488 fn check_with_config(config: InlayHintsConfig, ra_fixture: &str) {
455 let ra_fixture = 489 let ra_fixture =
456 format!("//- /main.rs crate:main deps:core\n{}\n{}", ra_fixture, FamousDefs::FIXTURE); 490 format!("//- /main.rs crate:main deps:core\n{}\n{}", ra_fixture, FamousDefs::FIXTURE);
@@ -471,17 +505,28 @@ mod tests {
471 } 505 }
472 506
473 #[test] 507 #[test]
474 fn param_hints_only() { 508 fn hints_disabled() {
475 check_with_config( 509 check_with_config(
476 InlayHintsConfig { 510 InlayHintsConfig {
477 parameter_hints: true,
478 type_hints: false, 511 type_hints: false,
512 parameter_hints: false,
479 chaining_hints: false, 513 chaining_hints: false,
480 max_length: None, 514 max_length: None,
481 }, 515 },
482 r#" 516 r#"
483fn foo(a: i32, b: i32) -> i32 { a + b } 517fn foo(a: i32, b: i32) -> i32 { a + b }
484fn main() { 518fn main() {
519 let _x = foo(4, 4);
520}"#,
521 );
522 }
523
524 #[test]
525 fn param_hints_only() {
526 check_params(
527 r#"
528fn foo(a: i32, b: i32) -> i32 { a + b }
529fn main() {
485 let _x = foo( 530 let _x = foo(
486 4, 531 4,
487 //^ a 532 //^ a
@@ -494,13 +539,7 @@ fn main() {
494 539
495 #[test] 540 #[test]
496 fn param_name_similar_to_fn_name_still_hints() { 541 fn param_name_similar_to_fn_name_still_hints() {
497 check_with_config( 542 check_params(
498 InlayHintsConfig {
499 parameter_hints: true,
500 type_hints: false,
501 chaining_hints: false,
502 max_length: None,
503 },
504 r#" 543 r#"
505fn max(x: i32, y: i32) -> i32 { x + y } 544fn max(x: i32, y: i32) -> i32 { x + y }
506fn main() { 545fn main() {
@@ -516,13 +555,7 @@ fn main() {
516 555
517 #[test] 556 #[test]
518 fn param_name_similar_to_fn_name() { 557 fn param_name_similar_to_fn_name() {
519 check_with_config( 558 check_params(
520 InlayHintsConfig {
521 parameter_hints: true,
522 type_hints: false,
523 chaining_hints: false,
524 max_length: None,
525 },
526 r#" 559 r#"
527fn param_with_underscore(with_underscore: i32) -> i32 { with_underscore } 560fn param_with_underscore(with_underscore: i32) -> i32 { with_underscore }
528fn main() { 561fn main() {
@@ -535,13 +568,7 @@ fn main() {
535 568
536 #[test] 569 #[test]
537 fn param_name_same_as_fn_name() { 570 fn param_name_same_as_fn_name() {
538 check_with_config( 571 check_params(
539 InlayHintsConfig {
540 parameter_hints: true,
541 type_hints: false,
542 chaining_hints: false,
543 max_length: None,
544 },
545 r#" 572 r#"
546fn foo(foo: i32) -> i32 { foo } 573fn foo(foo: i32) -> i32 { foo }
547fn main() { 574fn main() {
@@ -554,13 +581,7 @@ fn main() {
554 581
555 #[test] 582 #[test]
556 fn never_hide_param_when_multiple_params() { 583 fn never_hide_param_when_multiple_params() {
557 check_with_config( 584 check_params(
558 InlayHintsConfig {
559 parameter_hints: true,
560 type_hints: false,
561 chaining_hints: false,
562 max_length: None,
563 },
564 r#" 585 r#"
565fn foo(bar: i32, baz: i32) -> i32 { bar + baz } 586fn foo(bar: i32, baz: i32) -> i32 { bar + baz }
566fn main() { 587fn main() {
@@ -575,209 +596,56 @@ fn main() {
575 } 596 }
576 597
577 #[test] 598 #[test]
578 fn hints_disabled() { 599 fn hide_param_hints_for_clones() {
579 check_with_config( 600 check_params(
580 InlayHintsConfig {
581 type_hints: false,
582 parameter_hints: false,
583 chaining_hints: false,
584 max_length: None,
585 },
586 r#"
587fn foo(a: i32, b: i32) -> i32 { a + b }
588fn main() {
589 let _x = foo(4, 4);
590}"#,
591 );
592 }
593
594 #[test]
595 fn type_hints_only() {
596 check_with_config(
597 InlayHintsConfig {
598 type_hints: true,
599 parameter_hints: false,
600 chaining_hints: false,
601 max_length: None,
602 },
603 r#"
604fn foo(a: i32, b: i32) -> i32 { a + b }
605fn main() {
606 let _x = foo(4, 4);
607 //^^ i32
608}"#,
609 );
610 }
611
612 #[test]
613 fn default_generic_types_should_not_be_displayed() {
614 check(
615 r#"
616struct Test<K, T = u8> { k: K, t: T }
617
618fn main() {
619 let zz = Test { t: 23u8, k: 33 };
620 //^^ Test<i32>
621 let zz_ref = &zz;
622 //^^^^^^ &Test<i32>
623 let test = || zz;
624 //^^^^ || -> Test<i32>
625}"#,
626 );
627 }
628
629 #[test]
630 fn let_statement() {
631 check(
632 r#"
633#[derive(PartialEq)]
634enum Option<T> { None, Some(T) }
635
636#[derive(PartialEq)]
637struct Test { a: Option<u32>, b: u8 }
638
639fn main() {
640 struct InnerStruct {}
641
642 let test = 54;
643 //^^^^ i32
644 let test: i32 = 33;
645 let mut test = 33;
646 //^^^^^^^^ i32
647 let _ = 22;
648 let test = "test";
649 //^^^^ &str
650 let test = InnerStruct {};
651 //^^^^ InnerStruct
652
653 let test = unresolved();
654
655 let test = (42, 'a');
656 //^^^^ (i32, char)
657 let (a, (b, (c,)) = (2, (3, (9.2,));
658 //^ i32 ^ i32 ^ f64
659 let &x = &92;
660 //^ i32
661}"#,
662 );
663 }
664
665 #[test]
666 fn closure_parameters() {
667 check(
668 r#"
669fn main() {
670 let mut start = 0;
671 //^^^^^^^^^ i32
672 (0..2).for_each(|increment| { start += increment; });
673 //^^^^^^^^^ i32
674
675 let multiply =
676 //^^^^^^^^ |…| -> i32
677 | a, b| a * b
678 //^ i32 ^ i32
679 ;
680
681 let _: i32 = multiply(1, 2);
682 let multiply_ref = &multiply;
683 //^^^^^^^^^^^^ &|…| -> i32
684
685 let return_42 = || 42;
686 //^^^^^^^^^ || -> i32
687}"#,
688 );
689 }
690
691 #[test]
692 fn if_expr() {
693 check(
694 r#"
695enum Option<T> { None, Some(T) }
696use Option::*;
697
698struct Test { a: Option<u32>, b: u8 }
699
700fn main() {
701 let test = Some(Test { a: Some(3), b: 1 });
702 //^^^^ Option<Test>
703 if let None = &test {};
704 if let test = &test {};
705 //^^^^ &Option<Test>
706 if let Some(test) = &test {};
707 //^^^^ &Test
708 if let Some(Test { a, b }) = &test {};
709 //^ &Option<u32> ^ &u8
710 if let Some(Test { a: x, b: y }) = &test {};
711 //^ &Option<u32> ^ &u8
712 if let Some(Test { a: Some(x), b: y }) = &test {};
713 //^ &u32 ^ &u8
714 if let Some(Test { a: None, b: y }) = &test {};
715 //^ &u8
716 if let Some(Test { b: y, .. }) = &test {};
717 //^ &u8
718 if test == None {}
719}"#,
720 );
721 }
722
723 #[test]
724 fn while_expr() {
725 check(
726 r#" 601 r#"
727enum Option<T> { None, Some(T) } 602fn foo(bar: i32, baz: String, qux: f32) {}
728use Option::*;
729
730struct Test { a: Option<u32>, b: u8 }
731 603
732fn main() { 604fn main() {
733 let test = Some(Test { a: Some(3), b: 1 }); 605 let bar = 3;
734 //^^^^ Option<Test> 606 let baz = &"baz";
735 while let Some(Test { a: Some(x), b: y }) = &test {}; 607 let fez = 1.0;
736 //^ &u32 ^ &u8 608 foo(bar.clone(), baz.clone(), fez.clone());
737}"#, 609 //^^^^^^^^^^^ qux
610}
611"#,
738 ); 612 );
739 } 613 }
740 614
741 #[test] 615 #[test]
742 fn match_arm_list() { 616 fn self_param_hints() {
743 check( 617 check_params(
744 r#" 618 r#"
745enum Option<T> { None, Some(T) } 619struct Foo;
746use Option::*;
747 620
748struct Test { a: Option<u32>, b: u8 } 621impl Foo {
622 fn foo(self: Self) {}
623 fn bar(self: &Self) {}
624}
749 625
750fn main() { 626fn main() {
751 match Some(Test { a: Some(3), b: 1 }) { 627 Foo::foo(Foo);
752 None => (), 628 //^^^ self
753 test => (), 629 Foo::bar(&Foo);
754 //^^^^ Option<Test> 630 //^^^^ self
755 Some(Test { a: Some(x), b: y }) => (), 631}
756 //^ u32 ^ u8 632"#,
757 _ => {} 633 )
758 }
759}"#,
760 );
761 } 634 }
762 635
763 #[test] 636 #[test]
764 fn hint_truncation() { 637 fn param_name_hints_show_for_literals() {
765 check_with_config( 638 check_params(
766 InlayHintsConfig { max_length: Some(8), ..TEST_CONFIG }, 639 r#"pub fn test(a: i32, b: i32) -> [i32; 2] { [a, b] }
767 r#"
768struct Smol<T>(T);
769
770struct VeryLongOuterName<T>(T);
771
772fn main() { 640fn main() {
773 let a = Smol(0u32); 641 test(
774 //^ Smol<u32> 642 0x0fab272b,
775 let b = VeryLongOuterName(0usize); 643 //^^^^^^^^^^ a
776 //^ VeryLongOuterName<…> 644 0x0fab272b
777 let c = Smol(Smol(0u32)) 645 //^^^^^^^^^^ b
778 //^ Smol<Smol<…>> 646 );
779}"#, 647}"#,
780 ); 648 )
781 } 649 }
782 650
783 #[test] 651 #[test]
@@ -939,10 +807,129 @@ fn main() {
939 ); 807 );
940 } 808 }
941 809
810 // Type-Hint tests
811
812 #[test]
813 fn type_hints_only() {
814 check_types(
815 r#"
816fn foo(a: i32, b: i32) -> i32 { a + b }
817fn main() {
818 let _x = foo(4, 4);
819 //^^ i32
820}"#,
821 );
822 }
823
824 #[test]
825 fn default_generic_types_should_not_be_displayed() {
826 check(
827 r#"
828struct Test<K, T = u8> { k: K, t: T }
829
830fn main() {
831 let zz = Test { t: 23u8, k: 33 };
832 //^^ Test<i32>
833 let zz_ref = &zz;
834 //^^^^^^ &Test<i32>
835 let test = || zz;
836 //^^^^ || -> Test<i32>
837}"#,
838 );
839 }
840
841 #[test]
842 fn shorten_iterators_in_associated_params() {
843 check_types(
844 r#"
845use core::iter;
846
847pub struct SomeIter<T> {}
848
849impl<T> SomeIter<T> {
850 pub fn new() -> Self { SomeIter {} }
851 pub fn push(&mut self, t: T) {}
852}
853
854impl<T> Iterator for SomeIter<T> {
855 type Item = T;
856 fn next(&mut self) -> Option<Self::Item> {
857 None
858 }
859}
860
861fn main() {
862 let mut some_iter = SomeIter::new();
863 //^^^^^^^^^^^^^ SomeIter<Take<Repeat<i32>>>
864 some_iter.push(iter::repeat(2).take(2));
865 let iter_of_iters = some_iter.take(2);
866 //^^^^^^^^^^^^^ impl Iterator<Item = impl Iterator<Item = i32>>
867}
868"#,
869 );
870 }
871
872 #[test]
873 fn infer_call_method_return_associated_types_with_generic() {
874 check_types(
875 r#"
876 pub trait Default {
877 fn default() -> Self;
878 }
879 pub trait Foo {
880 type Bar: Default;
881 }
882
883 pub fn quux<T: Foo>() -> T::Bar {
884 let y = Default::default();
885 //^ <T as Foo>::Bar
886
887 y
888 }
889 "#,
890 );
891 }
892
893 #[test]
894 fn fn_hints() {
895 check_types(
896 r#"
897trait Sized {}
898
899fn foo() -> impl Fn() { loop {} }
900fn foo1() -> impl Fn(f64) { loop {} }
901fn foo2() -> impl Fn(f64, f64) { loop {} }
902fn foo3() -> impl Fn(f64, f64) -> u32 { loop {} }
903fn foo4() -> &'static dyn Fn(f64, f64) -> u32 { loop {} }
904fn foo5() -> &'static dyn Fn(&'static dyn Fn(f64, f64) -> u32, f64) -> u32 { loop {} }
905fn foo6() -> impl Fn(f64, f64) -> u32 + Sized { loop {} }
906fn foo7() -> *const (impl Fn(f64, f64) -> u32 + Sized) { loop {} }
907
908fn main() {
909 let foo = foo();
910 // ^^^ impl Fn()
911 let foo = foo1();
912 // ^^^ impl Fn(f64)
913 let foo = foo2();
914 // ^^^ impl Fn(f64, f64)
915 let foo = foo3();
916 // ^^^ impl Fn(f64, f64) -> u32
917 let foo = foo4();
918 // ^^^ &dyn Fn(f64, f64) -> u32
919 let foo = foo5();
920 // ^^^ &dyn Fn(&dyn Fn(f64, f64) -> u32, f64) -> u32
921 let foo = foo6();
922 // ^^^ impl Fn(f64, f64) -> u32 + Sized
923 let foo = foo7();
924 // ^^^ *const (impl Fn(f64, f64) -> u32 + Sized)
925}
926"#,
927 )
928 }
929
942 #[test] 930 #[test]
943 fn unit_structs_have_no_type_hints() { 931 fn unit_structs_have_no_type_hints() {
944 check_with_config( 932 check_types(
945 InlayHintsConfig { max_length: Some(8), ..TEST_CONFIG },
946 r#" 933 r#"
947enum Result<T, E> { Ok(T), Err(E) } 934enum Result<T, E> { Ok(T), Err(E) }
948use Result::*; 935use Result::*;
@@ -959,159 +946,116 @@ fn main() {
959 } 946 }
960 947
961 #[test] 948 #[test]
962 fn chaining_hints_ignore_comments() { 949 fn let_statement() {
963 check_expect( 950 check_types(
964 InlayHintsConfig {
965 parameter_hints: false,
966 type_hints: false,
967 chaining_hints: true,
968 max_length: None,
969 },
970 r#" 951 r#"
971struct A(B); 952#[derive(PartialEq)]
972impl A { fn into_b(self) -> B { self.0 } } 953enum Option<T> { None, Some(T) }
973struct B(C); 954
974impl B { fn into_c(self) -> C { self.0 } } 955#[derive(PartialEq)]
975struct C; 956struct Test { a: Option<u32>, b: u8 }
976 957
977fn main() { 958fn main() {
978 let c = A(B(C)) 959 struct InnerStruct {}
979 .into_b() // This is a comment 960
980 // This is another comment 961 let test = 54;
981 .into_c(); 962 //^^^^ i32
982} 963 let test: i32 = 33;
983"#, 964 let mut test = 33;
984 expect![[r#" 965 //^^^^^^^^ i32
985 [ 966 let _ = 22;
986 InlayHint { 967 let test = "test";
987 range: 148..173, 968 //^^^^ &str
988 kind: ChainingHint, 969 let test = InnerStruct {};
989 label: "B", 970 //^^^^ InnerStruct
990 }, 971
991 InlayHint { 972 let test = unresolved();
992 range: 148..155, 973
993 kind: ChainingHint, 974 let test = (42, 'a');
994 label: "A", 975 //^^^^ (i32, char)
995 }, 976 let (a, (b, (c,)) = (2, (3, (9.2,));
996 ] 977 //^ i32 ^ i32 ^ f64
997 "#]], 978 let &x = &92;
979 //^ i32
980}"#,
998 ); 981 );
999 } 982 }
1000 983
1001 #[test] 984 #[test]
1002 fn chaining_hints_without_newlines() { 985 fn if_expr() {
1003 check_with_config( 986 check_types(
1004 InlayHintsConfig {
1005 parameter_hints: false,
1006 type_hints: false,
1007 chaining_hints: true,
1008 max_length: None,
1009 },
1010 r#" 987 r#"
1011struct A(B); 988enum Option<T> { None, Some(T) }
1012impl A { fn into_b(self) -> B { self.0 } } 989use Option::*;
1013struct B(C); 990
1014impl B { fn into_c(self) -> C { self.0 } } 991struct Test { a: Option<u32>, b: u8 }
1015struct C;
1016 992
1017fn main() { 993fn main() {
1018 let c = A(B(C)).into_b().into_c(); 994 let test = Some(Test { a: Some(3), b: 1 });
995 //^^^^ Option<Test>
996 if let None = &test {};
997 if let test = &test {};
998 //^^^^ &Option<Test>
999 if let Some(test) = &test {};
1000 //^^^^ &Test
1001 if let Some(Test { a, b }) = &test {};
1002 //^ &Option<u32> ^ &u8
1003 if let Some(Test { a: x, b: y }) = &test {};
1004 //^ &Option<u32> ^ &u8
1005 if let Some(Test { a: Some(x), b: y }) = &test {};
1006 //^ &u32 ^ &u8
1007 if let Some(Test { a: None, b: y }) = &test {};
1008 //^ &u8
1009 if let Some(Test { b: y, .. }) = &test {};
1010 //^ &u8
1011 if test == None {}
1019}"#, 1012}"#,
1020 ); 1013 );
1021 } 1014 }
1022 1015
1023 #[test] 1016 #[test]
1024 fn struct_access_chaining_hints() { 1017 fn while_expr() {
1025 check_expect( 1018 check_types(
1026 InlayHintsConfig {
1027 parameter_hints: false,
1028 type_hints: false,
1029 chaining_hints: true,
1030 max_length: None,
1031 },
1032 r#" 1019 r#"
1033struct A { pub b: B } 1020enum Option<T> { None, Some(T) }
1034struct B { pub c: C } 1021use Option::*;
1035struct C(pub bool);
1036struct D;
1037 1022
1038impl D { 1023struct Test { a: Option<u32>, b: u8 }
1039 fn foo(&self) -> i32 { 42 }
1040}
1041 1024
1042fn main() { 1025fn main() {
1043 let x = A { b: B { c: C(true) } } 1026 let test = Some(Test { a: Some(3), b: 1 });
1044 .b 1027 //^^^^ Option<Test>
1045 .c 1028 while let Some(Test { a: Some(x), b: y }) = &test {};
1046 .0; 1029 //^ &u32 ^ &u8
1047 let x = D
1048 .foo();
1049}"#, 1030}"#,
1050 expect![[r#"
1051 [
1052 InlayHint {
1053 range: 144..191,
1054 kind: ChainingHint,
1055 label: "C",
1056 },
1057 InlayHint {
1058 range: 144..180,
1059 kind: ChainingHint,
1060 label: "B",
1061 },
1062 ]
1063 "#]],
1064 ); 1031 );
1065 } 1032 }
1066 1033
1067 #[test] 1034 #[test]
1068 fn generic_chaining_hints() { 1035 fn match_arm_list() {
1069 check_expect( 1036 check_types(
1070 InlayHintsConfig {
1071 parameter_hints: false,
1072 type_hints: false,
1073 chaining_hints: true,
1074 max_length: None,
1075 },
1076 r#" 1037 r#"
1077struct A<T>(T); 1038enum Option<T> { None, Some(T) }
1078struct B<T>(T); 1039use Option::*;
1079struct C<T>(T); 1040
1080struct X<T,R>(T, R); 1041struct Test { a: Option<u32>, b: u8 }
1081 1042
1082impl<T> A<T> {
1083 fn new(t: T) -> Self { A(t) }
1084 fn into_b(self) -> B<T> { B(self.0) }
1085}
1086impl<T> B<T> {
1087 fn into_c(self) -> C<T> { C(self.0) }
1088}
1089fn main() { 1043fn main() {
1090 let c = A::new(X(42, true)) 1044 match Some(Test { a: Some(3), b: 1 }) {
1091 .into_b() 1045 None => (),
1092 .into_c(); 1046 test => (),
1093} 1047 //^^^^ Option<Test>
1094"#, 1048 Some(Test { a: Some(x), b: y }) => (),
1095 expect![[r#" 1049 //^ u32 ^ u8
1096 [ 1050 _ => {}
1097 InlayHint { 1051 }
1098 range: 247..284, 1052}"#,
1099 kind: ChainingHint,
1100 label: "B<X<i32, bool>>",
1101 },
1102 InlayHint {
1103 range: 247..266,
1104 kind: ChainingHint,
1105 label: "A<X<i32, bool>>",
1106 },
1107 ]
1108 "#]],
1109 ); 1053 );
1110 } 1054 }
1111 1055
1112 #[test] 1056 #[test]
1113 fn incomplete_for_no_hint() { 1057 fn incomplete_for_no_hint() {
1114 check( 1058 check_types(
1115 r#" 1059 r#"
1116fn main() { 1060fn main() {
1117 let data = &[1i32, 2, 3]; 1061 let data = &[1i32, 2, 3];
@@ -1146,7 +1090,7 @@ fn main() {
1146 1090
1147 #[test] 1091 #[test]
1148 fn complete_for_hint() { 1092 fn complete_for_hint() {
1149 check( 1093 check_types(
1150 r#" 1094 r#"
1151pub struct Vec<T> {} 1095pub struct Vec<T> {}
1152 1096
@@ -1175,13 +1119,7 @@ fn main() {
1175 1119
1176 #[test] 1120 #[test]
1177 fn multi_dyn_trait_bounds() { 1121 fn multi_dyn_trait_bounds() {
1178 check_with_config( 1122 check_types(
1179 InlayHintsConfig {
1180 type_hints: true,
1181 parameter_hints: false,
1182 chaining_hints: false,
1183 max_length: None,
1184 },
1185 r#" 1123 r#"
1186pub struct Vec<T> {} 1124pub struct Vec<T> {}
1187 1125
@@ -1208,13 +1146,7 @@ fn main() {
1208 1146
1209 #[test] 1147 #[test]
1210 fn shorten_iterator_hints() { 1148 fn shorten_iterator_hints() {
1211 check_with_config( 1149 check_types(
1212 InlayHintsConfig {
1213 parameter_hints: false,
1214 type_hints: true,
1215 chaining_hints: false,
1216 max_length: None,
1217 },
1218 r#" 1150 r#"
1219use core::iter; 1151use core::iter;
1220 1152
@@ -1244,7 +1176,55 @@ fn main() {
1244 } 1176 }
1245 1177
1246 #[test] 1178 #[test]
1247 fn shorten_iterator_chaining_hints() { 1179 fn closures() {
1180 check(
1181 r#"
1182fn main() {
1183 let mut start = 0;
1184 //^^^^^^^^^ i32
1185 (0..2).for_each(|increment| { start += increment; });
1186 //^^^^^^^^^ i32
1187
1188 let multiply =
1189 //^^^^^^^^ |…| -> i32
1190 | a, b| a * b
1191 //^ i32 ^ i32
1192 ;
1193
1194 let _: i32 = multiply(1, 2);
1195 let multiply_ref = &multiply;
1196 //^^^^^^^^^^^^ &|…| -> i32
1197
1198 let return_42 = || 42;
1199 //^^^^^^^^^ || -> i32
1200}"#,
1201 );
1202 }
1203
1204 #[test]
1205 fn hint_truncation() {
1206 check_with_config(
1207 InlayHintsConfig { max_length: Some(8), ..TEST_CONFIG },
1208 r#"
1209struct Smol<T>(T);
1210
1211struct VeryLongOuterName<T>(T);
1212
1213fn main() {
1214 let a = Smol(0u32);
1215 //^ Smol<u32>
1216 let b = VeryLongOuterName(0usize);
1217 //^ VeryLongOuterName<…>
1218 let c = Smol(Smol(0u32))
1219 //^ Smol<Smol<…>>
1220}"#,
1221 );
1222 }
1223
1224 // Chaining hint tests
1225
1226 #[test]
1227 fn chaining_hints_ignore_comments() {
1248 check_expect( 1228 check_expect(
1249 InlayHintsConfig { 1229 InlayHintsConfig {
1250 parameter_hints: false, 1230 parameter_hints: false,
@@ -1253,46 +1233,30 @@ fn main() {
1253 max_length: None, 1233 max_length: None,
1254 }, 1234 },
1255 r#" 1235 r#"
1256use core::iter; 1236struct A(B);
1257 1237impl A { fn into_b(self) -> B { self.0 } }
1258struct MyIter; 1238struct B(C);
1259 1239impl B { fn into_c(self) -> C { self.0 } }
1260impl Iterator for MyIter { 1240struct C;
1261 type Item = ();
1262 fn next(&mut self) -> Option<Self::Item> {
1263 None
1264 }
1265}
1266 1241
1267fn main() { 1242fn main() {
1268 let _x = MyIter.by_ref() 1243 let c = A(B(C))
1269 .take(5) 1244 .into_b() // This is a comment
1270 .by_ref() 1245 // This is another comment
1271 .take(5) 1246 .into_c();
1272 .by_ref();
1273} 1247}
1274"#, 1248"#,
1275 expect![[r#" 1249 expect![[r#"
1276 [ 1250 [
1277 InlayHint { 1251 InlayHint {
1278 range: 175..242, 1252 range: 148..173,
1279 kind: ChainingHint,
1280 label: "impl Iterator<Item = ()>",
1281 },
1282 InlayHint {
1283 range: 175..225,
1284 kind: ChainingHint,
1285 label: "impl Iterator<Item = ()>",
1286 },
1287 InlayHint {
1288 range: 175..207,
1289 kind: ChainingHint, 1253 kind: ChainingHint,
1290 label: "impl Iterator<Item = ()>", 1254 label: "B",
1291 }, 1255 },
1292 InlayHint { 1256 InlayHint {
1293 range: 175..190, 1257 range: 148..155,
1294 kind: ChainingHint, 1258 kind: ChainingHint,
1295 label: "&mut MyIter", 1259 label: "A",
1296 }, 1260 },
1297 ] 1261 ]
1298 "#]], 1262 "#]],
@@ -1300,156 +1264,163 @@ fn main() {
1300 } 1264 }
1301 1265
1302 #[test] 1266 #[test]
1303 fn shorten_iterators_in_associated_params() { 1267 fn chaining_hints_without_newlines() {
1304 check_with_config( 1268 check_chains(
1269 r#"
1270struct A(B);
1271impl A { fn into_b(self) -> B { self.0 } }
1272struct B(C);
1273impl B { fn into_c(self) -> C { self.0 } }
1274struct C;
1275
1276fn main() {
1277 let c = A(B(C)).into_b().into_c();
1278}"#,
1279 );
1280 }
1281
1282 #[test]
1283 fn struct_access_chaining_hints() {
1284 check_expect(
1305 InlayHintsConfig { 1285 InlayHintsConfig {
1306 parameter_hints: false, 1286 parameter_hints: false,
1307 type_hints: true, 1287 type_hints: false,
1308 chaining_hints: false, 1288 chaining_hints: true,
1309 max_length: None, 1289 max_length: None,
1310 }, 1290 },
1311 r#" 1291 r#"
1312use core::iter; 1292struct A { pub b: B }
1313 1293struct B { pub c: C }
1314pub struct SomeIter<T> {} 1294struct C(pub bool);
1315 1295struct D;
1316impl<T> SomeIter<T> {
1317 pub fn new() -> Self { SomeIter {} }
1318 pub fn push(&mut self, t: T) {}
1319}
1320 1296
1321impl<T> Iterator for SomeIter<T> { 1297impl D {
1322 type Item = T; 1298 fn foo(&self) -> i32 { 42 }
1323 fn next(&mut self) -> Option<Self::Item> {
1324 None
1325 }
1326} 1299}
1327 1300
1328fn main() { 1301fn main() {
1329 let mut some_iter = SomeIter::new(); 1302 let x = A { b: B { c: C(true) } }
1330 //^^^^^^^^^^^^^ SomeIter<Take<Repeat<i32>>> 1303 .b
1331 some_iter.push(iter::repeat(2).take(2)); 1304 .c
1332 let iter_of_iters = some_iter.take(2); 1305 .0;
1333 //^^^^^^^^^^^^^ impl Iterator<Item = impl Iterator<Item = i32>> 1306 let x = D
1334} 1307 .foo();
1335"#, 1308}"#,
1309 expect![[r#"
1310 [
1311 InlayHint {
1312 range: 144..191,
1313 kind: ChainingHint,
1314 label: "C",
1315 },
1316 InlayHint {
1317 range: 144..180,
1318 kind: ChainingHint,
1319 label: "B",
1320 },
1321 ]
1322 "#]],
1336 ); 1323 );
1337 } 1324 }
1338 1325
1339 #[test] 1326 #[test]
1340 fn hide_param_hints_for_clones() { 1327 fn generic_chaining_hints() {
1341 check_with_config( 1328 check_expect(
1342 InlayHintsConfig { 1329 InlayHintsConfig {
1343 parameter_hints: true, 1330 parameter_hints: false,
1344 type_hints: false, 1331 type_hints: false,
1345 chaining_hints: false, 1332 chaining_hints: true,
1346 max_length: None, 1333 max_length: None,
1347 }, 1334 },
1348 r#" 1335 r#"
1349fn foo(bar: i32, baz: String, qux: f32) {} 1336struct A<T>(T);
1337struct B<T>(T);
1338struct C<T>(T);
1339struct X<T,R>(T, R);
1350 1340
1341impl<T> A<T> {
1342 fn new(t: T) -> Self { A(t) }
1343 fn into_b(self) -> B<T> { B(self.0) }
1344}
1345impl<T> B<T> {
1346 fn into_c(self) -> C<T> { C(self.0) }
1347}
1351fn main() { 1348fn main() {
1352 let bar = 3; 1349 let c = A::new(X(42, true))
1353 let baz = &"baz"; 1350 .into_b()
1354 let fez = 1.0; 1351 .into_c();
1355 foo(bar.clone(), baz.clone(), fez.clone());
1356 //^^^^^^^^^^^ qux
1357} 1352}
1358"#, 1353"#,
1354 expect![[r#"
1355 [
1356 InlayHint {
1357 range: 247..284,
1358 kind: ChainingHint,
1359 label: "B<X<i32, bool>>",
1360 },
1361 InlayHint {
1362 range: 247..266,
1363 kind: ChainingHint,
1364 label: "A<X<i32, bool>>",
1365 },
1366 ]
1367 "#]],
1359 ); 1368 );
1360 } 1369 }
1361 1370
1362 #[test] 1371 #[test]
1363 fn infer_call_method_return_associated_types_with_generic() { 1372 fn shorten_iterator_chaining_hints() {
1364 check( 1373 check_expect(
1374 InlayHintsConfig {
1375 parameter_hints: false,
1376 type_hints: false,
1377 chaining_hints: true,
1378 max_length: None,
1379 },
1365 r#" 1380 r#"
1366 pub trait Default { 1381use core::iter;
1367 fn default() -> Self;
1368 }
1369 pub trait Foo {
1370 type Bar: Default;
1371 }
1372 1382
1373 pub fn quux<T: Foo>() -> T::Bar { 1383struct MyIter;
1374 let y = Default::default();
1375 //^ <T as Foo>::Bar
1376 1384
1377 y 1385impl Iterator for MyIter {
1378 } 1386 type Item = ();
1379 "#, 1387 fn next(&mut self) -> Option<Self::Item> {
1380 ); 1388 None
1381 } 1389 }
1382
1383 #[test]
1384 fn self_param_hints() {
1385 check(
1386 r#"
1387struct Foo;
1388
1389impl Foo {
1390 fn foo(self: Self) {}
1391 fn bar(self: &Self) {}
1392} 1390}
1393 1391
1394fn main() { 1392fn main() {
1395 Foo::foo(Foo); 1393 let _x = MyIter.by_ref()
1396 //^^^ self 1394 .take(5)
1397 Foo::bar(&Foo); 1395 .by_ref()
1398 //^^^^ self 1396 .take(5)
1399} 1397 .by_ref();
1400"#,
1401 )
1402 }
1403
1404 #[test]
1405 fn fn_hints() {
1406 check(
1407 r#"
1408trait Sized {}
1409
1410fn foo() -> impl Fn() { loop {} }
1411fn foo1() -> impl Fn(f64) { loop {} }
1412fn foo2() -> impl Fn(f64, f64) { loop {} }
1413fn foo3() -> impl Fn(f64, f64) -> u32 { loop {} }
1414fn foo4() -> &'static dyn Fn(f64, f64) -> u32 { loop {} }
1415fn foo5() -> &'static dyn Fn(&'static dyn Fn(f64, f64) -> u32, f64) -> u32 { loop {} }
1416fn foo6() -> impl Fn(f64, f64) -> u32 + Sized { loop {} }
1417fn foo7() -> *const (impl Fn(f64, f64) -> u32 + Sized) { loop {} }
1418
1419fn main() {
1420 let foo = foo();
1421 // ^^^ impl Fn()
1422 let foo = foo1();
1423 // ^^^ impl Fn(f64)
1424 let foo = foo2();
1425 // ^^^ impl Fn(f64, f64)
1426 let foo = foo3();
1427 // ^^^ impl Fn(f64, f64) -> u32
1428 let foo = foo4();
1429 // ^^^ &dyn Fn(f64, f64) -> u32
1430 let foo = foo5();
1431 // ^^^ &dyn Fn(&dyn Fn(f64, f64) -> u32, f64) -> u32
1432 let foo = foo6();
1433 // ^^^ impl Fn(f64, f64) -> u32 + Sized
1434 let foo = foo7();
1435 // ^^^ *const (impl Fn(f64, f64) -> u32 + Sized)
1436} 1398}
1437"#, 1399"#,
1438 ) 1400 expect![[r#"
1439 } 1401 [
1440 1402 InlayHint {
1441 #[test] 1403 range: 175..242,
1442 fn param_name_hints_show_for_literals() { 1404 kind: ChainingHint,
1443 check( 1405 label: "impl Iterator<Item = ()>",
1444 r#"pub fn test(a: i32, b: i32) -> [i32; 2] { [a, b] } 1406 },
1445fn main() { 1407 InlayHint {
1446 test( 1408 range: 175..225,
1447 0x0fab272b, 1409 kind: ChainingHint,
1448 //^^^^^^^^^^ a 1410 label: "impl Iterator<Item = ()>",
1449 0x0fab272b 1411 },
1450 //^^^^^^^^^^ b 1412 InlayHint {
1451 ); 1413 range: 175..207,
1452}"#, 1414 kind: ChainingHint,
1453 ) 1415 label: "impl Iterator<Item = ()>",
1416 },
1417 InlayHint {
1418 range: 175..190,
1419 kind: ChainingHint,
1420 label: "&mut MyIter",
1421 },
1422 ]
1423 "#]],
1424 );
1454 } 1425 }
1455} 1426}