aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_def/src/item_tree
diff options
context:
space:
mode:
Diffstat (limited to 'crates/hir_def/src/item_tree')
-rw-r--r--crates/hir_def/src/item_tree/lower.rs186
-rw-r--r--crates/hir_def/src/item_tree/pretty.rs48
-rw-r--r--crates/hir_def/src/item_tree/tests.rs21
3 files changed, 151 insertions, 104 deletions
diff --git a/crates/hir_def/src/item_tree/lower.rs b/crates/hir_def/src/item_tree/lower.rs
index b4389371f..b83adec46 100644
--- a/crates/hir_def/src/item_tree/lower.rs
+++ b/crates/hir_def/src/item_tree/lower.rs
@@ -3,7 +3,6 @@
3use std::{collections::hash_map::Entry, mem, sync::Arc}; 3use std::{collections::hash_map::Entry, mem, sync::Arc};
4 4
5use hir_expand::{ast_id_map::AstIdMap, hygiene::Hygiene, name::known, HirFileId}; 5use hir_expand::{ast_id_map::AstIdMap, hygiene::Hygiene, name::known, HirFileId};
6use smallvec::SmallVec;
7use syntax::{ 6use syntax::{
8 ast::{self, ModuleItemOwner}, 7 ast::{self, ModuleItemOwner},
9 SyntaxNode, WalkEvent, 8 SyntaxNode, WalkEvent,
@@ -20,22 +19,10 @@ fn id<N: ItemTreeNode>(index: Idx<N>) -> FileItemTreeId<N> {
20 FileItemTreeId { index, _p: PhantomData } 19 FileItemTreeId { index, _p: PhantomData }
21} 20}
22 21
23struct ModItems(SmallVec<[ModItem; 1]>);
24
25impl<T> From<T> for ModItems
26where
27 T: Into<ModItem>,
28{
29 fn from(t: T) -> Self {
30 ModItems(SmallVec::from_buf([t.into(); 1]))
31 }
32}
33
34pub(super) struct Ctx<'a> { 22pub(super) struct Ctx<'a> {
35 db: &'a dyn DefDatabase, 23 db: &'a dyn DefDatabase,
36 tree: ItemTree, 24 tree: ItemTree,
37 hygiene: Hygiene, 25 hygiene: Hygiene,
38 file: HirFileId,
39 source_ast_id_map: Arc<AstIdMap>, 26 source_ast_id_map: Arc<AstIdMap>,
40 body_ctx: crate::body::LowerCtx<'a>, 27 body_ctx: crate::body::LowerCtx<'a>,
41 forced_visibility: Option<RawVisibilityId>, 28 forced_visibility: Option<RawVisibilityId>,
@@ -47,7 +34,6 @@ impl<'a> Ctx<'a> {
47 db, 34 db,
48 tree: ItemTree::default(), 35 tree: ItemTree::default(),
49 hygiene, 36 hygiene,
50 file,
51 source_ast_id_map: db.ast_id_map(file), 37 source_ast_id_map: db.ast_id_map(file),
52 body_ctx: crate::body::LowerCtx::new(db, file), 38 body_ctx: crate::body::LowerCtx::new(db, file),
53 forced_visibility: None, 39 forced_visibility: None,
@@ -55,11 +41,8 @@ impl<'a> Ctx<'a> {
55 } 41 }
56 42
57 pub(super) fn lower_module_items(mut self, item_owner: &dyn ModuleItemOwner) -> ItemTree { 43 pub(super) fn lower_module_items(mut self, item_owner: &dyn ModuleItemOwner) -> ItemTree {
58 self.tree.top_level = item_owner 44 self.tree.top_level =
59 .items() 45 item_owner.items().flat_map(|item| self.lower_mod_item(&item, false)).collect();
60 .flat_map(|item| self.lower_mod_item(&item, false))
61 .flat_map(|items| items.0)
62 .collect();
63 self.tree 46 self.tree
64 } 47 }
65 48
@@ -71,7 +54,6 @@ impl<'a> Ctx<'a> {
71 _ => None, 54 _ => None,
72 }) 55 })
73 .flat_map(|item| self.lower_mod_item(&item, false)) 56 .flat_map(|item| self.lower_mod_item(&item, false))
74 .flat_map(|items| items.0)
75 .collect(); 57 .collect();
76 58
77 // Non-items need to have their inner items collected. 59 // Non-items need to have their inner items collected.
@@ -98,7 +80,7 @@ impl<'a> Ctx<'a> {
98 self.tree.data_mut() 80 self.tree.data_mut()
99 } 81 }
100 82
101 fn lower_mod_item(&mut self, item: &ast::Item, inner: bool) -> Option<ModItems> { 83 fn lower_mod_item(&mut self, item: &ast::Item, inner: bool) -> Option<ModItem> {
102 // Collect inner items for 1-to-1-lowered items. 84 // Collect inner items for 1-to-1-lowered items.
103 match item { 85 match item {
104 ast::Item::Struct(_) 86 ast::Item::Struct(_)
@@ -129,34 +111,28 @@ impl<'a> Ctx<'a> {
129 }; 111 };
130 112
131 let attrs = RawAttrs::new(self.db, item, &self.hygiene); 113 let attrs = RawAttrs::new(self.db, item, &self.hygiene);
132 let items = match item { 114 let item: ModItem = match item {
133 ast::Item::Struct(ast) => self.lower_struct(ast).map(Into::into), 115 ast::Item::Struct(ast) => self.lower_struct(ast)?.into(),
134 ast::Item::Union(ast) => self.lower_union(ast).map(Into::into), 116 ast::Item::Union(ast) => self.lower_union(ast)?.into(),
135 ast::Item::Enum(ast) => self.lower_enum(ast).map(Into::into), 117 ast::Item::Enum(ast) => self.lower_enum(ast)?.into(),
136 ast::Item::Fn(ast) => self.lower_function(ast).map(Into::into), 118 ast::Item::Fn(ast) => self.lower_function(ast)?.into(),
137 ast::Item::TypeAlias(ast) => self.lower_type_alias(ast).map(Into::into), 119 ast::Item::TypeAlias(ast) => self.lower_type_alias(ast)?.into(),
138 ast::Item::Static(ast) => self.lower_static(ast).map(Into::into), 120 ast::Item::Static(ast) => self.lower_static(ast)?.into(),
139 ast::Item::Const(ast) => Some(self.lower_const(ast).into()), 121 ast::Item::Const(ast) => self.lower_const(ast).into(),
140 ast::Item::Module(ast) => self.lower_module(ast).map(Into::into), 122 ast::Item::Module(ast) => self.lower_module(ast)?.into(),
141 ast::Item::Trait(ast) => self.lower_trait(ast).map(Into::into), 123 ast::Item::Trait(ast) => self.lower_trait(ast)?.into(),
142 ast::Item::Impl(ast) => self.lower_impl(ast).map(Into::into), 124 ast::Item::Impl(ast) => self.lower_impl(ast)?.into(),
143 ast::Item::Use(ast) => Some(ModItems( 125 ast::Item::Use(ast) => self.lower_use(ast)?.into(),
144 self.lower_use(ast).into_iter().map(Into::into).collect::<SmallVec<_>>(), 126 ast::Item::ExternCrate(ast) => self.lower_extern_crate(ast)?.into(),
145 )), 127 ast::Item::MacroCall(ast) => self.lower_macro_call(ast)?.into(),
146 ast::Item::ExternCrate(ast) => self.lower_extern_crate(ast).map(Into::into), 128 ast::Item::MacroRules(ast) => self.lower_macro_rules(ast)?.into(),
147 ast::Item::MacroCall(ast) => self.lower_macro_call(ast).map(Into::into), 129 ast::Item::MacroDef(ast) => self.lower_macro_def(ast)?.into(),
148 ast::Item::MacroRules(ast) => self.lower_macro_rules(ast).map(Into::into), 130 ast::Item::ExternBlock(ast) => self.lower_extern_block(ast).into(),
149 ast::Item::MacroDef(ast) => self.lower_macro_def(ast).map(Into::into),
150 ast::Item::ExternBlock(ast) => Some(self.lower_extern_block(ast).into()),
151 }; 131 };
152 132
153 if !attrs.is_empty() { 133 self.add_attrs(item.into(), attrs.clone());
154 for item in items.iter().flat_map(|items| &items.0) {
155 self.add_attrs((*item).into(), attrs.clone());
156 }
157 }
158 134
159 items 135 Some(item)
160 } 136 }
161 137
162 fn add_attrs(&mut self, item: AttrOwner, attrs: RawAttrs) { 138 fn add_attrs(&mut self, item: AttrOwner, attrs: RawAttrs) {
@@ -190,12 +166,10 @@ impl<'a> Ctx<'a> {
190 }, 166 },
191 ast::Item(item) => { 167 ast::Item(item) => {
192 // FIXME: This triggers for macro calls in expression/pattern/type position 168 // FIXME: This triggers for macro calls in expression/pattern/type position
193 let mod_items = self.lower_mod_item(&item, true); 169 let mod_item = self.lower_mod_item(&item, true);
194 let current_block = block_stack.last(); 170 let current_block = block_stack.last();
195 if let (Some(mod_items), Some(block)) = (mod_items, current_block) { 171 if let (Some(mod_item), Some(block)) = (mod_item, current_block) {
196 if !mod_items.0.is_empty() { 172 self.data().inner_items.entry(*block).or_default().push(mod_item);
197 self.data().inner_items.entry(*block).or_default().extend(mod_items.0.iter().copied());
198 }
199 } 173 }
200 }, 174 },
201 _ => {} 175 _ => {}
@@ -480,10 +454,7 @@ impl<'a> Ctx<'a> {
480 items: module 454 items: module
481 .item_list() 455 .item_list()
482 .map(|list| { 456 .map(|list| {
483 list.items() 457 list.items().flat_map(|item| self.lower_mod_item(&item, false)).collect()
484 .flat_map(|item| self.lower_mod_item(&item, false))
485 .flat_map(|items| items.0)
486 .collect()
487 }) 458 })
488 .unwrap_or_else(|| { 459 .unwrap_or_else(|| {
489 cov_mark::hit!(name_res_works_for_broken_modules); 460 cov_mark::hit!(name_res_works_for_broken_modules);
@@ -503,7 +474,6 @@ impl<'a> Ctx<'a> {
503 self.lower_generic_params_and_inner_items(GenericsOwner::Trait(trait_def), trait_def); 474 self.lower_generic_params_and_inner_items(GenericsOwner::Trait(trait_def), trait_def);
504 let is_auto = trait_def.auto_token().is_some(); 475 let is_auto = trait_def.auto_token().is_some();
505 let is_unsafe = trait_def.unsafe_token().is_some(); 476 let is_unsafe = trait_def.unsafe_token().is_some();
506 let bounds = self.lower_type_bounds(trait_def);
507 let items = trait_def.assoc_item_list().map(|list| { 477 let items = trait_def.assoc_item_list().map(|list| {
508 let db = self.db; 478 let db = self.db;
509 self.with_inherited_visibility(visibility, |this| { 479 self.with_inherited_visibility(visibility, |this| {
@@ -526,7 +496,6 @@ impl<'a> Ctx<'a> {
526 generic_params, 496 generic_params,
527 is_auto, 497 is_auto,
528 is_unsafe, 498 is_unsafe,
529 bounds: bounds.into(),
530 items: items.unwrap_or_default(), 499 items: items.unwrap_or_default(),
531 ast_id, 500 ast_id,
532 }; 501 };
@@ -561,30 +530,13 @@ impl<'a> Ctx<'a> {
561 Some(id(self.data().impls.alloc(res))) 530 Some(id(self.data().impls.alloc(res)))
562 } 531 }
563 532
564 fn lower_use(&mut self, use_item: &ast::Use) -> Vec<FileItemTreeId<Import>> { 533 fn lower_use(&mut self, use_item: &ast::Use) -> Option<FileItemTreeId<Import>> {
565 let visibility = self.lower_visibility(use_item); 534 let visibility = self.lower_visibility(use_item);
566 let ast_id = self.source_ast_id_map.ast_id(use_item); 535 let ast_id = self.source_ast_id_map.ast_id(use_item);
536 let (use_tree, _) = lower_use_tree(self.db, &self.hygiene, use_item.use_tree()?)?;
567 537
568 // Every use item can expand to many `Import`s. 538 let res = Import { visibility, ast_id, use_tree };
569 let mut imports = Vec::new(); 539 Some(id(self.data().imports.alloc(res)))
570 let tree = self.tree.data_mut();
571 ModPath::expand_use_item(
572 self.db,
573 InFile::new(self.file, use_item.clone()),
574 &self.hygiene,
575 |path, _use_tree, is_glob, alias| {
576 imports.push(id(tree.imports.alloc(Import {
577 path: Interned::new(path),
578 alias,
579 visibility,
580 is_glob,
581 ast_id,
582 index: imports.len(),
583 })));
584 },
585 );
586
587 imports
588 } 540 }
589 541
590 fn lower_extern_crate( 542 fn lower_extern_crate(
@@ -884,3 +836,81 @@ fn lower_abi(abi: ast::Abi) -> Interned<str> {
884 } 836 }
885 } 837 }
886} 838}
839
840struct UseTreeLowering<'a> {
841 db: &'a dyn DefDatabase,
842 hygiene: &'a Hygiene,
843 mapping: Arena<ast::UseTree>,
844}
845
846impl UseTreeLowering<'_> {
847 fn lower_use_tree(&mut self, tree: ast::UseTree) -> Option<UseTree> {
848 if let Some(use_tree_list) = tree.use_tree_list() {
849 let prefix = match tree.path() {
850 // E.g. use something::{{{inner}}};
851 None => None,
852 // E.g. `use something::{inner}` (prefix is `None`, path is `something`)
853 // or `use something::{path::{inner::{innerer}}}` (prefix is `something::path`, path is `inner`)
854 Some(path) => {
855 match ModPath::from_src(self.db, path, &self.hygiene) {
856 Some(it) => Some(it),
857 None => return None, // FIXME: report errors somewhere
858 }
859 }
860 };
861
862 let list =
863 use_tree_list.use_trees().filter_map(|tree| self.lower_use_tree(tree)).collect();
864
865 Some(
866 self.use_tree(
867 UseTreeKind::Prefixed { prefix: prefix.map(Interned::new), list },
868 tree,
869 ),
870 )
871 } else {
872 let is_glob = tree.star_token().is_some();
873 let path = match tree.path() {
874 Some(path) => Some(ModPath::from_src(self.db, path, &self.hygiene)?),
875 None => None,
876 };
877 let alias = tree.rename().map(|a| {
878 a.name().map(|it| it.as_name()).map_or(ImportAlias::Underscore, ImportAlias::Alias)
879 });
880 if alias.is_some() && is_glob {
881 return None;
882 }
883
884 match (path, alias, is_glob) {
885 (path, None, true) => {
886 if path.is_none() {
887 cov_mark::hit!(glob_enum_group);
888 }
889 Some(self.use_tree(UseTreeKind::Glob { path: path.map(Interned::new) }, tree))
890 }
891 // Globs can't be renamed
892 (_, Some(_), true) | (None, None, false) => None,
893 // `bla::{ as Name}` is invalid
894 (None, Some(_), false) => None,
895 (Some(path), alias, false) => Some(
896 self.use_tree(UseTreeKind::Single { path: Interned::new(path), alias }, tree),
897 ),
898 }
899 }
900 }
901
902 fn use_tree(&mut self, kind: UseTreeKind, ast: ast::UseTree) -> UseTree {
903 let index = self.mapping.alloc(ast);
904 UseTree { index, kind }
905 }
906}
907
908pub(super) fn lower_use_tree(
909 db: &dyn DefDatabase,
910 hygiene: &Hygiene,
911 tree: ast::UseTree,
912) -> Option<(UseTree, Arena<ast::UseTree>)> {
913 let mut lowering = UseTreeLowering { db, hygiene, mapping: Arena::new() };
914 let tree = lowering.lower_use_tree(tree)?;
915 Some((tree, lowering.mapping))
916}
diff --git a/crates/hir_def/src/item_tree/pretty.rs b/crates/hir_def/src/item_tree/pretty.rs
index 9394a5de6..d1ee697cb 100644
--- a/crates/hir_def/src/item_tree/pretty.rs
+++ b/crates/hir_def/src/item_tree/pretty.rs
@@ -163,21 +163,46 @@ impl<'a> Printer<'a> {
163 } 163 }
164 } 164 }
165 165
166 fn print_use_tree(&mut self, use_tree: &UseTree) {
167 match &use_tree.kind {
168 UseTreeKind::Single { path, alias } => {
169 w!(self, "{}", path);
170 if let Some(alias) = alias {
171 w!(self, " as {}", alias);
172 }
173 }
174 UseTreeKind::Glob { path } => {
175 if let Some(path) = path {
176 w!(self, "{}::", path);
177 }
178 w!(self, "*");
179 }
180 UseTreeKind::Prefixed { prefix, list } => {
181 if let Some(prefix) = prefix {
182 w!(self, "{}::", prefix);
183 }
184 w!(self, "{{");
185 for (i, tree) in list.iter().enumerate() {
186 if i != 0 {
187 w!(self, ", ");
188 }
189 self.print_use_tree(tree);
190 }
191 w!(self, "}}");
192 }
193 }
194 }
195
166 fn print_mod_item(&mut self, item: ModItem) { 196 fn print_mod_item(&mut self, item: ModItem) {
167 self.print_attrs_of(item); 197 self.print_attrs_of(item);
168 198
169 match item { 199 match item {
170 ModItem::Import(it) => { 200 ModItem::Import(it) => {
171 let Import { visibility, path, is_glob, alias, ast_id: _, index } = &self.tree[it]; 201 let Import { visibility, use_tree, ast_id: _ } = &self.tree[it];
172 self.print_visibility(*visibility); 202 self.print_visibility(*visibility);
173 w!(self, "use {}", path); 203 w!(self, "use ");
174 if *is_glob { 204 self.print_use_tree(use_tree);
175 w!(self, "::*"); 205 wln!(self, ";");
176 }
177 if let Some(alias) = alias {
178 w!(self, " as {}", alias);
179 }
180 wln!(self, "; // {}", index);
181 } 206 }
182 ModItem::ExternCrate(it) => { 207 ModItem::ExternCrate(it) => {
183 let ExternCrate { name, alias, visibility, ast_id: _ } = &self.tree[it]; 208 let ExternCrate { name, alias, visibility, ast_id: _ } = &self.tree[it];
@@ -320,7 +345,6 @@ impl<'a> Printer<'a> {
320 visibility, 345 visibility,
321 is_auto, 346 is_auto,
322 is_unsafe, 347 is_unsafe,
323 bounds,
324 items, 348 items,
325 generic_params, 349 generic_params,
326 ast_id: _, 350 ast_id: _,
@@ -334,10 +358,6 @@ impl<'a> Printer<'a> {
334 } 358 }
335 w!(self, "trait {}", name); 359 w!(self, "trait {}", name);
336 self.print_generic_params(generic_params); 360 self.print_generic_params(generic_params);
337 if !bounds.is_empty() {
338 w!(self, ": ");
339 self.print_type_bounds(bounds);
340 }
341 self.print_where_clause_and_opening_brace(generic_params); 361 self.print_where_clause_and_opening_brace(generic_params);
342 self.indented(|this| { 362 self.indented(|this| {
343 for item in &**items { 363 for item in &**items {
diff --git a/crates/hir_def/src/item_tree/tests.rs b/crates/hir_def/src/item_tree/tests.rs
index 6407871b5..b362add5c 100644
--- a/crates/hir_def/src/item_tree/tests.rs
+++ b/crates/hir_def/src/item_tree/tests.rs
@@ -26,6 +26,8 @@ use globs::*;
26 26
27/// docs on import 27/// docs on import
28use crate::{A, B}; 28use crate::{A, B};
29
30use a::{c, d::{e}};
29 "#, 31 "#,
30 expect![[r##" 32 expect![[r##"
31 #![doc = " file comment"] // AttrId { is_doc_comment: true, ast_index: 0 } 33 #![doc = " file comment"] // AttrId { is_doc_comment: true, ast_index: 0 }
@@ -36,19 +38,14 @@ use crate::{A, B};
36 38
37 pub(super) extern crate bli; 39 pub(super) extern crate bli;
38 40
39 pub use crate::path::nested; // 0 41 pub use crate::path::{nested, items as renamed, Trait as _};
40
41 pub use crate::path::items as renamed; // 1
42 42
43 pub use crate::path::Trait as _; // 2 43 pub(self) use globs::*;
44
45 pub(self) use globs::*; // 0
46 44
47 #[doc = " docs on import"] // AttrId { is_doc_comment: true, ast_index: 0 } 45 #[doc = " docs on import"] // AttrId { is_doc_comment: true, ast_index: 0 }
48 pub(self) use crate::A; // 0 46 pub(self) use crate::{A, B};
49 47
50 #[doc = " docs on import"] // AttrId { is_doc_comment: true, ast_index: 0 } 48 pub(self) use a::{c, d::{e}};
51 pub(self) use crate::B; // 1
52 "##]], 49 "##]],
53 ); 50 );
54} 51}
@@ -183,7 +180,7 @@ trait Tr: SuperTrait + 'lifetime {
183 _: (), 180 _: (),
184 ) -> (); 181 ) -> ();
185 182
186 pub(self) trait Tr<Self>: SuperTrait + 'lifetime 183 pub(self) trait Tr<Self>
187 where 184 where
188 Self: SuperTrait, 185 Self: SuperTrait,
189 Self: 'lifetime 186 Self: 'lifetime
@@ -218,7 +215,7 @@ mod outline;
218 #[doc = " outer"] // AttrId { is_doc_comment: true, ast_index: 0 } 215 #[doc = " outer"] // AttrId { is_doc_comment: true, ast_index: 0 }
219 #[doc = " inner"] // AttrId { is_doc_comment: true, ast_index: 1 } 216 #[doc = " inner"] // AttrId { is_doc_comment: true, ast_index: 1 }
220 pub(self) mod inline { 217 pub(self) mod inline {
221 pub(self) use super::*; // 0 218 pub(self) use super::*;
222 219
223 // flags = 0x2 220 // flags = 0x2
224 pub(self) fn fn_in_module() -> (); 221 pub(self) fn fn_in_module() -> ();
@@ -353,7 +350,7 @@ trait Tr<'a, T: 'a>: Super {}
353 pub(self) union Union<'a, T, const U: u8> { 350 pub(self) union Union<'a, T, const U: u8> {
354 } 351 }
355 352
356 pub(self) trait Tr<'a, Self, T>: Super 353 pub(self) trait Tr<'a, Self, T>
357 where 354 where
358 Self: Super, 355 Self: Super,
359 T: 'a 356 T: 'a