aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLukas Wirth <[email protected]>2021-03-15 09:11:48 +0000
committerLukas Wirth <[email protected]>2021-03-15 11:10:18 +0000
commit6c782a53148dc2f34be2eafbdf872ab6497632fd (patch)
tree634e4bc975861908b0c79028eedfcc4e87a2ecfa
parentde360275416ca095102f2b17d6ca1de3bd091fdb (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
-rw-r--r--crates/hir/src/lib.rs53
-rw-r--r--crates/ide/src/goto_implementation.rs130
-rw-r--r--crates/ide/src/inlay_hints.rs2
3 files changed, 123 insertions, 62 deletions
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index eb1cd66fb..a9d3c9156 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -696,8 +696,8 @@ impl Adt {
696 } 696 }
697 } 697 }
698 698
699 pub fn krate(self, db: &dyn HirDatabase) -> Option<Crate> { 699 pub fn krate(self, db: &dyn HirDatabase) -> Crate {
700 Some(self.module(db).krate()) 700 self.module(db).krate()
701 } 701 }
702 702
703 pub fn name(self, db: &dyn HirDatabase) -> Name { 703 pub fn name(self, db: &dyn HirDatabase) -> Name {
@@ -1019,8 +1019,8 @@ impl TypeAlias {
1019 Module { id: self.id.lookup(db.upcast()).module(db.upcast()) } 1019 Module { id: self.id.lookup(db.upcast()).module(db.upcast()) }
1020 } 1020 }
1021 1021
1022 pub fn krate(self, db: &dyn HirDatabase) -> Option<Crate> { 1022 pub fn krate(self, db: &dyn HirDatabase) -> Crate {
1023 Some(self.module(db).krate()) 1023 self.module(db).krate()
1024 } 1024 }
1025 1025
1026 pub fn type_ref(self, db: &dyn HirDatabase) -> Option<TypeRef> { 1026 pub fn type_ref(self, db: &dyn HirDatabase) -> Option<TypeRef> {
@@ -1483,9 +1483,42 @@ impl Impl {
1483 1483
1484 inherent.all_impls().chain(trait_.all_impls()).map(Self::from).collect() 1484 inherent.all_impls().chain(trait_.all_impls()).map(Self::from).collect()
1485 } 1485 }
1486 pub fn for_trait(db: &dyn HirDatabase, krate: Crate, trait_: Trait) -> Vec<Impl> { 1486
1487 let impls = db.trait_impls_in_crate(krate.id); 1487 pub fn all_for_type(db: &dyn HirDatabase, Type { krate, ty }: Type) -> Vec<Impl> {
1488 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![],
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.iter().for_each(|&id| {
1501 all.extend(db.inherent_impls_in_crate(id).all_impls().map(Self::from).filter(filter))
1502 });
1503 for id in def_crates
1504 .iter()
1505 .flat_map(|&id| Crate { id }.reverse_dependencies(db))
1506 .map(|Crate { id }| id)
1507 .chain(def_crates.iter().copied())
1508 {
1509 all.extend(db.trait_impls_in_crate(id).all_impls().map(Self::from).filter(filter));
1510 }
1511 all
1512 }
1513
1514 pub fn all_for_trait(db: &dyn HirDatabase, trait_: Trait) -> Vec<Impl> {
1515 let krate = trait_.module(db).krate();
1516 let mut all = Vec::new();
1517 for Crate { id } in krate.reverse_dependencies(db).into_iter().chain(Some(krate)) {
1518 let impls = db.trait_impls_in_crate(id);
1519 all.extend(impls.for_trait(trait_.id).map(Self::from))
1520 }
1521 all
1489 } 1522 }
1490 1523
1491 // FIXME: the return type is wrong. This should be a hir version of 1524 // FIXME: the return type is wrong. This should be a hir version of
@@ -1913,12 +1946,6 @@ impl Type {
1913 self.ty.value.associated_type_parent_trait(db).map(Into::into) 1946 self.ty.value.associated_type_parent_trait(db).map(Into::into)
1914 } 1947 }
1915 1948
1916 // FIXME: provide required accessors such that it becomes implementable from outside.
1917 pub fn is_equal_for_find_impls(&self, other: &Type) -> bool {
1918 let rref = other.remove_ref();
1919 self.ty.value.equals_ctor(rref.as_ref().map_or(&other.ty.value, |it| &it.ty.value))
1920 }
1921
1922 fn derived(&self, ty: Ty) -> Type { 1949 fn derived(&self, ty: Ty) -> Type {
1923 Type { 1950 Type {
1924 krate: self.krate, 1951 krate: self.krate,
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 }