diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs index 6d75296a57..5d3196c2a2 100644 --- a/crates/ra_hir/src/source_binder.rs +++ b/crates/ra_hir/src/source_binder.rs @@ -140,12 +140,7 @@ impl Expansion { exp_info.map_token_down(token) } - pub fn source(&self, db: &impl HirDatabase) -> Source> { - let loc = db.lookup_intern_macro(self.macro_call_id); - Source::new(self.file_id(), loc.ast_id) - } - - fn file_id(&self) -> HirFileId { + pub fn file_id(&self) -> HirFileId { self.macro_call_id.as_file(MacroFileKind::Items) } } diff --git a/crates/ra_ide_api/src/expand_macro.rs b/crates/ra_ide_api/src/expand_macro.rs index 49c096ed55..bd557d4550 100644 --- a/crates/ra_ide_api/src/expand_macro.rs +++ b/crates/ra_ide_api/src/expand_macro.rs @@ -11,6 +11,45 @@ use ra_syntax::{ AstNode, NodeOrToken, SyntaxKind, SyntaxNode, WalkEvent, }; +pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option<(String, String)> { + let parse = db.parse(position.file_id); + let file = parse.tree(); + let name_ref = find_node_at_offset::(file.syntax(), position.offset)?; + let mac = name_ref.syntax().ancestors().find_map(ast::MacroCall::cast)?; + + let source = hir::Source::new(position.file_id.into(), mac.syntax()); + let expanded = expand_macro_recur(db, source, &mac)?; + + // FIXME: + // macro expansion may lose all white space information + // But we hope someday we can use ra_fmt for that + let res = insert_whitespaces(expanded); + Some((name_ref.text().to_string(), res)) +} + +fn expand_macro_recur( + db: &RootDatabase, + source: hir::Source<&SyntaxNode>, + macro_call: &ast::MacroCall, +) -> Option { + let analyzer = hir::SourceAnalyzer::new(db, source, None); + let expansion = analyzer.expand(db, ¯o_call)?; + let macro_file_id = expansion.file_id(); + let expanded: SyntaxNode = db.parse_or_expand(macro_file_id)?; + + let children = expanded.descendants().filter_map(ast::MacroCall::cast); + let mut replaces = FxHashMap::default(); + + for child in children.into_iter() { + let source = hir::Source::new(macro_file_id, source.ast); + let new_node = expand_macro_recur(db, source, &child)?; + + replaces.insert(child.syntax().clone().into(), new_node.into()); + } + + Some(replace_descendants(&expanded, &replaces)) +} + fn insert_whitespaces(syn: SyntaxNode) -> String { let mut res = String::new(); @@ -40,46 +79,6 @@ fn insert_whitespaces(syn: SyntaxNode) -> String { res } -fn expand_macro_recur( - db: &RootDatabase, - source: hir::Source<&SyntaxNode>, - macro_call: &ast::MacroCall, -) -> Option { - let analyzer = hir::SourceAnalyzer::new(db, source, None); - let expansion = analyzer.expand(db, ¯o_call)?; - let new_source = expansion.source(db); - let expanded: SyntaxNode = db.parse_or_expand(new_source.file_id)?; - - let children = expanded.descendants().filter_map(ast::MacroCall::cast); - let mut replaces = FxHashMap::default(); - - for child in children.into_iter() { - let source = new_source.with_ast(source.ast); - let new_node = expand_macro_recur(db, source, &child)?; - - replaces.insert(child.syntax().clone().into(), new_node.into()); - } - - Some(replace_descendants(&expanded, &replaces)) -} - -pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option<(String, String)> { - let parse = db.parse(position.file_id); - let file = parse.tree(); - let name_ref = find_node_at_offset::(file.syntax(), position.offset)?; - let mac = name_ref.syntax().ancestors().find_map(ast::MacroCall::cast)?; - - let source = hir::Source::new(position.file_id.into(), mac.syntax()); - - let expanded = expand_macro_recur(db, source, &mac)?; - - // FIXME: - // macro expansion may lose all white space information - // But we hope someday we can use ra_fmt for that - let res = insert_whitespaces(expanded); - Some((name_ref.text().to_string(), res)) -} - #[cfg(test)] mod tests { use crate::mock_analysis::analysis_and_position;