1 use hir::{Crate, Impl, Semantics};
2 use ide_db::RootDatabase;
3 use syntax::{algo::find_node_at_offset, ast, AstNode};
5 use crate::{display::TryToNav, FilePosition, NavigationTarget, RangeInfo};
7 // Feature: Go to Implementation
9 // Navigates to the impl block of structs, enums or traits. Also implemented as a code lens.
12 // | Editor | Shortcut
14 // | VS Code | kbd:[Ctrl+F12]
16 pub(crate) fn goto_implementation(
18 position: FilePosition,
19 ) -> Option<RangeInfo<Vec<NavigationTarget>>> {
20 let sema = Semantics::new(db);
21 let source_file = sema.parse(position.file_id);
22 let syntax = source_file.syntax().clone();
24 let krate = sema.to_module_def(position.file_id)?.krate();
26 if let Some(nominal_def) = find_node_at_offset::<ast::AdtDef>(&syntax, position.offset) {
27 return Some(RangeInfo::new(
28 nominal_def.syntax().text_range(),
29 impls_for_def(&sema, &nominal_def, krate)?,
31 } else if let Some(trait_def) = find_node_at_offset::<ast::Trait>(&syntax, position.offset) {
32 return Some(RangeInfo::new(
33 trait_def.syntax().text_range(),
34 impls_for_trait(&sema, &trait_def, krate)?,
42 sema: &Semantics<RootDatabase>,
45 ) -> Option<Vec<NavigationTarget>> {
47 ast::AdtDef::Struct(def) => sema.to_def(def)?.ty(sema.db),
48 ast::AdtDef::Enum(def) => sema.to_def(def)?.ty(sema.db),
49 ast::AdtDef::Union(def) => sema.to_def(def)?.ty(sema.db),
52 let impls = Impl::all_in_crate(sema.db, krate);
57 .filter(|impl_def| ty.is_equal_for_find_impls(&impl_def.target_ty(sema.db)))
58 .filter_map(|imp| imp.try_to_nav(sema.db))
64 sema: &Semantics<RootDatabase>,
67 ) -> Option<Vec<NavigationTarget>> {
68 let tr = sema.to_def(node)?;
70 let impls = Impl::for_trait(sema.db, krate, tr);
72 Some(impls.into_iter().filter_map(|imp| imp.try_to_nav(sema.db)).collect())
77 use ide_db::base_db::FileRange;
81 fn check(ra_fixture: &str) {
82 let (analysis, position, annotations) = fixture::annotations(ra_fixture);
84 let navs = analysis.goto_implementation(position).unwrap().unwrap().info;
86 let key = |frange: &FileRange| (frange.file_id, frange.range.start());
88 let mut expected = annotations
90 .map(|(range, data)| {
91 assert!(data.is_empty());
95 expected.sort_by_key(key);
99 .map(|nav| FileRange { file_id: nav.file_id, range: nav.focus_or_full_range() })
100 .collect::<Vec<_>>();
101 actual.sort_by_key(key);
103 assert_eq!(expected, actual);
107 fn goto_implementation_works() {
118 fn goto_implementation_works_multiple_blocks() {
131 fn goto_implementation_works_multiple_mods() {
148 fn goto_implementation_works_multiple_files() {
166 fn goto_implementation_for_trait() {
178 fn goto_implementation_for_trait_multiple_files() {
187 impl crate::T for crate::Foo {}
190 impl crate::T for crate::Foo {}
197 fn goto_implementation_all_impls() {
214 fn goto_implementation_to_builtin_derive() {
224 #[rustc_builtin_macro]