diff options
author | Lukas Wirth <[email protected]> | 2021-03-15 09:11:48 +0000 |
---|---|---|
committer | Lukas Wirth <[email protected]> | 2021-03-15 11:10:18 +0000 |
commit | 6c782a53148dc2f34be2eafbdf872ab6497632fd (patch) | |
tree | 634e4bc975861908b0c79028eedfcc4e87a2ecfa /crates/ide/src | |
parent | de360275416ca095102f2b17d6ca1de3bd091fdb (diff) |
Power up goto_implementation
by allowing it to be invoked on references of names, showing all (trait)
implementations of the given type in all crates including builtin types
Diffstat (limited to 'crates/ide/src')
-rw-r--r-- | crates/ide/src/goto_implementation.rs | 130 | ||||
-rw-r--r-- | crates/ide/src/inlay_hints.rs | 2 |
2 files changed, 83 insertions, 49 deletions
diff --git a/crates/ide/src/goto_implementation.rs b/crates/ide/src/goto_implementation.rs index 3990305fc..f4d7c14a6 100644 --- a/crates/ide/src/goto_implementation.rs +++ b/crates/ide/src/goto_implementation.rs | |||
@@ -1,6 +1,9 @@ | |||
1 | use hir::{Crate, Impl, Semantics}; | 1 | use hir::{Impl, Semantics}; |
2 | use ide_db::RootDatabase; | 2 | use ide_db::{ |
3 | use syntax::{algo::find_node_at_offset, ast, AstNode}; | 3 | defs::{Definition, NameClass, NameRefClass}, |
4 | RootDatabase, | ||
5 | }; | ||
6 | use syntax::{ast, AstNode}; | ||
4 | 7 | ||
5 | use crate::{display::TryToNav, FilePosition, NavigationTarget, RangeInfo}; | 8 | use crate::{display::TryToNav, FilePosition, NavigationTarget, RangeInfo}; |
6 | 9 | ||
@@ -21,55 +24,42 @@ pub(crate) fn goto_implementation( | |||
21 | let source_file = sema.parse(position.file_id); | 24 | let source_file = sema.parse(position.file_id); |
22 | let syntax = source_file.syntax().clone(); | 25 | let syntax = source_file.syntax().clone(); |
23 | 26 | ||
24 | let krate = sema.to_module_def(position.file_id)?.krate(); | 27 | let node = sema.find_node_at_offset_with_descend(&syntax, position.offset)?; |
25 | 28 | let def = match &node { | |
26 | if let Some(nominal_def) = find_node_at_offset::<ast::Adt>(&syntax, position.offset) { | 29 | ast::NameLike::Name(name) => { |
27 | return Some(RangeInfo::new( | 30 | NameClass::classify(&sema, name).map(|class| class.referenced_or_defined(sema.db)) |
28 | nominal_def.syntax().text_range(), | 31 | } |
29 | impls_for_def(&sema, &nominal_def, krate)?, | 32 | ast::NameLike::NameRef(name_ref) => { |
30 | )); | 33 | NameRefClass::classify(&sema, name_ref).map(|class| class.referenced(sema.db)) |
31 | } else if let Some(trait_def) = find_node_at_offset::<ast::Trait>(&syntax, position.offset) { | 34 | } |
32 | return Some(RangeInfo::new( | 35 | ast::NameLike::Lifetime(_) => None, |
33 | trait_def.syntax().text_range(), | 36 | }?; |
34 | impls_for_trait(&sema, &trait_def, krate)?, | 37 | let def = match def { |
35 | )); | 38 | Definition::ModuleDef(def) => def, |
36 | } | 39 | _ => return None, |
37 | |||
38 | None | ||
39 | } | ||
40 | |||
41 | fn impls_for_def( | ||
42 | sema: &Semantics<RootDatabase>, | ||
43 | node: &ast::Adt, | ||
44 | krate: Crate, | ||
45 | ) -> Option<Vec<NavigationTarget>> { | ||
46 | let ty = match node { | ||
47 | ast::Adt::Struct(def) => sema.to_def(def)?.ty(sema.db), | ||
48 | ast::Adt::Enum(def) => sema.to_def(def)?.ty(sema.db), | ||
49 | ast::Adt::Union(def) => sema.to_def(def)?.ty(sema.db), | ||
50 | }; | 40 | }; |
51 | 41 | let navs = match def { | |
52 | let impls = Impl::all_in_crate(sema.db, krate); | 42 | hir::ModuleDef::Trait(trait_) => impls_for_trait(&sema, trait_), |
53 | 43 | hir::ModuleDef::Adt(adt) => impls_for_ty(&sema, adt.ty(sema.db)), | |
54 | Some( | 44 | hir::ModuleDef::TypeAlias(alias) => impls_for_ty(&sema, alias.ty(sema.db)), |
55 | impls | 45 | hir::ModuleDef::BuiltinType(builtin) => { |
56 | .into_iter() | 46 | let module = sema.to_module_def(position.file_id)?; |
57 | .filter(|impl_def| ty.is_equal_for_find_impls(&impl_def.target_ty(sema.db))) | 47 | impls_for_ty(&sema, builtin.ty(sema.db, module)) |
58 | .filter_map(|imp| imp.try_to_nav(sema.db)) | 48 | } |
59 | .collect(), | 49 | _ => return None, |
60 | ) | 50 | }; |
51 | Some(RangeInfo { range: node.syntax().text_range(), info: navs }) | ||
61 | } | 52 | } |
62 | 53 | ||
63 | fn impls_for_trait( | 54 | fn impls_for_ty(sema: &Semantics<RootDatabase>, ty: hir::Type) -> Vec<NavigationTarget> { |
64 | sema: &Semantics<RootDatabase>, | 55 | Impl::all_for_type(sema.db, ty).into_iter().filter_map(|imp| imp.try_to_nav(sema.db)).collect() |
65 | node: &ast::Trait, | 56 | } |
66 | krate: Crate, | ||
67 | ) -> Option<Vec<NavigationTarget>> { | ||
68 | let tr = sema.to_def(node)?; | ||
69 | |||
70 | let impls = Impl::for_trait(sema.db, krate, tr); | ||
71 | 57 | ||
72 | Some(impls.into_iter().filter_map(|imp| imp.try_to_nav(sema.db)).collect()) | 58 | fn impls_for_trait(sema: &Semantics<RootDatabase>, trait_: hir::Trait) -> Vec<NavigationTarget> { |
59 | Impl::all_for_trait(sema.db, trait_) | ||
60 | .into_iter() | ||
61 | .filter_map(|imp| imp.try_to_nav(sema.db)) | ||
62 | .collect() | ||
73 | } | 63 | } |
74 | 64 | ||
75 | #[cfg(test)] | 65 | #[cfg(test)] |
@@ -226,4 +216,48 @@ macro Copy {} | |||
226 | "#, | 216 | "#, |
227 | ); | 217 | ); |
228 | } | 218 | } |
219 | |||
220 | #[test] | ||
221 | fn goto_implementation_type_alias() { | ||
222 | check( | ||
223 | r#" | ||
224 | struct Foo; | ||
225 | |||
226 | type Bar$0 = Foo; | ||
227 | |||
228 | impl Foo {} | ||
229 | //^^^ | ||
230 | impl Bar {} | ||
231 | //^^^ | ||
232 | "#, | ||
233 | ); | ||
234 | } | ||
235 | |||
236 | #[test] | ||
237 | fn goto_implementation_adt_generic() { | ||
238 | check( | ||
239 | r#" | ||
240 | struct Foo$0<T>; | ||
241 | |||
242 | impl<T> Foo<T> {} | ||
243 | //^^^^^^ | ||
244 | impl Foo<str> {} | ||
245 | //^^^^^^^^ | ||
246 | "#, | ||
247 | ); | ||
248 | } | ||
249 | |||
250 | #[test] | ||
251 | fn goto_implementation_builtin() { | ||
252 | check( | ||
253 | r#" | ||
254 | //- /lib.rs crate:main deps:core | ||
255 | fn foo(_: bool$0) {{}} | ||
256 | //- /libcore.rs crate:core | ||
257 | #[lang = "bool"] | ||
258 | impl bool {} | ||
259 | //^^^^ | ||
260 | "#, | ||
261 | ); | ||
262 | } | ||
229 | } | 263 | } |
diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs index 4ceb20742..16c04eeee 100644 --- a/crates/ide/src/inlay_hints.rs +++ b/crates/ide/src/inlay_hints.rs | |||
@@ -219,7 +219,7 @@ fn hint_iterator( | |||
219 | let strukt = std::iter::successors(Some(ty.clone()), |ty| ty.remove_ref()) | 219 | let strukt = std::iter::successors(Some(ty.clone()), |ty| ty.remove_ref()) |
220 | .last() | 220 | .last() |
221 | .and_then(|strukt| strukt.as_adt())?; | 221 | .and_then(|strukt| strukt.as_adt())?; |
222 | let krate = strukt.krate(db)?; | 222 | let krate = strukt.krate(db); |
223 | if krate != famous_defs.core()? { | 223 | if krate != famous_defs.core()? { |
224 | return None; | 224 | return None; |
225 | } | 225 | } |