aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2021-03-15 14:08:26 +0000
committerGitHub <[email protected]>2021-03-15 14:08:26 +0000
commitf2c39d0cdf708d6178740385f58d6b2b657e411a (patch)
tree83ed009ee98b3c1cfe1cbcc203c1c419c914569e
parent3962b0d53c8da6e3f95f54395d266cb99562bd47 (diff)
parent79561b9d2e901e2624f94ffa7bc6017f0249f23d (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]>
-rw-r--r--crates/hir/src/lib.rs58
-rw-r--r--crates/hir_ty/src/method_resolution.rs10
-rw-r--r--crates/ide/src/goto_implementation.rs130
-rw-r--r--crates/ide/src/inlay_hints.rs2
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};
51use hir_ty::{ 51use 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 @@
1use hir::{Crate, Impl, Semantics}; 1use hir::{Impl, Semantics};
2use ide_db::RootDatabase; 2use ide_db::{
3use syntax::{algo::find_node_at_offset, ast, AstNode}; 3 defs::{Definition, NameClass, NameRefClass},
4 RootDatabase,
5};
6use syntax::{ast, AstNode};
4 7
5use crate::{display::TryToNav, FilePosition, NavigationTarget, RangeInfo}; 8use 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
41fn 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
63fn impls_for_trait( 54fn 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()) 58fn 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#"
224struct Foo;
225
226type Bar$0 = Foo;
227
228impl Foo {}
229 //^^^
230impl Bar {}
231 //^^^
232"#,
233 );
234 }
235
236 #[test]
237 fn goto_implementation_adt_generic() {
238 check(
239 r#"
240struct Foo$0<T>;
241
242impl<T> Foo<T> {}
243 //^^^^^^
244impl 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
255fn foo(_: bool$0) {{}}
256//- /libcore.rs crate:core
257#[lang = "bool"]
258impl 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 }