]> git.lizzy.rs Git - rust.git/blobdiff - crates/ide/src/goto_implementation.rs
Explicitly check for reference locals or fields in Name classification
[rust.git] / crates / ide / src / goto_implementation.rs
index f4d7c14a62e11c2cd48db7865c9cc203fe6cd060..d1101230452f7b5a3f25d57446c87a61997cf223 100644 (file)
@@ -1,4 +1,4 @@
-use hir::{Impl, Semantics};
+use hir::{AsAssocItem, Impl, Semantics};
 use ide_db::{
     defs::{Definition, NameClass, NameRefClass},
     RootDatabase,
@@ -16,6 +16,8 @@
 //
 // | VS Code | kbd:[Ctrl+F12]
 // |===
+//
+// image::https://user-images.githubusercontent.com/48062697/113065566-02f85480-91b1-11eb-9288-aaad8abd8841.gif[]
 pub(crate) fn goto_implementation(
     db: &RootDatabase,
     position: FilePosition,
@@ -27,13 +29,14 @@ pub(crate) fn goto_implementation(
     let node = sema.find_node_at_offset_with_descend(&syntax, position.offset)?;
     let def = match &node {
         ast::NameLike::Name(name) => {
-            NameClass::classify(&sema, name).map(|class| class.referenced_or_defined(sema.db))
+            NameClass::classify(&sema, name).map(|class| class.defined_or_referenced_local())
         }
         ast::NameLike::NameRef(name_ref) => {
-            NameRefClass::classify(&sema, name_ref).map(|class| class.referenced(sema.db))
+            NameRefClass::classify(&sema, name_ref).map(|class| class.referenced_local())
         }
         ast::NameLike::Lifetime(_) => None,
     }?;
+
     let def = match def {
         Definition::ModuleDef(def) => def,
         _ => return None,
@@ -46,6 +49,18 @@ pub(crate) fn goto_implementation(
             let module = sema.to_module_def(position.file_id)?;
             impls_for_ty(&sema, builtin.ty(sema.db, module))
         }
+        hir::ModuleDef::Function(f) => {
+            let assoc = f.as_assoc_item(sema.db)?;
+            let name = assoc.name(sema.db)?;
+            let trait_ = assoc.containing_trait_or_trait_impl(sema.db)?;
+            impls_for_trait_item(&sema, trait_, name)
+        }
+        hir::ModuleDef::Const(c) => {
+            let assoc = c.as_assoc_item(sema.db)?;
+            let name = assoc.name(sema.db)?;
+            let trait_ = assoc.containing_trait_or_trait_impl(sema.db)?;
+            impls_for_trait_item(&sema, trait_, name)
+        }
         _ => return None,
     };
     Some(RangeInfo { range: node.syntax().text_range(), info: navs })
@@ -62,6 +77,23 @@ fn impls_for_trait(sema: &Semantics<RootDatabase>, trait_: hir::Trait) -> Vec<Na
         .collect()
 }
 
+fn impls_for_trait_item(
+    sema: &Semantics<RootDatabase>,
+    trait_: hir::Trait,
+    fun_name: hir::Name,
+) -> Vec<NavigationTarget> {
+    Impl::all_for_trait(sema.db, trait_)
+        .into_iter()
+        .filter_map(|imp| {
+            let item = imp.items(sema.db).iter().find_map(|itm| {
+                let itm_name = itm.name(sema.db)?;
+                (itm_name == fun_name).then(|| *itm)
+            })?;
+            item.try_to_nav(sema.db)
+        })
+        .collect()
+}
+
 #[cfg(test)]
 mod tests {
     use ide_db::base_db::FileRange;
@@ -204,15 +236,10 @@ impl T for &Foo {}
     fn goto_implementation_to_builtin_derive() {
         check(
             r#"
+//- minicore: copy, derive
   #[derive(Copy)]
 //^^^^^^^^^^^^^^^
 struct Foo$0;
-
-mod marker {
-    trait Copy {}
-}
-#[rustc_builtin_macro]
-macro Copy {}
 "#,
         );
     }
@@ -257,6 +284,44 @@ fn foo(_: bool$0) {{}}
 #[lang = "bool"]
 impl bool {}
    //^^^^
+"#,
+        );
+    }
+
+    #[test]
+    fn goto_implementation_trait_functions() {
+        check(
+            r#"
+trait Tr {
+    fn f$0();
+}
+
+struct S;
+
+impl Tr for S {
+    fn f() {
+     //^
+        println!("Hello, world!");
+    }
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn goto_implementation_trait_assoc_const() {
+        check(
+            r#"
+trait Tr {
+    const C$0: usize;
+}
+
+struct S;
+
+impl Tr for S {
+    const C: usize = 4;
+        //^
+}
 "#,
         );
     }