diff options
Diffstat (limited to 'crates/hir_def/src/item_tree.rs')
-rw-r--r-- | crates/hir_def/src/item_tree.rs | 134 |
1 files changed, 121 insertions, 13 deletions
diff --git a/crates/hir_def/src/item_tree.rs b/crates/hir_def/src/item_tree.rs index 4a5f44027..227337a8d 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)] |
@@ -563,6 +580,7 @@ pub struct Function { | |||
563 | pub abi: Option<Interned<str>>, | 580 | pub abi: Option<Interned<str>>, |
564 | pub params: IdRange<Param>, | 581 | pub params: IdRange<Param>, |
565 | pub ret_type: Interned<TypeRef>, | 582 | pub ret_type: Interned<TypeRef>, |
583 | pub async_ret_type: Option<Interned<TypeRef>>, | ||
566 | pub ast_id: FileAstId<ast::Fn>, | 584 | pub ast_id: FileAstId<ast::Fn>, |
567 | pub(crate) flags: FnFlags, | 585 | pub(crate) flags: FnFlags, |
568 | } | 586 | } |
@@ -644,7 +662,6 @@ pub struct Trait { | |||
644 | pub generic_params: Interned<GenericParams>, | 662 | pub generic_params: Interned<GenericParams>, |
645 | pub is_auto: bool, | 663 | pub is_auto: bool, |
646 | pub is_unsafe: bool, | 664 | pub is_unsafe: bool, |
647 | pub bounds: Box<[TypeBound]>, | ||
648 | pub items: Box<[AssocItem]>, | 665 | pub items: Box<[AssocItem]>, |
649 | pub ast_id: FileAstId<ast::Trait>, | 666 | pub ast_id: FileAstId<ast::Trait>, |
650 | } | 667 | } |
@@ -664,7 +681,7 @@ pub struct TypeAlias { | |||
664 | pub name: Name, | 681 | pub name: Name, |
665 | pub visibility: RawVisibilityId, | 682 | pub visibility: RawVisibilityId, |
666 | /// Bounds on the type alias itself. Only valid in trait declarations, eg. `type Assoc: Copy;`. | 683 | /// Bounds on the type alias itself. Only valid in trait declarations, eg. `type Assoc: Copy;`. |
667 | pub bounds: Box<[TypeBound]>, | 684 | pub bounds: Box<[Interned<TypeBound>]>, |
668 | pub generic_params: Interned<GenericParams>, | 685 | pub generic_params: Interned<GenericParams>, |
669 | pub type_ref: Option<Interned<TypeRef>>, | 686 | pub type_ref: Option<Interned<TypeRef>>, |
670 | pub is_extern: bool, | 687 | pub is_extern: bool, |
@@ -711,6 +728,97 @@ pub struct MacroDef { | |||
711 | pub ast_id: FileAstId<ast::MacroDef>, | 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 | macro_rules! impl_froms { | 822 | macro_rules! impl_froms { |
715 | ($e:ident { $($v:ident ($t:ty)),* $(,)? }) => { | 823 | ($e:ident { $($v:ident ($t:ty)),* $(,)? }) => { |
716 | $( | 824 | $( |