diff options
Diffstat (limited to 'crates/ra_hir/src/code_model.rs')
-rw-r--r-- | crates/ra_hir/src/code_model.rs | 54 |
1 files changed, 52 insertions, 2 deletions
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index f7efc1b66..4739246cb 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs | |||
@@ -1,8 +1,11 @@ | |||
1 | pub(crate) mod src; | 1 | pub(crate) mod src; |
2 | pub(crate) mod docs; | 2 | pub(crate) mod docs; |
3 | 3 | ||
4 | use std::iter; | ||
4 | use std::sync::Arc; | 5 | use std::sync::Arc; |
5 | 6 | ||
7 | use itertools::Itertools; | ||
8 | |||
6 | use ra_db::{CrateId, Edition, FileId, SourceRootId}; | 9 | use ra_db::{CrateId, Edition, FileId, SourceRootId}; |
7 | use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner}; | 10 | use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner}; |
8 | 11 | ||
@@ -820,7 +823,43 @@ impl Trait { | |||
820 | self.trait_data(db).items().to_vec() | 823 | self.trait_data(db).items().to_vec() |
821 | } | 824 | } |
822 | 825 | ||
823 | pub fn associated_type_by_name(self, db: &impl DefDatabase, name: Name) -> Option<TypeAlias> { | 826 | fn direct_super_traits(self, db: &impl HirDatabase) -> Vec<Trait> { |
827 | let resolver = self.resolver(db); | ||
828 | // returning the iterator directly doesn't easily work because of | ||
829 | // lifetime problems, but since there usually shouldn't be more than a | ||
830 | // few direct traits this should be fine (we could even use some kind of | ||
831 | // SmallVec if performance is a concern) | ||
832 | self.generic_params(db) | ||
833 | .where_predicates | ||
834 | .iter() | ||
835 | .filter_map(|pred| match &pred.type_ref { | ||
836 | TypeRef::Path(p) if p.as_ident() == Some(&crate::name::SELF_TYPE) => { | ||
837 | pred.bound.as_path() | ||
838 | } | ||
839 | _ => None, | ||
840 | }) | ||
841 | .filter_map(|path| { | ||
842 | match resolver.resolve_path_without_assoc_items(db, path).take_types() { | ||
843 | Some(crate::Resolution::Def(ModuleDef::Trait(t))) => Some(t), | ||
844 | _ => None, | ||
845 | } | ||
846 | }) | ||
847 | .collect() | ||
848 | } | ||
849 | |||
850 | /// Returns an iterator over the whole super trait hierarchy (not including | ||
851 | /// the trait itself). (This iterator may be infinite in case of circular | ||
852 | /// super trait dependencies, which are possible in malformed code.) | ||
853 | pub fn all_super_traits<'a>( | ||
854 | self, | ||
855 | db: &'a impl HirDatabase, | ||
856 | ) -> impl Iterator<Item = Trait> + 'a { | ||
857 | self.direct_super_traits(db).into_iter().flat_map(move |t| { | ||
858 | iter::once(t).chain(Box::new(t.all_super_traits(db)) as Box<dyn Iterator<Item = Trait>>) | ||
859 | }) | ||
860 | } | ||
861 | |||
862 | pub fn associated_type_by_name(self, db: &impl DefDatabase, name: &Name) -> Option<TypeAlias> { | ||
824 | let trait_data = self.trait_data(db); | 863 | let trait_data = self.trait_data(db); |
825 | trait_data | 864 | trait_data |
826 | .items() | 865 | .items() |
@@ -829,7 +868,18 @@ impl Trait { | |||
829 | TraitItem::TypeAlias(t) => Some(*t), | 868 | TraitItem::TypeAlias(t) => Some(*t), |
830 | _ => None, | 869 | _ => None, |
831 | }) | 870 | }) |
832 | .find(|t| t.name(db) == name) | 871 | .find(|t| &t.name(db) == name) |
872 | } | ||
873 | |||
874 | pub fn associated_type_by_name_including_super_traits( | ||
875 | self, | ||
876 | db: &impl HirDatabase, | ||
877 | name: &Name, | ||
878 | ) -> Option<TypeAlias> { | ||
879 | iter::once(self) | ||
880 | .chain(self.all_super_traits(db)) | ||
881 | .unique() | ||
882 | .find_map(|t| t.associated_type_by_name(db, name)) | ||
833 | } | 883 | } |
834 | 884 | ||
835 | pub(crate) fn trait_data(self, db: &impl DefDatabase) -> Arc<TraitData> { | 885 | pub(crate) fn trait_data(self, db: &impl DefDatabase) -> Arc<TraitData> { |