Skip to content

Commit efa84cd

Browse files
bors[bot]lf-
andauthored
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 <software@lfcode.ca>
2 parents 13da28c + 34ce057 commit efa84cd

File tree

2 files changed

+91
-7
lines changed

2 files changed

+91
-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: 86 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_item_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,34 @@ fn try_lookup_include_path(
99100
})
100101
}
101102

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+
/// ```
110+
fn 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+
102131
fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> {
103132
return tokens.max_by_key(priority);
104133
fn priority(n: &SyntaxToken) -> usize {
@@ -1259,6 +1288,60 @@ fn main() {
12591288
//- /foo.txt
12601289
// empty
12611290
//^ file
1291+
"#,
1292+
);
1293+
}
1294+
1295+
#[test]
1296+
fn goto_def_of_trait_impl_fn() {
1297+
check(
1298+
r#"
1299+
trait Twait {
1300+
fn a();
1301+
// ^
1302+
}
1303+
1304+
struct Stwuct;
1305+
1306+
impl 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#"
1317+
trait Twait {
1318+
const NOMS: bool;
1319+
// ^^^^
1320+
}
1321+
1322+
struct Stwuct;
1323+
1324+
impl 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#"
1335+
trait Twait {
1336+
type IsBad;
1337+
// ^^^^^
1338+
}
1339+
1340+
struct Stwuct;
1341+
1342+
impl Twait for Stwuct {
1343+
type IsBad$0 = !;
1344+
}
12621345
"#,
12631346
);
12641347
}

0 commit comments

Comments
 (0)