Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/ide/src/goto_definition.rs')
| -rw-r--r-- | crates/ide/src/goto_definition.rs | 218 |
1 files changed, 189 insertions, 29 deletions
diff --git a/crates/ide/src/goto_definition.rs b/crates/ide/src/goto_definition.rs index df73879aed..e10789fd47 100644 --- a/crates/ide/src/goto_definition.rs +++ b/crates/ide/src/goto_definition.rs @@ -1,7 +1,7 @@ -use std::convert::TryInto; +use std::{convert::TryInto, mem::discriminant}; use crate::{doc_links::token_as_doc_comment, FilePosition, NavigationTarget, RangeInfo, TryToNav}; -use hir::{AsAssocItem, Semantics}; +use hir::{AsAssocItem, AssocItem, Semantics}; use ide_db::{ base_db::{AnchoredPath, FileId, FileLoader}, defs::{Definition, IdentClass}, @@ -65,7 +65,7 @@ pub(crate) fn goto_definition( .definitions() .into_iter() .flat_map(|def| { - try_find_trait_item_definition(sema.db, &def) + try_filter_trait_item_definition(sema, &def) .unwrap_or_else(|| def_to_nav(sema.db, def)) }) .collect(), @@ -104,32 +104,37 @@ fn try_lookup_include_path( docs: None, }) } - -/// finds the trait definition of an impl'd item +/// finds the trait definition of an impl'd item, except function /// e.g. /// ```rust -/// trait A { fn a(); } +/// trait A { type a; } /// struct S; -/// impl A for S { fn a(); } // <-- on this function, will get the location of a() in the trait +/// impl A for S { type a = i32; } // <-- on this associate type, will get the location of a in the trait /// ``` -fn try_find_trait_item_definition( - db: &RootDatabase, +fn try_filter_trait_item_definition( + sema: &Semantics<RootDatabase>, def: &Definition, ) -> Option<Vec<NavigationTarget>> { - let name = def.name(db)?; + let db = sema.db; let assoc = def.as_assoc_item(db)?; - - let imp = match assoc.container(db) { - hir::AssocItemContainer::Impl(imp) => imp, - _ => return None, - }; - - let trait_ = imp.trait_(db)?; - trait_ - .items(db) - .iter() - .find_map(|itm| (itm.name(db)? == name).then(|| itm.try_to_nav(db)).flatten()) - .map(|it| vec![it]) + match assoc { + AssocItem::Function(..) => None, + AssocItem::Const(..) | AssocItem::TypeAlias(..) => { + let imp = match assoc.container(db) { + hir::AssocItemContainer::Impl(imp) => imp, + _ => return None, + }; + let trait_ = imp.trait_(db)?; + let name = def.name(db)?; + let discri_value = discriminant(&assoc); + trait_ + .items(db) + .iter() + .filter(|itm| discriminant(*itm) == discri_value) + .find_map(|itm| (itm.name(db)? == name).then(|| itm.try_to_nav(db)).flatten()) + .map(|it| vec![it]) + } + } } fn def_to_nav(db: &RootDatabase, def: Definition) -> Vec<NavigationTarget> { @@ -173,6 +178,23 @@ mod tests { } #[test] + fn goto_def_if_items_same_name() { + check( + r#" +trait Trait { + type A; + const A: i32; + //^ +} + +struct T; +impl Trait for T { + type A = i32; + const A$0: i32 = -9; +}"#, + ); + } + #[test] fn goto_def_in_mac_call_in_attr_invoc() { check( r#" @@ -1331,23 +1353,161 @@ fn main() { "#, ); } - - #[test] - fn goto_def_of_trait_impl_fn() { - check( - r#" + #[cfg(test)] + mod goto_impl_of_trait_fn { + use super::check; + #[test] + fn cursor_on_impl() { + check( + r#" trait Twait { fn a(); - // ^ } struct Stwuct; impl Twait for Stwuct { fn a$0(); + //^ +} + "#, + ); + } + #[test] + fn method_call() { + check( + r#" +trait Twait { + fn a(&self); +} + +struct Stwuct; + +impl Twait for Stwuct { + fn a(&self){}; + //^ +} +fn f() { + let s = Stwuct; + s.a$0(); +} + "#, + ); + } + #[test] + fn path_call() { + check( + r#" +trait Twait { + fn a(&self); +} + +struct Stwuct; + +impl Twait for Stwuct { + fn a(&self){}; + //^ +} +fn f() { + let s = Stwuct; + Stwuct::a$0(&s); +} + "#, + ); + } + #[test] + fn where_clause_can_work() { + check( + r#" +trait G { + fn g(&self); +} +trait Bound{} +trait EA{} +struct Gen<T>(T); +impl <T:EA> G for Gen<T> { + fn g(&self) { + } +} +impl <T> G for Gen<T> +where T : Bound +{ + fn g(&self){ + //^ + } +} +struct A; +impl Bound for A{} +fn f() { + let gen = Gen::<A>(A); + gen.g$0(); +} + "#, + ); + } + #[test] + fn wc_case_is_ok() { + check( + r#" +trait G { + fn g(&self); +} +trait BParent{} +trait Bound: BParent{} +struct Gen<T>(T); +impl <T> G for Gen<T> +where T : Bound +{ + fn g(&self){ + //^ + } +} +struct A; +impl Bound for A{} +fn f() { + let gen = Gen::<A>(A); + gen.g$0(); } "#, - ); + ); + } + + #[test] + fn method_call_defaulted() { + check( + r#" +trait Twait { + fn a(&self) {} + //^ +} + +struct Stwuct; + +impl Twait for Stwuct { +} +fn f() { + let s = Stwuct; + s.a$0(); +} + "#, + ); + } + + #[test] + fn method_call_on_generic() { + check( + r#" +trait Twait { + fn a(&self) {} + //^ +} + +fn f<T: Twait>(s: T) { + s.a$0(); +} + "#, + ); + } } #[test] |