diff options
Diffstat (limited to 'crates/ra_hir/src/code_model.rs')
-rw-r--r-- | crates/ra_hir/src/code_model.rs | 57 |
1 files changed, 55 insertions, 2 deletions
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index f7efc1b66..1bb2f9f28 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs | |||
@@ -820,7 +820,52 @@ impl Trait { | |||
820 | self.trait_data(db).items().to_vec() | 820 | self.trait_data(db).items().to_vec() |
821 | } | 821 | } |
822 | 822 | ||
823 | pub fn associated_type_by_name(self, db: &impl DefDatabase, name: Name) -> Option<TypeAlias> { | 823 | fn direct_super_traits(self, db: &impl HirDatabase) -> Vec<Trait> { |
824 | let resolver = self.resolver(db); | ||
825 | // returning the iterator directly doesn't easily work because of | ||
826 | // lifetime problems, but since there usually shouldn't be more than a | ||
827 | // few direct traits this should be fine (we could even use some kind of | ||
828 | // SmallVec if performance is a concern) | ||
829 | self.generic_params(db) | ||
830 | .where_predicates | ||
831 | .iter() | ||
832 | .filter_map(|pred| match &pred.type_ref { | ||
833 | TypeRef::Path(p) if p.as_ident() == Some(&crate::name::SELF_TYPE) => { | ||
834 | pred.bound.as_path() | ||
835 | } | ||
836 | _ => None, | ||
837 | }) | ||
838 | .filter_map(|path| { | ||
839 | match resolver.resolve_path_without_assoc_items(db, path).take_types() { | ||
840 | Some(crate::Resolution::Def(ModuleDef::Trait(t))) => Some(t), | ||
841 | _ => None, | ||
842 | } | ||
843 | }) | ||
844 | .collect() | ||
845 | } | ||
846 | |||
847 | /// Returns an iterator over the whole super trait hierarchy (including the | ||
848 | /// trait itself). | ||
849 | pub fn all_super_traits(self, db: &impl HirDatabase) -> Vec<Trait> { | ||
850 | // we need to take care a bit here to avoid infinite loops in case of cycles | ||
851 | // (i.e. if we have `trait A: B; trait B: A;`) | ||
852 | let mut result = vec![self]; | ||
853 | let mut i = 0; | ||
854 | while i < result.len() { | ||
855 | let t = result[i]; | ||
856 | // yeah this is quadratic, but trait hierarchies should be flat | ||
857 | // enough that this doesn't matter | ||
858 | for tt in t.direct_super_traits(db) { | ||
859 | if !result.contains(&tt) { | ||
860 | result.push(tt); | ||
861 | } | ||
862 | } | ||
863 | i += 1; | ||
864 | } | ||
865 | result | ||
866 | } | ||
867 | |||
868 | pub fn associated_type_by_name(self, db: &impl DefDatabase, name: &Name) -> Option<TypeAlias> { | ||
824 | let trait_data = self.trait_data(db); | 869 | let trait_data = self.trait_data(db); |
825 | trait_data | 870 | trait_data |
826 | .items() | 871 | .items() |
@@ -829,7 +874,15 @@ impl Trait { | |||
829 | TraitItem::TypeAlias(t) => Some(*t), | 874 | TraitItem::TypeAlias(t) => Some(*t), |
830 | _ => None, | 875 | _ => None, |
831 | }) | 876 | }) |
832 | .find(|t| t.name(db) == name) | 877 | .find(|t| &t.name(db) == name) |
878 | } | ||
879 | |||
880 | pub fn associated_type_by_name_including_super_traits( | ||
881 | self, | ||
882 | db: &impl HirDatabase, | ||
883 | name: &Name, | ||
884 | ) -> Option<TypeAlias> { | ||
885 | self.all_super_traits(db).into_iter().find_map(|t| t.associated_type_by_name(db, name)) | ||
833 | } | 886 | } |
834 | 887 | ||
835 | pub(crate) fn trait_data(self, db: &impl DefDatabase) -> Arc<TraitData> { | 888 | pub(crate) fn trait_data(self, db: &impl DefDatabase) -> Arc<TraitData> { |