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
This commit is contained in:
parent
de36027541
commit
6c782a5314
@ -696,8 +696,8 @@ impl Adt {
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
@ -1019,8 +1019,8 @@ impl TypeAlias {
|
||||
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> {
|
||||
@ -1483,9 +1483,42 @@ impl Impl {
|
||||
|
||||
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
|
||||
@ -1913,12 +1946,6 @@ impl Type {
|
||||
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,
|
||||
|
@ -1,6 +1,9 @@
|
||||
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};
|
||||
|
||||
@ -21,55 +24,42 @@ pub(crate) fn goto_implementation(
|
||||
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)?;
|
||||
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()
|
||||
}
|
||||
|
||||
let impls = Impl::for_trait(sema.db, krate, tr);
|
||||
|
||||
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)]
|
||||
@ -223,6 +213,50 @@ mod marker {
|
||||
}
|
||||
#[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 {}
|
||||
//^^^^
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
@ -219,7 +219,7 @@ fn hint_iterator(
|
||||
let strukt = std::iter::successors(Some(ty.clone()), |ty| ty.remove_ref())
|
||||
.last()
|
||||
.and_then(|strukt| strukt.as_adt())?;
|
||||
let krate = strukt.krate(db)?;
|
||||
let krate = strukt.krate(db);
|
||||
if krate != famous_defs.core()? {
|
||||
return None;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user