|
1 |
| -use hir::Semantics; |
| 1 | +use hir::{AsAssocItem, Semantics}; |
2 | 2 | use ide_db::{
|
3 | 3 | defs::{Definition, NameClass, NameRefClass},
|
4 | 4 | RootDatabase,
|
5 | 5 | };
|
6 | 6 | use syntax::{ast, match_ast, AstNode, SyntaxKind::*, T};
|
7 | 7 |
|
8 |
| -use crate::{FilePosition, NavigationTarget, RangeInfo}; |
| 8 | +use crate::{ |
| 9 | + goto_definition::goto_definition, navigation_target::TryToNav, FilePosition, NavigationTarget, |
| 10 | + RangeInfo, |
| 11 | +}; |
9 | 12 |
|
10 | 13 | // Feature: Go to Declaration
|
11 | 14 | //
|
12 | 15 | // Navigates to the declaration of an identifier.
|
13 | 16 | //
|
14 |
| -// This is currently the same as `Go to Definition` with the exception of outline modules where it |
15 |
| -// will navigate to the `mod name;` item declaration. |
| 17 | +// This is the same as `Go to Definition` with the following exceptions: |
| 18 | +// - outline modules will navigate to the `mod name;` item declaration |
| 19 | +// - trait assoc items will navigate to the assoc item of the trait declaration opposed to the trait impl |
16 | 20 | pub(crate) fn goto_declaration(
|
17 | 21 | db: &RootDatabase,
|
18 | 22 | position: FilePosition,
|
@@ -41,16 +45,28 @@ pub(crate) fn goto_declaration(
|
41 | 45 | _ => None
|
42 | 46 | }
|
43 | 47 | };
|
44 |
| - match def? { |
| 48 | + let assoc = match def? { |
45 | 49 | Definition::Module(module) => {
|
46 |
| - Some(NavigationTarget::from_module_to_decl(db, module)) |
| 50 | + return Some(NavigationTarget::from_module_to_decl(db, module)) |
47 | 51 | }
|
| 52 | + Definition::Const(c) => c.as_assoc_item(db), |
| 53 | + Definition::TypeAlias(ta) => ta.as_assoc_item(db), |
| 54 | + Definition::Function(f) => f.as_assoc_item(db), |
48 | 55 | _ => None,
|
49 |
| - } |
| 56 | + }?; |
| 57 | + |
| 58 | + let trait_ = assoc.containing_trait_impl(db)?; |
| 59 | + let name = Some(assoc.name(db)?); |
| 60 | + let item = trait_.items(db).into_iter().find(|it| it.name(db) == name)?; |
| 61 | + item.try_to_nav(db) |
50 | 62 | })
|
51 | 63 | .collect();
|
52 | 64 |
|
53 |
| - Some(RangeInfo::new(range, info)) |
| 65 | + if info.is_empty() { |
| 66 | + goto_definition(db, position) |
| 67 | + } else { |
| 68 | + Some(RangeInfo::new(range, info)) |
| 69 | + } |
54 | 70 | }
|
55 | 71 |
|
56 | 72 | #[cfg(test)]
|
@@ -109,4 +125,62 @@ mod foo {
|
109 | 125 | "#,
|
110 | 126 | )
|
111 | 127 | }
|
| 128 | + |
| 129 | + #[test] |
| 130 | + fn goto_decl_goto_def_fallback() { |
| 131 | + check( |
| 132 | + r#" |
| 133 | +struct Foo; |
| 134 | + // ^^^ |
| 135 | +impl Foo$0 {} |
| 136 | +"#, |
| 137 | + ); |
| 138 | + } |
| 139 | + |
| 140 | + #[test] |
| 141 | + fn goto_decl_assoc_item_no_impl_item() { |
| 142 | + check( |
| 143 | + r#" |
| 144 | +trait Trait { |
| 145 | + const C: () = (); |
| 146 | + // ^ |
| 147 | +} |
| 148 | +impl Trait for () {} |
| 149 | +
|
| 150 | +fn main() { |
| 151 | + <()>::C$0; |
| 152 | +} |
| 153 | +"#, |
| 154 | + ); |
| 155 | + } |
| 156 | + |
| 157 | + #[test] |
| 158 | + fn goto_decl_assoc_item() { |
| 159 | + check( |
| 160 | + r#" |
| 161 | +trait Trait { |
| 162 | + const C: () = (); |
| 163 | + // ^ |
| 164 | +} |
| 165 | +impl Trait for () { |
| 166 | + const C: () = (); |
| 167 | +} |
| 168 | +
|
| 169 | +fn main() { |
| 170 | + <()>::C$0; |
| 171 | +} |
| 172 | +"#, |
| 173 | + ); |
| 174 | + check( |
| 175 | + r#" |
| 176 | +trait Trait { |
| 177 | + const C: () = (); |
| 178 | + // ^ |
| 179 | +} |
| 180 | +impl Trait for () { |
| 181 | + const C$0: () = (); |
| 182 | +} |
| 183 | +"#, |
| 184 | + ); |
| 185 | + } |
112 | 186 | }
|
0 commit comments