@@ -523,21 +523,38 @@ impl<N: ItemTreeNode> Index<FileItemTreeId<N>> for ItemTree {
523
523
}
524
524
}
525
525
526
- /// A desugared `use` import.
527
526
#[ derive( Debug , Clone , Eq , PartialEq ) ]
528
527
pub struct Import {
529
- pub path : Interned < ModPath > ,
530
- pub alias : Option < ImportAlias > ,
531
528
pub visibility : RawVisibilityId ,
532
- pub is_glob : bool ,
533
- /// AST ID of the `use` item this import was derived from. Note that many `Import`s can map to
534
- /// the same `use` item.
535
529
pub ast_id : FileAstId < ast:: Use > ,
536
- /// Index of this `Import` when the containing `Use` is visited via `ModPath::expand_use_item`.
537
- ///
538
- /// This can be used to get the `UseTree` this `Import` corresponds to and allows emitting
539
- /// precise diagnostics.
540
- pub index : usize ,
530
+ pub use_tree : UseTree ,
531
+ }
532
+
533
+ #[ derive( Debug , Clone , Eq , PartialEq ) ]
534
+ pub struct UseTree {
535
+ pub index : Idx < ast:: UseTree > ,
536
+ kind : UseTreeKind ,
537
+ }
538
+
539
+ #[ derive( Debug , Clone , Eq , PartialEq ) ]
540
+ pub enum UseTreeKind {
541
+ /// ```
542
+ /// use path::to::Item;
543
+ /// use path::to::Item as Renamed;
544
+ /// use path::to::Trait as _;
545
+ /// ```
546
+ Single { path : Interned < ModPath > , alias : Option < ImportAlias > } ,
547
+
548
+ /// ```
549
+ /// use *; // (invalid, but can occur in nested tree)
550
+ /// use path::*;
551
+ /// ```
552
+ Glob { path : Option < Interned < ModPath > > } ,
553
+
554
+ /// ```
555
+ /// use prefix::{self, Item, ...};
556
+ /// ```
557
+ Prefixed { prefix : Option < Interned < ModPath > > , list : Box < [ UseTree ] > } ,
541
558
}
542
559
543
560
#[ derive( Debug , Clone , Eq , PartialEq ) ]
@@ -711,6 +728,97 @@ pub struct MacroDef {
711
728
pub ast_id : FileAstId < ast:: MacroDef > ,
712
729
}
713
730
731
+ impl Import {
732
+ /// Maps a `UseTree` contained in this import back to its AST node.
733
+ pub fn use_tree_to_ast (
734
+ & self ,
735
+ db : & dyn DefDatabase ,
736
+ file_id : HirFileId ,
737
+ index : Idx < ast:: UseTree > ,
738
+ ) -> ast:: UseTree {
739
+ // Re-lower the AST item and get the source map.
740
+ // Note: The AST unwraps are fine, since if they fail we should have never obtained `index`.
741
+ let ast = InFile :: new ( file_id, self . ast_id ) . to_node ( db. upcast ( ) ) ;
742
+ let ast_use_tree = ast. use_tree ( ) . expect ( "missing `use_tree`" ) ;
743
+ let hygiene = Hygiene :: new ( db. upcast ( ) , file_id) ;
744
+ let ( _, source_map) =
745
+ lower:: lower_use_tree ( db, & hygiene, ast_use_tree) . expect ( "failed to lower use tree" ) ;
746
+ source_map[ index] . clone ( )
747
+ }
748
+ }
749
+
750
+ impl UseTree {
751
+ /// Expands the `UseTree` into individually imported `ModPath`s.
752
+ pub fn expand (
753
+ & self ,
754
+ mut cb : impl FnMut ( Idx < ast:: UseTree > , ModPath , /* is_glob */ bool , Option < ImportAlias > ) ,
755
+ ) {
756
+ self . expand_impl ( None , & mut cb)
757
+ }
758
+
759
+ fn expand_impl (
760
+ & self ,
761
+ prefix : Option < ModPath > ,
762
+ cb : & mut dyn FnMut (
763
+ Idx < ast:: UseTree > ,
764
+ ModPath ,
765
+ /* is_glob */ bool ,
766
+ Option < ImportAlias > ,
767
+ ) ,
768
+ ) {
769
+ fn concat_mod_paths ( prefix : Option < ModPath > , path : & ModPath ) -> Option < ModPath > {
770
+ match ( prefix, & path. kind ) {
771
+ ( None , _) => Some ( path. clone ( ) ) ,
772
+ ( Some ( mut prefix) , PathKind :: Plain ) => {
773
+ for segment in path. segments ( ) {
774
+ prefix. push_segment ( segment. clone ( ) ) ;
775
+ }
776
+ Some ( prefix)
777
+ }
778
+ ( Some ( prefix) , PathKind :: Super ( 0 ) ) => {
779
+ // `some::path::self` == `some::path`
780
+ if path. segments ( ) . is_empty ( ) {
781
+ Some ( prefix)
782
+ } else {
783
+ None
784
+ }
785
+ }
786
+ ( Some ( _) , _) => None ,
787
+ }
788
+ }
789
+
790
+ match & self . kind {
791
+ UseTreeKind :: Single { path, alias } => {
792
+ if let Some ( path) = concat_mod_paths ( prefix, path) {
793
+ cb ( self . index , path, false , alias. clone ( ) ) ;
794
+ }
795
+ }
796
+ UseTreeKind :: Glob { path : Some ( path) } => {
797
+ if let Some ( path) = concat_mod_paths ( prefix, path) {
798
+ cb ( self . index , path, true , None ) ;
799
+ }
800
+ }
801
+ UseTreeKind :: Glob { path : None } => {
802
+ if let Some ( prefix) = prefix {
803
+ cb ( self . index , prefix, true , None ) ;
804
+ }
805
+ }
806
+ UseTreeKind :: Prefixed { prefix : additional_prefix, list } => {
807
+ let prefix = match additional_prefix {
808
+ Some ( path) => match concat_mod_paths ( prefix, path) {
809
+ Some ( path) => Some ( path) ,
810
+ None => return ,
811
+ } ,
812
+ None => prefix,
813
+ } ;
814
+ for tree in & * * list {
815
+ tree. expand_impl ( prefix. clone ( ) , cb) ;
816
+ }
817
+ }
818
+ }
819
+ }
820
+ }
821
+
714
822
macro_rules! impl_froms {
715
823
( $e: ident { $( $v: ident ( $t: ty) ) ,* $( , ) ? } ) => {
716
824
$(
0 commit comments