Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-def/src/item_tree.rs')
-rw-r--r--crates/hir-def/src/item_tree.rs279
1 files changed, 241 insertions, 38 deletions
diff --git a/crates/hir-def/src/item_tree.rs b/crates/hir-def/src/item_tree.rs
index 7cb833fdce..b5bf2feb82 100644
--- a/crates/hir-def/src/item_tree.rs
+++ b/crates/hir-def/src/item_tree.rs
@@ -61,7 +61,7 @@ use crate::{
db::DefDatabase,
generics::GenericParams,
path::{GenericArgs, ImportAlias, ModPath, Path, PathKind},
- type_ref::{Mutability, TraitRef, TypeBound, TypeRef},
+ type_ref::{Mutability, TraitRef, TypeBound, TypeRefId, TypesMap, TypesSourceMap},
visibility::{RawVisibility, VisibilityExplicitness},
BlockId, LocalLifetimeParamId, LocalTypeOrConstParamId, Lookup,
};
@@ -100,14 +100,20 @@ pub struct ItemTree {
impl ItemTree {
pub(crate) fn file_item_tree_query(db: &dyn DefDatabase, file_id: HirFileId) -> Arc<ItemTree> {
- let _p = tracing::info_span!("file_item_tree_query", ?file_id).entered();
- static EMPTY: OnceLock<Arc<ItemTree>> = OnceLock::new();
+ db.file_item_tree_with_source_map(file_id).0
+ }
- let syntax = db.parse_or_expand(file_id);
+ pub(crate) fn file_item_tree_with_source_map_query(
+ db: &dyn DefDatabase,
+ file_id: HirFileId,
+ ) -> (Arc<ItemTree>, Arc<ItemTreeSourceMaps>) {
+ let _p = tracing::info_span!("file_item_tree_query", ?file_id).entered();
+ static EMPTY: OnceLock<(Arc<ItemTree>, Arc<ItemTreeSourceMaps>)> = OnceLock::new();
let ctx = lower::Ctx::new(db, file_id);
+ let syntax = db.parse_or_expand(file_id);
let mut top_attrs = None;
- let mut item_tree = match_ast! {
+ let (mut item_tree, source_maps) = match_ast! {
match syntax {
ast::SourceFile(file) => {
top_attrs = Some(RawAttrs::new(db.upcast(), &file, ctx.span_map()));
@@ -137,42 +143,55 @@ impl ItemTree {
{
EMPTY
.get_or_init(|| {
- Arc::new(ItemTree {
- top_level: SmallVec::new_const(),
- attrs: FxHashMap::default(),
- data: None,
- })
+ (
+ Arc::new(ItemTree {
+ top_level: SmallVec::new_const(),
+ attrs: FxHashMap::default(),
+ data: None,
+ }),
+ Arc::default(),
+ )
})
.clone()
} else {
item_tree.shrink_to_fit();
- Arc::new(item_tree)
+ (Arc::new(item_tree), Arc::new(source_maps))
}
}
pub(crate) fn block_item_tree_query(db: &dyn DefDatabase, block: BlockId) -> Arc<ItemTree> {
+ db.block_item_tree_with_source_map(block).0
+ }
+
+ pub(crate) fn block_item_tree_with_source_map_query(
+ db: &dyn DefDatabase,
+ block: BlockId,
+ ) -> (Arc<ItemTree>, Arc<ItemTreeSourceMaps>) {
let _p = tracing::info_span!("block_item_tree_query", ?block).entered();
- static EMPTY: OnceLock<Arc<ItemTree>> = OnceLock::new();
+ static EMPTY: OnceLock<(Arc<ItemTree>, Arc<ItemTreeSourceMaps>)> = OnceLock::new();
let loc = block.lookup(db);
let block = loc.ast_id.to_node(db.upcast());
let ctx = lower::Ctx::new(db, loc.ast_id.file_id);
- let mut item_tree = ctx.lower_block(&block);
+ let (mut item_tree, source_maps) = ctx.lower_block(&block);
if item_tree.data.is_none() && item_tree.top_level.is_empty() && item_tree.attrs.is_empty()
{
EMPTY
.get_or_init(|| {
- Arc::new(ItemTree {
- top_level: SmallVec::new_const(),
- attrs: FxHashMap::default(),
- data: None,
- })
+ (
+ Arc::new(ItemTree {
+ top_level: SmallVec::new_const(),
+ attrs: FxHashMap::default(),
+ data: None,
+ }),
+ Arc::default(),
+ )
})
.clone()
} else {
item_tree.shrink_to_fit();
- Arc::new(item_tree)
+ (Arc::new(item_tree), Arc::new(source_maps))
}
}
@@ -309,6 +328,160 @@ struct ItemTreeData {
vis: ItemVisibilities,
}
+#[derive(Default, Debug, Eq, PartialEq)]
+pub struct ItemTreeSourceMaps {
+ all_concatenated: Box<[TypesSourceMap]>,
+ structs_offset: u32,
+ unions_offset: u32,
+ enum_generics_offset: u32,
+ variants_offset: u32,
+ consts_offset: u32,
+ statics_offset: u32,
+ trait_generics_offset: u32,
+ trait_alias_generics_offset: u32,
+ impls_offset: u32,
+ type_aliases_offset: u32,
+}
+
+#[derive(Clone, Copy)]
+pub struct GenericItemSourceMap<'a>(&'a [TypesSourceMap; 2]);
+
+impl<'a> GenericItemSourceMap<'a> {
+ #[inline]
+ pub fn item(self) -> &'a TypesSourceMap {
+ &self.0[0]
+ }
+
+ #[inline]
+ pub fn generics(self) -> &'a TypesSourceMap {
+ &self.0[1]
+ }
+}
+
+#[derive(Default, Debug, Eq, PartialEq)]
+pub struct GenericItemSourceMapBuilder {
+ pub item: TypesSourceMap,
+ pub generics: TypesSourceMap,
+}
+
+#[derive(Default, Debug, Eq, PartialEq)]
+struct ItemTreeSourceMapsBuilder {
+ functions: Vec<GenericItemSourceMapBuilder>,
+ structs: Vec<GenericItemSourceMapBuilder>,
+ unions: Vec<GenericItemSourceMapBuilder>,
+ enum_generics: Vec<TypesSourceMap>,
+ variants: Vec<TypesSourceMap>,
+ consts: Vec<TypesSourceMap>,
+ statics: Vec<TypesSourceMap>,
+ trait_generics: Vec<TypesSourceMap>,
+ trait_alias_generics: Vec<TypesSourceMap>,
+ impls: Vec<GenericItemSourceMapBuilder>,
+ type_aliases: Vec<GenericItemSourceMapBuilder>,
+}
+
+impl ItemTreeSourceMapsBuilder {
+ fn build(self) -> ItemTreeSourceMaps {
+ let ItemTreeSourceMapsBuilder {
+ functions,
+ structs,
+ unions,
+ enum_generics,
+ variants,
+ consts,
+ statics,
+ trait_generics,
+ trait_alias_generics,
+ impls,
+ type_aliases,
+ } = self;
+ let structs_offset = functions.len() as u32 * 2;
+ let unions_offset = structs_offset + (structs.len() as u32 * 2);
+ let enum_generics_offset = unions_offset + (unions.len() as u32 * 2);
+ let variants_offset = enum_generics_offset + (enum_generics.len() as u32);
+ let consts_offset = variants_offset + (variants.len() as u32);
+ let statics_offset = consts_offset + (consts.len() as u32);
+ let trait_generics_offset = statics_offset + (statics.len() as u32);
+ let trait_alias_generics_offset = trait_generics_offset + (trait_generics.len() as u32);
+ let impls_offset = trait_alias_generics_offset + (trait_alias_generics.len() as u32);
+ let type_aliases_offset = impls_offset + (impls.len() as u32 * 2);
+ let all_concatenated = generics_concat(functions)
+ .chain(generics_concat(structs))
+ .chain(generics_concat(unions))
+ .chain(enum_generics)
+ .chain(variants)
+ .chain(consts)
+ .chain(statics)
+ .chain(trait_generics)
+ .chain(trait_alias_generics)
+ .chain(generics_concat(impls))
+ .chain(generics_concat(type_aliases))
+ .collect();
+ return ItemTreeSourceMaps {
+ all_concatenated,
+ structs_offset,
+ unions_offset,
+ enum_generics_offset,
+ variants_offset,
+ consts_offset,
+ statics_offset,
+ trait_generics_offset,
+ trait_alias_generics_offset,
+ impls_offset,
+ type_aliases_offset,
+ };
+
+ fn generics_concat(
+ source_maps: Vec<GenericItemSourceMapBuilder>,
+ ) -> impl Iterator<Item = TypesSourceMap> {
+ source_maps.into_iter().flat_map(|it| [it.item, it.generics])
+ }
+ }
+}
+
+impl ItemTreeSourceMaps {
+ #[inline]
+ fn generic_item(&self, offset: u32, index: u32) -> GenericItemSourceMap<'_> {
+ GenericItemSourceMap(
+ self.all_concatenated[(offset + (index * 2)) as usize..][..2].try_into().unwrap(),
+ )
+ }
+
+ #[inline]
+ fn non_generic_item(&self, offset: u32, index: u32) -> &TypesSourceMap {
+ &self.all_concatenated[(offset + index) as usize]
+ }
+
+ #[inline]
+ pub fn function(&self, index: FileItemTreeId<Function>) -> GenericItemSourceMap<'_> {
+ self.generic_item(0, index.0.into_raw().into_u32())
+ }
+}
+
+macro_rules! index_item_source_maps {
+ ( $( $name:ident; $field:ident[$tree_id:ident]; $fn:ident; $ret:ty, )* ) => {
+ impl ItemTreeSourceMaps {
+ $(
+ #[inline]
+ pub fn $name(&self, index: FileItemTreeId<$tree_id>) -> $ret {
+ self.$fn(self.$field, index.0.into_raw().into_u32())
+ }
+ )*
+ }
+ };
+}
+index_item_source_maps! {
+ strukt; structs_offset[Struct]; generic_item; GenericItemSourceMap<'_>,
+ union; unions_offset[Union]; generic_item; GenericItemSourceMap<'_>,
+ enum_generic; enum_generics_offset[Enum]; non_generic_item; &TypesSourceMap,
+ variant; variants_offset[Variant]; non_generic_item; &TypesSourceMap,
+ konst; consts_offset[Const]; non_generic_item; &TypesSourceMap,
+ statik; statics_offset[Static]; non_generic_item; &TypesSourceMap,
+ trait_generic; trait_generics_offset[Trait]; non_generic_item; &TypesSourceMap,
+ trait_alias_generic; trait_alias_generics_offset[TraitAlias]; non_generic_item; &TypesSourceMap,
+ impl_; impls_offset[Impl]; generic_item; GenericItemSourceMap<'_>,
+ type_alias; type_aliases_offset[TypeAlias]; generic_item; GenericItemSourceMap<'_>,
+}
+
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub enum AttrOwner {
/// Attributes on an item.
@@ -364,7 +537,7 @@ pub trait ItemTreeNode: Clone {
fn attr_owner(id: FileItemTreeId<Self>) -> AttrOwner;
}
pub trait GenericsItemTreeNode: ItemTreeNode {
- fn generic_params(&self) -> &Interned<GenericParams>;
+ fn generic_params(&self) -> &Arc<GenericParams>;
}
pub struct FileItemTreeId<N>(Idx<N>);
@@ -429,6 +602,16 @@ impl TreeId {
}
}
+ pub fn item_tree_with_source_map(
+ &self,
+ db: &dyn DefDatabase,
+ ) -> (Arc<ItemTree>, Arc<ItemTreeSourceMaps>) {
+ match self.block {
+ Some(block) => db.block_item_tree_with_source_map(block),
+ None => db.file_item_tree_with_source_map(self.file),
+ }
+ }
+
pub fn file_id(self) -> HirFileId {
self.file
}
@@ -461,6 +644,13 @@ impl<N> ItemTreeId<N> {
self.tree.item_tree(db)
}
+ pub fn item_tree_with_source_map(
+ self,
+ db: &dyn DefDatabase,
+ ) -> (Arc<ItemTree>, Arc<ItemTreeSourceMaps>) {
+ self.tree.item_tree_with_source_map(db)
+ }
+
pub fn resolved<R>(self, db: &dyn DefDatabase, cb: impl FnOnce(&N) -> R) -> R
where
ItemTree: Index<FileItemTreeId<N>, Output = N>,
@@ -593,7 +783,7 @@ macro_rules! mod_items {
$(
impl GenericsItemTreeNode for $typ {
- fn generic_params(&self) -> &Interned<GenericParams> {
+ fn generic_params(&self) -> &Arc<GenericParams> {
&self.$generic_params
}
}
@@ -731,17 +921,18 @@ pub struct ExternBlock {
pub struct Function {
pub name: Name,
pub visibility: RawVisibilityId,
- pub explicit_generic_params: Interned<GenericParams>,
+ pub explicit_generic_params: Arc<GenericParams>,
pub abi: Option<Symbol>,
pub params: Box<[Param]>,
- pub ret_type: Interned<TypeRef>,
+ pub ret_type: TypeRefId,
pub ast_id: FileAstId<ast::Fn>,
+ pub types_map: Arc<TypesMap>,
pub(crate) flags: FnFlags,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Param {
- pub type_ref: Option<Interned<TypeRef>>,
+ pub type_ref: Option<TypeRefId>,
}
bitflags::bitflags! {
@@ -762,26 +953,28 @@ bitflags::bitflags! {
pub struct Struct {
pub name: Name,
pub visibility: RawVisibilityId,
- pub generic_params: Interned<GenericParams>,
+ pub generic_params: Arc<GenericParams>,
pub fields: Box<[Field]>,
pub shape: FieldsShape,
pub ast_id: FileAstId<ast::Struct>,
+ pub types_map: Arc<TypesMap>,
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Union {
pub name: Name,
pub visibility: RawVisibilityId,
- pub generic_params: Interned<GenericParams>,
+ pub generic_params: Arc<GenericParams>,
pub fields: Box<[Field]>,
pub ast_id: FileAstId<ast::Union>,
+ pub types_map: Arc<TypesMap>,
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Enum {
pub name: Name,
pub visibility: RawVisibilityId,
- pub generic_params: Interned<GenericParams>,
+ pub generic_params: Arc<GenericParams>,
pub variants: Range<FileItemTreeId<Variant>>,
pub ast_id: FileAstId<ast::Enum>,
}
@@ -792,6 +985,7 @@ pub struct Variant {
pub fields: Box<[Field]>,
pub shape: FieldsShape,
pub ast_id: FileAstId<ast::Variant>,
+ pub types_map: Arc<TypesMap>,
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
@@ -805,7 +999,7 @@ pub enum FieldsShape {
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Field {
pub name: Name,
- pub type_ref: Interned<TypeRef>,
+ pub type_ref: TypeRefId,
pub visibility: RawVisibilityId,
}
@@ -814,9 +1008,10 @@ pub struct Const {
/// `None` for `const _: () = ();`
pub name: Option<Name>,
pub visibility: RawVisibilityId,
- pub type_ref: Interned<TypeRef>,
+ pub type_ref: TypeRefId,
pub ast_id: FileAstId<ast::Const>,
pub has_body: bool,
+ pub types_map: Arc<TypesMap>,
}
#[derive(Debug, Clone, Eq, PartialEq)]
@@ -827,15 +1022,16 @@ pub struct Static {
pub mutable: bool,
pub has_safe_kw: bool,
pub has_unsafe_kw: bool,
- pub type_ref: Interned<TypeRef>,
+ pub type_ref: TypeRefId,
pub ast_id: FileAstId<ast::Static>,
+ pub types_map: Arc<TypesMap>,
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Trait {
pub name: Name,
pub visibility: RawVisibilityId,
- pub generic_params: Interned<GenericParams>,
+ pub generic_params: Arc<GenericParams>,
pub is_auto: bool,
pub is_unsafe: bool,
pub items: Box<[AssocItem]>,
@@ -846,19 +1042,20 @@ pub struct Trait {
pub struct TraitAlias {
pub name: Name,
pub visibility: RawVisibilityId,
- pub generic_params: Interned<GenericParams>,
+ pub generic_params: Arc<GenericParams>,
pub ast_id: FileAstId<ast::TraitAlias>,
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Impl {
- pub generic_params: Interned<GenericParams>,
- pub target_trait: Option<Interned<TraitRef>>,
- pub self_ty: Interned<TypeRef>,
+ pub generic_params: Arc<GenericParams>,
+ pub target_trait: Option<TraitRef>,
+ pub self_ty: TypeRefId,
pub is_negative: bool,
pub is_unsafe: bool,
pub items: Box<[AssocItem]>,
pub ast_id: FileAstId<ast::Impl>,
+ pub types_map: Arc<TypesMap>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
@@ -866,10 +1063,11 @@ pub struct TypeAlias {
pub name: Name,
pub visibility: RawVisibilityId,
/// Bounds on the type alias itself. Only valid in trait declarations, eg. `type Assoc: Copy;`.
- pub bounds: Box<[Interned<TypeBound>]>,
- pub generic_params: Interned<GenericParams>,
- pub type_ref: Option<Interned<TypeRef>>,
+ pub bounds: Box<[TypeBound]>,
+ pub generic_params: Arc<GenericParams>,
+ pub type_ref: Option<TypeRefId>,
pub ast_id: FileAstId<ast::TypeAlias>,
+ pub types_map: Arc<TypesMap>,
}
#[derive(Debug, Clone, Eq, PartialEq)]
@@ -968,6 +1166,11 @@ impl UseTree {
self.expand_impl(None, &mut cb)
}
+ /// The [`UseTreeKind`] of this `UseTree`.
+ pub fn kind(&self) -> &UseTreeKind {
+ &self.kind
+ }
+
fn expand_impl(
&self,
prefix: Option<ModPath>,