aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_def/src
diff options
context:
space:
mode:
authorJonas Schievink <[email protected]>2020-06-23 18:42:19 +0100
committerJonas Schievink <[email protected]>2020-06-24 15:53:56 +0100
commitc019002d17185f4e8be54a978ab5d67bc632f518 (patch)
treedcc7bbb30e35b179f53c8198835999d9166882b9 /crates/ra_hir_def/src
parentf9a1a9cd3c7757ca3f8ba59287b5d36645008b9b (diff)
Slightly reduce ItemTree memory footprint
Diffstat (limited to 'crates/ra_hir_def/src')
-rw-r--r--crates/ra_hir_def/src/attr.rs2
-rw-r--r--crates/ra_hir_def/src/item_tree.rs73
-rw-r--r--crates/ra_hir_def/src/item_tree/lower.rs46
3 files changed, 68 insertions, 53 deletions
diff --git a/crates/ra_hir_def/src/attr.rs b/crates/ra_hir_def/src/attr.rs
index e0f468bf3..197737ffc 100644
--- a/crates/ra_hir_def/src/attr.rs
+++ b/crates/ra_hir_def/src/attr.rs
@@ -38,6 +38,8 @@ impl ops::Deref for Attrs {
38} 38}
39 39
40impl Attrs { 40impl Attrs {
41 pub const EMPTY: Attrs = Attrs { entries: None };
42
41 pub(crate) fn attrs_query(db: &dyn DefDatabase, def: AttrDefId) -> Attrs { 43 pub(crate) fn attrs_query(db: &dyn DefDatabase, def: AttrDefId) -> Attrs {
42 match def { 44 match def {
43 AttrDefId::ModuleId(module) => { 45 AttrDefId::ModuleId(module) => {
diff --git a/crates/ra_hir_def/src/item_tree.rs b/crates/ra_hir_def/src/item_tree.rs
index a75271703..d55b3f777 100644
--- a/crates/ra_hir_def/src/item_tree.rs
+++ b/crates/ra_hir_def/src/item_tree.rs
@@ -35,16 +35,8 @@ use crate::{
35}; 35};
36use smallvec::SmallVec; 36use smallvec::SmallVec;
37 37
38/// The item tree of a source file. 38#[derive(Default, Debug, Eq, PartialEq)]
39#[derive(Debug, Eq, PartialEq)] 39struct ItemTreeData {
40pub struct ItemTree {
41 file_id: HirFileId,
42 top_level: Vec<ModItem>,
43 top_attrs: Attrs,
44 attrs: FxHashMap<ModItem, Attrs>,
45 empty_attrs: Attrs,
46 inner_items: FxHashMap<FileAstId<ast::ModuleItem>, SmallVec<[ModItem; 1]>>,
47
48 imports: Arena<Import>, 40 imports: Arena<Import>,
49 extern_crates: Arena<ExternCrate>, 41 extern_crates: Arena<ExternCrate>,
50 functions: Arena<Function>, 42 functions: Arena<Function>,
@@ -63,6 +55,26 @@ pub struct ItemTree {
63 exprs: Arena<Expr>, 55 exprs: Arena<Expr>,
64} 56}
65 57
58#[derive(Debug, Eq, PartialEq, Hash)]
59enum AttrOwner {
60 /// Attributes on an item.
61 ModItem(ModItem),
62 /// Inner attributes of the source file.
63 TopLevel,
64 // FIXME: Store variant and field attrs, and stop reparsing them in `attrs_query`.
65}
66
67/// The item tree of a source file.
68#[derive(Debug, Eq, PartialEq)]
69pub struct ItemTree {
70 file_id: HirFileId,
71 top_level: SmallVec<[ModItem; 1]>,
72 attrs: FxHashMap<AttrOwner, Attrs>,
73 inner_items: FxHashMap<FileAstId<ast::ModuleItem>, SmallVec<[ModItem; 1]>>,
74
75 data: Option<Box<ItemTreeData>>,
76}
77
66impl ItemTree { 78impl ItemTree {
67 pub fn item_tree_query(db: &dyn DefDatabase, file_id: HirFileId) -> Arc<ItemTree> { 79 pub fn item_tree_query(db: &dyn DefDatabase, file_id: HirFileId) -> Arc<ItemTree> {
68 let _p = ra_prof::profile("item_tree_query").detail(|| format!("{:?}", file_id)); 80 let _p = ra_prof::profile("item_tree_query").detail(|| format!("{:?}", file_id));
@@ -95,7 +107,9 @@ impl ItemTree {
95 } 107 }
96 }; 108 };
97 109
98 item_tree.top_attrs = top_attrs.unwrap_or_default(); 110 if let Some(attrs) = top_attrs {
111 item_tree.attrs.insert(AttrOwner::TopLevel, attrs);
112 }
99 Arc::new(item_tree) 113 Arc::new(item_tree)
100 } 114 }
101 115
@@ -103,26 +117,9 @@ impl ItemTree {
103 Self { 117 Self {
104 file_id, 118 file_id,
105 top_level: Default::default(), 119 top_level: Default::default(),
106 top_attrs: Default::default(),
107 attrs: Default::default(), 120 attrs: Default::default(),
108 empty_attrs: Default::default(),
109 inner_items: Default::default(), 121 inner_items: Default::default(),
110 imports: Default::default(), 122 data: Default::default(),
111 extern_crates: Default::default(),
112 functions: Default::default(),
113 structs: Default::default(),
114 fields: Default::default(),
115 unions: Default::default(),
116 enums: Default::default(),
117 variants: Default::default(),
118 consts: Default::default(),
119 statics: Default::default(),
120 traits: Default::default(),
121 impls: Default::default(),
122 type_aliases: Default::default(),
123 mods: Default::default(),
124 macro_calls: Default::default(),
125 exprs: Default::default(),
126 } 123 }
127 } 124 }
128 125
@@ -134,11 +131,11 @@ impl ItemTree {
134 131
135 /// Returns the inner attributes of the source file. 132 /// Returns the inner attributes of the source file.
136 pub fn top_level_attrs(&self) -> &Attrs { 133 pub fn top_level_attrs(&self) -> &Attrs {
137 &self.top_attrs 134 self.attrs.get(&AttrOwner::TopLevel).unwrap_or(&Attrs::EMPTY)
138 } 135 }
139 136
140 pub fn attrs(&self, of: ModItem) -> &Attrs { 137 pub fn attrs(&self, of: ModItem) -> &Attrs {
141 self.attrs.get(&of).unwrap_or(&self.empty_attrs) 138 self.attrs.get(&AttrOwner::ModItem(of)).unwrap_or(&Attrs::EMPTY)
142 } 139 }
143 140
144 /// Returns the lowered inner items that `ast` corresponds to. 141 /// Returns the lowered inner items that `ast` corresponds to.
@@ -169,6 +166,14 @@ impl ItemTree {
169 let ptr = map.get(id); 166 let ptr = map.get(id);
170 ptr.to_node(&root) 167 ptr.to_node(&root)
171 } 168 }
169
170 fn data(&self) -> &ItemTreeData {
171 self.data.as_ref().expect("attempted to access data of empty ItemTree")
172 }
173
174 fn data_mut(&mut self) -> &mut ItemTreeData {
175 self.data.get_or_insert_with(Box::default)
176 }
172} 177}
173 178
174/// Trait implemented by all nodes in the item tree. 179/// Trait implemented by all nodes in the item tree.
@@ -246,7 +251,7 @@ macro_rules! mod_items {
246 } 251 }
247 252
248 fn lookup(tree: &ItemTree, index: Idx<Self>) -> &Self { 253 fn lookup(tree: &ItemTree, index: Idx<Self>) -> &Self {
249 &tree.$fld[index] 254 &tree.data().$fld[index]
250 } 255 }
251 256
252 fn id_from_mod_item(mod_item: ModItem) -> Option<FileItemTreeId<Self>> { 257 fn id_from_mod_item(mod_item: ModItem) -> Option<FileItemTreeId<Self>> {
@@ -266,7 +271,7 @@ macro_rules! mod_items {
266 type Output = $typ; 271 type Output = $typ;
267 272
268 fn index(&self, index: Idx<$typ>) -> &Self::Output { 273 fn index(&self, index: Idx<$typ>) -> &Self::Output {
269 &self.$fld[index] 274 &self.data().$fld[index]
270 } 275 }
271 } 276 }
272 )+ 277 )+
@@ -296,7 +301,7 @@ macro_rules! impl_index {
296 type Output = $t; 301 type Output = $t;
297 302
298 fn index(&self, index: Idx<$t>) -> &Self::Output { 303 fn index(&self, index: Idx<$t>) -> &Self::Output {
299 &self.$fld[index] 304 &self.data().$fld[index]
300 } 305 }
301 } 306 }
302 )+ 307 )+
diff --git a/crates/ra_hir_def/src/item_tree/lower.rs b/crates/ra_hir_def/src/item_tree/lower.rs
index 733fcac7a..7d28fe7c6 100644
--- a/crates/ra_hir_def/src/item_tree/lower.rs
+++ b/crates/ra_hir_def/src/item_tree/lower.rs
@@ -66,6 +66,10 @@ impl Ctx {
66 self.tree 66 self.tree
67 } 67 }
68 68
69 fn data(&mut self) -> &mut ItemTreeData {
70 self.tree.data_mut()
71 }
72
69 fn lower_mod_item(&mut self, item: &ast::ModuleItem, inner: bool) -> Option<ModItems> { 73 fn lower_mod_item(&mut self, item: &ast::ModuleItem, inner: bool) -> Option<ModItems> {
70 assert!(inner || self.inner_items.is_empty()); 74 assert!(inner || self.inner_items.is_empty());
71 75
@@ -124,7 +128,7 @@ impl Ctx {
124 } 128 }
125 129
126 fn add_attrs(&mut self, item: ModItem, attrs: Attrs) { 130 fn add_attrs(&mut self, item: ModItem, attrs: Attrs) {
127 match self.tree.attrs.entry(item) { 131 match self.tree.attrs.entry(AttrOwner::ModItem(item)) {
128 Entry::Occupied(mut entry) => { 132 Entry::Occupied(mut entry) => {
129 *entry.get_mut() = entry.get().merge(attrs); 133 *entry.get_mut() = entry.get().merge(attrs);
130 } 134 }
@@ -169,7 +173,7 @@ impl Ctx {
169 ast::StructKind::Unit => StructDefKind::Unit, 173 ast::StructKind::Unit => StructDefKind::Unit,
170 }; 174 };
171 let res = Struct { name, visibility, generic_params, fields, ast_id, kind }; 175 let res = Struct { name, visibility, generic_params, fields, ast_id, kind };
172 Some(id(self.tree.structs.alloc(res))) 176 Some(id(self.data().structs.alloc(res)))
173 } 177 }
174 178
175 fn lower_fields(&mut self, strukt_kind: &ast::StructKind) -> Fields { 179 fn lower_fields(&mut self, strukt_kind: &ast::StructKind) -> Fields {
@@ -190,7 +194,7 @@ impl Ctx {
190 let start = self.next_field_idx(); 194 let start = self.next_field_idx();
191 for field in fields.fields() { 195 for field in fields.fields() {
192 if let Some(data) = self.lower_record_field(&field) { 196 if let Some(data) = self.lower_record_field(&field) {
193 self.tree.fields.alloc(data); 197 self.data().fields.alloc(data);
194 } 198 }
195 } 199 }
196 let end = self.next_field_idx(); 200 let end = self.next_field_idx();
@@ -209,7 +213,7 @@ impl Ctx {
209 let start = self.next_field_idx(); 213 let start = self.next_field_idx();
210 for (i, field) in fields.fields().enumerate() { 214 for (i, field) in fields.fields().enumerate() {
211 if let Some(data) = self.lower_tuple_field(i, &field) { 215 if let Some(data) = self.lower_tuple_field(i, &field) {
212 self.tree.fields.alloc(data); 216 self.data().fields.alloc(data);
213 } 217 }
214 } 218 }
215 let end = self.next_field_idx(); 219 let end = self.next_field_idx();
@@ -236,7 +240,7 @@ impl Ctx {
236 }; 240 };
237 let ast_id = self.source_ast_id_map.ast_id(union); 241 let ast_id = self.source_ast_id_map.ast_id(union);
238 let res = Union { name, visibility, generic_params, fields, ast_id }; 242 let res = Union { name, visibility, generic_params, fields, ast_id };
239 Some(id(self.tree.unions.alloc(res))) 243 Some(id(self.data().unions.alloc(res)))
240 } 244 }
241 245
242 fn lower_enum(&mut self, enum_: &ast::EnumDef) -> Option<FileItemTreeId<Enum>> { 246 fn lower_enum(&mut self, enum_: &ast::EnumDef) -> Option<FileItemTreeId<Enum>> {
@@ -249,14 +253,14 @@ impl Ctx {
249 }; 253 };
250 let ast_id = self.source_ast_id_map.ast_id(enum_); 254 let ast_id = self.source_ast_id_map.ast_id(enum_);
251 let res = Enum { name, visibility, generic_params, variants, ast_id }; 255 let res = Enum { name, visibility, generic_params, variants, ast_id };
252 Some(id(self.tree.enums.alloc(res))) 256 Some(id(self.data().enums.alloc(res)))
253 } 257 }
254 258
255 fn lower_variants(&mut self, variants: &ast::EnumVariantList) -> Range<Idx<Variant>> { 259 fn lower_variants(&mut self, variants: &ast::EnumVariantList) -> Range<Idx<Variant>> {
256 let start = self.next_variant_idx(); 260 let start = self.next_variant_idx();
257 for variant in variants.variants() { 261 for variant in variants.variants() {
258 if let Some(data) = self.lower_variant(&variant) { 262 if let Some(data) = self.lower_variant(&variant) {
259 self.tree.variants.alloc(data); 263 self.data().variants.alloc(data);
260 } 264 }
261 } 265 }
262 let end = self.next_variant_idx(); 266 let end = self.next_variant_idx();
@@ -327,7 +331,7 @@ impl Ctx {
327 }; 331 };
328 res.generic_params = self.lower_generic_params(GenericsOwner::Function(&res), func); 332 res.generic_params = self.lower_generic_params(GenericsOwner::Function(&res), func);
329 333
330 Some(id(self.tree.functions.alloc(res))) 334 Some(id(self.data().functions.alloc(res)))
331 } 335 }
332 336
333 fn lower_type_alias( 337 fn lower_type_alias(
@@ -341,7 +345,7 @@ impl Ctx {
341 let generic_params = self.lower_generic_params(GenericsOwner::TypeAlias, type_alias); 345 let generic_params = self.lower_generic_params(GenericsOwner::TypeAlias, type_alias);
342 let ast_id = self.source_ast_id_map.ast_id(type_alias); 346 let ast_id = self.source_ast_id_map.ast_id(type_alias);
343 let res = TypeAlias { name, visibility, bounds, generic_params, type_ref, ast_id }; 347 let res = TypeAlias { name, visibility, bounds, generic_params, type_ref, ast_id };
344 Some(id(self.tree.type_aliases.alloc(res))) 348 Some(id(self.data().type_aliases.alloc(res)))
345 } 349 }
346 350
347 fn lower_static(&mut self, static_: &ast::StaticDef) -> Option<FileItemTreeId<Static>> { 351 fn lower_static(&mut self, static_: &ast::StaticDef) -> Option<FileItemTreeId<Static>> {
@@ -351,7 +355,7 @@ impl Ctx {
351 let mutable = static_.mut_token().is_some(); 355 let mutable = static_.mut_token().is_some();
352 let ast_id = self.source_ast_id_map.ast_id(static_); 356 let ast_id = self.source_ast_id_map.ast_id(static_);
353 let res = Static { name, visibility, mutable, type_ref, ast_id }; 357 let res = Static { name, visibility, mutable, type_ref, ast_id };
354 Some(id(self.tree.statics.alloc(res))) 358 Some(id(self.data().statics.alloc(res)))
355 } 359 }
356 360
357 fn lower_const(&mut self, konst: &ast::ConstDef) -> FileItemTreeId<Const> { 361 fn lower_const(&mut self, konst: &ast::ConstDef) -> FileItemTreeId<Const> {
@@ -360,7 +364,7 @@ impl Ctx {
360 let visibility = self.lower_visibility(konst); 364 let visibility = self.lower_visibility(konst);
361 let ast_id = self.source_ast_id_map.ast_id(konst); 365 let ast_id = self.source_ast_id_map.ast_id(konst);
362 let res = Const { name, visibility, type_ref, ast_id }; 366 let res = Const { name, visibility, type_ref, ast_id };
363 id(self.tree.consts.alloc(res)) 367 id(self.data().consts.alloc(res))
364 } 368 }
365 369
366 fn lower_module(&mut self, module: &ast::Module) -> Option<FileItemTreeId<Mod>> { 370 fn lower_module(&mut self, module: &ast::Module) -> Option<FileItemTreeId<Mod>> {
@@ -386,7 +390,7 @@ impl Ctx {
386 }; 390 };
387 let ast_id = self.source_ast_id_map.ast_id(module); 391 let ast_id = self.source_ast_id_map.ast_id(module);
388 let res = Mod { name, visibility, kind, ast_id }; 392 let res = Mod { name, visibility, kind, ast_id };
389 Some(id(self.tree.mods.alloc(res))) 393 Some(id(self.data().mods.alloc(res)))
390 } 394 }
391 395
392 fn lower_trait(&mut self, trait_def: &ast::TraitDef) -> Option<FileItemTreeId<Trait>> { 396 fn lower_trait(&mut self, trait_def: &ast::TraitDef) -> Option<FileItemTreeId<Trait>> {
@@ -417,7 +421,7 @@ impl Ctx {
417 items: items.unwrap_or_default(), 421 items: items.unwrap_or_default(),
418 ast_id, 422 ast_id,
419 }; 423 };
420 Some(id(self.tree.traits.alloc(res))) 424 Some(id(self.data().traits.alloc(res)))
421 } 425 }
422 426
423 fn lower_impl(&mut self, impl_def: &ast::ImplDef) -> Option<FileItemTreeId<Impl>> { 427 fn lower_impl(&mut self, impl_def: &ast::ImplDef) -> Option<FileItemTreeId<Impl>> {
@@ -440,7 +444,7 @@ impl Ctx {
440 .collect(); 444 .collect();
441 let ast_id = self.source_ast_id_map.ast_id(impl_def); 445 let ast_id = self.source_ast_id_map.ast_id(impl_def);
442 let res = Impl { generic_params, target_trait, target_type, is_negative, items, ast_id }; 446 let res = Impl { generic_params, target_trait, target_type, is_negative, items, ast_id };
443 Some(id(self.tree.impls.alloc(res))) 447 Some(id(self.data().impls.alloc(res)))
444 } 448 }
445 449
446 fn lower_use(&mut self, use_item: &ast::UseItem) -> Vec<FileItemTreeId<Import>> { 450 fn lower_use(&mut self, use_item: &ast::UseItem) -> Vec<FileItemTreeId<Import>> {
@@ -451,7 +455,7 @@ impl Ctx {
451 455
452 // Every use item can expand to many `Import`s. 456 // Every use item can expand to many `Import`s.
453 let mut imports = Vec::new(); 457 let mut imports = Vec::new();
454 let tree = &mut self.tree; 458 let tree = self.tree.data_mut();
455 ModPath::expand_use_item( 459 ModPath::expand_use_item(
456 InFile::new(self.file, use_item.clone()), 460 InFile::new(self.file, use_item.clone()),
457 &self.hygiene, 461 &self.hygiene,
@@ -484,7 +488,7 @@ impl Ctx {
484 let is_macro_use = extern_crate.has_atom_attr("macro_use"); 488 let is_macro_use = extern_crate.has_atom_attr("macro_use");
485 489
486 let res = ExternCrate { path, alias, visibility, is_macro_use, ast_id }; 490 let res = ExternCrate { path, alias, visibility, is_macro_use, ast_id };
487 Some(id(self.tree.extern_crates.alloc(res))) 491 Some(id(self.data().extern_crates.alloc(res)))
488 } 492 }
489 493
490 fn lower_macro_call(&mut self, m: &ast::MacroCall) -> Option<FileItemTreeId<MacroCall>> { 494 fn lower_macro_call(&mut self, m: &ast::MacroCall) -> Option<FileItemTreeId<MacroCall>> {
@@ -511,7 +515,7 @@ impl Ctx {
511 515
512 let is_builtin = attrs.by_key("rustc_builtin_macro").exists(); 516 let is_builtin = attrs.by_key("rustc_builtin_macro").exists();
513 let res = MacroCall { name, path, is_export, is_builtin, is_local_inner, ast_id }; 517 let res = MacroCall { name, path, is_export, is_builtin, is_local_inner, ast_id };
514 Some(id(self.tree.macro_calls.alloc(res))) 518 Some(id(self.data().macro_calls.alloc(res)))
515 } 519 }
516 520
517 fn lower_extern_block(&mut self, block: &ast::ExternBlock) -> Vec<ModItem> { 521 fn lower_extern_block(&mut self, block: &ast::ExternBlock) -> Vec<ModItem> {
@@ -619,10 +623,14 @@ impl Ctx {
619 } 623 }
620 624
621 fn next_field_idx(&self) -> Idx<Field> { 625 fn next_field_idx(&self) -> Idx<Field> {
622 Idx::from_raw(RawId::from(self.tree.fields.len() as u32)) 626 Idx::from_raw(RawId::from(
627 self.tree.data.as_ref().map_or(0, |data| data.fields.len() as u32),
628 ))
623 } 629 }
624 fn next_variant_idx(&self) -> Idx<Variant> { 630 fn next_variant_idx(&self) -> Idx<Variant> {
625 Idx::from_raw(RawId::from(self.tree.variants.len() as u32)) 631 Idx::from_raw(RawId::from(
632 self.tree.data.as_ref().map_or(0, |data| data.variants.len() as u32),
633 ))
626 } 634 }
627} 635}
628 636