diff options
author | Seivan Heidari <[email protected]> | 2019-11-18 19:53:40 +0000 |
---|---|---|
committer | Seivan Heidari <[email protected]> | 2019-11-18 19:53:40 +0000 |
commit | 4bdb6351ac557851607df9d142c9e573c0fb5e1d (patch) | |
tree | 48b349958afceeeebecccd63e55004d5a924baff /crates/ra_ide_api/src/expand.rs | |
parent | aceeb0b85ee8228503f970ea602af71ff22216a0 (diff) | |
parent | a4f21801c54c65eafa337edc5e86de2c46b37544 (diff) |
Merge branch 'master' of https://github.com/rust-analyzer/rust-analyzer into feature/themes
Diffstat (limited to 'crates/ra_ide_api/src/expand.rs')
-rw-r--r-- | crates/ra_ide_api/src/expand.rs | 59 |
1 files changed, 59 insertions, 0 deletions
diff --git a/crates/ra_ide_api/src/expand.rs b/crates/ra_ide_api/src/expand.rs new file mode 100644 index 000000000..7f59e46d2 --- /dev/null +++ b/crates/ra_ide_api/src/expand.rs | |||
@@ -0,0 +1,59 @@ | |||
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.ast.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 | .ast | ||
29 | .descendants_with_tokens() | ||
30 | .filter_map(|it| it.into_token()) | ||
31 | .find_map(|it| expansion.map_token_up(node.with_ast(&it))); | ||
32 | |||
33 | match token { | ||
34 | Some(it) => FileRange { file_id: it.file_id.original_file(db), range: it.ast.text_range() }, | ||
35 | None => FileRange { file_id: node.file_id.original_file(db), range: node.ast.text_range() }, | ||
36 | } | ||
37 | } | ||
38 | |||
39 | pub(crate) fn descend_into_macros( | ||
40 | db: &RootDatabase, | ||
41 | file_id: FileId, | ||
42 | token: SyntaxToken, | ||
43 | ) -> Source<SyntaxToken> { | ||
44 | let src = Source::new(file_id.into(), token); | ||
45 | |||
46 | successors(Some(src), |token| { | ||
47 | let macro_call = token.ast.ancestors().find_map(ast::MacroCall::cast)?; | ||
48 | let tt = macro_call.token_tree()?; | ||
49 | if !token.ast.text_range().is_subrange(&tt.syntax().text_range()) { | ||
50 | return None; | ||
51 | } | ||
52 | let source_analyzer = | ||
53 | hir::SourceAnalyzer::new(db, token.with_ast(token.ast.parent()).as_ref(), None); | ||
54 | let exp = source_analyzer.expand(db, ¯o_call)?; | ||
55 | exp.map_token_down(db, token.as_ref()) | ||
56 | }) | ||
57 | .last() | ||
58 | .unwrap() | ||
59 | } | ||