diff options
Diffstat (limited to 'crates/ra_ide/src/expand.rs')
-rw-r--r-- | crates/ra_ide/src/expand.rs | 63 |
1 files changed, 63 insertions, 0 deletions
diff --git a/crates/ra_ide/src/expand.rs b/crates/ra_ide/src/expand.rs new file mode 100644 index 000000000..2f1abf509 --- /dev/null +++ b/crates/ra_ide/src/expand.rs | |||
@@ -0,0 +1,63 @@ | |||
1 | //! Utilities to work with files, produced by macros. | ||
2 | use std::iter::successors; | ||
3 | |||
4 | use hir::Source; | ||
5 | use ra_db::FileId; | ||
6 | use ra_syntax::{ast, AstNode, SyntaxNode, SyntaxToken}; | ||
7 | |||
8 | use crate::{db::RootDatabase, FileRange}; | ||
9 | |||
10 | pub(crate) fn original_range(db: &RootDatabase, node: Source<&SyntaxNode>) -> FileRange { | ||
11 | let expansion = match node.file_id.expansion_info(db) { | ||
12 | None => { | ||
13 | return FileRange { | ||
14 | file_id: node.file_id.original_file(db), | ||
15 | range: node.value.text_range(), | ||
16 | } | ||
17 | } | ||
18 | Some(it) => it, | ||
19 | }; | ||
20 | // FIXME: the following completely wrong. | ||
21 | // | ||
22 | // *First*, we should try to map first and last tokens of node, and, if that | ||
23 | // fails, return the range of the overall macro expansions. | ||
24 | // | ||
25 | // *Second*, we should handle recurside macro expansions | ||
26 | |||
27 | let token = node | ||
28 | .value | ||
29 | .descendants_with_tokens() | ||
30 | .filter_map(|it| it.into_token()) | ||
31 | .find_map(|it| expansion.map_token_up(node.with_value(&it))); | ||
32 | |||
33 | match token { | ||
34 | Some(it) => { | ||
35 | FileRange { file_id: it.file_id.original_file(db), range: it.value.text_range() } | ||
36 | } | ||
37 | None => { | ||
38 | FileRange { file_id: node.file_id.original_file(db), range: node.value.text_range() } | ||
39 | } | ||
40 | } | ||
41 | } | ||
42 | |||
43 | pub(crate) fn descend_into_macros( | ||
44 | db: &RootDatabase, | ||
45 | file_id: FileId, | ||
46 | token: SyntaxToken, | ||
47 | ) -> Source<SyntaxToken> { | ||
48 | let src = Source::new(file_id.into(), token); | ||
49 | |||
50 | successors(Some(src), |token| { | ||
51 | let macro_call = token.value.ancestors().find_map(ast::MacroCall::cast)?; | ||
52 | let tt = macro_call.token_tree()?; | ||
53 | if !token.value.text_range().is_subrange(&tt.syntax().text_range()) { | ||
54 | return None; | ||
55 | } | ||
56 | let source_analyzer = | ||
57 | hir::SourceAnalyzer::new(db, token.with_value(token.value.parent()).as_ref(), None); | ||
58 | let exp = source_analyzer.expand(db, token.with_value(¯o_call))?; | ||
59 | exp.map_token_down(db, token.as_ref()) | ||
60 | }) | ||
61 | .last() | ||
62 | .unwrap() | ||
63 | } | ||