@@ -26,8 +26,8 @@ use hir_ty::{
2626 autoderef,
2727 display:: { HirDisplayError , HirFormatter } ,
2828 expr:: ExprValidator ,
29- method_resolution, ApplicationTy , Canonical , InEnvironment , Substs , TraitEnvironment , Ty ,
30- TyDefId , TypeCtor ,
29+ method_resolution, ApplicationTy , Canonical , GenericPredicate , InEnvironment , OpaqueTyId ,
30+ Substs , TraitEnvironment , Ty , TyDefId , TypeCtor , TypeWalk ,
3131} ;
3232use ra_db:: { CrateId , CrateName , Edition , FileId } ;
3333use ra_prof:: profile;
@@ -1380,6 +1380,87 @@ impl Type {
13801380 ty : InEnvironment { value : ty, environment : self . ty . environment . clone ( ) } ,
13811381 }
13821382 }
1383+
1384+ /// Returns a flattened list of all the ADTs and Traits mentioned in the type
1385+ pub fn flattened_type_items ( & self , db : & dyn HirDatabase ) -> Vec < AdtOrTrait > {
1386+ fn push_new_item ( item : AdtOrTrait , acc : & mut Vec < AdtOrTrait > ) {
1387+ if !acc. contains ( & item) {
1388+ acc. push ( item) ;
1389+ }
1390+ }
1391+
1392+ fn push_bounds (
1393+ db : & dyn HirDatabase ,
1394+ predicates : & [ GenericPredicate ] ,
1395+ acc : & mut Vec < AdtOrTrait > ,
1396+ ) {
1397+ for p in predicates. iter ( ) {
1398+ match p {
1399+ GenericPredicate :: Implemented ( trait_ref) => {
1400+ push_new_item ( Trait :: from ( trait_ref. trait_ ) . into ( ) , acc) ;
1401+ walk_types ( db, & trait_ref. substs , acc) ;
1402+ }
1403+ GenericPredicate :: Projection ( _) => { }
1404+ GenericPredicate :: Error => ( ) ,
1405+ }
1406+ }
1407+ }
1408+
1409+ fn walk_types < T : TypeWalk > ( db : & dyn HirDatabase , tw : & T , acc : & mut Vec < AdtOrTrait > ) {
1410+ tw. walk ( & mut |ty| walk_type ( db, ty, acc) ) ;
1411+ }
1412+
1413+ fn walk_type ( db : & dyn HirDatabase , ty : & Ty , acc : & mut Vec < AdtOrTrait > ) {
1414+ match ty. strip_references ( ) {
1415+ Ty :: Apply ( ApplicationTy { ctor, parameters, .. } ) => {
1416+ match ctor {
1417+ TypeCtor :: Adt ( adt_id) => push_new_item ( Adt :: from ( * adt_id) . into ( ) , acc) ,
1418+ _ => ( ) ,
1419+ }
1420+ // adt params, tuples, etc...
1421+ walk_types ( db, parameters, acc) ;
1422+ }
1423+ Ty :: Dyn ( predicates) => {
1424+ push_bounds ( db, predicates, acc) ;
1425+ }
1426+ Ty :: Placeholder ( id) => {
1427+ let generic_params = db. generic_params ( id. parent ) ;
1428+ let param_data = & generic_params. types [ id. local_id ] ;
1429+ match param_data. provenance {
1430+ hir_def:: generics:: TypeParamProvenance :: ArgumentImplTrait => {
1431+ let predicates: Vec < _ > = db
1432+ . generic_predicates_for_param ( * id)
1433+ . into_iter ( )
1434+ . map ( |pred| pred. value . clone ( ) )
1435+ . collect ( ) ;
1436+ push_bounds ( db, & predicates, acc) ;
1437+ }
1438+ _ => ( ) ,
1439+ }
1440+ }
1441+ Ty :: Opaque ( opaque_ty) => {
1442+ let bounds = match opaque_ty. opaque_ty_id {
1443+ OpaqueTyId :: ReturnTypeImplTrait ( func, idx) => {
1444+ let datas = db
1445+ . return_type_impl_traits ( func)
1446+ . expect ( "impl trait id without data" ) ;
1447+ let data = ( * datas)
1448+ . as_ref ( )
1449+ . map ( |rpit| rpit. impl_traits [ idx as usize ] . bounds . clone ( ) ) ;
1450+ data. clone ( ) . subst ( & opaque_ty. parameters )
1451+ }
1452+ } ;
1453+ push_bounds ( db, & bounds. value , acc) ;
1454+ walk_types ( db, & opaque_ty. parameters , acc) ;
1455+ }
1456+ _ => ( ) ,
1457+ }
1458+ }
1459+
1460+ let mut res: Vec < AdtOrTrait > = Vec :: new ( ) ; // not a Set to preserve the order
1461+ walk_type ( db, & self . ty . value , & mut res) ;
1462+ res
1463+ }
13831464}
13841465
13851466impl HirDisplay for Type {
@@ -1488,3 +1569,26 @@ pub trait HasVisibility {
14881569 vis. is_visible_from ( db. upcast ( ) , module. id )
14891570 }
14901571}
1572+
1573+ #[ derive( Clone , Copy , Debug , PartialEq , Eq , Hash ) ]
1574+ pub enum AdtOrTrait {
1575+ Adt ( Adt ) ,
1576+ Trait ( Trait ) ,
1577+ }
1578+ impl_froms ! ( AdtOrTrait : Adt , Trait ) ;
1579+
1580+ impl AdtOrTrait {
1581+ pub fn module ( self , db : & dyn HirDatabase ) -> Module {
1582+ match self {
1583+ AdtOrTrait :: Adt ( adt) => adt. module ( db) ,
1584+ AdtOrTrait :: Trait ( trait_) => trait_. module ( db) ,
1585+ }
1586+ }
1587+
1588+ pub fn name ( self , db : & dyn HirDatabase ) -> Name {
1589+ match self {
1590+ AdtOrTrait :: Adt ( adt) => adt. name ( db) ,
1591+ AdtOrTrait :: Trait ( trait_) => trait_. name ( db) ,
1592+ }
1593+ }
1594+ }
0 commit comments