aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_hir/src/code_model.rs108
-rw-r--r--crates/ra_hir/src/lib.rs8
-rw-r--r--crates/ra_hir_ty/src/lib.rs6
-rw-r--r--crates/ra_ide/src/display/navigation_target.rs9
-rw-r--r--crates/ra_ide/src/hover.rs811
-rw-r--r--crates/ra_ide/src/lib.rs2
-rw-r--r--crates/rust-analyzer/src/config.rs1
-rw-r--r--crates/rust-analyzer/src/main_loop/handlers.rs46
8 files changed, 956 insertions, 35 deletions
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs
index 1a9f6cc76..c22eb451b 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, Ty, 29 method_resolution, ApplicationTy, Canonical, GenericPredicate, InEnvironment, OpaqueTyId,
30 TyDefId, TypeCtor, 30 Substs, TraitEnvironment, Ty, TyDefId, TypeCtor, TypeWalk,
31}; 31};
32use ra_db::{CrateId, CrateName, Edition, FileId}; 32use ra_db::{CrateId, CrateName, Edition, FileId};
33use ra_prof::profile; 33use ra_prof::profile;
@@ -1380,6 +1380,87 @@ impl Type {
1380 ty: InEnvironment { value: ty, environment: self.ty.environment.clone() }, 1380 ty: InEnvironment { value: ty, environment: self.ty.environment.clone() },
1381 } 1381 }
1382 } 1382 }
1383
1384 /// Returns a flattened list of all the ADTs and Traits mentioned in the type
1385 pub fn flattened_type_items(&self, db: &dyn HirDatabase) -> Vec<AdtOrTrait> {
1386 fn push_new_item(item: AdtOrTrait, acc: &mut Vec<AdtOrTrait>) {
1387 if !acc.contains(&item) {
1388 acc.push(item);
1389 }
1390 }
1391
1392 fn push_bounds(
1393 db: &dyn HirDatabase,
1394 predicates: &[GenericPredicate],
1395 acc: &mut Vec<AdtOrTrait>,
1396 ) {
1397 for p in predicates.iter() {
1398 match p {
1399 GenericPredicate::Implemented(trait_ref) => {
1400 push_new_item(Trait::from(trait_ref.trait_).into(), acc);
1401 walk_types(db, &trait_ref.substs, acc);
1402 }
1403 GenericPredicate::Projection(_) => {}
1404 GenericPredicate::Error => (),
1405 }
1406 }
1407 }
1408
1409 fn walk_types<T: TypeWalk>(db: &dyn HirDatabase, tw: &T, acc: &mut Vec<AdtOrTrait>) {
1410 tw.walk(&mut |ty| walk_type(db, ty, acc));
1411 }
1412
1413 fn walk_type(db: &dyn HirDatabase, ty: &Ty, acc: &mut Vec<AdtOrTrait>) {
1414 match ty.strip_references() {
1415 Ty::Apply(ApplicationTy { ctor, parameters, .. }) => {
1416 match ctor {
1417 TypeCtor::Adt(adt_id) => push_new_item(Adt::from(*adt_id).into(), acc),
1418 _ => (),
1419 }
1420 // adt params, tuples, etc...
1421 walk_types(db, parameters, acc);
1422 }
1423 Ty::Dyn(predicates) => {
1424 push_bounds(db, predicates, acc);
1425 }
1426 Ty::Placeholder(id) => {
1427 let generic_params = db.generic_params(id.parent);
1428 let param_data = &generic_params.types[id.local_id];
1429 match param_data.provenance {
1430 hir_def::generics::TypeParamProvenance::ArgumentImplTrait => {
1431 let predicates: Vec<_> = db
1432 .generic_predicates_for_param(*id)
1433 .into_iter()
1434 .map(|pred| pred.value.clone())
1435 .collect();
1436 push_bounds(db, &predicates, acc);
1437 }
1438 _ => (),
1439 }
1440 }
1441 Ty::Opaque(opaque_ty) => {
1442 let bounds = match opaque_ty.opaque_ty_id {
1443 OpaqueTyId::ReturnTypeImplTrait(func, idx) => {
1444 let datas = db
1445 .return_type_impl_traits(func)
1446 .expect("impl trait id without data");
1447 let data = (*datas)
1448 .as_ref()
1449 .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
1450 data.clone().subst(&opaque_ty.parameters)
1451 }
1452 };
1453 push_bounds(db, &bounds.value, acc);
1454 walk_types(db, &opaque_ty.parameters, acc);
1455 }
1456 _ => (),
1457 }
1458 }
1459
1460 let mut res: Vec<AdtOrTrait> = Vec::new(); // not a Set to preserve the order
1461 walk_type(db, &self.ty.value, &mut res);
1462 res
1463 }
1383} 1464}
1384 1465
1385impl HirDisplay for Type { 1466impl HirDisplay for Type {
@@ -1488,3 +1569,26 @@ pub trait HasVisibility {
1488 vis.is_visible_from(db.upcast(), module.id) 1569 vis.is_visible_from(db.upcast(), module.id)
1489 } 1570 }
1490} 1571}
1572
1573#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1574pub enum AdtOrTrait {
1575 Adt(Adt),
1576 Trait(Trait),
1577}
1578impl_froms!(AdtOrTrait: Adt, Trait);
1579
1580impl AdtOrTrait {
1581 pub fn module(self, db: &dyn HirDatabase) -> Module {
1582 match self {
1583 AdtOrTrait::Adt(adt) => adt.module(db),
1584 AdtOrTrait::Trait(trait_) => trait_.module(db),
1585 }
1586 }
1587
1588 pub fn name(self, db: &dyn HirDatabase) -> Name {
1589 match self {
1590 AdtOrTrait::Adt(adt) => adt.name(db),
1591 AdtOrTrait::Trait(trait_) => trait_.name(db),
1592 }
1593 }
1594}
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs
index 3364a822f..eded039e4 100644
--- a/crates/ra_hir/src/lib.rs
+++ b/crates/ra_hir/src/lib.rs
@@ -51,10 +51,10 @@ mod has_source;
51 51
52pub use crate::{ 52pub use crate::{
53 code_model::{ 53 code_model::{
54 Adt, AsAssocItem, AssocItem, AssocItemContainer, AttrDef, Const, Crate, CrateDependency, 54 Adt, AdtOrTrait, AsAssocItem, AssocItem, AssocItemContainer, AttrDef, Const, Crate,
55 DefWithBody, Docs, Enum, EnumVariant, Field, FieldSource, Function, GenericDef, HasAttrs, 55 CrateDependency, DefWithBody, Docs, Enum, EnumVariant, Field, FieldSource, Function,
56 HasVisibility, ImplDef, Local, MacroDef, Module, ModuleDef, ScopeDef, Static, Struct, 56 GenericDef, HasAttrs, HasVisibility, ImplDef, Local, MacroDef, Module, ModuleDef, ScopeDef,
57 Trait, Type, TypeAlias, TypeParam, Union, VariantDef, Visibility, 57 Static, Struct, Trait, Type, TypeAlias, TypeParam, Union, VariantDef, Visibility,
58 }, 58 },
59 has_source::HasSource, 59 has_source::HasSource,
60 semantics::{original_range, PathResolution, Semantics, SemanticsScope}, 60 semantics::{original_range, PathResolution, Semantics, SemanticsScope},
diff --git a/crates/ra_hir_ty/src/lib.rs b/crates/ra_hir_ty/src/lib.rs
index 2b9372b4b..9d4d6aaa4 100644
--- a/crates/ra_hir_ty/src/lib.rs
+++ b/crates/ra_hir_ty/src/lib.rs
@@ -1052,10 +1052,10 @@ pub enum OpaqueTyId {
1052 1052
1053#[derive(Clone, PartialEq, Eq, Debug, Hash)] 1053#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1054pub struct ReturnTypeImplTraits { 1054pub struct ReturnTypeImplTraits {
1055 pub(crate) impl_traits: Vec<ReturnTypeImplTrait>, 1055 pub impl_traits: Vec<ReturnTypeImplTrait>,
1056} 1056}
1057 1057
1058#[derive(Clone, PartialEq, Eq, Debug, Hash)] 1058#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1059pub(crate) struct ReturnTypeImplTrait { 1059pub struct ReturnTypeImplTrait {
1060 pub(crate) bounds: Binders<Vec<GenericPredicate>>, 1060 pub bounds: Binders<Vec<GenericPredicate>>,
1061} 1061}
diff --git a/crates/ra_ide/src/display/navigation_target.rs b/crates/ra_ide/src/display/navigation_target.rs
index c7bb1e69f..325b247bb 100644
--- a/crates/ra_ide/src/display/navigation_target.rs
+++ b/crates/ra_ide/src/display/navigation_target.rs
@@ -321,6 +321,15 @@ impl ToNav for hir::Adt {
321 } 321 }
322} 322}
323 323
324impl ToNav for hir::AdtOrTrait {
325 fn to_nav(&self, db: &RootDatabase) -> NavigationTarget {
326 match self {
327 hir::AdtOrTrait::Adt(adt) => adt.to_nav(db),
328 hir::AdtOrTrait::Trait(trait_) => trait_.to_nav(db),
329 }
330 }
331}
332
324impl ToNav for hir::AssocItem { 333impl ToNav for hir::AssocItem {
325 fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { 334 fn to_nav(&self, db: &RootDatabase) -> NavigationTarget {
326 match self { 335 match self {
diff --git a/crates/ra_ide/src/hover.rs b/crates/ra_ide/src/hover.rs
index ad78b7671..c434e5c8b 100644
--- a/crates/ra_ide/src/hover.rs
+++ b/crates/ra_ide/src/hover.rs
@@ -1,8 +1,8 @@
1use std::iter::once; 1use std::iter::once;
2 2
3use hir::{ 3use hir::{
4 Adt, AsAssocItem, AssocItemContainer, Documentation, FieldSource, HasSource, HirDisplay, 4 Adt, AdtOrTrait, AsAssocItem, AssocItemContainer, Documentation, FieldSource, HasSource,
5 ModuleDef, ModuleSource, Semantics, 5 HirDisplay, Module, ModuleDef, ModuleSource, Semantics,
6}; 6};
7use itertools::Itertools; 7use itertools::Itertools;
8use ra_db::SourceDatabase; 8use ra_db::SourceDatabase;
@@ -24,19 +24,21 @@ pub struct HoverConfig {
24 pub implementations: bool, 24 pub implementations: bool,
25 pub run: bool, 25 pub run: bool,
26 pub debug: bool, 26 pub debug: bool,
27 pub goto_type_def: bool,
27} 28}
28 29
29impl Default for HoverConfig { 30impl Default for HoverConfig {
30 fn default() -> Self { 31 fn default() -> Self {
31 Self { implementations: true, run: true, debug: true } 32 Self { implementations: true, run: true, debug: true, goto_type_def: true }
32 } 33 }
33} 34}
34 35
35impl HoverConfig { 36impl HoverConfig {
36 pub const NO_ACTIONS: Self = Self { implementations: false, run: false, debug: false }; 37 pub const NO_ACTIONS: Self =
38 Self { implementations: false, run: false, debug: false, goto_type_def: false };
37 39
38 pub fn any(&self) -> bool { 40 pub fn any(&self) -> bool {
39 self.implementations || self.runnable() 41 self.implementations || self.runnable() || self.goto_type_def
40 } 42 }
41 43
42 pub fn none(&self) -> bool { 44 pub fn none(&self) -> bool {
@@ -52,6 +54,13 @@ impl HoverConfig {
52pub enum HoverAction { 54pub enum HoverAction {
53 Runnable(Runnable), 55 Runnable(Runnable),
54 Implementaion(FilePosition), 56 Implementaion(FilePosition),
57 GoToType(Vec<HoverGotoTypeData>),
58}
59
60#[derive(Debug, Clone, Eq, PartialEq)]
61pub struct HoverGotoTypeData {
62 pub mod_path: String,
63 pub nav: NavigationTarget,
55} 64}
56 65
57/// Contains the results when hovering over an item 66/// Contains the results when hovering over an item
@@ -138,6 +147,10 @@ pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeIn
138 res.push_action(action); 147 res.push_action(action);
139 } 148 }
140 149
150 if let Some(action) = goto_type_action(db, name_kind) {
151 res.push_action(action);
152 }
153
141 return Some(RangeInfo::new(range, res)); 154 return Some(RangeInfo::new(range, res));
142 } 155 }
143 } 156 }
@@ -218,6 +231,24 @@ fn runnable_action(
218 } 231 }
219} 232}
220 233
234fn goto_type_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> {
235 match def {
236 Definition::Local(it) => {
237 let ty = it.ty(db);
238 let v = ty.flattened_type_items(db);
239 let targets = v.into_iter()
240 .map(|it| HoverGotoTypeData {
241 mod_path: adt_or_trait_mod_path(db, &it),
242 nav: it.to_nav(db),
243 })
244 .collect_vec();
245
246 Some(HoverAction::GoToType(targets))
247 }
248 _ => None,
249 }
250}
251
221fn hover_text( 252fn hover_text(
222 docs: Option<String>, 253 docs: Option<String>,
223 desc: Option<String>, 254 desc: Option<String>,
@@ -248,25 +279,30 @@ fn definition_owner_name(db: &RootDatabase, def: &Definition) -> Option<String>
248 .map(|name| name.to_string()) 279 .map(|name| name.to_string())
249} 280}
250 281
251fn determine_mod_path(db: &RootDatabase, def: &Definition) -> Option<String> { 282fn determine_mod_path(db: &RootDatabase, module: Module, name: Option<String>) -> String {
252 let mod_path = def.module(db).map(|module| { 283 once(db.crate_graph()[module.krate().into()].display_name.as_ref().map(ToString::to_string))
253 once(db.crate_graph()[module.krate().into()].display_name.as_ref().map(ToString::to_string)) 284 .chain(
254 .chain( 285 module
255 module 286 .path_to_root(db)
256 .path_to_root(db) 287 .into_iter()
257 .into_iter() 288 .rev()
258 .rev() 289 .map(|it| it.name(db).map(|name| name.to_string())),
259 .map(|it| it.name(db).map(|name| name.to_string())), 290 )
260 ) 291 .chain(once(name))
261 .chain(once(definition_owner_name(db, def))) 292 .flatten()
262 .flatten() 293 .join("::")
263 .join("::") 294}
264 }); 295
265 mod_path 296fn adt_or_trait_mod_path(db: &RootDatabase, item: &AdtOrTrait) -> String {
297 determine_mod_path(db, item.module(db), Some(item.name(db).to_string()))
298}
299
300fn definition_mod_path(db: &RootDatabase, def: &Definition) -> Option<String> {
301 def.module(db).map(|module| determine_mod_path(db, module, definition_owner_name(db, def)))
266} 302}
267 303
268fn hover_text_from_name_kind(db: &RootDatabase, def: Definition) -> Option<String> { 304fn hover_text_from_name_kind(db: &RootDatabase, def: Definition) -> Option<String> {
269 let mod_path = determine_mod_path(db, &def); 305 let mod_path = definition_mod_path(db, &def);
270 return match def { 306 return match def {
271 Definition::Macro(it) => { 307 Definition::Macro(it) => {
272 let src = it.source(db); 308 let src = it.source(db);
@@ -1310,4 +1346,737 @@ fn func(foo: i32) { if true { <|>foo; }; }
1310 ] 1346 ]
1311 "###); 1347 "###);
1312 } 1348 }
1349
1350 #[test]
1351 fn test_hover_struct_has_goto_type_action() {
1352 let (_, actions) = check_hover_result(
1353 "
1354 //- /main.rs
1355 struct S{ f1: u32 }
1356
1357 fn main() {
1358 let s<|>t = S{ f1:0 };
1359 }
1360 ",
1361 &["S"],
1362 );
1363 assert_debug_snapshot!(actions,
1364 @r###"
1365 [
1366 GoToType(
1367 [
1368 HoverGotoTypeData {
1369 mod_path: "S",
1370 nav: NavigationTarget {
1371 file_id: FileId(
1372 1,
1373 ),
1374 full_range: 0..19,
1375 name: "S",
1376 kind: STRUCT_DEF,
1377 focus_range: Some(
1378 7..8,
1379 ),
1380 container_name: None,
1381 description: Some(
1382 "struct S",
1383 ),
1384 docs: None,
1385 },
1386 },
1387 ],
1388 ),
1389 ]
1390 "###);
1391 }
1392
1393 #[test]
1394 fn test_hover_generic_struct_has_goto_type_actions() {
1395 let (_, actions) = check_hover_result(
1396 "
1397 //- /main.rs
1398 struct Arg(u32);
1399 struct S<T>{ f1: T }
1400
1401 fn main() {
1402 let s<|>t = S{ f1:Arg(0) };
1403 }
1404 ",
1405 &["S<Arg>"],
1406 );
1407 assert_debug_snapshot!(actions,
1408 @r###"
1409 [
1410 GoToType(
1411 [
1412 HoverGotoTypeData {
1413 mod_path: "S",
1414 nav: NavigationTarget {
1415 file_id: FileId(
1416 1,
1417 ),
1418 full_range: 17..37,
1419 name: "S",
1420 kind: STRUCT_DEF,
1421 focus_range: Some(
1422 24..25,
1423 ),
1424 container_name: None,
1425 description: Some(
1426 "struct S",
1427 ),
1428 docs: None,
1429 },
1430 },
1431 HoverGotoTypeData {
1432 mod_path: "Arg",
1433 nav: NavigationTarget {
1434 file_id: FileId(
1435 1,
1436 ),
1437 full_range: 0..16,
1438 name: "Arg",
1439 kind: STRUCT_DEF,
1440 focus_range: Some(
1441 7..10,
1442 ),
1443 container_name: None,
1444 description: Some(
1445 "struct Arg",
1446 ),
1447 docs: None,
1448 },
1449 },
1450 ],
1451 ),
1452 ]
1453 "###);
1454 }
1455
1456 #[test]
1457 fn test_hover_generic_struct_has_flattened_goto_type_actions() {
1458 let (_, actions) = check_hover_result(
1459 "
1460 //- /main.rs
1461 struct Arg(u32);
1462 struct S<T>{ f1: T }
1463
1464 fn main() {
1465 let s<|>t = S{ f1: S{ f1: Arg(0) } };
1466 }
1467 ",
1468 &["S<S<Arg>>"],
1469 );
1470 assert_debug_snapshot!(actions,
1471 @r###"
1472 [
1473 GoToType(
1474 [
1475 HoverGotoTypeData {
1476 mod_path: "S",
1477 nav: NavigationTarget {
1478 file_id: FileId(
1479 1,
1480 ),
1481 full_range: 17..37,
1482 name: "S",
1483 kind: STRUCT_DEF,
1484 focus_range: Some(
1485 24..25,
1486 ),
1487 container_name: None,
1488 description: Some(
1489 "struct S",
1490 ),
1491 docs: None,
1492 },
1493 },
1494 HoverGotoTypeData {
1495 mod_path: "Arg",
1496 nav: NavigationTarget {
1497 file_id: FileId(
1498 1,
1499 ),
1500 full_range: 0..16,
1501 name: "Arg",
1502 kind: STRUCT_DEF,
1503 focus_range: Some(
1504 7..10,
1505 ),
1506 container_name: None,
1507 description: Some(
1508 "struct Arg",
1509 ),
1510 docs: None,
1511 },
1512 },
1513 ],
1514 ),
1515 ]
1516 "###);
1517 }
1518
1519 #[test]
1520 fn test_hover_tuple_has_goto_type_actions() {
1521 let (_, actions) = check_hover_result(
1522 "
1523 //- /main.rs
1524 struct A(u32);
1525 struct B(u32);
1526 mod M {
1527 pub struct C(u32);
1528 }
1529
1530 fn main() {
1531 let s<|>t = (A(1), B(2), M::C(3) );
1532 }
1533 ",
1534 &["(A, B, C)"],
1535 );
1536 assert_debug_snapshot!(actions,
1537 @r###"
1538 [
1539 GoToType(
1540 [
1541 HoverGotoTypeData {
1542 mod_path: "A",
1543 nav: NavigationTarget {
1544 file_id: FileId(
1545 1,
1546 ),
1547 full_range: 0..14,
1548 name: "A",
1549 kind: STRUCT_DEF,
1550 focus_range: Some(
1551 7..8,
1552 ),
1553 container_name: None,
1554 description: Some(
1555 "struct A",
1556 ),
1557 docs: None,
1558 },
1559 },
1560 HoverGotoTypeData {
1561 mod_path: "B",
1562 nav: NavigationTarget {
1563 file_id: FileId(
1564 1,
1565 ),
1566 full_range: 15..29,
1567 name: "B",
1568 kind: STRUCT_DEF,
1569 focus_range: Some(
1570 22..23,
1571 ),
1572 container_name: None,
1573 description: Some(
1574 "struct B",
1575 ),
1576 docs: None,
1577 },
1578 },
1579 HoverGotoTypeData {
1580 mod_path: "M::C",
1581 nav: NavigationTarget {
1582 file_id: FileId(
1583 1,
1584 ),
1585 full_range: 42..60,
1586 name: "C",
1587 kind: STRUCT_DEF,
1588 focus_range: Some(
1589 53..54,
1590 ),
1591 container_name: None,
1592 description: Some(
1593 "pub struct C",
1594 ),
1595 docs: None,
1596 },
1597 },
1598 ],
1599 ),
1600 ]
1601 "###);
1602 }
1603
1604 #[test]
1605 fn test_hover_return_impl_trait_has_goto_type_action() {
1606 let (_, actions) = check_hover_result(
1607 "
1608 //- /main.rs
1609 trait Foo {}
1610
1611 fn foo() -> impl Foo {}
1612
1613 fn main() {
1614 let s<|>t = foo();
1615 }
1616 ",
1617 &["impl Foo"],
1618 );
1619 assert_debug_snapshot!(actions,
1620 @r###"
1621 [
1622 GoToType(
1623 [
1624 HoverGotoTypeData {
1625 mod_path: "Foo",
1626 nav: NavigationTarget {
1627 file_id: FileId(
1628 1,
1629 ),
1630 full_range: 0..12,
1631 name: "Foo",
1632 kind: TRAIT_DEF,
1633 focus_range: Some(
1634 6..9,
1635 ),
1636 container_name: None,
1637 description: Some(
1638 "trait Foo",
1639 ),
1640 docs: None,
1641 },
1642 },
1643 ],
1644 ),
1645 ]
1646 "###);
1647 }
1648
1649 #[test]
1650 fn test_hover_generic_return_impl_trait_has_goto_type_action() {
1651 let (_, actions) = check_hover_result(
1652 "
1653 //- /main.rs
1654 trait Foo<T> {}
1655 struct S;
1656
1657 fn foo() -> impl Foo<S> {}
1658
1659 fn main() {
1660 let s<|>t = foo();
1661 }
1662 ",
1663 &["impl Foo<S>"],
1664 );
1665 assert_debug_snapshot!(actions,
1666 @r###"
1667 [
1668 GoToType(
1669 [
1670 HoverGotoTypeData {
1671 mod_path: "Foo",
1672 nav: NavigationTarget {
1673 file_id: FileId(
1674 1,
1675 ),
1676 full_range: 0..15,
1677 name: "Foo",
1678 kind: TRAIT_DEF,
1679 focus_range: Some(
1680 6..9,
1681 ),
1682 container_name: None,
1683 description: Some(
1684 "trait Foo",
1685 ),
1686 docs: None,
1687 },
1688 },
1689 HoverGotoTypeData {
1690 mod_path: "S",
1691 nav: NavigationTarget {
1692 file_id: FileId(
1693 1,
1694 ),
1695 full_range: 16..25,
1696 name: "S",
1697 kind: STRUCT_DEF,
1698 focus_range: Some(
1699 23..24,
1700 ),
1701 container_name: None,
1702 description: Some(
1703 "struct S",
1704 ),
1705 docs: None,
1706 },
1707 },
1708 ],
1709 ),
1710 ]
1711 "###);
1712 }
1713
1714 #[test]
1715 fn test_hover_arg_impl_trait_has_goto_type_action() {
1716 let (_, actions) = check_hover_result(
1717 "
1718 //- /lib.rs
1719 trait Foo {}
1720 fn foo(ar<|>g: &impl Foo) {}
1721 ",
1722 &["&impl Foo"],
1723 );
1724 assert_debug_snapshot!(actions,
1725 @r###"
1726 [
1727 GoToType(
1728 [
1729 HoverGotoTypeData {
1730 mod_path: "Foo",
1731 nav: NavigationTarget {
1732 file_id: FileId(
1733 1,
1734 ),
1735 full_range: 0..12,
1736 name: "Foo",
1737 kind: TRAIT_DEF,
1738 focus_range: Some(
1739 6..9,
1740 ),
1741 container_name: None,
1742 description: Some(
1743 "trait Foo",
1744 ),
1745 docs: None,
1746 },
1747 },
1748 ],
1749 ),
1750 ]
1751 "###);
1752 }
1753
1754 #[test]
1755 fn test_hover_arg_generic_impl_trait_has_goto_type_action() {
1756 let (_, actions) = check_hover_result(
1757 "
1758 //- /lib.rs
1759 trait Foo<T> {}
1760 struct S {}
1761 fn foo(ar<|>g: &impl Foo<S>) {}
1762 ",
1763 &["&impl Foo<S>"],
1764 );
1765 assert_debug_snapshot!(actions,
1766 @r###"
1767 [
1768 GoToType(
1769 [
1770 HoverGotoTypeData {
1771 mod_path: "Foo",
1772 nav: NavigationTarget {
1773 file_id: FileId(
1774 1,
1775 ),
1776 full_range: 0..15,
1777 name: "Foo",
1778 kind: TRAIT_DEF,
1779 focus_range: Some(
1780 6..9,
1781 ),
1782 container_name: None,
1783 description: Some(
1784 "trait Foo",
1785 ),
1786 docs: None,
1787 },
1788 },
1789 HoverGotoTypeData {
1790 mod_path: "S",
1791 nav: NavigationTarget {
1792 file_id: FileId(
1793 1,
1794 ),
1795 full_range: 16..27,
1796 name: "S",
1797 kind: STRUCT_DEF,
1798 focus_range: Some(
1799 23..24,
1800 ),
1801 container_name: None,
1802 description: Some(
1803 "struct S",
1804 ),
1805 docs: None,
1806 },
1807 },
1808 ],
1809 ),
1810 ]
1811 "###);
1812 }
1813
1814 #[test]
1815 fn test_hover_dyn_return_has_goto_type_action() {
1816 let (_, actions) = check_hover_result(
1817 "
1818 //- /main.rs
1819 trait Foo {}
1820 struct S;
1821 impl Foo for S {}
1822
1823 struct B<T>{}
1824
1825 fn foo() -> B<dyn Foo> {}
1826
1827 fn main() {
1828 let s<|>t = foo();
1829 }
1830 ",
1831 &["B<dyn Foo>"],
1832 );
1833 assert_debug_snapshot!(actions,
1834 @r###"
1835 [
1836 GoToType(
1837 [
1838 HoverGotoTypeData {
1839 mod_path: "B",
1840 nav: NavigationTarget {
1841 file_id: FileId(
1842 1,
1843 ),
1844 full_range: 41..54,
1845 name: "B",
1846 kind: STRUCT_DEF,
1847 focus_range: Some(
1848 48..49,
1849 ),
1850 container_name: None,
1851 description: Some(
1852 "struct B",
1853 ),
1854 docs: None,
1855 },
1856 },
1857 HoverGotoTypeData {
1858 mod_path: "Foo",
1859 nav: NavigationTarget {
1860 file_id: FileId(
1861 1,
1862 ),
1863 full_range: 0..12,
1864 name: "Foo",
1865 kind: TRAIT_DEF,
1866 focus_range: Some(
1867 6..9,
1868 ),
1869 container_name: None,
1870 description: Some(
1871 "trait Foo",
1872 ),
1873 docs: None,
1874 },
1875 },
1876 ],
1877 ),
1878 ]
1879 "###);
1880 }
1881
1882 #[test]
1883 fn test_hover_dyn_arg_has_goto_type_action() {
1884 let (_, actions) = check_hover_result(
1885 "
1886 //- /lib.rs
1887 trait Foo {}
1888 fn foo(ar<|>g: &dyn Foo) {}
1889 ",
1890 &["&dyn Foo"],
1891 );
1892 assert_debug_snapshot!(actions,
1893 @r###"
1894 [
1895 GoToType(
1896 [
1897 HoverGotoTypeData {
1898 mod_path: "Foo",
1899 nav: NavigationTarget {
1900 file_id: FileId(
1901 1,
1902 ),
1903 full_range: 0..12,
1904 name: "Foo",
1905 kind: TRAIT_DEF,
1906 focus_range: Some(
1907 6..9,
1908 ),
1909 container_name: None,
1910 description: Some(
1911 "trait Foo",
1912 ),
1913 docs: None,
1914 },
1915 },
1916 ],
1917 ),
1918 ]
1919 "###);
1920 }
1921
1922 #[test]
1923 fn test_hover_generic_dyn_arg_has_goto_type_action() {
1924 let (_, actions) = check_hover_result(
1925 "
1926 //- /lib.rs
1927 trait Foo<T> {}
1928 struct S {}
1929 fn foo(ar<|>g: &dyn Foo<S>) {}
1930 ",
1931 &["&dyn Foo<S>"],
1932 );
1933 assert_debug_snapshot!(actions,
1934 @r###"
1935 [
1936 GoToType(
1937 [
1938 HoverGotoTypeData {
1939 mod_path: "Foo",
1940 nav: NavigationTarget {
1941 file_id: FileId(
1942 1,
1943 ),
1944 full_range: 0..15,
1945 name: "Foo",
1946 kind: TRAIT_DEF,
1947 focus_range: Some(
1948 6..9,
1949 ),
1950 container_name: None,
1951 description: Some(
1952 "trait Foo",
1953 ),
1954 docs: None,
1955 },
1956 },
1957 HoverGotoTypeData {
1958 mod_path: "S",
1959 nav: NavigationTarget {
1960 file_id: FileId(
1961 1,
1962 ),
1963 full_range: 16..27,
1964 name: "S",
1965 kind: STRUCT_DEF,
1966 focus_range: Some(
1967 23..24,
1968 ),
1969 container_name: None,
1970 description: Some(
1971 "struct S",
1972 ),
1973 docs: None,
1974 },
1975 },
1976 ],
1977 ),
1978 ]
1979 "###);
1980 }
1981
1982 #[test]
1983 fn test_hover_arg_goto_type_action() {
1984 let (_, actions) = check_hover_result(
1985 "
1986 //- /lib.rs
1987 trait ImplTrait<T> {}
1988 trait DynTrait<T> {}
1989 struct B<T> {}
1990 struct S {}
1991
1992 fn foo(a<|>rg: &impl ImplTrait<B<dyn DynTrait<S>>>) {}
1993 ",
1994 &["&impl ImplTrait<B<dyn DynTrait<S>>>"],
1995 );
1996 assert_debug_snapshot!(actions,
1997 @r###"
1998 [
1999 GoToType(
2000 [
2001 HoverGotoTypeData {
2002 mod_path: "ImplTrait",
2003 nav: NavigationTarget {
2004 file_id: FileId(
2005 1,
2006 ),
2007 full_range: 0..21,
2008 name: "ImplTrait",
2009 kind: TRAIT_DEF,
2010 focus_range: Some(
2011 6..15,
2012 ),
2013 container_name: None,
2014 description: Some(
2015 "trait ImplTrait",
2016 ),
2017 docs: None,
2018 },
2019 },
2020 HoverGotoTypeData {
2021 mod_path: "S",
2022 nav: NavigationTarget {
2023 file_id: FileId(
2024 1,
2025 ),
2026 full_range: 58..69,
2027 name: "S",
2028 kind: STRUCT_DEF,
2029 focus_range: Some(
2030 65..66,
2031 ),
2032 container_name: None,
2033 description: Some(
2034 "struct S",
2035 ),
2036 docs: None,
2037 },
2038 },
2039 HoverGotoTypeData {
2040 mod_path: "DynTrait",
2041 nav: NavigationTarget {
2042 file_id: FileId(
2043 1,
2044 ),
2045 full_range: 22..42,
2046 name: "DynTrait",
2047 kind: TRAIT_DEF,
2048 focus_range: Some(
2049 28..36,
2050 ),
2051 container_name: None,
2052 description: Some(
2053 "trait DynTrait",
2054 ),
2055 docs: None,
2056 },
2057 },
2058 HoverGotoTypeData {
2059 mod_path: "B",
2060 nav: NavigationTarget {
2061 file_id: FileId(
2062 1,
2063 ),
2064 full_range: 43..57,
2065 name: "B",
2066 kind: STRUCT_DEF,
2067 focus_range: Some(
2068 50..51,
2069 ),
2070 container_name: None,
2071 description: Some(
2072 "struct B",
2073 ),
2074 docs: None,
2075 },
2076 },
2077 ],
2078 ),
2079 ]
2080 "###);
2081 }
1313} 2082}
diff --git a/crates/ra_ide/src/lib.rs b/crates/ra_ide/src/lib.rs
index 51dc1f041..be9ab62c0 100644
--- a/crates/ra_ide/src/lib.rs
+++ b/crates/ra_ide/src/lib.rs
@@ -66,7 +66,7 @@ pub use crate::{
66 display::{file_structure, FunctionSignature, NavigationTarget, StructureNode}, 66 display::{file_structure, FunctionSignature, NavigationTarget, StructureNode},
67 expand_macro::ExpandedMacro, 67 expand_macro::ExpandedMacro,
68 folding_ranges::{Fold, FoldKind}, 68 folding_ranges::{Fold, FoldKind},
69 hover::{HoverAction, HoverConfig, HoverResult}, 69 hover::{HoverAction, HoverConfig, HoverGotoTypeData, HoverResult},
70 inlay_hints::{InlayHint, InlayHintsConfig, InlayKind}, 70 inlay_hints::{InlayHint, InlayHintsConfig, InlayKind},
71 references::{Declaration, Reference, ReferenceAccess, ReferenceKind, ReferenceSearchResult}, 71 references::{Declaration, Reference, ReferenceAccess, ReferenceKind, ReferenceSearchResult},
72 runnables::{Runnable, RunnableKind, TestId}, 72 runnables::{Runnable, RunnableKind, TestId},
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index 0df7427cb..aa2c4ae15 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/crates/rust-analyzer/src/config.rs
@@ -296,6 +296,7 @@ impl Config {
296 set(value, "/hoverActions/implementations", &mut self.hover.implementations); 296 set(value, "/hoverActions/implementations", &mut self.hover.implementations);
297 set(value, "/hoverActions/run", &mut self.hover.run); 297 set(value, "/hoverActions/run", &mut self.hover.run);
298 set(value, "/hoverActions/debug", &mut self.hover.debug); 298 set(value, "/hoverActions/debug", &mut self.hover.debug);
299 set(value, "/hoverActions/gotoTypeDef", &mut self.hover.goto_type_def);
299 } else { 300 } else {
300 self.hover = HoverConfig::NO_ACTIONS; 301 self.hover = HoverConfig::NO_ACTIONS;
301 } 302 }
diff --git a/crates/rust-analyzer/src/main_loop/handlers.rs b/crates/rust-analyzer/src/main_loop/handlers.rs
index f3868bf17..2d7e649d2 100644
--- a/crates/rust-analyzer/src/main_loop/handlers.rs
+++ b/crates/rust-analyzer/src/main_loop/handlers.rs
@@ -18,8 +18,8 @@ use lsp_types::{
18 TextDocumentIdentifier, Url, WorkspaceEdit, 18 TextDocumentIdentifier, Url, WorkspaceEdit,
19}; 19};
20use ra_ide::{ 20use ra_ide::{
21 FileId, FilePosition, FileRange, HoverAction, Query, RangeInfo, Runnable, RunnableKind, 21 FileId, FilePosition, FileRange, HoverAction, HoverGotoTypeData, NavigationTarget, Query,
22 SearchScope, TextEdit, 22 RangeInfo, Runnable, RunnableKind, SearchScope, TextEdit,
23}; 23};
24use ra_prof::profile; 24use ra_prof::profile;
25use ra_project_model::TargetKind; 25use ra_project_model::TargetKind;
@@ -1150,6 +1150,23 @@ fn debug_single_command(runnable: &lsp_ext::Runnable) -> Command {
1150 } 1150 }
1151} 1151}
1152 1152
1153fn goto_location_command(snap: &GlobalStateSnapshot, nav: &NavigationTarget) -> Option<Command> {
1154 let value = if snap.config.client_caps.location_link {
1155 let link = to_proto::location_link(snap, None, nav.clone()).ok()?;
1156 to_value(link).ok()?
1157 } else {
1158 let range = FileRange { file_id: nav.file_id(), range: nav.range() };
1159 let location = to_proto::location(snap, range).ok()?;
1160 to_value(location).ok()?
1161 };
1162
1163 Some(Command {
1164 title: nav.name().to_string(),
1165 command: "rust-analyzer.gotoLocation".into(),
1166 arguments: Some(vec![value]),
1167 })
1168}
1169
1153fn to_command_link(command: Command, tooltip: String) -> lsp_ext::CommandLink { 1170fn to_command_link(command: Command, tooltip: String) -> lsp_ext::CommandLink {
1154 lsp_ext::CommandLink { tooltip: Some(tooltip), command } 1171 lsp_ext::CommandLink { tooltip: Some(tooltip), command }
1155} 1172}
@@ -1180,7 +1197,7 @@ fn show_impl_command_link(
1180 None 1197 None
1181} 1198}
1182 1199
1183fn to_runnable_action( 1200fn runnable_action_links(
1184 snap: &GlobalStateSnapshot, 1201 snap: &GlobalStateSnapshot,
1185 file_id: FileId, 1202 file_id: FileId,
1186 runnable: Runnable, 1203 runnable: Runnable,
@@ -1208,6 +1225,26 @@ fn to_runnable_action(
1208 }) 1225 })
1209} 1226}
1210 1227
1228fn goto_type_action_links(
1229 snap: &GlobalStateSnapshot,
1230 nav_targets: &[HoverGotoTypeData],
1231) -> Option<lsp_ext::CommandLinkGroup> {
1232 if !snap.config.hover.goto_type_def || nav_targets.is_empty() {
1233 return None;
1234 }
1235
1236 Some(lsp_ext::CommandLinkGroup {
1237 title: Some("Go to ".into()),
1238 commands: nav_targets
1239 .iter()
1240 .filter_map(|it| {
1241 goto_location_command(snap, &it.nav)
1242 .map(|cmd| to_command_link(cmd, it.mod_path.clone()))
1243 })
1244 .collect(),
1245 })
1246}
1247
1211fn prepare_hover_actions( 1248fn prepare_hover_actions(
1212 snap: &GlobalStateSnapshot, 1249 snap: &GlobalStateSnapshot,
1213 file_id: FileId, 1250 file_id: FileId,
@@ -1221,7 +1258,8 @@ fn prepare_hover_actions(
1221 .iter() 1258 .iter()
1222 .filter_map(|it| match it { 1259 .filter_map(|it| match it {
1223 HoverAction::Implementaion(position) => show_impl_command_link(snap, position), 1260 HoverAction::Implementaion(position) => show_impl_command_link(snap, position),
1224 HoverAction::Runnable(r) => to_runnable_action(snap, file_id, r.clone()), 1261 HoverAction::Runnable(r) => runnable_action_links(snap, file_id, r.clone()),
1262 HoverAction::GoToType(targets) => goto_type_action_links(snap, targets),
1225 }) 1263 })
1226 .collect() 1264 .collect()
1227} 1265}