aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2021-06-07 05:52:38 +0100
committerGitHub <[email protected]>2021-06-07 05:52:38 +0100
commitefa84cd08d9e4d1d464ffc6832a1d1b1c85aed23 (patch)
tree062f9e4fdb3e675c5a361e3f14a5659a6f4bb810
parent13da28cc2bc1b59f7af817eca36927a71edb023c (diff)
parent34ce05781fbca1bc6b717cce3bee6bd9923248b2 (diff)
Merge #9106
9106: feat: goto definition on an impl fn goes to that fn in the trait r=lf- a=lf- e.g. if you have a trait T and `impl T for S` for some struct, if you goto definition on some function name inside the impl, it will go to the definition of that function inside the `trait T` block, rather than the current behaviour of not going anywhere at all. ![ra goto def trait the other way](https://user-images.githubusercontent.com/6652840/120403989-39aa3280-c2fa-11eb-9359-639346878acd.gif) Co-authored-by: Jade <[email protected]>
-rw-r--r--crates/hir/src/lib.rs9
-rw-r--r--crates/ide/src/goto_definition.rs89
2 files changed, 91 insertions, 7 deletions
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index b43d61d0e..c2b68a853 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -50,7 +50,6 @@ use hir_def::{
50 per_ns::PerNs, 50 per_ns::PerNs,
51 resolver::{HasResolver, Resolver}, 51 resolver::{HasResolver, Resolver},
52 src::HasSource as _, 52 src::HasSource as _,
53 type_ref::TraitRef,
54 AdtId, AssocContainerId, AssocItemId, AssocItemLoc, AttrDefId, ConstId, ConstParamId, 53 AdtId, AssocContainerId, AssocItemId, AssocItemLoc, AttrDefId, ConstId, ConstParamId,
55 DefWithBodyId, EnumId, FunctionId, GenericDefId, HasModule, ImplId, LifetimeParamId, 54 DefWithBodyId, EnumId, FunctionId, GenericDefId, HasModule, ImplId, LifetimeParamId,
56 LocalEnumVariantId, LocalFieldId, Lookup, ModuleId, StaticId, StructId, TraitId, TypeAliasId, 55 LocalEnumVariantId, LocalFieldId, Lookup, ModuleId, StaticId, StructId, TraitId, TypeAliasId,
@@ -1797,9 +1796,11 @@ impl Impl {
1797 } 1796 }
1798 1797
1799 // FIXME: the return type is wrong. This should be a hir version of 1798 // FIXME: the return type is wrong. This should be a hir version of
1800 // `TraitRef` (ie, resolved `TypeRef`). 1799 // `TraitRef` (to account for parameters and qualifiers)
1801 pub fn trait_(self, db: &dyn HirDatabase) -> Option<TraitRef> { 1800 pub fn trait_(self, db: &dyn HirDatabase) -> Option<Trait> {
1802 db.impl_data(self.id).target_trait.as_deref().cloned() 1801 let trait_ref = db.impl_trait(self.id)?.skip_binders().clone();
1802 let id = hir_ty::from_chalk_trait_id(trait_ref.trait_id);
1803 Some(Trait { id })
1803 } 1804 }
1804 1805
1805 pub fn self_ty(self, db: &dyn HirDatabase) -> Type { 1806 pub fn self_ty(self, db: &dyn HirDatabase) -> Type {
diff --git a/crates/ide/src/goto_definition.rs b/crates/ide/src/goto_definition.rs
index b0bfd646e..2d36c34e9 100644
--- a/crates/ide/src/goto_definition.rs
+++ b/crates/ide/src/goto_definition.rs
@@ -1,10 +1,10 @@
1use std::convert::TryInto; 1use std::convert::TryInto;
2 2
3use either::Either; 3use either::Either;
4use hir::{InFile, Semantics}; 4use hir::{AsAssocItem, InFile, ModuleDef, Semantics};
5use ide_db::{ 5use ide_db::{
6 base_db::{AnchoredPath, FileId, FileLoader}, 6 base_db::{AnchoredPath, FileId, FileLoader},
7 defs::{NameClass, NameRefClass}, 7 defs::{Definition, NameClass, NameRefClass},
8 RootDatabase, 8 RootDatabase,
9}; 9};
10use syntax::{ 10use syntax::{
@@ -57,7 +57,8 @@ pub(crate) fn goto_definition(
57 }, 57 },
58 ast::Name(name) => { 58 ast::Name(name) => {
59 let def = NameClass::classify(&sema, &name)?.referenced_or_defined(sema.db); 59 let def = NameClass::classify(&sema, &name)?.referenced_or_defined(sema.db);
60 def.try_to_nav(sema.db) 60 try_find_trait_item_definition(&sema.db, &def)
61 .or_else(|| def.try_to_nav(sema.db))
61 }, 62 },
62 ast::Lifetime(lt) => if let Some(name_class) = NameClass::classify_lifetime(&sema, &lt) { 63 ast::Lifetime(lt) => if let Some(name_class) = NameClass::classify_lifetime(&sema, &lt) {
63 let def = name_class.referenced_or_defined(sema.db); 64 let def = name_class.referenced_or_defined(sema.db);
@@ -99,6 +100,34 @@ fn try_lookup_include_path(
99 }) 100 })
100} 101}
101 102
103/// finds the trait definition of an impl'd item
104/// e.g.
105/// ```rust
106/// trait A { fn a(); }
107/// struct S;
108/// impl A for S { fn a(); } // <-- on this function, will get the location of a() in the trait
109/// ```
110fn try_find_trait_item_definition(db: &RootDatabase, def: &Definition) -> Option<NavigationTarget> {
111 let name = def.name(db)?;
112 let assoc = match def {
113 Definition::ModuleDef(ModuleDef::Function(f)) => f.as_assoc_item(db),
114 Definition::ModuleDef(ModuleDef::Const(c)) => c.as_assoc_item(db),
115 Definition::ModuleDef(ModuleDef::TypeAlias(ty)) => ty.as_assoc_item(db),
116 _ => None,
117 }?;
118
119 let imp = match assoc.container(db) {
120 hir::AssocItemContainer::Impl(imp) => imp,
121 _ => return None,
122 };
123
124 let trait_ = imp.trait_(db)?;
125 trait_
126 .items(db)
127 .iter()
128 .find_map(|itm| (itm.name(db)? == name).then(|| itm.try_to_nav(db)).flatten())
129}
130
102fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> { 131fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> {
103 return tokens.max_by_key(priority); 132 return tokens.max_by_key(priority);
104 fn priority(n: &SyntaxToken) -> usize { 133 fn priority(n: &SyntaxToken) -> usize {
@@ -1262,4 +1291,58 @@ fn main() {
1262"#, 1291"#,
1263 ); 1292 );
1264 } 1293 }
1294
1295 #[test]
1296 fn goto_def_of_trait_impl_fn() {
1297 check(
1298 r#"
1299trait Twait {
1300 fn a();
1301 // ^
1302}
1303
1304struct Stwuct;
1305
1306impl Twait for Stwuct {
1307 fn a$0();
1308}
1309"#,
1310 );
1311 }
1312
1313 #[test]
1314 fn goto_def_of_trait_impl_const() {
1315 check(
1316 r#"
1317trait Twait {
1318 const NOMS: bool;
1319 // ^^^^
1320}
1321
1322struct Stwuct;
1323
1324impl Twait for Stwuct {
1325 const NOMS$0: bool = true;
1326}
1327"#,
1328 );
1329 }
1330
1331 #[test]
1332 fn goto_def_of_trait_impl_type_alias() {
1333 check(
1334 r#"
1335trait Twait {
1336 type IsBad;
1337 // ^^^^^
1338}
1339
1340struct Stwuct;
1341
1342impl Twait for Stwuct {
1343 type IsBad$0 = !;
1344}
1345"#,
1346 );
1347 }
1265} 1348}