aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide/src/expand.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide/src/expand.rs')
-rw-r--r--crates/ra_ide/src/expand.rs89
1 files changed, 59 insertions, 30 deletions
diff --git a/crates/ra_ide/src/expand.rs b/crates/ra_ide/src/expand.rs
index 2f1abf509..7a22bb0a4 100644
--- a/crates/ra_ide/src/expand.rs
+++ b/crates/ra_ide/src/expand.rs
@@ -1,42 +1,71 @@
1//! Utilities to work with files, produced by macros. 1//! Utilities to work with files, produced by macros.
2use std::iter::successors; 2use std::iter::successors;
3 3
4use hir::Source; 4use hir::{InFile, Origin};
5use ra_db::FileId; 5use ra_db::FileId;
6use ra_syntax::{ast, AstNode, SyntaxNode, SyntaxToken}; 6use ra_syntax::{ast, AstNode, SyntaxNode, SyntaxToken, TextRange};
7 7
8use crate::{db::RootDatabase, FileRange}; 8use crate::{db::RootDatabase, FileRange};
9 9
10pub(crate) fn original_range(db: &RootDatabase, node: Source<&SyntaxNode>) -> FileRange { 10pub(crate) fn original_range(db: &RootDatabase, node: InFile<&SyntaxNode>) -> FileRange {
11 let expansion = match node.file_id.expansion_info(db) { 11 if let Some((range, Origin::Call)) = original_range_and_origin(db, node) {
12 None => { 12 return range;
13 }
14
15 if let Some(expansion) = node.file_id.expansion_info(db) {
16 if let Some(call_node) = expansion.call_node() {
13 return FileRange { 17 return FileRange {
14 file_id: node.file_id.original_file(db), 18 file_id: call_node.file_id.original_file(db),
15 range: node.value.text_range(), 19 range: call_node.value.text_range(),
16 } 20 };
17 } 21 }
18 Some(it) => it, 22 }
19 }; 23
20 // FIXME: the following completely wrong. 24 FileRange { file_id: node.file_id.original_file(db), range: node.value.text_range() }
21 // 25}
22 // *First*, we should try to map first and last tokens of node, and, if that 26
23 // fails, return the range of the overall macro expansions. 27fn original_range_and_origin(
24 // 28 db: &RootDatabase,
25 // *Second*, we should handle recurside macro expansions 29 node: InFile<&SyntaxNode>,
26 30) -> Option<(FileRange, Origin)> {
27 let token = node 31 let expansion = node.file_id.expansion_info(db)?;
28 .value 32
29 .descendants_with_tokens() 33 // the input node has only one token ?
30 .filter_map(|it| it.into_token()) 34 let single = node.value.first_token()? == node.value.last_token()?;
31 .find_map(|it| expansion.map_token_up(node.with_value(&it))); 35
32 36 // FIXME: We should handle recurside macro expansions
33 match token { 37 let (range, origin) = node.value.descendants().find_map(|it| {
34 Some(it) => { 38 let first = it.first_token()?;
35 FileRange { file_id: it.file_id.original_file(db), range: it.value.text_range() } 39 let last = it.last_token()?;
40
41 if !single && first == last {
42 return None;
36 } 43 }
37 None => { 44
38 FileRange { file_id: node.file_id.original_file(db), range: node.value.text_range() } 45 // Try to map first and last tokens of node, and, if success, return the union range of mapped tokens
46 let (first, first_origin) = expansion.map_token_up(node.with_value(&first))?;
47 let (last, last_origin) = expansion.map_token_up(node.with_value(&last))?;
48
49 if first.file_id != last.file_id || first_origin != last_origin {
50 return None;
39 } 51 }
52
53 // FIXME: Add union method in TextRange
54 Some((
55 first.with_value(union_range(first.value.text_range(), last.value.text_range())),
56 first_origin,
57 ))
58 })?;
59
60 return Some((
61 FileRange { file_id: range.file_id.original_file(db), range: range.value },
62 origin,
63 ));
64
65 fn union_range(a: TextRange, b: TextRange) -> TextRange {
66 let start = a.start().min(b.start());
67 let end = a.end().max(b.end());
68 TextRange::from_to(start, end)
40 } 69 }
41} 70}
42 71
@@ -44,8 +73,8 @@ pub(crate) fn descend_into_macros(
44 db: &RootDatabase, 73 db: &RootDatabase,
45 file_id: FileId, 74 file_id: FileId,
46 token: SyntaxToken, 75 token: SyntaxToken,
47) -> Source<SyntaxToken> { 76) -> InFile<SyntaxToken> {
48 let src = Source::new(file_id.into(), token); 77 let src = InFile::new(file_id.into(), token);
49 78
50 successors(Some(src), |token| { 79 successors(Some(src), |token| {
51 let macro_call = token.value.ancestors().find_map(ast::MacroCall::cast)?; 80 let macro_call = token.value.ancestors().find_map(ast::MacroCall::cast)?;