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.rs218
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]