diff options
Diffstat (limited to 'crates/hir_def/src/item_tree.rs')
-rw-r--r-- | crates/hir_def/src/item_tree.rs | 131 |
1 files changed, 119 insertions, 12 deletions
diff --git a/crates/hir_def/src/item_tree.rs b/crates/hir_def/src/item_tree.rs index 11767d100..c4d20c416 100644 --- a/crates/hir_def/src/item_tree.rs +++ b/crates/hir_def/src/item_tree.rs | |||
@@ -523,21 +523,38 @@ impl<N: ItemTreeNode> Index<FileItemTreeId<N>> for ItemTree { | |||
523 | } | 523 | } |
524 | } | 524 | } |
525 | 525 | ||
526 | /// A desugared `use` import. | ||
527 | #[derive(Debug, Clone, Eq, PartialEq)] | 526 | #[derive(Debug, Clone, Eq, PartialEq)] |
528 | pub struct Import { | 527 | pub struct Import { |
529 | pub path: Interned<ModPath>, | ||
530 | pub alias: Option<ImportAlias>, | ||
531 | pub visibility: RawVisibilityId, | 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 | pub ast_id: FileAstId<ast::Use>, | 529 | pub ast_id: FileAstId<ast::Use>, |
536 | /// Index of this `Import` when the containing `Use` is visited via `ModPath::expand_use_item`. | 530 | pub use_tree: UseTree, |
537 | /// | 531 | } |
538 | /// This can be used to get the `UseTree` this `Import` corresponds to and allows emitting | 532 | |
539 | /// precise diagnostics. | 533 | #[derive(Debug, Clone, Eq, PartialEq)] |
540 | pub index: usize, | 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 | #[derive(Debug, Clone, Eq, PartialEq)] | 560 | #[derive(Debug, Clone, Eq, PartialEq)] |
@@ -644,7 +661,6 @@ pub struct Trait { | |||
644 | pub generic_params: Interned<GenericParams>, | 661 | pub generic_params: Interned<GenericParams>, |
645 | pub is_auto: bool, | 662 | pub is_auto: bool, |
646 | pub is_unsafe: bool, | 663 | pub is_unsafe: bool, |
647 | pub bounds: Box<[Interned<TypeBound>]>, | ||
648 | pub items: Box<[AssocItem]>, | 664 | pub items: Box<[AssocItem]>, |
649 | pub ast_id: FileAstId<ast::Trait>, | 665 | pub ast_id: FileAstId<ast::Trait>, |
650 | } | 666 | } |
@@ -711,6 +727,97 @@ pub struct MacroDef { | |||
711 | pub ast_id: FileAstId<ast::MacroDef>, | 727 | pub ast_id: FileAstId<ast::MacroDef>, |
712 | } | 728 | } |
713 | 729 | ||
730 | impl Import { | ||
731 | /// Maps a `UseTree` contained in this import back to its AST node. | ||
732 | pub fn use_tree_to_ast( | ||
733 | &self, | ||
734 | db: &dyn DefDatabase, | ||
735 | file_id: HirFileId, | ||
736 | index: Idx<ast::UseTree>, | ||
737 | ) -> ast::UseTree { | ||
738 | // Re-lower the AST item and get the source map. | ||
739 | // Note: The AST unwraps are fine, since if they fail we should have never obtained `index`. | ||
740 | let ast = InFile::new(file_id, self.ast_id).to_node(db.upcast()); | ||
741 | let ast_use_tree = ast.use_tree().expect("missing `use_tree`"); | ||
742 | let hygiene = Hygiene::new(db.upcast(), file_id); | ||
743 | let (_, source_map) = | ||
744 | lower::lower_use_tree(db, &hygiene, ast_use_tree).expect("failed to lower use tree"); | ||
745 | source_map[index].clone() | ||
746 | } | ||
747 | } | ||
748 | |||
749 | impl UseTree { | ||
750 | /// Expands the `UseTree` into individually imported `ModPath`s. | ||
751 | pub fn expand( | ||
752 | &self, | ||
753 | mut cb: impl FnMut(Idx<ast::UseTree>, ModPath, /* is_glob */ bool, Option<ImportAlias>), | ||
754 | ) { | ||
755 | self.expand_impl(None, &mut cb) | ||
756 | } | ||
757 | |||
758 | fn expand_impl( | ||
759 | &self, | ||
760 | prefix: Option<ModPath>, | ||
761 | cb: &mut dyn FnMut( | ||
762 | Idx<ast::UseTree>, | ||
763 | ModPath, | ||
764 | /* is_glob */ bool, | ||
765 | Option<ImportAlias>, | ||
766 | ), | ||
767 | ) { | ||
768 | fn concat_mod_paths(prefix: Option<ModPath>, path: &ModPath) -> Option<ModPath> { | ||
769 | match (prefix, &path.kind) { | ||
770 | (None, _) => Some(path.clone()), | ||
771 | (Some(mut prefix), PathKind::Plain) => { | ||
772 | for segment in path.segments() { | ||
773 | prefix.push_segment(segment.clone()); | ||
774 | } | ||
775 | Some(prefix) | ||
776 | } | ||
777 | (Some(prefix), PathKind::Super(0)) => { | ||
778 | // `some::path::self` == `some::path` | ||
779 | if path.segments().is_empty() { | ||
780 | Some(prefix) | ||
781 | } else { | ||
782 | None | ||
783 | } | ||
784 | } | ||
785 | (Some(_), _) => None, | ||
786 | } | ||
787 | } | ||
788 | |||
789 | match &self.kind { | ||
790 | UseTreeKind::Single { path, alias } => { | ||
791 | if let Some(path) = concat_mod_paths(prefix, path) { | ||
792 | cb(self.index, path, false, alias.clone()); | ||
793 | } | ||
794 | } | ||
795 | UseTreeKind::Glob { path: Some(path) } => { | ||
796 | if let Some(path) = concat_mod_paths(prefix, path) { | ||
797 | cb(self.index, path, true, None); | ||
798 | } | ||
799 | } | ||
800 | UseTreeKind::Glob { path: None } => { | ||
801 | if let Some(prefix) = prefix { | ||
802 | cb(self.index, prefix, true, None); | ||
803 | } | ||
804 | } | ||
805 | UseTreeKind::Prefixed { prefix: additional_prefix, list } => { | ||
806 | let prefix = match additional_prefix { | ||
807 | Some(path) => match concat_mod_paths(prefix, path) { | ||
808 | Some(path) => Some(path), | ||
809 | None => return, | ||
810 | }, | ||
811 | None => prefix, | ||
812 | }; | ||
813 | for tree in &**list { | ||
814 | tree.expand_impl(prefix.clone(), cb); | ||
815 | } | ||
816 | } | ||
817 | } | ||
818 | } | ||
819 | } | ||
820 | |||
714 | macro_rules! impl_froms { | 821 | macro_rules! impl_froms { |
715 | ($e:ident { $($v:ident ($t:ty)),* $(,)? }) => { | 822 | ($e:ident { $($v:ident ($t:ty)),* $(,)? }) => { |
716 | $( | 823 | $( |