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/lib.rs | 1 + crates/ra_analysis/src/syntax_ptr.rs | 67 ++++++++++++++++++++++++++++++++++++ crates/ra_syntax/Cargo.toml | 1 + 3 files changed, 69 insertions(+) create mode 100644 crates/ra_analysis/src/syntax_ptr.rs (limited to 'crates') diff --git a/crates/ra_analysis/src/lib.rs b/crates/ra_analysis/src/lib.rs index a67cac21e..363c72c0b 100644 --- a/crates/ra_analysis/src/lib.rs +++ b/crates/ra_analysis/src/lib.rs @@ -12,6 +12,7 @@ mod descriptors; mod imp; mod symbol_index; mod completion; +mod syntax_ptr; use std::{ fmt, 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); +} diff --git a/crates/ra_syntax/Cargo.toml b/crates/ra_syntax/Cargo.toml index 7efebab8b..043c9bacd 100644 --- a/crates/ra_syntax/Cargo.toml +++ b/crates/ra_syntax/Cargo.toml @@ -11,6 +11,7 @@ itertools = "0.7.8" drop_bomb = "0.1.4" parking_lot = "0.6.0" rowan = "0.1.1" +text_unit = "0.1.5" [dev-dependencies] test_utils = { path = "../test_utils" } -- cgit v1.2.3