aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_analysis/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_analysis/src')
-rw-r--r--crates/ra_analysis/src/lib.rs1
-rw-r--r--crates/ra_analysis/src/macros.rs64
-rw-r--r--crates/ra_analysis/src/syntax_highlighting.rs62
3 files changed, 67 insertions, 60 deletions
diff --git a/crates/ra_analysis/src/lib.rs b/crates/ra_analysis/src/lib.rs
index 98abe8523..67b1c1482 100644
--- a/crates/ra_analysis/src/lib.rs
+++ b/crates/ra_analysis/src/lib.rs
@@ -18,6 +18,7 @@ pub mod mock_analysis;
18 18
19mod extend_selection; 19mod extend_selection;
20mod syntax_highlighting; 20mod syntax_highlighting;
21mod macros;
21 22
22use std::{fmt, sync::Arc}; 23use std::{fmt, sync::Arc};
23 24
diff --git a/crates/ra_analysis/src/macros.rs b/crates/ra_analysis/src/macros.rs
new file mode 100644
index 000000000..c0dd49dc8
--- /dev/null
+++ b/crates/ra_analysis/src/macros.rs
@@ -0,0 +1,64 @@
1/// Begining of macro expansion.
2///
3/// This code should be moved out of ra_analysis into hir (?) ideally.
4use ra_syntax::{ast, AstNode, SourceFileNode, TextRange};
5
6use crate::{db::RootDatabase, FileId};
7
8pub(crate) fn expand(
9 _db: &RootDatabase,
10 _file_id: FileId,
11 macro_call: ast::MacroCall,
12) -> Option<MacroExpansion> {
13 let path = macro_call.path()?;
14 if path.qualifier().is_some() {
15 return None;
16 }
17 let name_ref = path.segment()?.name_ref()?;
18 if name_ref.text() != "ctry" {
19 return None;
20 }
21
22 let arg = macro_call.token_tree()?;
23 let text = format!(
24 r"
25 fn dummy() {{
26 match {} {{
27 None => return Ok(None),
28 Some(it) => it,
29 }}
30 }}",
31 arg.syntax().text()
32 );
33 let file = SourceFileNode::parse(&text);
34 let match_expr = file.syntax().descendants().find_map(ast::MatchExpr::cast)?;
35 let match_arg = match_expr.expr()?;
36 let ranges_map = vec![(arg.syntax().range(), match_arg.syntax().range())];
37 let res = MacroExpansion {
38 source_file: file,
39 ranges_map,
40 };
41 Some(res)
42}
43
44pub(crate) struct MacroExpansion {
45 pub(crate) source_file: SourceFileNode,
46 pub(crate) ranges_map: Vec<(TextRange, TextRange)>,
47}
48
49impl MacroExpansion {
50 pub(crate) fn source_file(&self) -> &SourceFileNode {
51 &self.source_file
52 }
53 pub(crate) fn map_range_back(&self, tgt_range: TextRange) -> Option<TextRange> {
54 for (s_range, t_range) in self.ranges_map.iter() {
55 if tgt_range.is_subrange(&t_range) {
56 let tgt_at_zero_range = tgt_range - tgt_range.start();
57 let tgt_range_offset = tgt_range.start() - t_range.start();
58 let src_range = tgt_at_zero_range + tgt_range_offset + s_range.start();
59 return Some(src_range);
60 }
61 }
62 None
63 }
64}
diff --git a/crates/ra_analysis/src/syntax_highlighting.rs b/crates/ra_analysis/src/syntax_highlighting.rs
index 98551df8f..38219da71 100644
--- a/crates/ra_analysis/src/syntax_highlighting.rs
+++ b/crates/ra_analysis/src/syntax_highlighting.rs
@@ -1,4 +1,4 @@
1use ra_syntax::{ast, AstNode, SourceFileNode, TextRange}; 1use ra_syntax::{ast, AstNode,};
2use ra_editor::HighlightedRange; 2use ra_editor::HighlightedRange;
3use ra_db::SyntaxDatabase; 3use ra_db::SyntaxDatabase;
4 4
@@ -15,7 +15,7 @@ pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Cancelable<Vec<Hi
15 .descendants() 15 .descendants()
16 .filter_map(ast::MacroCall::cast) 16 .filter_map(ast::MacroCall::cast)
17 { 17 {
18 if let Some(exp) = expand(db, file_id, macro_call) { 18 if let Some(exp) = crate::macros::expand(db, file_id, macro_call) {
19 let mapped_ranges = ra_editor::highlight(exp.source_file()) 19 let mapped_ranges = ra_editor::highlight(exp.source_file())
20 .into_iter() 20 .into_iter()
21 .filter_map(|r| { 21 .filter_map(|r| {
@@ -32,64 +32,6 @@ pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Cancelable<Vec<Hi
32 Ok(res) 32 Ok(res)
33} 33}
34 34
35fn expand(
36 _db: &RootDatabase,
37 _file_id: FileId,
38 macro_call: ast::MacroCall,
39) -> Option<MacroExpansion> {
40 let path = macro_call.path()?;
41 if path.qualifier().is_some() {
42 return None;
43 }
44 let name_ref = path.segment()?.name_ref()?;
45 if name_ref.text() != "ctry" {
46 return None;
47 }
48
49 let arg = macro_call.token_tree()?;
50 let text = format!(
51 r"
52 fn dummy() {{
53 match {} {{
54 None => return Ok(None),
55 Some(it) => it,
56 }}
57 }}",
58 arg.syntax().text()
59 );
60 let file = SourceFileNode::parse(&text);
61 let match_expr = file.syntax().descendants().find_map(ast::MatchExpr::cast)?;
62 let match_arg = match_expr.expr()?;
63 let ranges_map = vec![(arg.syntax().range(), match_arg.syntax().range())];
64 let res = MacroExpansion {
65 source_file: file,
66 ranges_map,
67 };
68 Some(res)
69}
70
71struct MacroExpansion {
72 source_file: SourceFileNode,
73 ranges_map: Vec<(TextRange, TextRange)>,
74}
75
76impl MacroExpansion {
77 fn source_file(&self) -> &SourceFileNode {
78 &self.source_file
79 }
80 fn map_range_back(&self, tgt_range: TextRange) -> Option<TextRange> {
81 for (s_range, t_range) in self.ranges_map.iter() {
82 if tgt_range.is_subrange(&t_range) {
83 let tgt_at_zero_range = tgt_range - tgt_range.start();
84 let tgt_range_offset = tgt_range.start() - t_range.start();
85 let src_range = tgt_at_zero_range + tgt_range_offset + s_range.start();
86 return Some(src_range);
87 }
88 }
89 None
90 }
91}
92
93#[cfg(test)] 35#[cfg(test)]
94mod tests { 36mod tests {
95 use crate::mock_analysis::single_file; 37 use crate::mock_analysis::single_file;