@@ -4,8 +4,9 @@ use common::indexmap::IndexSet;
4
4
use rustc_hash:: { FxHashMap , FxHashSet } ;
5
5
6
6
use super :: {
7
- scope_graph_viz:: ScopeGraphFormatter , Body , Enum , ExprId , Func , FuncParamName , IdentId ,
8
- IngotId , ItemKind , TopLevelMod , Use , VariantKind , Visibility ,
7
+ scope_graph_viz:: ScopeGraphFormatter , AttrListId , Body , Const , Contract , Enum , ExprId ,
8
+ FieldDef , Func , FuncParam , FuncParamName , GenericParam , IdentId , Impl , ImplTrait , IngotId ,
9
+ ItemKind , Mod , TopLevelMod , Trait , TypeAlias , Use , VariantDef , VariantKind , Visibility ,
9
10
} ;
10
11
use crate :: {
11
12
hir_def:: { BodyKind , GenericParamOwner } ,
@@ -130,6 +131,31 @@ impl<'db> ScopeId<'db> {
130
131
}
131
132
}
132
133
134
+ /// Resolves the `ScopeId` to `T`.
135
+ /// Returns `None` if the resolution is not defined for this scope.
136
+ pub fn resolve_to < T > ( self , db : & ' db dyn HirDb ) -> Option < T >
137
+ where
138
+ T : FromScope < ' db > ,
139
+ {
140
+ T :: from_scope ( self , db)
141
+ }
142
+
143
+ /// Returns attributes being applied to the scope.
144
+ pub fn attrs ( self , db : & ' db dyn HirDb ) -> Option < AttrListId < ' db > > {
145
+ match self {
146
+ ScopeId :: Item ( item) => item. attrs ( db) ,
147
+ ScopeId :: Field ( ..) => {
148
+ let def: & FieldDef = self . resolve_to ( db) . unwrap ( ) ;
149
+ Some ( def. attributes )
150
+ }
151
+ ScopeId :: Variant ( ..) => {
152
+ let def: & VariantDef = self . resolve_to ( db) . unwrap ( ) ;
153
+ Some ( def. attributes )
154
+ }
155
+ _ => None ,
156
+ }
157
+ }
158
+
133
159
/// Returns the scope graph containing this scope.
134
160
pub fn scope_graph ( self , db : & ' db dyn HirDb ) -> & ' db ScopeGraph < ' db > {
135
161
self . top_mod ( db) . scope_graph ( db)
@@ -157,7 +183,7 @@ impl<'db> ScopeId<'db> {
157
183
}
158
184
}
159
185
160
- /// Returns true if `self` is a transitive reflexive child of `of`.
186
+ /// Returns ` true` if `self` is a transitive reflexive child of `of`.
161
187
pub fn is_transitive_child_of ( self , db : & dyn HirDb , of : ScopeId ) -> bool {
162
188
let mut current = Some ( self ) ;
163
189
@@ -238,19 +264,6 @@ impl<'db> ScopeId<'db> {
238
264
}
239
265
}
240
266
241
- pub fn is_enum ( self ) -> bool {
242
- matches ! ( self , ScopeId :: Item ( ItemKind :: Enum ( _) ) )
243
- }
244
-
245
- pub fn is_mod ( self ) -> bool {
246
- matches ! ( self , ScopeId :: Item ( ItemKind :: Mod ( _) | ItemKind :: TopMod ( _) ) )
247
- }
248
-
249
- /// Returns `true` if the scope is a trait definition.
250
- pub fn is_trait ( self ) -> bool {
251
- matches ! ( self , ScopeId :: Item ( ItemKind :: Trait ( _) ) )
252
- }
253
-
254
267
/// Returns the item that contains this scope.
255
268
pub fn parent_item ( self , db : & ' db dyn HirDb ) -> Option < ItemKind < ' db > > {
256
269
let mut parent = self . parent ( db) ?;
@@ -268,39 +281,22 @@ impl<'db> ScopeId<'db> {
268
281
match self . data ( db) . id {
269
282
ScopeId :: Item ( item) => item. name ( db) ,
270
283
271
- ScopeId :: Variant ( parent, idx) => {
272
- let enum_: Enum = parent. try_into ( ) . unwrap ( ) ;
273
- enum_. variants ( db) . data ( db) [ idx] . name . to_opt ( )
274
- }
284
+ ScopeId :: Variant ( ..) => self . resolve_to :: < & VariantDef > ( db) . unwrap ( ) . name . to_opt ( ) ,
275
285
276
- ScopeId :: Field ( FieldParent :: Item ( parent) , idx) => match parent {
277
- ItemKind :: Struct ( s) => s. fields ( db) . data ( db) [ idx] . name . to_opt ( ) ,
278
- ItemKind :: Contract ( c) => c. fields ( db) . data ( db) [ idx] . name . to_opt ( ) ,
279
- _ => unreachable ! ( ) ,
280
- } ,
281
- ScopeId :: Field ( FieldParent :: Variant ( parent, vidx) , fidx) => {
282
- let enum_: Enum = parent. try_into ( ) . unwrap ( ) ;
283
- match enum_. variants ( db) . data ( db) [ vidx] . kind {
284
- VariantKind :: Record ( fields) => fields. data ( db) [ fidx] . name . to_opt ( ) ,
285
- _ => unreachable ! ( ) ,
286
- }
287
- }
286
+ ScopeId :: Field ( ..) => self . resolve_to :: < & FieldDef > ( db) . unwrap ( ) . name . to_opt ( ) ,
288
287
289
- ScopeId :: FuncParam ( parent, idx) => {
290
- let func: Func = parent. try_into ( ) . unwrap ( ) ;
291
- let param = & func. params ( db) . to_opt ( ) ?. data ( db) [ idx] ;
288
+ ScopeId :: FuncParam ( ..) => {
289
+ let param: & FuncParam = self . resolve_to ( db) . unwrap ( ) ;
292
290
if let Some ( FuncParamName :: Ident ( ident) ) = param. label {
293
291
Some ( ident)
294
292
} else {
295
293
param. name ( )
296
294
}
297
295
}
298
296
299
- ScopeId :: GenericParam ( parent, idx) => {
300
- let parent = GenericParamOwner :: from_item_opt ( parent) . unwrap ( ) ;
301
-
302
- let params = & parent. params ( db) . data ( db) [ idx] ;
303
- params. name ( ) . to_opt ( )
297
+ ScopeId :: GenericParam ( ..) => {
298
+ let param: & GenericParam = self . resolve_to ( db) . unwrap ( ) ;
299
+ param. name ( ) . to_opt ( )
304
300
}
305
301
306
302
ScopeId :: Block ( ..) => None ,
@@ -366,6 +362,7 @@ impl<'db> ScopeId<'db> {
366
362
ScopeId :: Block ( _, _) => "block" ,
367
363
}
368
364
}
365
+
369
366
pub fn pretty_path ( self , db : & dyn HirDb ) -> Option < String > {
370
367
let name = match self {
371
368
ScopeId :: Block ( body, expr) => format ! ( "{{block{}}}" , body. iter_block( db) [ & expr] ) ,
@@ -594,6 +591,103 @@ pub struct SelfEdge();
594
591
#[ derive( Debug , Clone , Copy , PartialEq , Eq , PartialOrd , Ord , Hash ) ]
595
592
pub struct AnonEdge ( ) ;
596
593
594
+ pub trait FromScope < ' db > : Sized {
595
+ fn from_scope ( scope : ScopeId < ' db > , db : & ' db dyn HirDb ) -> Option < Self > ;
596
+ }
597
+
598
+ impl < ' db > FromScope < ' db > for ItemKind < ' db > {
599
+ fn from_scope ( scope : ScopeId < ' db > , _db : & ' db dyn HirDb ) -> Option < Self > {
600
+ match scope {
601
+ ScopeId :: Item ( item) => Some ( item) ,
602
+ _ => None ,
603
+ }
604
+ }
605
+ }
606
+
607
+ macro_rules! item_from_scope {
608
+ ( $( $item_ty: ty, ) * ) => {
609
+ $(
610
+ impl <' db> FromScope <' db> for $item_ty {
611
+ fn from_scope( scope: ScopeId <' db>, db: & ' db dyn HirDb ) -> Option <Self > {
612
+ scope. resolve_to:: <ItemKind >( db) . and_then( |item| item. try_into( ) . ok( ) )
613
+ }
614
+ }
615
+ ) *
616
+ } ;
617
+ }
618
+
619
+ item_from_scope ! {
620
+ TopLevelMod <' db>,
621
+ Mod <' db>,
622
+ Func <' db>,
623
+ Contract <' db>,
624
+ Enum <' db>,
625
+ TypeAlias <' db>,
626
+ Impl <' db>,
627
+ Trait <' db>,
628
+ ImplTrait <' db>,
629
+ Const <' db>,
630
+ Use <' db>,
631
+ Body <' db>,
632
+ }
633
+
634
+ impl < ' db > FromScope < ' db > for & ' db FieldDef < ' db > {
635
+ fn from_scope ( scope : ScopeId < ' db > , db : & ' db dyn HirDb ) -> Option < Self > {
636
+ let ScopeId :: Field ( parent, idx) = scope else {
637
+ return None ;
638
+ } ;
639
+
640
+ match parent {
641
+ FieldParent :: Item ( item) => match item {
642
+ ItemKind :: Struct ( s) => Some ( & s. fields ( db) . data ( db) [ idx] ) ,
643
+ ItemKind :: Contract ( c) => Some ( & c. fields ( db) . data ( db) [ idx] ) ,
644
+ _ => unreachable ! ( ) ,
645
+ } ,
646
+
647
+ FieldParent :: Variant ( parent, vidx) => {
648
+ let enum_: Enum = parent. try_into ( ) . unwrap ( ) ;
649
+ match enum_. variants ( db) . data ( db) [ vidx] . kind {
650
+ VariantKind :: Record ( fields) => Some ( & fields. data ( db) [ idx] ) ,
651
+ _ => unreachable ! ( ) ,
652
+ }
653
+ }
654
+ }
655
+ }
656
+ }
657
+
658
+ impl < ' db > FromScope < ' db > for & ' db VariantDef < ' db > {
659
+ fn from_scope ( scope : ScopeId < ' db > , db : & ' db dyn HirDb ) -> Option < Self > {
660
+ let ScopeId :: Variant ( parent, idx) = scope else {
661
+ return None ;
662
+ } ;
663
+ let enum_: Enum = parent. try_into ( ) . unwrap ( ) ;
664
+
665
+ Some ( & enum_. variants ( db) . data ( db) [ idx] )
666
+ }
667
+ }
668
+
669
+ impl < ' db > FromScope < ' db > for & ' db FuncParam < ' db > {
670
+ fn from_scope ( scope : ScopeId < ' db > , db : & ' db dyn HirDb ) -> Option < Self > {
671
+ let ScopeId :: FuncParam ( parent, idx) = scope else {
672
+ return None ;
673
+ } ;
674
+
675
+ let func: Func = parent. try_into ( ) . unwrap ( ) ;
676
+ func. params ( db) . to_opt ( ) . map ( |params| & params. data ( db) [ idx] )
677
+ }
678
+ }
679
+
680
+ impl < ' db > FromScope < ' db > for & ' db GenericParam < ' db > {
681
+ fn from_scope ( scope : ScopeId < ' db > , db : & ' db dyn HirDb ) -> Option < Self > {
682
+ let ScopeId :: GenericParam ( parent, idx) = scope else {
683
+ return None ;
684
+ } ;
685
+
686
+ let parent = GenericParamOwner :: from_item_opt ( parent) . unwrap ( ) ;
687
+ Some ( & parent. params ( db) . data ( db) [ idx] )
688
+ }
689
+ }
690
+
597
691
#[ cfg( test) ]
598
692
mod tests {
599
693
0 commit comments