|
1 | 1 | use std::convert::TryInto;
|
2 | 2 |
|
3 | 3 | use either::Either;
|
4 |
| -use hir::{InFile, Semantics}; |
| 4 | +use hir::{AsAssocItem, InFile, ModuleDef, Semantics}; |
5 | 5 | use ide_db::{
|
6 | 6 | base_db::{AnchoredPath, FileId, FileLoader},
|
7 |
| - defs::{NameClass, NameRefClass}, |
| 7 | + defs::{Definition, NameClass, NameRefClass}, |
8 | 8 | RootDatabase,
|
9 | 9 | };
|
10 | 10 | use syntax::{
|
@@ -57,7 +57,8 @@ pub(crate) fn goto_definition(
|
57 | 57 | },
|
58 | 58 | ast::Name(name) => {
|
59 | 59 | 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)) |
61 | 62 | },
|
62 | 63 | ast::Lifetime(lt) => if let Some(name_class) = NameClass::classify_lifetime(&sema, <) {
|
63 | 64 | let def = name_class.referenced_or_defined(sema.db);
|
@@ -99,6 +100,32 @@ fn try_lookup_include_path(
|
99 | 100 | })
|
100 | 101 | }
|
101 | 102 |
|
| 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 | + |
102 | 129 | fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> {
|
103 | 130 | return tokens.max_by_key(priority);
|
104 | 131 | fn priority(n: &SyntaxToken) -> usize {
|
@@ -1259,6 +1286,24 @@ fn main() {
|
1259 | 1286 | //- /foo.txt
|
1260 | 1287 | // empty
|
1261 | 1288 | //^ 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 | +} |
1262 | 1307 | "#,
|
1263 | 1308 | );
|
1264 | 1309 | }
|
|
0 commit comments