mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-26 13:03:31 +00:00
Slightly reduce ItemTree memory footprint
This commit is contained in:
parent
f9a1a9cd3c
commit
c019002d17
3 changed files with 68 additions and 53 deletions
|
@ -38,6 +38,8 @@ impl ops::Deref for Attrs {
|
|||
}
|
||||
|
||||
impl Attrs {
|
||||
pub const EMPTY: Attrs = Attrs { entries: None };
|
||||
|
||||
pub(crate) fn attrs_query(db: &dyn DefDatabase, def: AttrDefId) -> Attrs {
|
||||
match def {
|
||||
AttrDefId::ModuleId(module) => {
|
||||
|
|
|
@ -35,16 +35,8 @@ use crate::{
|
|||
};
|
||||
use smallvec::SmallVec;
|
||||
|
||||
/// The item tree of a source file.
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
pub struct ItemTree {
|
||||
file_id: HirFileId,
|
||||
top_level: Vec<ModItem>,
|
||||
top_attrs: Attrs,
|
||||
attrs: FxHashMap<ModItem, Attrs>,
|
||||
empty_attrs: Attrs,
|
||||
inner_items: FxHashMap<FileAstId<ast::ModuleItem>, SmallVec<[ModItem; 1]>>,
|
||||
|
||||
#[derive(Default, Debug, Eq, PartialEq)]
|
||||
struct ItemTreeData {
|
||||
imports: Arena<Import>,
|
||||
extern_crates: Arena<ExternCrate>,
|
||||
functions: Arena<Function>,
|
||||
|
@ -63,6 +55,26 @@ pub struct ItemTree {
|
|||
exprs: Arena<Expr>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Hash)]
|
||||
enum AttrOwner {
|
||||
/// Attributes on an item.
|
||||
ModItem(ModItem),
|
||||
/// Inner attributes of the source file.
|
||||
TopLevel,
|
||||
// FIXME: Store variant and field attrs, and stop reparsing them in `attrs_query`.
|
||||
}
|
||||
|
||||
/// The item tree of a source file.
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
pub struct ItemTree {
|
||||
file_id: HirFileId,
|
||||
top_level: SmallVec<[ModItem; 1]>,
|
||||
attrs: FxHashMap<AttrOwner, Attrs>,
|
||||
inner_items: FxHashMap<FileAstId<ast::ModuleItem>, SmallVec<[ModItem; 1]>>,
|
||||
|
||||
data: Option<Box<ItemTreeData>>,
|
||||
}
|
||||
|
||||
impl ItemTree {
|
||||
pub fn item_tree_query(db: &dyn DefDatabase, file_id: HirFileId) -> Arc<ItemTree> {
|
||||
let _p = ra_prof::profile("item_tree_query").detail(|| format!("{:?}", file_id));
|
||||
|
@ -95,7 +107,9 @@ impl ItemTree {
|
|||
}
|
||||
};
|
||||
|
||||
item_tree.top_attrs = top_attrs.unwrap_or_default();
|
||||
if let Some(attrs) = top_attrs {
|
||||
item_tree.attrs.insert(AttrOwner::TopLevel, attrs);
|
||||
}
|
||||
Arc::new(item_tree)
|
||||
}
|
||||
|
||||
|
@ -103,26 +117,9 @@ impl ItemTree {
|
|||
Self {
|
||||
file_id,
|
||||
top_level: Default::default(),
|
||||
top_attrs: Default::default(),
|
||||
attrs: Default::default(),
|
||||
empty_attrs: Default::default(),
|
||||
inner_items: Default::default(),
|
||||
imports: Default::default(),
|
||||
extern_crates: Default::default(),
|
||||
functions: Default::default(),
|
||||
structs: Default::default(),
|
||||
fields: Default::default(),
|
||||
unions: Default::default(),
|
||||
enums: Default::default(),
|
||||
variants: Default::default(),
|
||||
consts: Default::default(),
|
||||
statics: Default::default(),
|
||||
traits: Default::default(),
|
||||
impls: Default::default(),
|
||||
type_aliases: Default::default(),
|
||||
mods: Default::default(),
|
||||
macro_calls: Default::default(),
|
||||
exprs: Default::default(),
|
||||
data: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -134,11 +131,11 @@ impl ItemTree {
|
|||
|
||||
/// Returns the inner attributes of the source file.
|
||||
pub fn top_level_attrs(&self) -> &Attrs {
|
||||
&self.top_attrs
|
||||
self.attrs.get(&AttrOwner::TopLevel).unwrap_or(&Attrs::EMPTY)
|
||||
}
|
||||
|
||||
pub fn attrs(&self, of: ModItem) -> &Attrs {
|
||||
self.attrs.get(&of).unwrap_or(&self.empty_attrs)
|
||||
self.attrs.get(&AttrOwner::ModItem(of)).unwrap_or(&Attrs::EMPTY)
|
||||
}
|
||||
|
||||
/// Returns the lowered inner items that `ast` corresponds to.
|
||||
|
@ -169,6 +166,14 @@ impl ItemTree {
|
|||
let ptr = map.get(id);
|
||||
ptr.to_node(&root)
|
||||
}
|
||||
|
||||
fn data(&self) -> &ItemTreeData {
|
||||
self.data.as_ref().expect("attempted to access data of empty ItemTree")
|
||||
}
|
||||
|
||||
fn data_mut(&mut self) -> &mut ItemTreeData {
|
||||
self.data.get_or_insert_with(Box::default)
|
||||
}
|
||||
}
|
||||
|
||||
/// Trait implemented by all nodes in the item tree.
|
||||
|
@ -246,7 +251,7 @@ macro_rules! mod_items {
|
|||
}
|
||||
|
||||
fn lookup(tree: &ItemTree, index: Idx<Self>) -> &Self {
|
||||
&tree.$fld[index]
|
||||
&tree.data().$fld[index]
|
||||
}
|
||||
|
||||
fn id_from_mod_item(mod_item: ModItem) -> Option<FileItemTreeId<Self>> {
|
||||
|
@ -266,7 +271,7 @@ macro_rules! mod_items {
|
|||
type Output = $typ;
|
||||
|
||||
fn index(&self, index: Idx<$typ>) -> &Self::Output {
|
||||
&self.$fld[index]
|
||||
&self.data().$fld[index]
|
||||
}
|
||||
}
|
||||
)+
|
||||
|
@ -296,7 +301,7 @@ macro_rules! impl_index {
|
|||
type Output = $t;
|
||||
|
||||
fn index(&self, index: Idx<$t>) -> &Self::Output {
|
||||
&self.$fld[index]
|
||||
&self.data().$fld[index]
|
||||
}
|
||||
}
|
||||
)+
|
||||
|
|
|
@ -66,6 +66,10 @@ impl Ctx {
|
|||
self.tree
|
||||
}
|
||||
|
||||
fn data(&mut self) -> &mut ItemTreeData {
|
||||
self.tree.data_mut()
|
||||
}
|
||||
|
||||
fn lower_mod_item(&mut self, item: &ast::ModuleItem, inner: bool) -> Option<ModItems> {
|
||||
assert!(inner || self.inner_items.is_empty());
|
||||
|
||||
|
@ -124,7 +128,7 @@ impl Ctx {
|
|||
}
|
||||
|
||||
fn add_attrs(&mut self, item: ModItem, attrs: Attrs) {
|
||||
match self.tree.attrs.entry(item) {
|
||||
match self.tree.attrs.entry(AttrOwner::ModItem(item)) {
|
||||
Entry::Occupied(mut entry) => {
|
||||
*entry.get_mut() = entry.get().merge(attrs);
|
||||
}
|
||||
|
@ -169,7 +173,7 @@ impl Ctx {
|
|||
ast::StructKind::Unit => StructDefKind::Unit,
|
||||
};
|
||||
let res = Struct { name, visibility, generic_params, fields, ast_id, kind };
|
||||
Some(id(self.tree.structs.alloc(res)))
|
||||
Some(id(self.data().structs.alloc(res)))
|
||||
}
|
||||
|
||||
fn lower_fields(&mut self, strukt_kind: &ast::StructKind) -> Fields {
|
||||
|
@ -190,7 +194,7 @@ impl Ctx {
|
|||
let start = self.next_field_idx();
|
||||
for field in fields.fields() {
|
||||
if let Some(data) = self.lower_record_field(&field) {
|
||||
self.tree.fields.alloc(data);
|
||||
self.data().fields.alloc(data);
|
||||
}
|
||||
}
|
||||
let end = self.next_field_idx();
|
||||
|
@ -209,7 +213,7 @@ impl Ctx {
|
|||
let start = self.next_field_idx();
|
||||
for (i, field) in fields.fields().enumerate() {
|
||||
if let Some(data) = self.lower_tuple_field(i, &field) {
|
||||
self.tree.fields.alloc(data);
|
||||
self.data().fields.alloc(data);
|
||||
}
|
||||
}
|
||||
let end = self.next_field_idx();
|
||||
|
@ -236,7 +240,7 @@ impl Ctx {
|
|||
};
|
||||
let ast_id = self.source_ast_id_map.ast_id(union);
|
||||
let res = Union { name, visibility, generic_params, fields, ast_id };
|
||||
Some(id(self.tree.unions.alloc(res)))
|
||||
Some(id(self.data().unions.alloc(res)))
|
||||
}
|
||||
|
||||
fn lower_enum(&mut self, enum_: &ast::EnumDef) -> Option<FileItemTreeId<Enum>> {
|
||||
|
@ -249,14 +253,14 @@ impl Ctx {
|
|||
};
|
||||
let ast_id = self.source_ast_id_map.ast_id(enum_);
|
||||
let res = Enum { name, visibility, generic_params, variants, ast_id };
|
||||
Some(id(self.tree.enums.alloc(res)))
|
||||
Some(id(self.data().enums.alloc(res)))
|
||||
}
|
||||
|
||||
fn lower_variants(&mut self, variants: &ast::EnumVariantList) -> Range<Idx<Variant>> {
|
||||
let start = self.next_variant_idx();
|
||||
for variant in variants.variants() {
|
||||
if let Some(data) = self.lower_variant(&variant) {
|
||||
self.tree.variants.alloc(data);
|
||||
self.data().variants.alloc(data);
|
||||
}
|
||||
}
|
||||
let end = self.next_variant_idx();
|
||||
|
@ -327,7 +331,7 @@ impl Ctx {
|
|||
};
|
||||
res.generic_params = self.lower_generic_params(GenericsOwner::Function(&res), func);
|
||||
|
||||
Some(id(self.tree.functions.alloc(res)))
|
||||
Some(id(self.data().functions.alloc(res)))
|
||||
}
|
||||
|
||||
fn lower_type_alias(
|
||||
|
@ -341,7 +345,7 @@ impl Ctx {
|
|||
let generic_params = self.lower_generic_params(GenericsOwner::TypeAlias, type_alias);
|
||||
let ast_id = self.source_ast_id_map.ast_id(type_alias);
|
||||
let res = TypeAlias { name, visibility, bounds, generic_params, type_ref, ast_id };
|
||||
Some(id(self.tree.type_aliases.alloc(res)))
|
||||
Some(id(self.data().type_aliases.alloc(res)))
|
||||
}
|
||||
|
||||
fn lower_static(&mut self, static_: &ast::StaticDef) -> Option<FileItemTreeId<Static>> {
|
||||
|
@ -351,7 +355,7 @@ impl Ctx {
|
|||
let mutable = static_.mut_token().is_some();
|
||||
let ast_id = self.source_ast_id_map.ast_id(static_);
|
||||
let res = Static { name, visibility, mutable, type_ref, ast_id };
|
||||
Some(id(self.tree.statics.alloc(res)))
|
||||
Some(id(self.data().statics.alloc(res)))
|
||||
}
|
||||
|
||||
fn lower_const(&mut self, konst: &ast::ConstDef) -> FileItemTreeId<Const> {
|
||||
|
@ -360,7 +364,7 @@ impl Ctx {
|
|||
let visibility = self.lower_visibility(konst);
|
||||
let ast_id = self.source_ast_id_map.ast_id(konst);
|
||||
let res = Const { name, visibility, type_ref, ast_id };
|
||||
id(self.tree.consts.alloc(res))
|
||||
id(self.data().consts.alloc(res))
|
||||
}
|
||||
|
||||
fn lower_module(&mut self, module: &ast::Module) -> Option<FileItemTreeId<Mod>> {
|
||||
|
@ -386,7 +390,7 @@ impl Ctx {
|
|||
};
|
||||
let ast_id = self.source_ast_id_map.ast_id(module);
|
||||
let res = Mod { name, visibility, kind, ast_id };
|
||||
Some(id(self.tree.mods.alloc(res)))
|
||||
Some(id(self.data().mods.alloc(res)))
|
||||
}
|
||||
|
||||
fn lower_trait(&mut self, trait_def: &ast::TraitDef) -> Option<FileItemTreeId<Trait>> {
|
||||
|
@ -417,7 +421,7 @@ impl Ctx {
|
|||
items: items.unwrap_or_default(),
|
||||
ast_id,
|
||||
};
|
||||
Some(id(self.tree.traits.alloc(res)))
|
||||
Some(id(self.data().traits.alloc(res)))
|
||||
}
|
||||
|
||||
fn lower_impl(&mut self, impl_def: &ast::ImplDef) -> Option<FileItemTreeId<Impl>> {
|
||||
|
@ -440,7 +444,7 @@ impl Ctx {
|
|||
.collect();
|
||||
let ast_id = self.source_ast_id_map.ast_id(impl_def);
|
||||
let res = Impl { generic_params, target_trait, target_type, is_negative, items, ast_id };
|
||||
Some(id(self.tree.impls.alloc(res)))
|
||||
Some(id(self.data().impls.alloc(res)))
|
||||
}
|
||||
|
||||
fn lower_use(&mut self, use_item: &ast::UseItem) -> Vec<FileItemTreeId<Import>> {
|
||||
|
@ -451,7 +455,7 @@ impl Ctx {
|
|||
|
||||
// Every use item can expand to many `Import`s.
|
||||
let mut imports = Vec::new();
|
||||
let tree = &mut self.tree;
|
||||
let tree = self.tree.data_mut();
|
||||
ModPath::expand_use_item(
|
||||
InFile::new(self.file, use_item.clone()),
|
||||
&self.hygiene,
|
||||
|
@ -484,7 +488,7 @@ impl Ctx {
|
|||
let is_macro_use = extern_crate.has_atom_attr("macro_use");
|
||||
|
||||
let res = ExternCrate { path, alias, visibility, is_macro_use, ast_id };
|
||||
Some(id(self.tree.extern_crates.alloc(res)))
|
||||
Some(id(self.data().extern_crates.alloc(res)))
|
||||
}
|
||||
|
||||
fn lower_macro_call(&mut self, m: &ast::MacroCall) -> Option<FileItemTreeId<MacroCall>> {
|
||||
|
@ -511,7 +515,7 @@ impl Ctx {
|
|||
|
||||
let is_builtin = attrs.by_key("rustc_builtin_macro").exists();
|
||||
let res = MacroCall { name, path, is_export, is_builtin, is_local_inner, ast_id };
|
||||
Some(id(self.tree.macro_calls.alloc(res)))
|
||||
Some(id(self.data().macro_calls.alloc(res)))
|
||||
}
|
||||
|
||||
fn lower_extern_block(&mut self, block: &ast::ExternBlock) -> Vec<ModItem> {
|
||||
|
@ -619,10 +623,14 @@ impl Ctx {
|
|||
}
|
||||
|
||||
fn next_field_idx(&self) -> Idx<Field> {
|
||||
Idx::from_raw(RawId::from(self.tree.fields.len() as u32))
|
||||
Idx::from_raw(RawId::from(
|
||||
self.tree.data.as_ref().map_or(0, |data| data.fields.len() as u32),
|
||||
))
|
||||
}
|
||||
fn next_variant_idx(&self) -> Idx<Variant> {
|
||||
Idx::from_raw(RawId::from(self.tree.variants.len() as u32))
|
||||
Idx::from_raw(RawId::from(
|
||||
self.tree.data.as_ref().map_or(0, |data| data.variants.len() as u32),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue