From 950e8b8182897da60bcece70d84e9f0b6dc88632 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 30 Oct 2018 21:23:23 +0300 Subject: introduce syntax-ptr --- crates/ra_analysis/src/syntax_ptr.rs | 67 ++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 crates/ra_analysis/src/syntax_ptr.rs (limited to 'crates/ra_analysis/src/syntax_ptr.rs') diff --git a/crates/ra_analysis/src/syntax_ptr.rs b/crates/ra_analysis/src/syntax_ptr.rs new file mode 100644 index 000000000..863ad2672 --- /dev/null +++ b/crates/ra_analysis/src/syntax_ptr.rs @@ -0,0 +1,67 @@ +use ra_syntax::{ + File, TextRange, SyntaxKind, SyntaxNode, SyntaxNodeRef, + ast::{self, AstNode}, +}; + +use crate::FileId; +use crate::db::SyntaxDatabase; + +/// SyntaxPtr is a cheap `Copy` id which identifies a particular syntax node, +/// without retainig syntax tree in memory. You need to explicitelly `resovle` +/// `SyntaxPtr` to get a `SyntaxNode` +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub(crate) struct SyntaxPtr { + file_id: FileId, + local: LocalSyntaxPtr, +} + +impl SyntaxPtr { + pub(crate) fn new(file_id: FileId, node: SyntaxNodeRef) -> SyntaxPtr { + let local = LocalSyntaxPtr::new(node); + SyntaxPtr { file_id, local } + } + + pub(crate) fn resolve(self, db: &impl SyntaxDatabase) -> SyntaxNode { + let syntax = db.file_syntax(self.file_id); + self.local.resolve(&syntax) + } +} + + +/// A pionter to a syntax node inside a file. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +struct LocalSyntaxPtr { + range: TextRange, + kind: SyntaxKind, +} + +impl LocalSyntaxPtr { + fn new(node: SyntaxNodeRef) -> LocalSyntaxPtr { + LocalSyntaxPtr { + range: node.range(), + kind: node.kind(), + } + } + + fn resolve(self, file: &File) -> SyntaxNode { + let mut curr = file.syntax(); + loop { + if curr.range() == self.range && curr.kind() == self.kind { + return curr.owned(); + } + curr = curr.children() + .find(|it| self.range.is_subrange(&it.range())) + .unwrap_or_else(|| panic!("can't resovle local ptr to SyntaxNode: {:?}", self)) + } + } +} + + +#[test] +fn test_local_syntax_ptr() { + let file = File::parse("struct Foo { f: u32, }"); + let field = file.syntax().descendants().find_map(ast::NamedFieldDef::cast).unwrap(); + let ptr = LocalSyntaxPtr::new(field.syntax()); + let field_syntax = ptr.resolve(&file); + assert_eq!(field.syntax(), field_syntax); +} -- cgit v1.2.3