From 77f90caf2deeb6a2d2c8196399fbba61bf0c461d Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 29 Oct 2019 11:15:51 +0300 Subject: start ra_hir_def crate --- crates/ra_hir/src/source_id.rs | 132 +++++++---------------------------------- 1 file changed, 22 insertions(+), 110 deletions(-) (limited to 'crates/ra_hir/src/source_id.rs') diff --git a/crates/ra_hir/src/source_id.rs b/crates/ra_hir/src/source_id.rs index a4dd99598..260b79661 100644 --- a/crates/ra_hir/src/source_id.rs +++ b/crates/ra_hir/src/source_id.rs @@ -2,18 +2,18 @@ use std::{ hash::{Hash, Hasher}, - marker::PhantomData, sync::Arc, }; -use ra_arena::{impl_arena_id, Arena, RawId}; -use ra_syntax::{ast, AstNode, SyntaxNode, SyntaxNodePtr}; +pub use hir_def::ast_id_map::{AstIdMap, ErasedFileAstId, FileAstId}; +use ra_syntax::{AstNode, SyntaxNode}; use crate::{db::AstDatabase, HirFileId}; /// `AstId` points to an AST node in any file. /// /// It is stable across reparses, and can be used as salsa key/value. +// FIXME: isn't this just a `Source>` ? #[derive(Debug)] pub(crate) struct AstId { file_id: HirFileId, @@ -40,122 +40,34 @@ impl Hash for AstId { } impl AstId { + pub fn new(file_id: HirFileId, file_ast_id: FileAstId) -> AstId { + AstId { file_id, file_ast_id } + } + pub(crate) fn file_id(&self) -> HirFileId { self.file_id } pub(crate) fn to_node(&self, db: &impl AstDatabase) -> N { - let syntax_node = db.ast_id_to_node(self.file_id, self.file_ast_id.raw); + let syntax_node = db.ast_id_to_node(self.file_id, self.file_ast_id.into()); N::cast(syntax_node).unwrap() } } -/// `AstId` points to an AST node in a specific file. -#[derive(Debug)] -pub(crate) struct FileAstId { - raw: ErasedFileAstId, - _ty: PhantomData N>, -} - -impl Clone for FileAstId { - fn clone(&self) -> FileAstId { - *self - } -} -impl Copy for FileAstId {} - -impl PartialEq for FileAstId { - fn eq(&self, other: &Self) -> bool { - self.raw == other.raw - } -} -impl Eq for FileAstId {} -impl Hash for FileAstId { - fn hash(&self, hasher: &mut H) { - self.raw.hash(hasher); - } -} - -impl FileAstId { - pub(crate) fn with_file_id(self, file_id: HirFileId) -> AstId { - AstId { file_id, file_ast_id: self } - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct ErasedFileAstId(RawId); -impl_arena_id!(ErasedFileAstId); - -/// Maps items' `SyntaxNode`s to `ErasedFileAstId`s and back. -#[derive(Debug, PartialEq, Eq, Default)] -pub struct AstIdMap { - arena: Arena, +pub(crate) fn ast_id_map_query(db: &impl AstDatabase, file_id: HirFileId) -> Arc { + let map = if let Some(node) = db.parse_or_expand(file_id) { + AstIdMap::from_source(&node) + } else { + AstIdMap::default() + }; + Arc::new(map) } -impl AstIdMap { - pub(crate) fn ast_id_map_query(db: &impl AstDatabase, file_id: HirFileId) -> Arc { - let map = if let Some(node) = db.parse_or_expand(file_id) { - AstIdMap::from_source(&node) - } else { - AstIdMap::default() - }; - Arc::new(map) - } - - pub(crate) fn file_item_query( - db: &impl AstDatabase, - file_id: HirFileId, - ast_id: ErasedFileAstId, - ) -> SyntaxNode { - let node = db.parse_or_expand(file_id).unwrap(); - db.ast_id_map(file_id).arena[ast_id].to_node(&node) - } - - pub(crate) fn ast_id(&self, item: &N) -> FileAstId { - let ptr = SyntaxNodePtr::new(item.syntax()); - let raw = match self.arena.iter().find(|(_id, i)| **i == ptr) { - Some((it, _)) => it, - None => panic!( - "Can't find {:?} in AstIdMap:\n{:?}", - item.syntax(), - self.arena.iter().map(|(_id, i)| i).collect::>(), - ), - }; - - FileAstId { raw, _ty: PhantomData } - } - - fn from_source(node: &SyntaxNode) -> AstIdMap { - assert!(node.parent().is_none()); - let mut res = AstIdMap { arena: Arena::default() }; - // By walking the tree in bread-first order we make sure that parents - // get lower ids then children. That is, adding a new child does not - // change parent's id. This means that, say, adding a new function to a - // trait does not change ids of top-level items, which helps caching. - bfs(node, |it| { - if let Some(module_item) = ast::ModuleItem::cast(it.clone()) { - res.alloc(module_item.syntax()); - } else if let Some(macro_call) = ast::MacroCall::cast(it) { - res.alloc(macro_call.syntax()); - } - }); - res - } - - fn alloc(&mut self, item: &SyntaxNode) -> ErasedFileAstId { - self.arena.alloc(SyntaxNodePtr::new(item)) - } -} - -/// Walks the subtree in bfs order, calling `f` for each node. -fn bfs(node: &SyntaxNode, mut f: impl FnMut(SyntaxNode)) { - let mut curr_layer = vec![node.clone()]; - let mut next_layer = vec![]; - while !curr_layer.is_empty() { - curr_layer.drain(..).for_each(|node| { - next_layer.extend(node.children()); - f(node); - }); - std::mem::swap(&mut curr_layer, &mut next_layer); - } +pub(crate) fn file_item_query( + db: &impl AstDatabase, + file_id: HirFileId, + ast_id: ErasedFileAstId, +) -> SyntaxNode { + let node = db.parse_or_expand(file_id).unwrap(); + db.ast_id_map(file_id)[ast_id].to_node(&node) } -- cgit v1.2.3