aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide_api/src/expand.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide_api/src/expand.rs')
-rw-r--r--crates/ra_ide_api/src/expand.rs42
1 files changed, 42 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..5f1fb9a12
--- /dev/null
+++ b/crates/ra_ide_api/src/expand.rs
@@ -0,0 +1,42 @@
1//! Utilities to work with files, produced by macros.
2use std::iter::successors;
3
4use hir::Source;
5use ra_db::FileId;
6use ra_syntax::{ast, AstNode, SyntaxNode, SyntaxToken};
7
8use crate::{db::RootDatabase, FileRange};
9
10pub(crate) fn original_range(db: &RootDatabase, node: Source<&SyntaxNode>) -> FileRange {
11 let text_range = node.ast.text_range();
12 let (file_id, range) = node
13 .file_id
14 .expansion_info(db)
15 .and_then(|expansion_info| expansion_info.find_range(text_range))
16 .unwrap_or((node.file_id, text_range));
17
18 // FIXME: handle recursive macro generated macro
19 FileRange { file_id: file_id.original_file(db), range }
20}
21
22pub(crate) fn descend_into_macros(
23 db: &RootDatabase,
24 file_id: FileId,
25 token: SyntaxToken,
26) -> Source<SyntaxToken> {
27 let src = Source::new(file_id.into(), token);
28
29 successors(Some(src), |token| {
30 let macro_call = token.ast.ancestors().find_map(ast::MacroCall::cast)?;
31 let tt = macro_call.token_tree()?;
32 if !token.ast.text_range().is_subrange(&tt.syntax().text_range()) {
33 return None;
34 }
35 let source_analyzer =
36 hir::SourceAnalyzer::new(db, token.with_ast(token.ast.parent()).as_ref(), None);
37 let exp = source_analyzer.expand(db, &macro_call)?;
38 exp.map_token_down(db, token.as_ref())
39 })
40 .last()
41 .unwrap()
42}