diff options
-rw-r--r-- | crates/ra_hir/src/code_model.rs | 85 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/lib.rs | 53 | ||||
-rw-r--r-- | crates/ra_ide/src/hover.rs | 255 |
3 files changed, 328 insertions, 65 deletions
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index d0a8199a6..ffd5278ec 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs | |||
@@ -26,8 +26,8 @@ use hir_ty::{ | |||
26 | autoderef, | 26 | autoderef, |
27 | display::{HirDisplayError, HirFormatter}, | 27 | display::{HirDisplayError, HirFormatter}, |
28 | expr::ExprValidator, | 28 | expr::ExprValidator, |
29 | method_resolution, ApplicationTy, Canonical, InEnvironment, Substs, TraitEnvironment, TraitRef, | 29 | method_resolution, ApplicationTy, Canonical, GenericPredicate, InEnvironment, Substs, |
30 | Ty, TyDefId, TypeCtor, | 30 | TraitEnvironment, Ty, TyDefId, TypeCtor, |
31 | }; | 31 | }; |
32 | use ra_db::{CrateId, CrateName, Edition, FileId}; | 32 | use ra_db::{CrateId, CrateName, Edition, FileId}; |
33 | use ra_prof::profile; | 33 | use ra_prof::profile; |
@@ -1379,8 +1379,17 @@ impl Type { | |||
1379 | self.ty.value.dyn_trait().map(Into::into) | 1379 | self.ty.value.dyn_trait().map(Into::into) |
1380 | } | 1380 | } |
1381 | 1381 | ||
1382 | pub fn as_impl_trait(&self, db: &dyn HirDatabase) -> Option<Trait> { | 1382 | pub fn as_impl_traits(&self, db: &dyn HirDatabase) -> Option<Vec<Trait>> { |
1383 | self.ty.value.impl_trait_ref(db).map(|it| it.trait_.into()) | 1383 | self.ty.value.impl_trait_bounds(db).map(|it| { |
1384 | it.into_iter() | ||
1385 | .filter_map(|pred| match pred { | ||
1386 | hir_ty::GenericPredicate::Implemented(trait_ref) => { | ||
1387 | Some(Trait::from(trait_ref.trait_)) | ||
1388 | } | ||
1389 | _ => None, | ||
1390 | }) | ||
1391 | .collect() | ||
1392 | }) | ||
1384 | } | 1393 | } |
1385 | 1394 | ||
1386 | pub fn as_associated_type_parent_trait(&self, db: &dyn HirDatabase) -> Option<Trait> { | 1395 | pub fn as_associated_type_parent_trait(&self, db: &dyn HirDatabase) -> Option<Trait> { |
@@ -1410,71 +1419,77 @@ impl Type { | |||
1410 | } | 1419 | } |
1411 | 1420 | ||
1412 | pub fn walk(&self, db: &dyn HirDatabase, mut cb: impl FnMut(Type)) { | 1421 | pub fn walk(&self, db: &dyn HirDatabase, mut cb: impl FnMut(Type)) { |
1413 | // TypeWalk::walk does not preserve items order! | 1422 | // TypeWalk::walk for a Ty at first visits parameters and only after that the Ty itself. |
1414 | fn walk_substs(db: &dyn HirDatabase, substs: &Substs, cb: &mut impl FnMut(Type)) { | 1423 | // We need a different order here. |
1424 | |||
1425 | fn walk_substs( | ||
1426 | db: &dyn HirDatabase, | ||
1427 | type_: &Type, | ||
1428 | substs: &Substs, | ||
1429 | cb: &mut impl FnMut(Type), | ||
1430 | ) { | ||
1415 | for ty in substs.iter() { | 1431 | for ty in substs.iter() { |
1416 | walk_ty(db, ty, cb); | 1432 | walk_type(db, &type_.derived(ty.clone()), cb); |
1417 | } | 1433 | } |
1418 | } | 1434 | } |
1419 | 1435 | ||
1420 | fn walk_trait( | 1436 | fn walk_bounds( |
1421 | db: &dyn HirDatabase, | 1437 | db: &dyn HirDatabase, |
1422 | ty: Ty, | 1438 | type_: &Type, |
1423 | trait_ref: &TraitRef, | 1439 | bounds: &[GenericPredicate], |
1424 | cb: &mut impl FnMut(Type), | 1440 | cb: &mut impl FnMut(Type), |
1425 | ) { | 1441 | ) { |
1426 | let def_db: &dyn DefDatabase = db.upcast(); | 1442 | for pred in bounds { |
1427 | let resolver = trait_ref.trait_.resolver(def_db); | 1443 | match pred { |
1428 | let krate = trait_ref.trait_.lookup(def_db).container.module(def_db).krate; | 1444 | GenericPredicate::Implemented(trait_ref) => { |
1429 | cb(Type::new_with_resolver_inner(db, krate, &resolver, ty)); | 1445 | cb(type_.clone()); |
1430 | walk_substs(db, &trait_ref.substs, cb); | 1446 | walk_substs(db, type_, &trait_ref.substs, cb); |
1447 | } | ||
1448 | _ => (), | ||
1449 | } | ||
1450 | } | ||
1431 | } | 1451 | } |
1432 | 1452 | ||
1433 | fn walk_ty(db: &dyn HirDatabase, ty: &Ty, cb: &mut impl FnMut(Type)) { | 1453 | fn walk_type(db: &dyn HirDatabase, type_: &Type, cb: &mut impl FnMut(Type)) { |
1434 | let def_db: &dyn DefDatabase = db.upcast(); | 1454 | let ty = type_.ty.value.strip_references(); |
1435 | let ty = ty.strip_references(); | ||
1436 | match ty { | 1455 | match ty { |
1437 | Ty::Apply(ApplicationTy { ctor, parameters }) => { | 1456 | Ty::Apply(ApplicationTy { ctor, parameters }) => { |
1438 | match ctor { | 1457 | match ctor { |
1439 | TypeCtor::Adt(adt) => { | 1458 | TypeCtor::Adt(_) => { |
1440 | cb(Type::from_def(db, adt.module(def_db).krate, *adt)); | 1459 | cb(type_.derived(ty.clone())); |
1441 | } | 1460 | } |
1442 | TypeCtor::AssociatedType(_) => { | 1461 | TypeCtor::AssociatedType(_) => { |
1443 | if let Some(trait_id) = ty.associated_type_parent_trait(db) { | 1462 | if let Some(_) = ty.associated_type_parent_trait(db) { |
1444 | let resolver = trait_id.resolver(def_db); | 1463 | cb(type_.derived(ty.clone())); |
1445 | let krate = trait_id.lookup(def_db).container.module(def_db).krate; | ||
1446 | cb(Type::new_with_resolver_inner(db, krate, &resolver, ty.clone())); | ||
1447 | } | 1464 | } |
1448 | } | 1465 | } |
1449 | _ => (), | 1466 | _ => (), |
1450 | } | 1467 | } |
1451 | 1468 | ||
1452 | // adt params, tuples, etc... | 1469 | // adt params, tuples, etc... |
1453 | walk_substs(db, parameters, cb); | 1470 | walk_substs(db, type_, parameters, cb); |
1454 | } | 1471 | } |
1455 | Ty::Opaque(opaque_ty) => { | 1472 | Ty::Opaque(opaque_ty) => { |
1456 | if let Some(trait_ref) = ty.impl_trait_ref(db) { | 1473 | if let Some(bounds) = ty.impl_trait_bounds(db) { |
1457 | walk_trait(db, ty.clone(), &trait_ref, cb); | 1474 | walk_bounds(db, &type_.derived(ty.clone()), &bounds, cb); |
1458 | } | 1475 | } |
1459 | 1476 | ||
1460 | walk_substs(db, &opaque_ty.parameters, cb); | 1477 | walk_substs(db, type_, &opaque_ty.parameters, cb); |
1461 | } | 1478 | } |
1462 | Ty::Placeholder(_) => { | 1479 | Ty::Placeholder(_) => { |
1463 | if let Some(trait_ref) = ty.impl_trait_ref(db) { | 1480 | if let Some(bounds) = ty.impl_trait_bounds(db) { |
1464 | walk_trait(db, ty.clone(), &trait_ref, cb); | 1481 | walk_bounds(db, &type_.derived(ty.clone()), &bounds, cb); |
1465 | } | 1482 | } |
1466 | } | 1483 | } |
1467 | Ty::Dyn(_) => { | 1484 | Ty::Dyn(bounds) => { |
1468 | if let Some(trait_ref) = ty.dyn_trait_ref() { | 1485 | walk_bounds(db, &type_.derived(ty.clone()), bounds.as_ref(), cb); |
1469 | walk_trait(db, ty.clone(), trait_ref, cb); | ||
1470 | } | ||
1471 | } | 1486 | } |
1472 | 1487 | ||
1473 | _ => (), | 1488 | _ => (), |
1474 | } | 1489 | } |
1475 | } | 1490 | } |
1476 | 1491 | ||
1477 | walk_ty(db, &self.ty.value, &mut cb); | 1492 | walk_type(db, self, &mut cb); |
1478 | } | 1493 | } |
1479 | } | 1494 | } |
1480 | 1495 | ||
diff --git a/crates/ra_hir_ty/src/lib.rs b/crates/ra_hir_ty/src/lib.rs index 25ab9d872..f22232324 100644 --- a/crates/ra_hir_ty/src/lib.rs +++ b/crates/ra_hir_ty/src/lib.rs | |||
@@ -73,6 +73,7 @@ pub use lower::{ | |||
73 | pub use traits::{InEnvironment, Obligation, ProjectionPredicate, TraitEnvironment}; | 73 | pub use traits::{InEnvironment, Obligation, ProjectionPredicate, TraitEnvironment}; |
74 | 74 | ||
75 | pub use chalk_ir::{BoundVar, DebruijnIndex}; | 75 | pub use chalk_ir::{BoundVar, DebruijnIndex}; |
76 | use itertools::Itertools; | ||
76 | 77 | ||
77 | /// A type constructor or type name: this might be something like the primitive | 78 | /// A type constructor or type name: this might be something like the primitive |
78 | /// type `bool`, a struct like `Vec`, or things like function pointers or | 79 | /// type `bool`, a struct like `Vec`, or things like function pointers or |
@@ -815,6 +816,11 @@ impl Ty { | |||
815 | } | 816 | } |
816 | } | 817 | } |
817 | 818 | ||
819 | /// If this is a `dyn Trait`, returns that trait. | ||
820 | pub fn dyn_trait(&self) -> Option<TraitId> { | ||
821 | self.dyn_trait_ref().map(|it| it.trait_) | ||
822 | } | ||
823 | |||
818 | fn builtin_deref(&self) -> Option<Ty> { | 824 | fn builtin_deref(&self) -> Option<Ty> { |
819 | match self { | 825 | match self { |
820 | Ty::Apply(a_ty) => match a_ty.ctor { | 826 | Ty::Apply(a_ty) => match a_ty.ctor { |
@@ -867,18 +873,7 @@ impl Ty { | |||
867 | } | 873 | } |
868 | } | 874 | } |
869 | 875 | ||
870 | /// If this is a `dyn Trait`, returns that trait. | 876 | pub fn impl_trait_bounds(&self, db: &dyn HirDatabase) -> Option<Vec<GenericPredicate>> { |
871 | pub fn dyn_trait(&self) -> Option<TraitId> { | ||
872 | match self { | ||
873 | Ty::Dyn(predicates) => predicates.iter().find_map(|pred| match pred { | ||
874 | GenericPredicate::Implemented(tr) => Some(tr.trait_), | ||
875 | _ => None, | ||
876 | }), | ||
877 | _ => None, | ||
878 | } | ||
879 | } | ||
880 | |||
881 | pub fn impl_trait_ref(&self, db: &dyn HirDatabase) -> Option<TraitRef> { | ||
882 | match self { | 877 | match self { |
883 | Ty::Opaque(opaque_ty) => { | 878 | Ty::Opaque(opaque_ty) => { |
884 | let predicates = match opaque_ty.opaque_ty_id { | 879 | let predicates = match opaque_ty.opaque_ty_id { |
@@ -892,25 +887,21 @@ impl Ty { | |||
892 | } | 887 | } |
893 | }; | 888 | }; |
894 | 889 | ||
895 | predicates.and_then(|it| { | 890 | predicates.map(|it| it.value) |
896 | it.value.iter().find_map(|pred| match pred { | ||
897 | GenericPredicate::Implemented(tr) => Some(tr.clone()), | ||
898 | _ => None, | ||
899 | }) | ||
900 | }) | ||
901 | } | 891 | } |
902 | Ty::Placeholder(id) => { | 892 | Ty::Placeholder(id) => { |
903 | let generic_params = db.generic_params(id.parent); | 893 | let generic_params = db.generic_params(id.parent); |
904 | let param_data = &generic_params.types[id.local_id]; | 894 | let param_data = &generic_params.types[id.local_id]; |
905 | match param_data.provenance { | 895 | match param_data.provenance { |
906 | hir_def::generics::TypeParamProvenance::ArgumentImplTrait => db | 896 | hir_def::generics::TypeParamProvenance::ArgumentImplTrait => { |
907 | .generic_predicates_for_param(*id) | 897 | let predicates = db |
908 | .into_iter() | 898 | .generic_predicates_for_param(*id) |
909 | .map(|pred| pred.value.clone()) | 899 | .into_iter() |
910 | .find_map(|pred| match pred { | 900 | .map(|pred| pred.value.clone()) |
911 | GenericPredicate::Implemented(tr) => Some(tr.clone()), | 901 | .collect_vec(); |
912 | _ => None, | 902 | |
913 | }), | 903 | Some(predicates) |
904 | } | ||
914 | _ => None, | 905 | _ => None, |
915 | } | 906 | } |
916 | } | 907 | } |
@@ -926,6 +917,12 @@ impl Ty { | |||
926 | _ => None, | 917 | _ => None, |
927 | } | 918 | } |
928 | } | 919 | } |
920 | Ty::Projection(projection_ty) => { | ||
921 | match projection_ty.associated_ty.lookup(db.upcast()).container { | ||
922 | AssocContainerId::TraitId(trait_id) => Some(trait_id), | ||
923 | _ => None, | ||
924 | } | ||
925 | } | ||
929 | _ => None, | 926 | _ => None, |
930 | } | 927 | } |
931 | } | 928 | } |
@@ -1104,10 +1101,10 @@ pub enum OpaqueTyId { | |||
1104 | 1101 | ||
1105 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] | 1102 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] |
1106 | pub struct ReturnTypeImplTraits { | 1103 | pub struct ReturnTypeImplTraits { |
1107 | pub impl_traits: Vec<ReturnTypeImplTrait>, | 1104 | pub(crate) impl_traits: Vec<ReturnTypeImplTrait>, |
1108 | } | 1105 | } |
1109 | 1106 | ||
1110 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] | 1107 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] |
1111 | pub struct ReturnTypeImplTrait { | 1108 | pub(crate) struct ReturnTypeImplTrait { |
1112 | pub bounds: Binders<Vec<GenericPredicate>>, | 1109 | pub bounds: Binders<Vec<GenericPredicate>>, |
1113 | } | 1110 | } |
diff --git a/crates/ra_ide/src/hover.rs b/crates/ra_ide/src/hover.rs index c2909e200..d870e4cbc 100644 --- a/crates/ra_ide/src/hover.rs +++ b/crates/ra_ide/src/hover.rs | |||
@@ -248,8 +248,8 @@ fn goto_type_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> { | |||
248 | push_new_def(adt.into()); | 248 | push_new_def(adt.into()); |
249 | } else if let Some(trait_) = t.as_dyn_trait() { | 249 | } else if let Some(trait_) = t.as_dyn_trait() { |
250 | push_new_def(trait_.into()); | 250 | push_new_def(trait_.into()); |
251 | } else if let Some(trait_) = t.as_impl_trait(db) { | 251 | } else if let Some(traits) = t.as_impl_traits(db) { |
252 | push_new_def(trait_.into()); | 252 | traits.into_iter().for_each(|it| push_new_def(it.into())); |
253 | } else if let Some(trait_) = t.as_associated_type_parent_trait(db) { | 253 | } else if let Some(trait_) = t.as_associated_type_parent_trait(db) { |
254 | push_new_def(trait_.into()); | 254 | push_new_def(trait_.into()); |
255 | } | 255 | } |
@@ -1735,6 +1735,176 @@ fn func(foo: i32) { if true { <|>foo; }; } | |||
1735 | } | 1735 | } |
1736 | 1736 | ||
1737 | #[test] | 1737 | #[test] |
1738 | fn test_hover_return_impl_traits_has_goto_type_action() { | ||
1739 | let (_, actions) = check_hover_result( | ||
1740 | " | ||
1741 | //- /main.rs | ||
1742 | trait Foo {} | ||
1743 | trait Bar {} | ||
1744 | |||
1745 | fn foo() -> impl Foo + Bar {} | ||
1746 | |||
1747 | fn main() { | ||
1748 | let s<|>t = foo(); | ||
1749 | } | ||
1750 | ", | ||
1751 | &["impl Foo + Bar"], | ||
1752 | ); | ||
1753 | assert_debug_snapshot!(actions, | ||
1754 | @r###" | ||
1755 | [ | ||
1756 | GoToType( | ||
1757 | [ | ||
1758 | HoverGotoTypeData { | ||
1759 | mod_path: "Foo", | ||
1760 | nav: NavigationTarget { | ||
1761 | file_id: FileId( | ||
1762 | 1, | ||
1763 | ), | ||
1764 | full_range: 0..12, | ||
1765 | name: "Foo", | ||
1766 | kind: TRAIT_DEF, | ||
1767 | focus_range: Some( | ||
1768 | 6..9, | ||
1769 | ), | ||
1770 | container_name: None, | ||
1771 | description: Some( | ||
1772 | "trait Foo", | ||
1773 | ), | ||
1774 | docs: None, | ||
1775 | }, | ||
1776 | }, | ||
1777 | HoverGotoTypeData { | ||
1778 | mod_path: "Bar", | ||
1779 | nav: NavigationTarget { | ||
1780 | file_id: FileId( | ||
1781 | 1, | ||
1782 | ), | ||
1783 | full_range: 13..25, | ||
1784 | name: "Bar", | ||
1785 | kind: TRAIT_DEF, | ||
1786 | focus_range: Some( | ||
1787 | 19..22, | ||
1788 | ), | ||
1789 | container_name: None, | ||
1790 | description: Some( | ||
1791 | "trait Bar", | ||
1792 | ), | ||
1793 | docs: None, | ||
1794 | }, | ||
1795 | }, | ||
1796 | ], | ||
1797 | ), | ||
1798 | ] | ||
1799 | "###); | ||
1800 | } | ||
1801 | |||
1802 | #[test] | ||
1803 | fn test_hover_generic_return_impl_traits_has_goto_type_action() { | ||
1804 | let (_, actions) = check_hover_result( | ||
1805 | " | ||
1806 | //- /main.rs | ||
1807 | trait Foo<T> {} | ||
1808 | trait Bar<T> {} | ||
1809 | struct S1 {} | ||
1810 | struct S2 {} | ||
1811 | |||
1812 | fn foo() -> impl Foo<S1> + Bar<S2> {} | ||
1813 | |||
1814 | fn main() { | ||
1815 | let s<|>t = foo(); | ||
1816 | } | ||
1817 | ", | ||
1818 | &["impl Foo<S1> + Bar<S2>"], | ||
1819 | ); | ||
1820 | assert_debug_snapshot!(actions, | ||
1821 | @r###" | ||
1822 | [ | ||
1823 | GoToType( | ||
1824 | [ | ||
1825 | HoverGotoTypeData { | ||
1826 | mod_path: "Foo", | ||
1827 | nav: NavigationTarget { | ||
1828 | file_id: FileId( | ||
1829 | 1, | ||
1830 | ), | ||
1831 | full_range: 0..15, | ||
1832 | name: "Foo", | ||
1833 | kind: TRAIT_DEF, | ||
1834 | focus_range: Some( | ||
1835 | 6..9, | ||
1836 | ), | ||
1837 | container_name: None, | ||
1838 | description: Some( | ||
1839 | "trait Foo", | ||
1840 | ), | ||
1841 | docs: None, | ||
1842 | }, | ||
1843 | }, | ||
1844 | HoverGotoTypeData { | ||
1845 | mod_path: "Bar", | ||
1846 | nav: NavigationTarget { | ||
1847 | file_id: FileId( | ||
1848 | 1, | ||
1849 | ), | ||
1850 | full_range: 16..31, | ||
1851 | name: "Bar", | ||
1852 | kind: TRAIT_DEF, | ||
1853 | focus_range: Some( | ||
1854 | 22..25, | ||
1855 | ), | ||
1856 | container_name: None, | ||
1857 | description: Some( | ||
1858 | "trait Bar", | ||
1859 | ), | ||
1860 | docs: None, | ||
1861 | }, | ||
1862 | }, | ||
1863 | HoverGotoTypeData { | ||
1864 | mod_path: "S1", | ||
1865 | nav: NavigationTarget { | ||
1866 | file_id: FileId( | ||
1867 | 1, | ||
1868 | ), | ||
1869 | full_range: 32..44, | ||
1870 | name: "S1", | ||
1871 | kind: STRUCT_DEF, | ||
1872 | focus_range: Some( | ||
1873 | 39..41, | ||
1874 | ), | ||
1875 | container_name: None, | ||
1876 | description: Some( | ||
1877 | "struct S1", | ||
1878 | ), | ||
1879 | docs: None, | ||
1880 | }, | ||
1881 | }, | ||
1882 | HoverGotoTypeData { | ||
1883 | mod_path: "S2", | ||
1884 | nav: NavigationTarget { | ||
1885 | file_id: FileId( | ||
1886 | 1, | ||
1887 | ), | ||
1888 | full_range: 45..57, | ||
1889 | name: "S2", | ||
1890 | kind: STRUCT_DEF, | ||
1891 | focus_range: Some( | ||
1892 | 52..54, | ||
1893 | ), | ||
1894 | container_name: None, | ||
1895 | description: Some( | ||
1896 | "struct S2", | ||
1897 | ), | ||
1898 | docs: None, | ||
1899 | }, | ||
1900 | }, | ||
1901 | ], | ||
1902 | ), | ||
1903 | ] | ||
1904 | "###); | ||
1905 | } | ||
1906 | |||
1907 | #[test] | ||
1738 | fn test_hover_arg_impl_trait_has_goto_type_action() { | 1908 | fn test_hover_arg_impl_trait_has_goto_type_action() { |
1739 | let (_, actions) = check_hover_result( | 1909 | let (_, actions) = check_hover_result( |
1740 | " | 1910 | " |
@@ -1775,6 +1945,87 @@ fn func(foo: i32) { if true { <|>foo; }; } | |||
1775 | } | 1945 | } |
1776 | 1946 | ||
1777 | #[test] | 1947 | #[test] |
1948 | fn test_hover_arg_impl_traits_has_goto_type_action() { | ||
1949 | let (_, actions) = check_hover_result( | ||
1950 | " | ||
1951 | //- /lib.rs | ||
1952 | trait Foo {} | ||
1953 | trait Bar<T> {} | ||
1954 | struct S{} | ||
1955 | |||
1956 | fn foo(ar<|>g: &impl Foo + Bar<S>) {} | ||
1957 | ", | ||
1958 | &["&impl Foo + Bar<S>"], | ||
1959 | ); | ||
1960 | assert_debug_snapshot!(actions, | ||
1961 | @r###" | ||
1962 | [ | ||
1963 | GoToType( | ||
1964 | [ | ||
1965 | HoverGotoTypeData { | ||
1966 | mod_path: "Foo", | ||
1967 | nav: NavigationTarget { | ||
1968 | file_id: FileId( | ||
1969 | 1, | ||
1970 | ), | ||
1971 | full_range: 0..12, | ||
1972 | name: "Foo", | ||
1973 | kind: TRAIT_DEF, | ||
1974 | focus_range: Some( | ||
1975 | 6..9, | ||
1976 | ), | ||
1977 | container_name: None, | ||
1978 | description: Some( | ||
1979 | "trait Foo", | ||
1980 | ), | ||
1981 | docs: None, | ||
1982 | }, | ||
1983 | }, | ||
1984 | HoverGotoTypeData { | ||
1985 | mod_path: "Bar", | ||
1986 | nav: NavigationTarget { | ||
1987 | file_id: FileId( | ||
1988 | 1, | ||
1989 | ), | ||
1990 | full_range: 13..28, | ||
1991 | name: "Bar", | ||
1992 | kind: TRAIT_DEF, | ||
1993 | focus_range: Some( | ||
1994 | 19..22, | ||
1995 | ), | ||
1996 | container_name: None, | ||
1997 | description: Some( | ||
1998 | "trait Bar", | ||
1999 | ), | ||
2000 | docs: None, | ||
2001 | }, | ||
2002 | }, | ||
2003 | HoverGotoTypeData { | ||
2004 | mod_path: "S", | ||
2005 | nav: NavigationTarget { | ||
2006 | file_id: FileId( | ||
2007 | 1, | ||
2008 | ), | ||
2009 | full_range: 29..39, | ||
2010 | name: "S", | ||
2011 | kind: STRUCT_DEF, | ||
2012 | focus_range: Some( | ||
2013 | 36..37, | ||
2014 | ), | ||
2015 | container_name: None, | ||
2016 | description: Some( | ||
2017 | "struct S", | ||
2018 | ), | ||
2019 | docs: None, | ||
2020 | }, | ||
2021 | }, | ||
2022 | ], | ||
2023 | ), | ||
2024 | ] | ||
2025 | "###); | ||
2026 | } | ||
2027 | |||
2028 | #[test] | ||
1778 | fn test_hover_arg_generic_impl_trait_has_goto_type_action() { | 2029 | fn test_hover_arg_generic_impl_trait_has_goto_type_action() { |
1779 | let (_, actions) = check_hover_result( | 2030 | let (_, actions) = check_hover_result( |
1780 | " | 2031 | " |