diff options
author | Seivan Heidari <[email protected]> | 2019-12-23 14:35:31 +0000 |
---|---|---|
committer | Seivan Heidari <[email protected]> | 2019-12-23 14:35:31 +0000 |
commit | b21d9337d9200e2cfdc90b386591c72c302dc03e (patch) | |
tree | f81f5c08f821115cee26fa4d3ceaae88c7807fd5 /crates/ra_ide/src/expand.rs | |
parent | 18a0937585b836ec5ed054b9ae48e0156ab6d9ef (diff) | |
parent | ce07a2daa9e53aa86a769f8641b14c2878444fbc (diff) |
Merge branch 'master' into feature/themes
Diffstat (limited to 'crates/ra_ide/src/expand.rs')
-rw-r--r-- | crates/ra_ide/src/expand.rs | 89 |
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. |
2 | use std::iter::successors; | 2 | use std::iter::successors; |
3 | 3 | ||
4 | use hir::Source; | 4 | use hir::{InFile, Origin}; |
5 | use ra_db::FileId; | 5 | use ra_db::FileId; |
6 | use ra_syntax::{ast, AstNode, SyntaxNode, SyntaxToken}; | 6 | use ra_syntax::{ast, AstNode, SyntaxNode, SyntaxToken, TextRange}; |
7 | 7 | ||
8 | use crate::{db::RootDatabase, FileRange}; | 8 | use crate::{db::RootDatabase, FileRange}; |
9 | 9 | ||
10 | pub(crate) fn original_range(db: &RootDatabase, node: Source<&SyntaxNode>) -> FileRange { | 10 | pub(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. | 27 | fn 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)?; |