diff options
Diffstat (limited to 'crates/ide/src')
-rw-r--r-- | crates/ide/src/hover.rs | 29 | ||||
-rw-r--r-- | crates/ide/src/inlay_hints.rs | 1032 |
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)] |
29 | pub struct HoverConfig { | 29 | pub 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 { | |||
38 | impl HoverConfig { | 39 | impl 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 { | |||
62 | pub enum HoverAction { | 64 | pub 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 | ||
221 | fn 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 | |||
214 | fn runnable_action( | 233 | fn 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 | ||
344 | fn is_argument_similar_to_param_name(argument: &ast::Expr, param_name: &str) -> bool { | 344 | fn 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#" |
483 | fn foo(a: i32, b: i32) -> i32 { a + b } | 518 | fn foo(a: i32, b: i32) -> i32 { a + b } |
484 | fn main() { | 519 | fn 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#" | ||
531 | fn foo(a: i32, b: i32) -> i32 { a + b } | ||
532 | fn 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#" |
505 | fn max(x: i32, y: i32) -> i32 { x + y } | 547 | fn max(x: i32, y: i32) -> i32 { x + y } |
506 | fn main() { | 548 | fn 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#" |
527 | fn param_with_underscore(with_underscore: i32) -> i32 { with_underscore } | 563 | fn param_with_underscore(with_underscore: i32) -> i32 { with_underscore } |
528 | fn main() { | 564 | fn main() { |
@@ -531,17 +567,20 @@ fn main() { | |||
531 | ); | 567 | ); |
532 | }"#, | 568 | }"#, |
533 | ); | 569 | ); |
570 | check_params( | ||
571 | r#" | ||
572 | fn param_with_underscore(underscore: i32) -> i32 { underscore } | ||
573 | fn 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#" |
546 | fn foo(foo: i32) -> i32 { foo } | 585 | fn foo(foo: i32) -> i32 { foo } |
547 | fn main() { | 586 | fn 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#" |
565 | fn foo(bar: i32, baz: i32) -> i32 { bar + baz } | 598 | fn foo(foo: i32, bar: i32) -> i32 { bar + baz } |
566 | fn main() { | 599 | fn 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#" |
587 | fn foo(a: i32, b: i32) -> i32 { a + b } | 614 | fn foo(bar: i32, baz: f32) {} |
615 | |||
588 | fn main() { | 616 | fn 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#" | ||
633 | struct Foo; | ||
634 | |||
635 | impl Foo { | ||
636 | fn foo(self: Self) {} | ||
637 | fn bar(self: &Self) {} | ||
638 | } | ||
639 | |||
640 | fn 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] } | ||
654 | fn 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#" | ||
669 | enum Option<T> { None, Some(T) } | ||
670 | use Option::*; | ||
671 | |||
672 | struct FileId {} | ||
673 | struct SmolStr {} | ||
674 | |||
675 | struct TextRange {} | ||
676 | struct SyntaxKind {} | ||
677 | struct NavigationTarget {} | ||
678 | |||
679 | struct Test {} | ||
680 | |||
681 | impl 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 | |||
696 | fn test_func(mut foo: i32, bar: i32, msg: &str, _: i32, last: i32) -> i32 { | ||
697 | foo + bar | ||
698 | } | ||
699 | |||
700 | fn 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#" | ||
731 | fn check(ra_fixture_thing: &str) {} | ||
732 | |||
733 | fn map(f: i32) {} | ||
734 | fn filter(predicate: i32) {} | ||
735 | |||
736 | fn strip_suffix(suffix: &str) {} | ||
737 | fn stripsuffix(suffix: &str) {} | ||
738 | fn same(same: u32) {} | ||
739 | fn same2(_same2: u32) {} | ||
740 | |||
741 | fn enum_matches_param_name(completion_kind: CompletionKind) {} | ||
742 | |||
743 | fn foo(param: u32) {} | ||
744 | fn bar(param_eter: u32) {} | ||
745 | |||
746 | enum CompletionKind { | ||
747 | Keyword, | ||
748 | } | ||
749 | |||
750 | fn non_ident_pat((a, b): (u32, u32)) {} | ||
751 | |||
752 | fn 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#" |
604 | fn foo(a: i32, b: i32) -> i32 { a + b } | 797 | fn foo(a: i32, b: i32) -> i32 { a + b } |
605 | fn main() { | 798 | fn 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#" | ||
826 | use core::iter; | ||
827 | |||
828 | pub struct SomeIter<T> {} | ||
829 | |||
830 | impl<T> SomeIter<T> { | ||
831 | pub fn new() -> Self { SomeIter {} } | ||
832 | pub fn push(&mut self, t: T) {} | ||
833 | } | ||
834 | |||
835 | impl<T> Iterator for SomeIter<T> { | ||
836 | type Item = T; | ||
837 | fn next(&mut self) -> Option<Self::Item> { | ||
838 | None | ||
839 | } | ||
840 | } | ||
841 | |||
842 | fn 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#" | ||
878 | trait Sized {} | ||
879 | |||
880 | fn foo() -> impl Fn() { loop {} } | ||
881 | fn foo1() -> impl Fn(f64) { loop {} } | ||
882 | fn foo2() -> impl Fn(f64, f64) { loop {} } | ||
883 | fn foo3() -> impl Fn(f64, f64) -> u32 { loop {} } | ||
884 | fn foo4() -> &'static dyn Fn(f64, f64) -> u32 { loop {} } | ||
885 | fn foo5() -> &'static dyn Fn(&'static dyn Fn(f64, f64) -> u32, f64) -> u32 { loop {} } | ||
886 | fn foo6() -> impl Fn(f64, f64) -> u32 + Sized { loop {} } | ||
887 | fn foo7() -> *const (impl Fn(f64, f64) -> u32 + Sized) { loop {} } | ||
888 | |||
889 | fn 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#" | ||
915 | enum Result<T, E> { Ok(T), Err(E) } | ||
916 | use Result::*; | ||
917 | |||
918 | struct SyntheticSyntax; | ||
919 | |||
920 | fn 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)] |
634 | enum Option<T> { None, Some(T) } | 934 | enum 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#" | ||
669 | fn 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#" |
695 | enum Option<T> { None, Some(T) } | 969 | enum Option<T> { None, Some(T) } |
696 | use Option::*; | 970 | use 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#" |
727 | enum Option<T> { None, Some(T) } | 1001 | enum Option<T> { None, Some(T) } |
728 | use Option::*; | 1002 | use 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#" |
745 | enum Option<T> { None, Some(T) } | 1019 | enum Option<T> { None, Some(T) } |
746 | use Option::*; | 1020 | use 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#" |
768 | struct Smol<T>(T); | ||
769 | |||
770 | struct VeryLongOuterName<T>(T); | ||
771 | |||
772 | fn main() { | 1041 | fn 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#" |
787 | enum Option<T> { None, Some(T) } | 1049 | pub struct Vec<T> {} |
788 | use Option::*; | ||
789 | |||
790 | struct FileId {} | ||
791 | struct SmolStr {} | ||
792 | |||
793 | struct TextRange {} | ||
794 | struct SyntaxKind {} | ||
795 | struct NavigationTarget {} | ||
796 | |||
797 | struct Test {} | ||
798 | |||
799 | impl Test { | ||
800 | fn method(&self, mut param: i32) -> i32 { param * 2 } | ||
801 | 1050 | ||
802 | fn from_syntax( | 1051 | impl<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 | ||
814 | fn test_func(mut foo: i32, bar: i32, msg: &str, _: i32, last: i32) -> i32 { | 1056 | impl<T> IntoIterator for Vec<T> { |
815 | foo + bar | 1057 | type Item=T; |
816 | } | 1058 | } |
817 | 1059 | ||
818 | fn main() { | 1060 | fn 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#" |
851 | fn map(f: i32) {} | 1076 | pub struct Vec<T> {} |
852 | fn filter(predicate: i32) {} | ||
853 | 1077 | ||
854 | struct TestVarContainer { | 1078 | impl<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 | ||
858 | impl TestVarContainer { | 1083 | impl<T> IntoIterator for Vec<T> { |
859 | fn test_var(&self) -> i32 { | 1084 | type Item=T; |
860 | self.test_var | ||
861 | } | ||
862 | } | 1085 | } |
863 | 1086 | ||
864 | struct Test {} | 1087 | fn main() { |
865 | 1088 | let mut data = Vec::new(); | |
866 | impl 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#" | ||
1105 | pub struct Vec<T> {} | ||
880 | 1106 | ||
881 | fn frob(&self, frob: bool) {} | 1107 | impl<T> Vec<T> { |
1108 | pub fn new() -> Self { Vec {} } | ||
882 | } | 1109 | } |
883 | 1110 | ||
884 | struct Param {} | 1111 | pub struct Box<T> {} |
885 | |||
886 | fn different_order(param: &Param) {} | ||
887 | fn different_order_mut(param: &mut Param) {} | ||
888 | fn has_underscore(_param: bool) {} | ||
889 | fn enum_matches_param_name(completion_kind: CompletionKind) {} | ||
890 | fn param_destructuring_omitted_1((a, b): (u32, u32)) {} | ||
891 | fn param_destructuring_omitted_2(TestVarContainer { test_var: _ }: TestVarContainer) {} | ||
892 | |||
893 | fn twiddle(twiddle: bool) {} | ||
894 | fn doo(_doo: bool) {} | ||
895 | 1112 | ||
896 | enum CompletionKind { | 1113 | trait Display {} |
897 | Keyword, | 1114 | trait Sync {} |
898 | } | ||
899 | 1115 | ||
900 | fn main() { | 1116 | fn 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); | 1132 | use core::iter; |
914 | 1133 | ||
915 | twiddle(true); | 1134 | struct MyIter; |
916 | doo(true); | ||
917 | 1135 | ||
918 | const TWIDDLE_UPPERCASE: bool = true; | 1136 | impl 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 {}; | 1143 | fn main() { |
922 | different_order(¶m_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#" | ||
1163 | fn 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#" |
947 | enum Result<T, E> { Ok(T), Err(E) } | 1190 | struct Smol<T>(T); |
948 | use Result::*; | ||
949 | 1191 | ||
950 | struct SyntheticSyntax; | 1192 | struct VeryLongOuterName<T>(T); |
951 | 1193 | ||
952 | fn main() { | 1194 | fn 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#" |
1011 | struct A(B); | 1251 | struct A(B); |
1012 | impl A { fn into_b(self) -> B { self.0 } } | 1252 | impl 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#" | ||
1116 | fn main() { | ||
1117 | let data = &[1i32, 2, 3]; | ||
1118 | //^^^^ &[i32; 3] | ||
1119 | for i | ||
1120 | }"#, | ||
1121 | ); | ||
1122 | check( | ||
1123 | r#" | ||
1124 | pub struct Vec<T> {} | ||
1125 | |||
1126 | impl<T> Vec<T> { | ||
1127 | pub fn new() -> Self { Vec {} } | ||
1128 | pub fn push(&mut self, t: T) {} | ||
1129 | } | ||
1130 | |||
1131 | impl<T> IntoIterator for Vec<T> { | ||
1132 | type Item=T; | ||
1133 | } | ||
1134 | |||
1135 | fn 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#" | ||
1151 | pub struct Vec<T> {} | ||
1152 | |||
1153 | impl<T> Vec<T> { | ||
1154 | pub fn new() -> Self { Vec {} } | ||
1155 | pub fn push(&mut self, t: T) {} | ||
1156 | } | ||
1157 | |||
1158 | impl<T> IntoIterator for Vec<T> { | ||
1159 | type Item=T; | ||
1160 | } | ||
1161 | |||
1162 | fn 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#" | ||
1186 | pub struct Vec<T> {} | ||
1187 | |||
1188 | impl<T> Vec<T> { | ||
1189 | pub fn new() -> Self { Vec {} } | ||
1190 | } | ||
1191 | |||
1192 | pub struct Box<T> {} | ||
1193 | |||
1194 | trait Display {} | ||
1195 | trait Sync {} | ||
1196 | |||
1197 | fn 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#" | ||
1219 | use core::iter; | ||
1220 | |||
1221 | struct MyIter; | ||
1222 | |||
1223 | impl Iterator for MyIter { | ||
1224 | type Item = (); | ||
1225 | fn next(&mut self) -> Option<Self::Item> { | ||
1226 | None | ||
1227 | } | ||
1228 | } | ||
1229 | |||
1230 | fn 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#" | ||
1312 | use core::iter; | ||
1313 | |||
1314 | pub struct SomeIter<T> {} | ||
1315 | |||
1316 | impl<T> SomeIter<T> { | ||
1317 | pub fn new() -> Self { SomeIter {} } | ||
1318 | pub fn push(&mut self, t: T) {} | ||
1319 | } | ||
1320 | |||
1321 | impl<T> Iterator for SomeIter<T> { | ||
1322 | type Item = T; | ||
1323 | fn next(&mut self) -> Option<Self::Item> { | ||
1324 | None | ||
1325 | } | ||
1326 | } | ||
1327 | |||
1328 | fn 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#" | ||
1349 | fn foo(bar: i32, baz: String, qux: f32) {} | ||
1350 | |||
1351 | fn 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#" | ||
1387 | struct Foo; | ||
1388 | |||
1389 | impl Foo { | ||
1390 | fn foo(self: Self) {} | ||
1391 | fn bar(self: &Self) {} | ||
1392 | } | ||
1393 | |||
1394 | fn 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#" | ||
1408 | trait Sized {} | ||
1409 | |||
1410 | fn foo() -> impl Fn() { loop {} } | ||
1411 | fn foo1() -> impl Fn(f64) { loop {} } | ||
1412 | fn foo2() -> impl Fn(f64, f64) { loop {} } | ||
1413 | fn foo3() -> impl Fn(f64, f64) -> u32 { loop {} } | ||
1414 | fn foo4() -> &'static dyn Fn(f64, f64) -> u32 { loop {} } | ||
1415 | fn foo5() -> &'static dyn Fn(&'static dyn Fn(f64, f64) -> u32, f64) -> u32 { loop {} } | ||
1416 | fn foo6() -> impl Fn(f64, f64) -> u32 + Sized { loop {} } | ||
1417 | fn foo7() -> *const (impl Fn(f64, f64) -> u32 + Sized) { loop {} } | ||
1418 | |||
1419 | fn 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] } | ||
1445 | fn main() { | ||
1446 | test( | ||
1447 | 0x0fab272b, | ||
1448 | //^^^^^^^^^^ a | ||
1449 | 0x0fab272b | ||
1450 | //^^^^^^^^^^ b | ||
1451 | ); | ||
1452 | }"#, | ||
1453 | ) | ||
1454 | } | ||
1455 | } | 1407 | } |