From c50157f33025b6ff01809b975a3d12c0e43a0072 Mon Sep 17 00:00:00 2001 From: vsrs Date: Wed, 10 Jun 2020 21:24:36 +0300 Subject: Add `Go to Type Definition` hover action. --- crates/ra_hir/src/code_model.rs | 108 +++++++++++++++++++++++++++++++++++++++- crates/ra_hir/src/lib.rs | 8 +-- 2 files changed, 110 insertions(+), 6 deletions(-) (limited to 'crates/ra_hir/src') diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index 1a9f6cc76..c22eb451b 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs @@ -26,8 +26,8 @@ use hir_ty::{ autoderef, display::{HirDisplayError, HirFormatter}, expr::ExprValidator, - method_resolution, ApplicationTy, Canonical, InEnvironment, Substs, TraitEnvironment, Ty, - TyDefId, TypeCtor, + method_resolution, ApplicationTy, Canonical, GenericPredicate, InEnvironment, OpaqueTyId, + Substs, TraitEnvironment, Ty, TyDefId, TypeCtor, TypeWalk, }; use ra_db::{CrateId, CrateName, Edition, FileId}; use ra_prof::profile; @@ -1380,6 +1380,87 @@ impl Type { ty: InEnvironment { value: ty, environment: self.ty.environment.clone() }, } } + + /// Returns a flattened list of all the ADTs and Traits mentioned in the type + pub fn flattened_type_items(&self, db: &dyn HirDatabase) -> Vec { + fn push_new_item(item: AdtOrTrait, acc: &mut Vec) { + if !acc.contains(&item) { + acc.push(item); + } + } + + fn push_bounds( + db: &dyn HirDatabase, + predicates: &[GenericPredicate], + acc: &mut Vec, + ) { + for p in predicates.iter() { + match p { + GenericPredicate::Implemented(trait_ref) => { + push_new_item(Trait::from(trait_ref.trait_).into(), acc); + walk_types(db, &trait_ref.substs, acc); + } + GenericPredicate::Projection(_) => {} + GenericPredicate::Error => (), + } + } + } + + fn walk_types(db: &dyn HirDatabase, tw: &T, acc: &mut Vec) { + tw.walk(&mut |ty| walk_type(db, ty, acc)); + } + + fn walk_type(db: &dyn HirDatabase, ty: &Ty, acc: &mut Vec) { + match ty.strip_references() { + Ty::Apply(ApplicationTy { ctor, parameters, .. }) => { + match ctor { + TypeCtor::Adt(adt_id) => push_new_item(Adt::from(*adt_id).into(), acc), + _ => (), + } + // adt params, tuples, etc... + walk_types(db, parameters, acc); + } + Ty::Dyn(predicates) => { + push_bounds(db, predicates, acc); + } + Ty::Placeholder(id) => { + let generic_params = db.generic_params(id.parent); + let param_data = &generic_params.types[id.local_id]; + match param_data.provenance { + hir_def::generics::TypeParamProvenance::ArgumentImplTrait => { + let predicates: Vec<_> = db + .generic_predicates_for_param(*id) + .into_iter() + .map(|pred| pred.value.clone()) + .collect(); + push_bounds(db, &predicates, acc); + } + _ => (), + } + } + Ty::Opaque(opaque_ty) => { + let bounds = match opaque_ty.opaque_ty_id { + OpaqueTyId::ReturnTypeImplTrait(func, idx) => { + let datas = db + .return_type_impl_traits(func) + .expect("impl trait id without data"); + let data = (*datas) + .as_ref() + .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone()); + data.clone().subst(&opaque_ty.parameters) + } + }; + push_bounds(db, &bounds.value, acc); + walk_types(db, &opaque_ty.parameters, acc); + } + _ => (), + } + } + + let mut res: Vec = Vec::new(); // not a Set to preserve the order + walk_type(db, &self.ty.value, &mut res); + res + } } impl HirDisplay for Type { @@ -1488,3 +1569,26 @@ pub trait HasVisibility { vis.is_visible_from(db.upcast(), module.id) } } + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub enum AdtOrTrait { + Adt(Adt), + Trait(Trait), +} +impl_froms!(AdtOrTrait: Adt, Trait); + +impl AdtOrTrait { + pub fn module(self, db: &dyn HirDatabase) -> Module { + match self { + AdtOrTrait::Adt(adt) => adt.module(db), + AdtOrTrait::Trait(trait_) => trait_.module(db), + } + } + + pub fn name(self, db: &dyn HirDatabase) -> Name { + match self { + AdtOrTrait::Adt(adt) => adt.name(db), + AdtOrTrait::Trait(trait_) => trait_.name(db), + } + } +} diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index 3364a822f..eded039e4 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs @@ -51,10 +51,10 @@ mod has_source; pub use crate::{ code_model::{ - Adt, AsAssocItem, AssocItem, AssocItemContainer, AttrDef, Const, Crate, CrateDependency, - DefWithBody, Docs, Enum, EnumVariant, Field, FieldSource, Function, GenericDef, HasAttrs, - HasVisibility, ImplDef, Local, MacroDef, Module, ModuleDef, ScopeDef, Static, Struct, - Trait, Type, TypeAlias, TypeParam, Union, VariantDef, Visibility, + Adt, AdtOrTrait, AsAssocItem, AssocItem, AssocItemContainer, AttrDef, Const, Crate, + CrateDependency, DefWithBody, Docs, Enum, EnumVariant, Field, FieldSource, Function, + GenericDef, HasAttrs, HasVisibility, ImplDef, Local, MacroDef, Module, ModuleDef, ScopeDef, + Static, Struct, Trait, Type, TypeAlias, TypeParam, Union, VariantDef, Visibility, }, has_source::HasSource, semantics::{original_range, PathResolution, Semantics, SemanticsScope}, -- cgit v1.2.3