}
}
- pub fn krate(self, db: &dyn HirDatabase) -> Option<Crate> {
- Some(self.module(db).krate())
+ pub fn krate(self, db: &dyn HirDatabase) -> Crate {
+ self.module(db).krate()
}
pub fn name(self, db: &dyn HirDatabase) -> Name {
Module { id: self.id.lookup(db.upcast()).module(db.upcast()) }
}
- pub fn krate(self, db: &dyn HirDatabase) -> Option<Crate> {
- Some(self.module(db).krate())
+ pub fn krate(self, db: &dyn HirDatabase) -> Crate {
+ self.module(db).krate()
}
pub fn type_ref(self, db: &dyn HirDatabase) -> Option<TypeRef> {
inherent.all_impls().chain(trait_.all_impls()).map(Self::from).collect()
}
- pub fn for_trait(db: &dyn HirDatabase, krate: Crate, trait_: Trait) -> Vec<Impl> {
- let impls = db.trait_impls_in_crate(krate.id);
- impls.for_trait(trait_.id).map(Self::from).collect()
+
+ pub fn all_for_type(db: &dyn HirDatabase, Type { krate, ty }: Type) -> Vec<Impl> {
+ let def_crates = match ty.value.def_crates(db, krate) {
+ Some(def_crates) => def_crates,
+ None => return vec![],
+ };
+
+ let filter = |impl_def: &Impl| {
+ let target_ty = impl_def.target_ty(db);
+ let rref = target_ty.remove_ref();
+ ty.value.equals_ctor(rref.as_ref().map_or(&target_ty.ty.value, |it| &it.ty.value))
+ };
+
+ let mut all = Vec::new();
+ def_crates.iter().for_each(|&id| {
+ all.extend(db.inherent_impls_in_crate(id).all_impls().map(Self::from).filter(filter))
+ });
+ for id in def_crates
+ .iter()
+ .flat_map(|&id| Crate { id }.reverse_dependencies(db))
+ .map(|Crate { id }| id)
+ .chain(def_crates.iter().copied())
+ {
+ all.extend(db.trait_impls_in_crate(id).all_impls().map(Self::from).filter(filter));
+ }
+ all
+ }
+
+ pub fn all_for_trait(db: &dyn HirDatabase, trait_: Trait) -> Vec<Impl> {
+ let krate = trait_.module(db).krate();
+ let mut all = Vec::new();
+ for Crate { id } in krate.reverse_dependencies(db).into_iter().chain(Some(krate)) {
+ let impls = db.trait_impls_in_crate(id);
+ all.extend(impls.for_trait(trait_.id).map(Self::from))
+ }
+ all
}
// FIXME: the return type is wrong. This should be a hir version of
self.ty.value.associated_type_parent_trait(db).map(Into::into)
}
- // FIXME: provide required accessors such that it becomes implementable from outside.
- pub fn is_equal_for_find_impls(&self, other: &Type) -> bool {
- let rref = other.remove_ref();
- self.ty.value.equals_ctor(rref.as_ref().map_or(&other.ty.value, |it| &it.ty.value))
- }
-
fn derived(&self, ty: Ty) -> Type {
Type {
krate: self.krate,
-use hir::{Crate, Impl, Semantics};
-use ide_db::RootDatabase;
-use syntax::{algo::find_node_at_offset, ast, AstNode};
+use hir::{Impl, Semantics};
+use ide_db::{
+ defs::{Definition, NameClass, NameRefClass},
+ RootDatabase,
+};
+use syntax::{ast, AstNode};
use crate::{display::TryToNav, FilePosition, NavigationTarget, RangeInfo};
let source_file = sema.parse(position.file_id);
let syntax = source_file.syntax().clone();
- let krate = sema.to_module_def(position.file_id)?.krate();
-
- if let Some(nominal_def) = find_node_at_offset::<ast::Adt>(&syntax, position.offset) {
- return Some(RangeInfo::new(
- nominal_def.syntax().text_range(),
- impls_for_def(&sema, &nominal_def, krate)?,
- ));
- } else if let Some(trait_def) = find_node_at_offset::<ast::Trait>(&syntax, position.offset) {
- return Some(RangeInfo::new(
- trait_def.syntax().text_range(),
- impls_for_trait(&sema, &trait_def, krate)?,
- ));
- }
-
- None
-}
-
-fn impls_for_def(
- sema: &Semantics<RootDatabase>,
- node: &ast::Adt,
- krate: Crate,
-) -> Option<Vec<NavigationTarget>> {
- let ty = match node {
- ast::Adt::Struct(def) => sema.to_def(def)?.ty(sema.db),
- ast::Adt::Enum(def) => sema.to_def(def)?.ty(sema.db),
- ast::Adt::Union(def) => sema.to_def(def)?.ty(sema.db),
+ let node = sema.find_node_at_offset_with_descend(&syntax, position.offset)?;
+ let def = match &node {
+ ast::NameLike::Name(name) => {
+ NameClass::classify(&sema, name).map(|class| class.referenced_or_defined(sema.db))
+ }
+ ast::NameLike::NameRef(name_ref) => {
+ NameRefClass::classify(&sema, name_ref).map(|class| class.referenced(sema.db))
+ }
+ ast::NameLike::Lifetime(_) => None,
+ }?;
+ let def = match def {
+ Definition::ModuleDef(def) => def,
+ _ => return None,
};
-
- let impls = Impl::all_in_crate(sema.db, krate);
-
- Some(
- impls
- .into_iter()
- .filter(|impl_def| ty.is_equal_for_find_impls(&impl_def.target_ty(sema.db)))
- .filter_map(|imp| imp.try_to_nav(sema.db))
- .collect(),
- )
+ let navs = match def {
+ hir::ModuleDef::Trait(trait_) => impls_for_trait(&sema, trait_),
+ hir::ModuleDef::Adt(adt) => impls_for_ty(&sema, adt.ty(sema.db)),
+ hir::ModuleDef::TypeAlias(alias) => impls_for_ty(&sema, alias.ty(sema.db)),
+ hir::ModuleDef::BuiltinType(builtin) => {
+ let module = sema.to_module_def(position.file_id)?;
+ impls_for_ty(&sema, builtin.ty(sema.db, module))
+ }
+ _ => return None,
+ };
+ Some(RangeInfo { range: node.syntax().text_range(), info: navs })
}
-fn impls_for_trait(
- sema: &Semantics<RootDatabase>,
- node: &ast::Trait,
- krate: Crate,
-) -> Option<Vec<NavigationTarget>> {
- let tr = sema.to_def(node)?;
-
- let impls = Impl::for_trait(sema.db, krate, tr);
+fn impls_for_ty(sema: &Semantics<RootDatabase>, ty: hir::Type) -> Vec<NavigationTarget> {
+ Impl::all_for_type(sema.db, ty).into_iter().filter_map(|imp| imp.try_to_nav(sema.db)).collect()
+}
- Some(impls.into_iter().filter_map(|imp| imp.try_to_nav(sema.db)).collect())
+fn impls_for_trait(sema: &Semantics<RootDatabase>, trait_: hir::Trait) -> Vec<NavigationTarget> {
+ Impl::all_for_trait(sema.db, trait_)
+ .into_iter()
+ .filter_map(|imp| imp.try_to_nav(sema.db))
+ .collect()
}
#[cfg(test)]
}
#[rustc_builtin_macro]
macro Copy {}
+"#,
+ );
+ }
+
+ #[test]
+ fn goto_implementation_type_alias() {
+ check(
+ r#"
+struct Foo;
+
+type Bar$0 = Foo;
+
+impl Foo {}
+ //^^^
+impl Bar {}
+ //^^^
+"#,
+ );
+ }
+
+ #[test]
+ fn goto_implementation_adt_generic() {
+ check(
+ r#"
+struct Foo$0<T>;
+
+impl<T> Foo<T> {}
+ //^^^^^^
+impl Foo<str> {}
+ //^^^^^^^^
+"#,
+ );
+ }
+
+ #[test]
+ fn goto_implementation_builtin() {
+ check(
+ r#"
+//- /lib.rs crate:main deps:core
+fn foo(_: bool$0) {{}}
+//- /libcore.rs crate:core
+#[lang = "bool"]
+impl bool {}
+ //^^^^
"#,
);
}