diff options
Diffstat (limited to 'crates/ra_analysis')
-rw-r--r-- | crates/ra_analysis/src/lib.rs | 1 | ||||
-rw-r--r-- | crates/ra_analysis/src/syntax_ptr.rs | 67 |
2 files changed, 68 insertions, 0 deletions
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; | |||
12 | mod imp; | 12 | mod imp; |
13 | mod symbol_index; | 13 | mod symbol_index; |
14 | mod completion; | 14 | mod completion; |
15 | mod syntax_ptr; | ||
15 | 16 | ||
16 | use std::{ | 17 | use std::{ |
17 | fmt, | 18 | 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 @@ | |||
1 | use ra_syntax::{ | ||
2 | File, TextRange, SyntaxKind, SyntaxNode, SyntaxNodeRef, | ||
3 | ast::{self, AstNode}, | ||
4 | }; | ||
5 | |||
6 | use crate::FileId; | ||
7 | use crate::db::SyntaxDatabase; | ||
8 | |||
9 | /// SyntaxPtr is a cheap `Copy` id which identifies a particular syntax node, | ||
10 | /// without retainig syntax tree in memory. You need to explicitelly `resovle` | ||
11 | /// `SyntaxPtr` to get a `SyntaxNode` | ||
12 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | ||
13 | pub(crate) struct SyntaxPtr { | ||
14 | file_id: FileId, | ||
15 | local: LocalSyntaxPtr, | ||
16 | } | ||
17 | |||
18 | impl SyntaxPtr { | ||
19 | pub(crate) fn new(file_id: FileId, node: SyntaxNodeRef) -> SyntaxPtr { | ||
20 | let local = LocalSyntaxPtr::new(node); | ||
21 | SyntaxPtr { file_id, local } | ||
22 | } | ||
23 | |||
24 | pub(crate) fn resolve(self, db: &impl SyntaxDatabase) -> SyntaxNode { | ||
25 | let syntax = db.file_syntax(self.file_id); | ||
26 | self.local.resolve(&syntax) | ||
27 | } | ||
28 | } | ||
29 | |||
30 | |||
31 | /// A pionter to a syntax node inside a file. | ||
32 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | ||
33 | struct LocalSyntaxPtr { | ||
34 | range: TextRange, | ||
35 | kind: SyntaxKind, | ||
36 | } | ||
37 | |||
38 | impl LocalSyntaxPtr { | ||
39 | fn new(node: SyntaxNodeRef) -> LocalSyntaxPtr { | ||
40 | LocalSyntaxPtr { | ||
41 | range: node.range(), | ||
42 | kind: node.kind(), | ||
43 | } | ||
44 | } | ||
45 | |||
46 | fn resolve(self, file: &File) -> SyntaxNode { | ||
47 | let mut curr = file.syntax(); | ||
48 | loop { | ||
49 | if curr.range() == self.range && curr.kind() == self.kind { | ||
50 | return curr.owned(); | ||
51 | } | ||
52 | curr = curr.children() | ||
53 | .find(|it| self.range.is_subrange(&it.range())) | ||
54 | .unwrap_or_else(|| panic!("can't resovle local ptr to SyntaxNode: {:?}", self)) | ||
55 | } | ||
56 | } | ||
57 | } | ||
58 | |||
59 | |||
60 | #[test] | ||
61 | fn test_local_syntax_ptr() { | ||
62 | let file = File::parse("struct Foo { f: u32, }"); | ||
63 | let field = file.syntax().descendants().find_map(ast::NamedFieldDef::cast).unwrap(); | ||
64 | let ptr = LocalSyntaxPtr::new(field.syntax()); | ||
65 | let field_syntax = ptr.resolve(&file); | ||
66 | assert_eq!(field.syntax(), field_syntax); | ||
67 | } | ||