aboutsummaryrefslogtreecommitdiff
path: root/crates/ide/src/goto_definition.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ide/src/goto_definition.rs')
-rw-r--r--crates/ide/src/goto_definition.rs89
1 files changed, 86 insertions, 3 deletions
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}