aboutsummaryrefslogtreecommitdiff
path: root/crates/ide/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ide/src')
-rw-r--r--crates/ide/src/hover.rs29
-rw-r--r--crates/ide/src/inlay_hints.rs1032
2 files changed, 520 insertions, 541 deletions
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs
index 04598cd06..455a27e48 100644
--- a/crates/ide/src/hover.rs
+++ b/crates/ide/src/hover.rs
@@ -28,6 +28,7 @@ use crate::{
28#[derive(Clone, Debug, PartialEq, Eq)] 28#[derive(Clone, Debug, PartialEq, Eq)]
29pub struct HoverConfig { 29pub struct HoverConfig {
30 pub implementations: bool, 30 pub implementations: bool,
31 pub references: bool,
31 pub run: bool, 32 pub run: bool,
32 pub debug: bool, 33 pub debug: bool,
33 pub goto_type_def: bool, 34 pub goto_type_def: bool,
@@ -38,6 +39,7 @@ pub struct HoverConfig {
38impl HoverConfig { 39impl HoverConfig {
39 pub const NO_ACTIONS: Self = Self { 40 pub const NO_ACTIONS: Self = Self {
40 implementations: false, 41 implementations: false,
42 references: false,
41 run: false, 43 run: false,
42 debug: false, 44 debug: false,
43 goto_type_def: false, 45 goto_type_def: false,
@@ -46,7 +48,7 @@ impl HoverConfig {
46 }; 48 };
47 49
48 pub fn any(&self) -> bool { 50 pub fn any(&self) -> bool {
49 self.implementations || self.runnable() || self.goto_type_def 51 self.implementations || self.references || self.runnable() || self.goto_type_def
50 } 52 }
51 53
52 pub fn none(&self) -> bool { 54 pub fn none(&self) -> bool {
@@ -62,6 +64,7 @@ impl HoverConfig {
62pub enum HoverAction { 64pub enum HoverAction {
63 Runnable(Runnable), 65 Runnable(Runnable),
64 Implementation(FilePosition), 66 Implementation(FilePosition),
67 Reference(FilePosition),
65 GoToType(Vec<HoverGotoTypeData>), 68 GoToType(Vec<HoverGotoTypeData>),
66} 69}
67 70
@@ -148,6 +151,10 @@ pub(crate) fn hover(
148 res.actions.push(action); 151 res.actions.push(action);
149 } 152 }
150 153
154 if let Some(action) = show_fn_references_action(db, definition) {
155 res.actions.push(action);
156 }
157
151 if let Some(action) = runnable_action(&sema, definition, position.file_id) { 158 if let Some(action) = runnable_action(&sema, definition, position.file_id) {
152 res.actions.push(action); 159 res.actions.push(action);
153 } 160 }
@@ -211,6 +218,18 @@ fn show_implementations_action(db: &RootDatabase, def: Definition) -> Option<Hov
211 adt.try_to_nav(db).map(to_action) 218 adt.try_to_nav(db).map(to_action)
212} 219}
213 220
221fn show_fn_references_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> {
222 match def {
223 Definition::ModuleDef(ModuleDef::Function(it)) => it.try_to_nav(db).map(|nav_target| {
224 HoverAction::Reference(FilePosition {
225 file_id: nav_target.file_id,
226 offset: nav_target.focus_or_full_range().start(),
227 })
228 }),
229 _ => None,
230 }
231}
232
214fn runnable_action( 233fn runnable_action(
215 sema: &Semantics<RootDatabase>, 234 sema: &Semantics<RootDatabase>,
216 def: Definition, 235 def: Definition,
@@ -2377,6 +2396,14 @@ fn foo_$0test() {}
2377"#, 2396"#,
2378 expect![[r#" 2397 expect![[r#"
2379 [ 2398 [
2399 Reference(
2400 FilePosition {
2401 file_id: FileId(
2402 0,
2403 ),
2404 offset: 11,
2405 },
2406 ),
2380 Runnable( 2407 Runnable(
2381 Runnable { 2408 Runnable {
2382 nav: NavigationTarget { 2409 nav: NavigationTarget {
diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs
index d6dfa0183..821c61403 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 }
@@ -316,11 +315,12 @@ fn should_hide_param_name_hint(
316 param_name: &str, 315 param_name: &str,
317 argument: &ast::Expr, 316 argument: &ast::Expr,
318) -> bool { 317) -> bool {
318 // These are to be tested in the `parameter_hint_heuristics` test
319 // hide when: 319 // hide when:
320 // - the parameter name is a suffix of the function's name 320 // - the parameter name is a suffix of the function's name
321 // - the argument is an enum whose name is equal to the parameter 321 // - 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 322 // - exact argument<->parameter match(ignoring leading underscore) or parameter is a prefix/suffix
323 // of parameter with _ splitting it off 323 // of argument with _ splitting it off
324 // - param starts with `ra_fixture` 324 // - param starts with `ra_fixture`
325 // - param is a well known name in an unary function 325 // - param is a well known name in an unary function
326 326
@@ -342,23 +342,22 @@ fn should_hide_param_name_hint(
342} 342}
343 343
344fn is_argument_similar_to_param_name(argument: &ast::Expr, param_name: &str) -> bool { 344fn is_argument_similar_to_param_name(argument: &ast::Expr, param_name: &str) -> bool {
345 match get_string_representation(argument) { 345 // check whether param_name and argument are the same or
346 None => false, 346 // whether param_name is a prefix/suffix of argument(split at `_`)
347 Some(argument) => { 347 let argument = match get_string_representation(argument) {
348 let mut res = false; 348 Some(argument) => argument,
349 if let Some(first) = argument.bytes().skip_while(|&c| c == b'_').position(|c| c == b'_') 349 None => return false,
350 { 350 };
351 res |= param_name == argument[..first].trim_start_matches('_'); 351
352 } 352 let param_name = param_name.trim_start_matches('_');
353 if let Some(last) = 353 let argument = argument.trim_start_matches('_');
354 argument.bytes().rev().skip_while(|&c| c == b'_').position(|c| c == b'_') 354 if argument.strip_prefix(param_name).map_or(false, |s| s.starts_with('_')) {
355 { 355 return true;
356 res |= param_name == argument[last..].trim_end_matches('_');
357 }
358 res |= argument == param_name;
359 res
360 }
361 } 356 }
357 if argument.strip_suffix(param_name).map_or(false, |s| s.ends_with('_')) {
358 return true;
359 }
360 argument == param_name
362} 361}
363 362
364/// Hide the parameter name of an unary function if it is a `_` - prefixed suffix of the function's name, or equal. 363/// Hide the parameter name of an unary function if it is a `_` - prefixed suffix of the function's name, or equal.
@@ -397,7 +396,7 @@ fn get_string_representation(expr: &ast::Expr) -> Option<String> {
397 ast::Expr::MethodCallExpr(method_call_expr) => { 396 ast::Expr::MethodCallExpr(method_call_expr) => {
398 let name_ref = method_call_expr.name_ref()?; 397 let name_ref = method_call_expr.name_ref()?;
399 match name_ref.text().as_str() { 398 match name_ref.text().as_str() {
400 "clone" => method_call_expr.receiver().map(|rec| rec.to_string()), 399 "clone" | "as_ref" => method_call_expr.receiver().map(|rec| rec.to_string()),
401 name_ref => Some(name_ref.to_owned()), 400 name_ref => Some(name_ref.to_owned()),
402 } 401 }
403 } 402 }
@@ -451,6 +450,42 @@ mod tests {
451 check_with_config(TEST_CONFIG, ra_fixture); 450 check_with_config(TEST_CONFIG, ra_fixture);
452 } 451 }
453 452
453 fn check_params(ra_fixture: &str) {
454 check_with_config(
455 InlayHintsConfig {
456 parameter_hints: true,
457 type_hints: false,
458 chaining_hints: false,
459 max_length: None,
460 },
461 ra_fixture,
462 );
463 }
464
465 fn check_types(ra_fixture: &str) {
466 check_with_config(
467 InlayHintsConfig {
468 parameter_hints: false,
469 type_hints: true,
470 chaining_hints: false,
471 max_length: None,
472 },
473 ra_fixture,
474 );
475 }
476
477 fn check_chains(ra_fixture: &str) {
478 check_with_config(
479 InlayHintsConfig {
480 parameter_hints: false,
481 type_hints: false,
482 chaining_hints: true,
483 max_length: None,
484 },
485 ra_fixture,
486 );
487 }
488
454 fn check_with_config(config: InlayHintsConfig, ra_fixture: &str) { 489 fn check_with_config(config: InlayHintsConfig, ra_fixture: &str) {
455 let ra_fixture = 490 let ra_fixture =
456 format!("//- /main.rs crate:main deps:core\n{}\n{}", ra_fixture, FamousDefs::FIXTURE); 491 format!("//- /main.rs crate:main deps:core\n{}\n{}", ra_fixture, FamousDefs::FIXTURE);
@@ -471,17 +506,30 @@ mod tests {
471 } 506 }
472 507
473 #[test] 508 #[test]
474 fn param_hints_only() { 509 fn hints_disabled() {
475 check_with_config( 510 check_with_config(
476 InlayHintsConfig { 511 InlayHintsConfig {
477 parameter_hints: true,
478 type_hints: false, 512 type_hints: false,
513 parameter_hints: false,
479 chaining_hints: false, 514 chaining_hints: false,
480 max_length: None, 515 max_length: None,
481 }, 516 },
482 r#" 517 r#"
483fn foo(a: i32, b: i32) -> i32 { a + b } 518fn foo(a: i32, b: i32) -> i32 { a + b }
484fn main() { 519fn main() {
520 let _x = foo(4, 4);
521}"#,
522 );
523 }
524
525 // Parameter hint tests
526
527 #[test]
528 fn param_hints_only() {
529 check_params(
530 r#"
531fn foo(a: i32, b: i32) -> i32 { a + b }
532fn main() {
485 let _x = foo( 533 let _x = foo(
486 4, 534 4,
487 //^ a 535 //^ a
@@ -494,13 +542,7 @@ fn main() {
494 542
495 #[test] 543 #[test]
496 fn param_name_similar_to_fn_name_still_hints() { 544 fn param_name_similar_to_fn_name_still_hints() {
497 check_with_config( 545 check_params(
498 InlayHintsConfig {
499 parameter_hints: true,
500 type_hints: false,
501 chaining_hints: false,
502 max_length: None,
503 },
504 r#" 546 r#"
505fn max(x: i32, y: i32) -> i32 { x + y } 547fn max(x: i32, y: i32) -> i32 { x + y }
506fn main() { 548fn main() {
@@ -516,13 +558,7 @@ fn main() {
516 558
517 #[test] 559 #[test]
518 fn param_name_similar_to_fn_name() { 560 fn param_name_similar_to_fn_name() {
519 check_with_config( 561 check_params(
520 InlayHintsConfig {
521 parameter_hints: true,
522 type_hints: false,
523 chaining_hints: false,
524 max_length: None,
525 },
526 r#" 562 r#"
527fn param_with_underscore(with_underscore: i32) -> i32 { with_underscore } 563fn param_with_underscore(with_underscore: i32) -> i32 { with_underscore }
528fn main() { 564fn main() {
@@ -531,17 +567,20 @@ fn main() {
531 ); 567 );
532}"#, 568}"#,
533 ); 569 );
570 check_params(
571 r#"
572fn param_with_underscore(underscore: i32) -> i32 { underscore }
573fn main() {
574 let _x = param_with_underscore(
575 4,
576 );
577}"#,
578 );
534 } 579 }
535 580
536 #[test] 581 #[test]
537 fn param_name_same_as_fn_name() { 582 fn param_name_same_as_fn_name() {
538 check_with_config( 583 check_params(
539 InlayHintsConfig {
540 parameter_hints: true,
541 type_hints: false,
542 chaining_hints: false,
543 max_length: None,
544 },
545 r#" 584 r#"
546fn foo(foo: i32) -> i32 { foo } 585fn foo(foo: i32) -> i32 { foo }
547fn main() { 586fn main() {
@@ -554,52 +593,206 @@ fn main() {
554 593
555 #[test] 594 #[test]
556 fn never_hide_param_when_multiple_params() { 595 fn never_hide_param_when_multiple_params() {
557 check_with_config( 596 check_params(
558 InlayHintsConfig {
559 parameter_hints: true,
560 type_hints: false,
561 chaining_hints: false,
562 max_length: None,
563 },
564 r#" 597 r#"
565fn foo(bar: i32, baz: i32) -> i32 { bar + baz } 598fn foo(foo: i32, bar: i32) -> i32 { bar + baz }
566fn main() { 599fn main() {
567 let _x = foo( 600 let _x = foo(
568 4, 601 4,
569 //^ bar 602 //^ foo
570 8, 603 8,
571 //^ baz 604 //^ bar
572 ); 605 );
573}"#, 606}"#,
574 ); 607 );
575 } 608 }
576 609
577 #[test] 610 #[test]
578 fn hints_disabled() { 611 fn param_hints_look_through_as_ref_and_clone() {
579 check_with_config( 612 check_params(
580 InlayHintsConfig {
581 type_hints: false,
582 parameter_hints: false,
583 chaining_hints: false,
584 max_length: None,
585 },
586 r#" 613 r#"
587fn foo(a: i32, b: i32) -> i32 { a + b } 614fn foo(bar: i32, baz: f32) {}
615
588fn main() { 616fn main() {
589 let _x = foo(4, 4); 617 let bar = 3;
618 let baz = &"baz";
619 let fez = 1.0;
620 foo(bar.clone(), bar.clone());
621 //^^^^^^^^^^^ baz
622 foo(bar.as_ref(), bar.as_ref());
623 //^^^^^^^^^^^^ baz
624}
625"#,
626 );
627 }
628
629 #[test]
630 fn self_param_hints() {
631 check_params(
632 r#"
633struct Foo;
634
635impl Foo {
636 fn foo(self: Self) {}
637 fn bar(self: &Self) {}
638}
639
640fn main() {
641 Foo::foo(Foo);
642 //^^^ self
643 Foo::bar(&Foo);
644 //^^^^ self
645}
646"#,
647 )
648 }
649
650 #[test]
651 fn param_name_hints_show_for_literals() {
652 check_params(
653 r#"pub fn test(a: i32, b: i32) -> [i32; 2] { [a, b] }
654fn main() {
655 test(
656 0xa_b,
657 //^^^^^ a
658 0xa_b,
659 //^^^^^ b
660 );
661}"#,
662 )
663 }
664
665 #[test]
666 fn function_call_parameter_hint() {
667 check_params(
668 r#"
669enum Option<T> { None, Some(T) }
670use Option::*;
671
672struct FileId {}
673struct SmolStr {}
674
675struct TextRange {}
676struct SyntaxKind {}
677struct NavigationTarget {}
678
679struct Test {}
680
681impl Test {
682 fn method(&self, mut param: i32) -> i32 { param * 2 }
683
684 fn from_syntax(
685 file_id: FileId,
686 name: SmolStr,
687 focus_range: Option<TextRange>,
688 full_range: TextRange,
689 kind: SyntaxKind,
690 docs: Option<String>,
691 ) -> NavigationTarget {
692 NavigationTarget {}
693 }
694}
695
696fn test_func(mut foo: i32, bar: i32, msg: &str, _: i32, last: i32) -> i32 {
697 foo + bar
698}
699
700fn main() {
701 let not_literal = 1;
702 let _: i32 = test_func(1, 2, "hello", 3, not_literal);
703 //^ foo ^ bar ^^^^^^^ msg ^^^^^^^^^^^ last
704 let t: Test = Test {};
705 t.method(123);
706 //^^^ param
707 Test::method(&t, 3456);
708 //^^ self ^^^^ param
709 Test::from_syntax(
710 FileId {},
711 //^^^^^^^^^ file_id
712 "impl".into(),
713 //^^^^^^^^^^^^^ name
714 None,
715 //^^^^ focus_range
716 TextRange {},
717 //^^^^^^^^^^^^ full_range
718 SyntaxKind {},
719 //^^^^^^^^^^^^^ kind
720 None,
721 //^^^^ docs
722 );
723}"#,
724 );
725 }
726
727 #[test]
728 fn parameter_hint_heuristics() {
729 check_params(
730 r#"
731fn check(ra_fixture_thing: &str) {}
732
733fn map(f: i32) {}
734fn filter(predicate: i32) {}
735
736fn strip_suffix(suffix: &str) {}
737fn stripsuffix(suffix: &str) {}
738fn same(same: u32) {}
739fn same2(_same2: u32) {}
740
741fn enum_matches_param_name(completion_kind: CompletionKind) {}
742
743fn foo(param: u32) {}
744fn bar(param_eter: u32) {}
745
746enum CompletionKind {
747 Keyword,
748}
749
750fn non_ident_pat((a, b): (u32, u32)) {}
751
752fn main() {
753 check("");
754
755 map(0);
756 filter(0);
757
758 strip_suffix("");
759 stripsuffix("");
760 //^^ suffix
761 same(0);
762 same2(0);
763
764 enum_matches_param_name(CompletionKind::Keyword);
765
766 let param = 0;
767 foo(param);
768 let param_end = 0;
769 foo(param_end);
770 let start_param = 0;
771 foo(start_param);
772 let param2 = 0;
773 foo(param2);
774 //^^^^^^ param
775
776 let param_eter = 0;
777 bar(param_eter);
778 let param_eter_end = 0;
779 bar(param_eter_end);
780 let start_param_eter = 0;
781 bar(start_param_eter);
782 let param_eter2 = 0;
783 bar(param_eter2);
784 //^^^^^^^^^^^ param_eter
785
786 non_ident_pat((0, 0));
590}"#, 787}"#,
591 ); 788 );
592 } 789 }
593 790
791 // Type-Hint tests
792
594 #[test] 793 #[test]
595 fn type_hints_only() { 794 fn type_hints_only() {
596 check_with_config( 795 check_types(
597 InlayHintsConfig {
598 type_hints: true,
599 parameter_hints: false,
600 chaining_hints: false,
601 max_length: None,
602 },
603 r#" 796 r#"
604fn foo(a: i32, b: i32) -> i32 { a + b } 797fn foo(a: i32, b: i32) -> i32 { a + b }
605fn main() { 798fn main() {
@@ -627,8 +820,115 @@ fn main() {
627 } 820 }
628 821
629 #[test] 822 #[test]
823 fn shorten_iterators_in_associated_params() {
824 check_types(
825 r#"
826use core::iter;
827
828pub struct SomeIter<T> {}
829
830impl<T> SomeIter<T> {
831 pub fn new() -> Self { SomeIter {} }
832 pub fn push(&mut self, t: T) {}
833}
834
835impl<T> Iterator for SomeIter<T> {
836 type Item = T;
837 fn next(&mut self) -> Option<Self::Item> {
838 None
839 }
840}
841
842fn main() {
843 let mut some_iter = SomeIter::new();
844 //^^^^^^^^^^^^^ SomeIter<Take<Repeat<i32>>>
845 some_iter.push(iter::repeat(2).take(2));
846 let iter_of_iters = some_iter.take(2);
847 //^^^^^^^^^^^^^ impl Iterator<Item = impl Iterator<Item = i32>>
848}
849"#,
850 );
851 }
852
853 #[test]
854 fn infer_call_method_return_associated_types_with_generic() {
855 check_types(
856 r#"
857 pub trait Default {
858 fn default() -> Self;
859 }
860 pub trait Foo {
861 type Bar: Default;
862 }
863
864 pub fn quux<T: Foo>() -> T::Bar {
865 let y = Default::default();
866 //^ <T as Foo>::Bar
867
868 y
869 }
870 "#,
871 );
872 }
873
874 #[test]
875 fn fn_hints() {
876 check_types(
877 r#"
878trait Sized {}
879
880fn foo() -> impl Fn() { loop {} }
881fn foo1() -> impl Fn(f64) { loop {} }
882fn foo2() -> impl Fn(f64, f64) { loop {} }
883fn foo3() -> impl Fn(f64, f64) -> u32 { loop {} }
884fn foo4() -> &'static dyn Fn(f64, f64) -> u32 { loop {} }
885fn foo5() -> &'static dyn Fn(&'static dyn Fn(f64, f64) -> u32, f64) -> u32 { loop {} }
886fn foo6() -> impl Fn(f64, f64) -> u32 + Sized { loop {} }
887fn foo7() -> *const (impl Fn(f64, f64) -> u32 + Sized) { loop {} }
888
889fn main() {
890 let foo = foo();
891 // ^^^ impl Fn()
892 let foo = foo1();
893 // ^^^ impl Fn(f64)
894 let foo = foo2();
895 // ^^^ impl Fn(f64, f64)
896 let foo = foo3();
897 // ^^^ impl Fn(f64, f64) -> u32
898 let foo = foo4();
899 // ^^^ &dyn Fn(f64, f64) -> u32
900 let foo = foo5();
901 // ^^^ &dyn Fn(&dyn Fn(f64, f64) -> u32, f64) -> u32
902 let foo = foo6();
903 // ^^^ impl Fn(f64, f64) -> u32 + Sized
904 let foo = foo7();
905 // ^^^ *const (impl Fn(f64, f64) -> u32 + Sized)
906}
907"#,
908 )
909 }
910
911 #[test]
912 fn unit_structs_have_no_type_hints() {
913 check_types(
914 r#"
915enum Result<T, E> { Ok(T), Err(E) }
916use Result::*;
917
918struct SyntheticSyntax;
919
920fn main() {
921 match Ok(()) {
922 Ok(_) => (),
923 Err(SyntheticSyntax) => (),
924 }
925}"#,
926 );
927 }
928
929 #[test]
630 fn let_statement() { 930 fn let_statement() {
631 check( 931 check_types(
632 r#" 932 r#"
633#[derive(PartialEq)] 933#[derive(PartialEq)]
634enum Option<T> { None, Some(T) } 934enum Option<T> { None, Some(T) }
@@ -663,34 +963,8 @@ fn main() {
663 } 963 }
664 964
665 #[test] 965 #[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() { 966 fn if_expr() {
693 check( 967 check_types(
694 r#" 968 r#"
695enum Option<T> { None, Some(T) } 969enum Option<T> { None, Some(T) }
696use Option::*; 970use Option::*;
@@ -722,7 +996,7 @@ fn main() {
722 996
723 #[test] 997 #[test]
724 fn while_expr() { 998 fn while_expr() {
725 check( 999 check_types(
726 r#" 1000 r#"
727enum Option<T> { None, Some(T) } 1001enum Option<T> { None, Some(T) }
728use Option::*; 1002use Option::*;
@@ -740,7 +1014,7 @@ fn main() {
740 1014
741 #[test] 1015 #[test]
742 fn match_arm_list() { 1016 fn match_arm_list() {
743 check( 1017 check_types(
744 r#" 1018 r#"
745enum Option<T> { None, Some(T) } 1019enum Option<T> { None, Some(T) }
746use Option::*; 1020use Option::*;
@@ -761,203 +1035,175 @@ fn main() {
761 } 1035 }
762 1036
763 #[test] 1037 #[test]
764 fn hint_truncation() { 1038 fn incomplete_for_no_hint() {
765 check_with_config( 1039 check_types(
766 InlayHintsConfig { max_length: Some(8), ..TEST_CONFIG },
767 r#" 1040 r#"
768struct Smol<T>(T);
769
770struct VeryLongOuterName<T>(T);
771
772fn main() { 1041fn main() {
773 let a = Smol(0u32); 1042 let data = &[1i32, 2, 3];
774 //^ Smol<u32> 1043 //^^^^ &[i32; 3]
775 let b = VeryLongOuterName(0usize); 1044 for i
776 //^ VeryLongOuterName<…>
777 let c = Smol(Smol(0u32))
778 //^ Smol<Smol<…>>
779}"#, 1045}"#,
780 ); 1046 );
781 }
782
783 #[test]
784 fn function_call_parameter_hint() {
785 check( 1047 check(
786 r#" 1048 r#"
787enum Option<T> { None, Some(T) } 1049pub struct Vec<T> {}
788use Option::*;
789
790struct FileId {}
791struct SmolStr {}
792
793struct TextRange {}
794struct SyntaxKind {}
795struct NavigationTarget {}
796
797struct Test {}
798
799impl Test {
800 fn method(&self, mut param: i32) -> i32 { param * 2 }
801 1050
802 fn from_syntax( 1051impl<T> Vec<T> {
803 file_id: FileId, 1052 pub fn new() -> Self { Vec {} }
804 name: SmolStr, 1053 pub fn push(&mut self, t: T) {}
805 focus_range: Option<TextRange>,
806 full_range: TextRange,
807 kind: SyntaxKind,
808 docs: Option<String>,
809 ) -> NavigationTarget {
810 NavigationTarget {}
811 }
812} 1054}
813 1055
814fn test_func(mut foo: i32, bar: i32, msg: &str, _: i32, last: i32) -> i32 { 1056impl<T> IntoIterator for Vec<T> {
815 foo + bar 1057 type Item=T;
816} 1058}
817 1059
818fn main() { 1060fn main() {
819 let not_literal = 1; 1061 let mut data = Vec::new();
820 //^^^^^^^^^^^ i32 1062 //^^^^^^^^ Vec<&str>
821 let _: i32 = test_func(1, 2, "hello", 3, not_literal); 1063 data.push("foo");
822 //^ foo ^ bar ^^^^^^^ msg ^^^^^^^^^^^ last 1064 for i in
823 let t: Test = Test {}; 1065
824 t.method(123); 1066 println!("Unit expr");
825 //^^^ param 1067}
826 Test::method(&t, 3456); 1068"#,
827 //^^ self ^^^^ param
828 Test::from_syntax(
829 FileId {},
830 //^^^^^^^^^ file_id
831 "impl".into(),
832 //^^^^^^^^^^^^^ name
833 None,
834 //^^^^ focus_range
835 TextRange {},
836 //^^^^^^^^^^^^ full_range
837 SyntaxKind {},
838 //^^^^^^^^^^^^^ kind
839 None,
840 //^^^^ docs
841 );
842}"#,
843 ); 1069 );
844 } 1070 }
845 1071
846 #[test] 1072 #[test]
847 fn omitted_parameters_hints_heuristics() { 1073 fn complete_for_hint() {
848 check_with_config( 1074 check_types(
849 InlayHintsConfig { max_length: Some(8), ..TEST_CONFIG },
850 r#" 1075 r#"
851fn map(f: i32) {} 1076pub struct Vec<T> {}
852fn filter(predicate: i32) {}
853 1077
854struct TestVarContainer { 1078impl<T> Vec<T> {
855 test_var: i32, 1079 pub fn new() -> Self { Vec {} }
1080 pub fn push(&mut self, t: T) {}
856} 1081}
857 1082
858impl TestVarContainer { 1083impl<T> IntoIterator for Vec<T> {
859 fn test_var(&self) -> i32 { 1084 type Item=T;
860 self.test_var
861 }
862} 1085}
863 1086
864struct Test {} 1087fn main() {
865 1088 let mut data = Vec::new();
866impl Test { 1089 //^^^^^^^^ Vec<&str>
867 fn map(self, f: i32) -> Self { 1090 data.push("foo");
868 self 1091 for i in data {
869 } 1092 //^ &str
870 1093 let z = i;
871 fn filter(self, predicate: i32) -> Self { 1094 //^ &str
872 self
873 } 1095 }
874 1096}
875 fn field(self, value: i32) -> Self { 1097"#,
876 self 1098 );
877 } 1099 }
878 1100
879 fn no_hints_expected(&self, _: i32, test_var: i32) {} 1101 #[test]
1102 fn multi_dyn_trait_bounds() {
1103 check_types(
1104 r#"
1105pub struct Vec<T> {}
880 1106
881 fn frob(&self, frob: bool) {} 1107impl<T> Vec<T> {
1108 pub fn new() -> Self { Vec {} }
882} 1109}
883 1110
884struct Param {} 1111pub struct Box<T> {}
885
886fn different_order(param: &Param) {}
887fn different_order_mut(param: &mut Param) {}
888fn has_underscore(_param: bool) {}
889fn enum_matches_param_name(completion_kind: CompletionKind) {}
890fn param_destructuring_omitted_1((a, b): (u32, u32)) {}
891fn param_destructuring_omitted_2(TestVarContainer { test_var: _ }: TestVarContainer) {}
892
893fn twiddle(twiddle: bool) {}
894fn doo(_doo: bool) {}
895 1112
896enum CompletionKind { 1113trait Display {}
897 Keyword, 1114trait Sync {}
898}
899 1115
900fn main() { 1116fn main() {
901 let container: TestVarContainer = TestVarContainer { test_var: 42 }; 1117 let _v = Vec::<Box<&(dyn Display + Sync)>>::new();
902 let test: Test = Test {}; 1118 //^^ Vec<Box<&(dyn Display + Sync)>>
903 1119 let _v = Vec::<Box<*const (dyn Display + Sync)>>::new();
904 map(22); 1120 //^^ Vec<Box<*const (dyn Display + Sync)>>
905 filter(33); 1121 let _v = Vec::<Box<dyn Display + Sync>>::new();
906 1122 //^^ Vec<Box<dyn Display + Sync>>
907 let test_processed: Test = test.map(1).filter(2).field(3); 1123}
1124"#,
1125 );
1126 }
908 1127
909 let test_var: i32 = 55; 1128 #[test]
910 test_processed.no_hints_expected(22, test_var); 1129 fn shorten_iterator_hints() {
911 test_processed.no_hints_expected(33, container.test_var); 1130 check_types(
912 test_processed.no_hints_expected(44, container.test_var()); 1131 r#"
913 test_processed.frob(false); 1132use core::iter;
914 1133
915 twiddle(true); 1134struct MyIter;
916 doo(true);
917 1135
918 const TWIDDLE_UPPERCASE: bool = true; 1136impl Iterator for MyIter {
919 twiddle(TWIDDLE_UPPERCASE); 1137 type Item = ();
1138 fn next(&mut self) -> Option<Self::Item> {
1139 None
1140 }
1141}
920 1142
921 let mut param_begin: Param = Param {}; 1143fn main() {
922 different_order(&param_begin); 1144 let _x = MyIter;
923 different_order(&mut param_begin); 1145 //^^ MyIter
1146 let _x = iter::repeat(0);
1147 //^^ impl Iterator<Item = i32>
1148 fn generic<T: Clone>(t: T) {
1149 let _x = iter::repeat(t);
1150 //^^ impl Iterator<Item = T>
1151 let _chained = iter::repeat(t).take(10);
1152 //^^^^^^^^ impl Iterator<Item = T>
1153 }
1154}
1155"#,
1156 );
1157 }
924 1158
925 let param: bool = true; 1159 #[test]
926 has_underscore(param); 1160 fn closures() {
1161 check(
1162 r#"
1163fn main() {
1164 let mut start = 0;
1165 //^^^^^^^^^ i32
1166 (0..2).for_each(|increment| { start += increment; });
1167 //^^^^^^^^^ i32
927 1168
928 enum_matches_param_name(CompletionKind::Keyword); 1169 let multiply =
1170 //^^^^^^^^ |…| -> i32
1171 | a, b| a * b
1172 //^ i32 ^ i32
1173 ;
929 1174
930 let a: f64 = 7.0; 1175 let _: i32 = multiply(1, 2);
931 let b: f64 = 4.0; 1176 let multiply_ref = &multiply;
932 let _: f64 = a.div_euclid(b); 1177 //^^^^^^^^^^^^ &|…| -> i32
933 let _: f64 = a.abs_sub(b);
934 1178
935 let range: (u32, u32) = (3, 5); 1179 let return_42 = || 42;
936 param_destructuring_omitted_1(range); 1180 //^^^^^^^^^ || -> i32
937 param_destructuring_omitted_2(container);
938}"#, 1181}"#,
939 ); 1182 );
940 } 1183 }
941 1184
942 #[test] 1185 #[test]
943 fn unit_structs_have_no_type_hints() { 1186 fn hint_truncation() {
944 check_with_config( 1187 check_with_config(
945 InlayHintsConfig { max_length: Some(8), ..TEST_CONFIG }, 1188 InlayHintsConfig { max_length: Some(8), ..TEST_CONFIG },
946 r#" 1189 r#"
947enum Result<T, E> { Ok(T), Err(E) } 1190struct Smol<T>(T);
948use Result::*;
949 1191
950struct SyntheticSyntax; 1192struct VeryLongOuterName<T>(T);
951 1193
952fn main() { 1194fn main() {
953 match Ok(()) { 1195 let a = Smol(0u32);
954 Ok(_) => (), 1196 //^ Smol<u32>
955 Err(SyntheticSyntax) => (), 1197 let b = VeryLongOuterName(0usize);
956 } 1198 //^ VeryLongOuterName<…>
1199 let c = Smol(Smol(0u32))
1200 //^ Smol<Smol<…>>
957}"#, 1201}"#,
958 ); 1202 );
959 } 1203 }
960 1204
1205 // Chaining hint tests
1206
961 #[test] 1207 #[test]
962 fn chaining_hints_ignore_comments() { 1208 fn chaining_hints_ignore_comments() {
963 check_expect( 1209 check_expect(
@@ -1000,13 +1246,7 @@ fn main() {
1000 1246
1001 #[test] 1247 #[test]
1002 fn chaining_hints_without_newlines() { 1248 fn chaining_hints_without_newlines() {
1003 check_with_config( 1249 check_chains(
1004 InlayHintsConfig {
1005 parameter_hints: false,
1006 type_hints: false,
1007 chaining_hints: true,
1008 max_length: None,
1009 },
1010 r#" 1250 r#"
1011struct A(B); 1251struct A(B);
1012impl A { fn into_b(self) -> B { self.0 } } 1252impl A { fn into_b(self) -> B { self.0 } }
@@ -1110,140 +1350,6 @@ fn main() {
1110 } 1350 }
1111 1351
1112 #[test] 1352 #[test]
1113 fn incomplete_for_no_hint() {
1114 check(
1115 r#"
1116fn main() {
1117 let data = &[1i32, 2, 3];
1118 //^^^^ &[i32; 3]
1119 for i
1120}"#,
1121 );
1122 check(
1123 r#"
1124pub struct Vec<T> {}
1125
1126impl<T> Vec<T> {
1127 pub fn new() -> Self { Vec {} }
1128 pub fn push(&mut self, t: T) {}
1129}
1130
1131impl<T> IntoIterator for Vec<T> {
1132 type Item=T;
1133}
1134
1135fn main() {
1136 let mut data = Vec::new();
1137 //^^^^^^^^ Vec<&str>
1138 data.push("foo");
1139 for i in
1140
1141 println!("Unit expr");
1142}
1143"#,
1144 );
1145 }
1146
1147 #[test]
1148 fn complete_for_hint() {
1149 check(
1150 r#"
1151pub struct Vec<T> {}
1152
1153impl<T> Vec<T> {
1154 pub fn new() -> Self { Vec {} }
1155 pub fn push(&mut self, t: T) {}
1156}
1157
1158impl<T> IntoIterator for Vec<T> {
1159 type Item=T;
1160}
1161
1162fn main() {
1163 let mut data = Vec::new();
1164 //^^^^^^^^ Vec<&str>
1165 data.push("foo");
1166 for i in data {
1167 //^ &str
1168 let z = i;
1169 //^ &str
1170 }
1171}
1172"#,
1173 );
1174 }
1175
1176 #[test]
1177 fn multi_dyn_trait_bounds() {
1178 check_with_config(
1179 InlayHintsConfig {
1180 type_hints: true,
1181 parameter_hints: false,
1182 chaining_hints: false,
1183 max_length: None,
1184 },
1185 r#"
1186pub struct Vec<T> {}
1187
1188impl<T> Vec<T> {
1189 pub fn new() -> Self { Vec {} }
1190}
1191
1192pub struct Box<T> {}
1193
1194trait Display {}
1195trait Sync {}
1196
1197fn main() {
1198 let _v = Vec::<Box<&(dyn Display + Sync)>>::new();
1199 //^^ Vec<Box<&(dyn Display + Sync)>>
1200 let _v = Vec::<Box<*const (dyn Display + Sync)>>::new();
1201 //^^ Vec<Box<*const (dyn Display + Sync)>>
1202 let _v = Vec::<Box<dyn Display + Sync>>::new();
1203 //^^ Vec<Box<dyn Display + Sync>>
1204}
1205"#,
1206 );
1207 }
1208
1209 #[test]
1210 fn shorten_iterator_hints() {
1211 check_with_config(
1212 InlayHintsConfig {
1213 parameter_hints: false,
1214 type_hints: true,
1215 chaining_hints: false,
1216 max_length: None,
1217 },
1218 r#"
1219use core::iter;
1220
1221struct MyIter;
1222
1223impl Iterator for MyIter {
1224 type Item = ();
1225 fn next(&mut self) -> Option<Self::Item> {
1226 None
1227 }
1228}
1229
1230fn main() {
1231 let _x = MyIter;
1232 //^^ MyIter
1233 let _x = iter::repeat(0);
1234 //^^ impl Iterator<Item = i32>
1235 fn generic<T: Clone>(t: T) {
1236 let _x = iter::repeat(t);
1237 //^^ impl Iterator<Item = T>
1238 let _chained = iter::repeat(t).take(10);
1239 //^^^^^^^^ impl Iterator<Item = T>
1240 }
1241}
1242"#,
1243 );
1244 }
1245
1246 #[test]
1247 fn shorten_iterator_chaining_hints() { 1353 fn shorten_iterator_chaining_hints() {
1248 check_expect( 1354 check_expect(
1249 InlayHintsConfig { 1355 InlayHintsConfig {
@@ -1298,158 +1404,4 @@ fn main() {
1298 "#]], 1404 "#]],
1299 ); 1405 );
1300 } 1406 }
1301
1302 #[test]
1303 fn shorten_iterators_in_associated_params() {
1304 check_with_config(
1305 InlayHintsConfig {
1306 parameter_hints: false,
1307 type_hints: true,
1308 chaining_hints: false,
1309 max_length: None,
1310 },
1311 r#"
1312use core::iter;
1313
1314pub struct SomeIter<T> {}
1315
1316impl<T> SomeIter<T> {
1317 pub fn new() -> Self { SomeIter {} }
1318 pub fn push(&mut self, t: T) {}
1319}
1320
1321impl<T> Iterator for SomeIter<T> {
1322 type Item = T;
1323 fn next(&mut self) -> Option<Self::Item> {
1324 None
1325 }
1326}
1327
1328fn main() {
1329 let mut some_iter = SomeIter::new();
1330 //^^^^^^^^^^^^^ SomeIter<Take<Repeat<i32>>>
1331 some_iter.push(iter::repeat(2).take(2));
1332 let iter_of_iters = some_iter.take(2);
1333 //^^^^^^^^^^^^^ impl Iterator<Item = impl Iterator<Item = i32>>
1334}
1335"#,
1336 );
1337 }
1338
1339 #[test]
1340 fn hide_param_hints_for_clones() {
1341 check_with_config(
1342 InlayHintsConfig {
1343 parameter_hints: true,
1344 type_hints: false,
1345 chaining_hints: false,
1346 max_length: None,
1347 },
1348 r#"
1349fn foo(bar: i32, baz: String, qux: f32) {}
1350
1351fn main() {
1352 let bar = 3;
1353 let baz = &"baz";
1354 let fez = 1.0;
1355 foo(bar.clone(), baz.clone(), fez.clone());
1356 //^^^^^^^^^^^ qux
1357}
1358"#,
1359 );
1360 }
1361
1362 #[test]
1363 fn infer_call_method_return_associated_types_with_generic() {
1364 check(
1365 r#"
1366 pub trait Default {
1367 fn default() -> Self;
1368 }
1369 pub trait Foo {
1370 type Bar: Default;
1371 }
1372
1373 pub fn quux<T: Foo>() -> T::Bar {
1374 let y = Default::default();
1375 //^ <T as Foo>::Bar
1376
1377 y
1378 }
1379 "#,
1380 );
1381 }
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}
1393
1394fn main() {
1395 Foo::foo(Foo);
1396 //^^^ self
1397 Foo::bar(&Foo);
1398 //^^^^ self
1399}
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}
1437"#,
1438 )
1439 }
1440
1441 #[test]
1442 fn param_name_hints_show_for_literals() {
1443 check(
1444 r#"pub fn test(a: i32, b: i32) -> [i32; 2] { [a, b] }
1445fn main() {
1446 test(
1447 0x0fab272b,
1448 //^^^^^^^^^^ a
1449 0x0fab272b
1450 //^^^^^^^^^^ b
1451 );
1452}"#,
1453 )
1454 }
1455} 1407}