Skip to content

Commit 8a57c73

Browse files
committed
feat: goto definition on an impl fn goes to that fn in the trait
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.
1 parent 13da28c commit 8a57c73

File tree

2 files changed

+53
-7
lines changed

2 files changed

+53
-7
lines changed

crates/hir/src/lib.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@ use hir_def::{
5050
per_ns::PerNs,
5151
resolver::{HasResolver, Resolver},
5252
src::HasSource as _,
53-
type_ref::TraitRef,
5453
AdtId, AssocContainerId, AssocItemId, AssocItemLoc, AttrDefId, ConstId, ConstParamId,
5554
DefWithBodyId, EnumId, FunctionId, GenericDefId, HasModule, ImplId, LifetimeParamId,
5655
LocalEnumVariantId, LocalFieldId, Lookup, ModuleId, StaticId, StructId, TraitId, TypeAliasId,
@@ -1797,9 +1796,11 @@ impl Impl {
17971796
}
17981797

17991798
// FIXME: the return type is wrong. This should be a hir version of
1800-
// `TraitRef` (ie, resolved `TypeRef`).
1801-
pub fn trait_(self, db: &dyn HirDatabase) -> Option<TraitRef> {
1802-
db.impl_data(self.id).target_trait.as_deref().cloned()
1799+
// `TraitRef` (to account for parameters and qualifiers)
1800+
pub fn trait_(self, db: &dyn HirDatabase) -> Option<Trait> {
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 })
18031804
}
18041805

18051806
pub fn self_ty(self, db: &dyn HirDatabase) -> Type {

crates/ide/src/goto_definition.rs

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
use std::convert::TryInto;
22

33
use either::Either;
4-
use hir::{InFile, Semantics};
4+
use hir::{AsAssocItem, InFile, ModuleDef, Semantics};
55
use ide_db::{
66
base_db::{AnchoredPath, FileId, FileLoader},
7-
defs::{NameClass, NameRefClass},
7+
defs::{Definition, NameClass, NameRefClass},
88
RootDatabase,
99
};
1010
use syntax::{
@@ -57,7 +57,8 @@ pub(crate) fn goto_definition(
5757
},
5858
ast::Name(name) => {
5959
let def = NameClass::classify(&sema, &name)?.referenced_or_defined(sema.db);
60-
def.try_to_nav(sema.db)
60+
try_find_trait_fn_definition(&sema.db, &def)
61+
.or_else(|| def.try_to_nav(sema.db))
6162
},
6263
ast::Lifetime(lt) => if let Some(name_class) = NameClass::classify_lifetime(&sema, &lt) {
6364
let def = name_class.referenced_or_defined(sema.db);
@@ -99,6 +100,32 @@ fn try_lookup_include_path(
99100
})
100101
}
101102

103+
/// finds the trait definition of an impl'd function
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+
/// ```
110+
fn try_find_trait_fn_definition(db: &RootDatabase, def: &Definition) -> Option<NavigationTarget> {
111+
match def {
112+
Definition::ModuleDef(ModuleDef::Function(f)) => {
113+
let name = def.name(db)?;
114+
let assoc = f.as_assoc_item(db)?;
115+
let imp = match assoc.container(db) {
116+
hir::AssocItemContainer::Impl(imp) => imp,
117+
_ => return None,
118+
};
119+
let trait_ = imp.trait_(db)?;
120+
trait_
121+
.items(db)
122+
.iter()
123+
.find_map(|itm| (itm.name(db)? == name).then(|| itm.try_to_nav(db)).flatten())
124+
}
125+
_ => None,
126+
}
127+
}
128+
102129
fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> {
103130
return tokens.max_by_key(priority);
104131
fn priority(n: &SyntaxToken) -> usize {
@@ -1259,6 +1286,24 @@ fn main() {
12591286
//- /foo.txt
12601287
// empty
12611288
//^ file
1289+
"#,
1290+
);
1291+
}
1292+
1293+
#[test]
1294+
fn goto_def_of_trait_impl_fn() {
1295+
check(
1296+
r#"
1297+
trait Twait {
1298+
fn a();
1299+
// ^
1300+
}
1301+
1302+
struct Stwuct;
1303+
1304+
impl Twait for Stwuct {
1305+
fn a$0();
1306+
}
12621307
"#,
12631308
);
12641309
}

0 commit comments

Comments
 (0)