diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2021-03-15 14:08:26 +0000 |
---|---|---|
committer | GitHub <[email protected]> | 2021-03-15 14:08:26 +0000 |
commit | f2c39d0cdf708d6178740385f58d6b2b657e411a (patch) | |
tree | 83ed009ee98b3c1cfe1cbcc203c1c419c914569e /crates | |
parent | 3962b0d53c8da6e3f95f54395d266cb99562bd47 (diff) | |
parent | 79561b9d2e901e2624f94ffa7bc6017f0249f23d (diff) |
Merge #8020
8020: Power up goto_implementation r=matklad a=Veykril
by allowing it to be invoked on references of names, now showing all (trait)
implementations of the given type in all crates instead of just the defining
crate as well as including support for builtin types
![image](https://user-images.githubusercontent.com/3757771/111144403-52bb0700-8587-11eb-9205-7a2a5b8b75a3.png)
Example screenshot of `impl`s of Box in `log`, `alloc`, `std` and the current crate. Before you had to invoke it on the definition where it would only show the `impls` in `alloc`.
Co-authored-by: Lukas Wirth <[email protected]>
Diffstat (limited to 'crates')
-rw-r--r-- | crates/hir/src/lib.rs | 58 | ||||
-rw-r--r-- | crates/hir_ty/src/method_resolution.rs | 10 | ||||
-rw-r--r-- | crates/ide/src/goto_implementation.rs | 130 | ||||
-rw-r--r-- | crates/ide/src/inlay_hints.rs | 2 |
4 files changed, 136 insertions, 64 deletions
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 25e5bfb01..c5161dadd 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs | |||
@@ -51,7 +51,8 @@ use hir_expand::{diagnostics::DiagnosticSink, name::name, MacroDefKind}; | |||
51 | use hir_ty::{ | 51 | use hir_ty::{ |
52 | autoderef, | 52 | autoderef, |
53 | display::{write_bounds_like_dyn_trait_with_prefix, HirDisplayError, HirFormatter}, | 53 | display::{write_bounds_like_dyn_trait_with_prefix, HirDisplayError, HirFormatter}, |
54 | method_resolution, to_assoc_type_id, | 54 | method_resolution::{self, TyFingerprint}, |
55 | to_assoc_type_id, | ||
55 | traits::{FnTrait, Solution, SolutionVariables}, | 56 | traits::{FnTrait, Solution, SolutionVariables}, |
56 | AliasTy, BoundVar, CallableDefId, CallableSig, Canonical, DebruijnIndex, GenericPredicate, | 57 | AliasTy, BoundVar, CallableDefId, CallableSig, Canonical, DebruijnIndex, GenericPredicate, |
57 | InEnvironment, Interner, Obligation, ProjectionPredicate, ProjectionTy, Scalar, Substs, Ty, | 58 | InEnvironment, Interner, Obligation, ProjectionPredicate, ProjectionTy, Scalar, Substs, Ty, |
@@ -695,8 +696,8 @@ impl Adt { | |||
695 | } | 696 | } |
696 | } | 697 | } |
697 | 698 | ||
698 | pub fn krate(self, db: &dyn HirDatabase) -> Option<Crate> { | 699 | pub fn krate(self, db: &dyn HirDatabase) -> Crate { |
699 | Some(self.module(db).krate()) | 700 | self.module(db).krate() |
700 | } | 701 | } |
701 | 702 | ||
702 | pub fn name(self, db: &dyn HirDatabase) -> Name { | 703 | pub fn name(self, db: &dyn HirDatabase) -> Name { |
@@ -1018,8 +1019,8 @@ impl TypeAlias { | |||
1018 | Module { id: self.id.lookup(db.upcast()).module(db.upcast()) } | 1019 | Module { id: self.id.lookup(db.upcast()).module(db.upcast()) } |
1019 | } | 1020 | } |
1020 | 1021 | ||
1021 | pub fn krate(self, db: &dyn HirDatabase) -> Option<Crate> { | 1022 | pub fn krate(self, db: &dyn HirDatabase) -> Crate { |
1022 | Some(self.module(db).krate()) | 1023 | self.module(db).krate() |
1023 | } | 1024 | } |
1024 | 1025 | ||
1025 | pub fn type_ref(self, db: &dyn HirDatabase) -> Option<TypeRef> { | 1026 | pub fn type_ref(self, db: &dyn HirDatabase) -> Option<TypeRef> { |
@@ -1482,9 +1483,44 @@ impl Impl { | |||
1482 | 1483 | ||
1483 | inherent.all_impls().chain(trait_.all_impls()).map(Self::from).collect() | 1484 | inherent.all_impls().chain(trait_.all_impls()).map(Self::from).collect() |
1484 | } | 1485 | } |
1485 | pub fn for_trait(db: &dyn HirDatabase, krate: Crate, trait_: Trait) -> Vec<Impl> { | 1486 | |
1486 | let impls = db.trait_impls_in_crate(krate.id); | 1487 | pub fn all_for_type(db: &dyn HirDatabase, Type { krate, ty }: Type) -> Vec<Impl> { |
1487 | impls.for_trait(trait_.id).map(Self::from).collect() | 1488 | let def_crates = match ty.value.def_crates(db, krate) { |
1489 | Some(def_crates) => def_crates, | ||
1490 | None => return Vec::new(), | ||
1491 | }; | ||
1492 | |||
1493 | let filter = |impl_def: &Impl| { | ||
1494 | let target_ty = impl_def.target_ty(db); | ||
1495 | let rref = target_ty.remove_ref(); | ||
1496 | ty.value.equals_ctor(rref.as_ref().map_or(&target_ty.ty.value, |it| &it.ty.value)) | ||
1497 | }; | ||
1498 | |||
1499 | let mut all = Vec::new(); | ||
1500 | def_crates.into_iter().for_each(|id| { | ||
1501 | all.extend(db.inherent_impls_in_crate(id).all_impls().map(Self::from).filter(filter)) | ||
1502 | }); | ||
1503 | let fp = TyFingerprint::for_impl(&ty.value); | ||
1504 | for id in db.crate_graph().iter() { | ||
1505 | match fp { | ||
1506 | Some(fp) => all.extend( | ||
1507 | db.trait_impls_in_crate(id).for_self_ty(fp).map(Self::from).filter(filter), | ||
1508 | ), | ||
1509 | None => all | ||
1510 | .extend(db.trait_impls_in_crate(id).all_impls().map(Self::from).filter(filter)), | ||
1511 | } | ||
1512 | } | ||
1513 | all | ||
1514 | } | ||
1515 | |||
1516 | pub fn all_for_trait(db: &dyn HirDatabase, trait_: Trait) -> Vec<Impl> { | ||
1517 | let krate = trait_.module(db).krate(); | ||
1518 | let mut all = Vec::new(); | ||
1519 | for Crate { id } in krate.reverse_dependencies(db).into_iter().chain(Some(krate)) { | ||
1520 | let impls = db.trait_impls_in_crate(id); | ||
1521 | all.extend(impls.for_trait(trait_.id).map(Self::from)) | ||
1522 | } | ||
1523 | all | ||
1488 | } | 1524 | } |
1489 | 1525 | ||
1490 | // FIXME: the return type is wrong. This should be a hir version of | 1526 | // FIXME: the return type is wrong. This should be a hir version of |
@@ -1932,12 +1968,6 @@ impl Type { | |||
1932 | self.ty.value.associated_type_parent_trait(db).map(Into::into) | 1968 | self.ty.value.associated_type_parent_trait(db).map(Into::into) |
1933 | } | 1969 | } |
1934 | 1970 | ||
1935 | // FIXME: provide required accessors such that it becomes implementable from outside. | ||
1936 | pub fn is_equal_for_find_impls(&self, other: &Type) -> bool { | ||
1937 | let rref = other.remove_ref(); | ||
1938 | self.ty.value.equals_ctor(rref.as_ref().map_or(&other.ty.value, |it| &it.ty.value)) | ||
1939 | } | ||
1940 | |||
1941 | fn derived(&self, ty: Ty) -> Type { | 1971 | fn derived(&self, ty: Ty) -> Type { |
1942 | Type { | 1972 | Type { |
1943 | krate: self.krate, | 1973 | krate: self.krate, |
diff --git a/crates/hir_ty/src/method_resolution.rs b/crates/hir_ty/src/method_resolution.rs index 741440006..be72c4a1c 100644 --- a/crates/hir_ty/src/method_resolution.rs +++ b/crates/hir_ty/src/method_resolution.rs | |||
@@ -44,7 +44,7 @@ impl TyFingerprint { | |||
44 | /// Creates a TyFingerprint for looking up an impl. Only certain types can | 44 | /// Creates a TyFingerprint for looking up an impl. Only certain types can |
45 | /// have impls: if we have some `struct S`, we can have an `impl S`, but not | 45 | /// have impls: if we have some `struct S`, we can have an `impl S`, but not |
46 | /// `impl &S`. Hence, this will return `None` for reference types and such. | 46 | /// `impl &S`. Hence, this will return `None` for reference types and such. |
47 | pub(crate) fn for_impl(ty: &Ty) -> Option<TyFingerprint> { | 47 | pub fn for_impl(ty: &Ty) -> Option<TyFingerprint> { |
48 | let fp = match *ty.interned(&Interner) { | 48 | let fp = match *ty.interned(&Interner) { |
49 | TyKind::Str => TyFingerprint::Str, | 49 | TyKind::Str => TyFingerprint::Str, |
50 | TyKind::Never => TyFingerprint::Never, | 50 | TyKind::Never => TyFingerprint::Never, |
@@ -141,6 +141,14 @@ impl TraitImpls { | |||
141 | } | 141 | } |
142 | } | 142 | } |
143 | 143 | ||
144 | /// Queries all trait impls for the given type. | ||
145 | pub fn for_self_ty(&self, fp: TyFingerprint) -> impl Iterator<Item = ImplId> + '_ { | ||
146 | self.map | ||
147 | .values() | ||
148 | .flat_map(move |impls| impls.get(&None).into_iter().chain(impls.get(&Some(fp)))) | ||
149 | .flat_map(|it| it.iter().copied()) | ||
150 | } | ||
151 | |||
144 | /// Queries all impls of the given trait. | 152 | /// Queries all impls of the given trait. |
145 | pub fn for_trait(&self, trait_: TraitId) -> impl Iterator<Item = ImplId> + '_ { | 153 | pub fn for_trait(&self, trait_: TraitId) -> impl Iterator<Item = ImplId> + '_ { |
146 | self.map | 154 | self.map |
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 | } |