mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-10-02 06:41:48 +00:00
move source_id to a separate file
This commit is contained in:
parent
8254244e49
commit
0b820cacab
8 changed files with 128 additions and 120 deletions
113
crates/ra_hir/src/source_id.rs
Normal file
113
crates/ra_hir/src/source_id.rs
Normal file
|
@ -0,0 +1,113 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use ra_arena::{Arena, RawId, impl_arena_id};
|
||||
use ra_syntax::{SyntaxNodePtr, TreeArc, SyntaxNode, SourceFile, AstNode, ast};
|
||||
|
||||
use crate::{HirFileId, DefDatabase};
|
||||
|
||||
/// Identifier of item within a specific file. This is stable over reparses, so
|
||||
/// it's OK to use it as a salsa key/value.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct SourceFileItemId(RawId);
|
||||
impl_arena_id!(SourceFileItemId);
|
||||
|
||||
impl SourceFileItemId {
|
||||
pub(crate) fn with_file_id(self, file_id: HirFileId) -> SourceItemId {
|
||||
SourceItemId { file_id, item_id: self }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct SourceItemId {
|
||||
pub(crate) file_id: HirFileId,
|
||||
pub(crate) item_id: SourceFileItemId,
|
||||
}
|
||||
|
||||
/// Maps items' `SyntaxNode`s to `SourceFileItemId`s and back.
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct SourceFileItems {
|
||||
file_id: HirFileId,
|
||||
arena: Arena<SourceFileItemId, SyntaxNodePtr>,
|
||||
}
|
||||
|
||||
impl SourceFileItems {
|
||||
pub(crate) fn file_items_query(
|
||||
db: &impl DefDatabase,
|
||||
file_id: HirFileId,
|
||||
) -> Arc<SourceFileItems> {
|
||||
let source_file = db.hir_parse(file_id);
|
||||
Arc::new(SourceFileItems::from_source_file(&source_file, file_id))
|
||||
}
|
||||
|
||||
pub(crate) fn file_item_query(
|
||||
db: &impl DefDatabase,
|
||||
source_item_id: SourceItemId,
|
||||
) -> TreeArc<SyntaxNode> {
|
||||
let source_file = db.hir_parse(source_item_id.file_id);
|
||||
db.file_items(source_item_id.file_id)[source_item_id.item_id]
|
||||
.to_node(&source_file)
|
||||
.to_owned()
|
||||
}
|
||||
|
||||
pub(crate) fn from_source_file(
|
||||
source_file: &SourceFile,
|
||||
file_id: HirFileId,
|
||||
) -> SourceFileItems {
|
||||
let mut res = SourceFileItems { file_id, 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(source_file.syntax(), |it| {
|
||||
if let Some(module_item) = ast::ModuleItem::cast(it) {
|
||||
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) -> SourceFileItemId {
|
||||
self.arena.alloc(SyntaxNodePtr::new(item))
|
||||
}
|
||||
pub(crate) fn id_of(&self, file_id: HirFileId, item: &SyntaxNode) -> SourceFileItemId {
|
||||
assert_eq!(
|
||||
self.file_id, file_id,
|
||||
"SourceFileItems: wrong file, expected {:?}, got {:?}",
|
||||
self.file_id, file_id
|
||||
);
|
||||
self.id_of_unchecked(item)
|
||||
}
|
||||
pub(crate) fn id_of_unchecked(&self, item: &SyntaxNode) -> SourceFileItemId {
|
||||
let ptr = SyntaxNodePtr::new(item);
|
||||
if let Some((id, _)) = self.arena.iter().find(|(_id, i)| **i == ptr) {
|
||||
return id;
|
||||
}
|
||||
panic!(
|
||||
"Can't find {:?} in SourceFileItems:\n{:?}",
|
||||
item,
|
||||
self.arena.iter().map(|(_id, i)| i).collect::<Vec<_>>(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Index<SourceFileItemId> for SourceFileItems {
|
||||
type Output = SyntaxNodePtr;
|
||||
fn index(&self, idx: SourceFileItemId) -> &SyntaxNodePtr {
|
||||
&self.arena[idx]
|
||||
}
|
||||
}
|
||||
|
||||
/// 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];
|
||||
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);
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue