aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_db/src/syntax_ptr.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_db/src/syntax_ptr.rs')
-rw-r--r--crates/ra_db/src/syntax_ptr.rs48
1 files changed, 48 insertions, 0 deletions
diff --git a/crates/ra_db/src/syntax_ptr.rs b/crates/ra_db/src/syntax_ptr.rs
new file mode 100644
index 000000000..dac94dd36
--- /dev/null
+++ b/crates/ra_db/src/syntax_ptr.rs
@@ -0,0 +1,48 @@
1use ra_syntax::{SourceFileNode, SyntaxKind, SyntaxNode, SyntaxNodeRef, TextRange};
2
3/// A pionter to a syntax node inside a file.
4#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
5pub struct LocalSyntaxPtr {
6 range: TextRange,
7 kind: SyntaxKind,
8}
9
10impl LocalSyntaxPtr {
11 pub fn new(node: SyntaxNodeRef) -> LocalSyntaxPtr {
12 LocalSyntaxPtr {
13 range: node.range(),
14 kind: node.kind(),
15 }
16 }
17
18 pub fn resolve(self, file: &SourceFileNode) -> SyntaxNode {
19 let mut curr = file.syntax();
20 loop {
21 if curr.range() == self.range && curr.kind() == self.kind {
22 return curr.owned();
23 }
24 curr = curr
25 .children()
26 .find(|it| self.range.is_subrange(&it.range()))
27 .unwrap_or_else(|| panic!("can't resolve local ptr to SyntaxNode: {:?}", self))
28 }
29 }
30
31 pub fn range(self) -> TextRange {
32 self.range
33 }
34}
35
36#[test]
37fn test_local_syntax_ptr() {
38 use ra_syntax::{ast, AstNode};
39 let file = SourceFileNode::parse("struct Foo { f: u32, }");
40 let field = file
41 .syntax()
42 .descendants()
43 .find_map(ast::NamedFieldDef::cast)
44 .unwrap();
45 let ptr = LocalSyntaxPtr::new(field.syntax());
46 let field_syntax = ptr.resolve(&file);
47 assert_eq!(field.syntax(), field_syntax);
48}