aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_hir/src/source_binder.rs7
-rw-r--r--crates/ra_ide_api/src/expand_macro.rs79
2 files changed, 40 insertions, 46 deletions
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs
index 6d75296a5..5d3196c2a 100644
--- a/crates/ra_hir/src/source_binder.rs
+++ b/crates/ra_hir/src/source_binder.rs
@@ -140,12 +140,7 @@ impl Expansion {
140 exp_info.map_token_down(token) 140 exp_info.map_token_down(token)
141 } 141 }
142 142
143 pub fn source(&self, db: &impl HirDatabase) -> Source<AstId<ast::MacroCall>> { 143 pub fn file_id(&self) -> HirFileId {
144 let loc = db.lookup_intern_macro(self.macro_call_id);
145 Source::new(self.file_id(), loc.ast_id)
146 }
147
148 fn file_id(&self) -> HirFileId {
149 self.macro_call_id.as_file(MacroFileKind::Items) 144 self.macro_call_id.as_file(MacroFileKind::Items)
150 } 145 }
151} 146}
diff --git a/crates/ra_ide_api/src/expand_macro.rs b/crates/ra_ide_api/src/expand_macro.rs
index 49c096ed5..bd557d455 100644
--- a/crates/ra_ide_api/src/expand_macro.rs
+++ b/crates/ra_ide_api/src/expand_macro.rs
@@ -11,33 +11,20 @@ use ra_syntax::{
11 AstNode, NodeOrToken, SyntaxKind, SyntaxNode, WalkEvent, 11 AstNode, NodeOrToken, SyntaxKind, SyntaxNode, WalkEvent,
12}; 12};
13 13
14fn insert_whitespaces(syn: SyntaxNode) -> String { 14pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option<(String, String)> {
15 let mut res = String::new(); 15 let parse = db.parse(position.file_id);
16 16 let file = parse.tree();
17 let mut token_iter = syn 17 let name_ref = find_node_at_offset::<ast::NameRef>(file.syntax(), position.offset)?;
18 .preorder_with_tokens() 18 let mac = name_ref.syntax().ancestors().find_map(ast::MacroCall::cast)?;
19 .filter_map(|event| {
20 if let WalkEvent::Enter(NodeOrToken::Token(token)) = event {
21 Some(token)
22 } else {
23 None
24 }
25 })
26 .peekable();
27 19
28 while let Some(token) = token_iter.next() { 20 let source = hir::Source::new(position.file_id.into(), mac.syntax());
29 res += &token.text().to_string(); 21 let expanded = expand_macro_recur(db, source, &mac)?;
30 if token.kind().is_keyword()
31 || token.kind().is_literal()
32 || token.kind() == SyntaxKind::IDENT
33 {
34 if !token_iter.peek().map(|it| it.kind().is_punct()).unwrap_or(false) {
35 res += " ";
36 }
37 }
38 }
39 22
40 res 23 // FIXME:
24 // macro expansion may lose all white space information
25 // But we hope someday we can use ra_fmt for that
26 let res = insert_whitespaces(expanded);
27 Some((name_ref.text().to_string(), res))
41} 28}
42 29
43fn expand_macro_recur( 30fn expand_macro_recur(
@@ -47,14 +34,14 @@ fn expand_macro_recur(
47) -> Option<SyntaxNode> { 34) -> Option<SyntaxNode> {
48 let analyzer = hir::SourceAnalyzer::new(db, source, None); 35 let analyzer = hir::SourceAnalyzer::new(db, source, None);
49 let expansion = analyzer.expand(db, &macro_call)?; 36 let expansion = analyzer.expand(db, &macro_call)?;
50 let new_source = expansion.source(db); 37 let macro_file_id = expansion.file_id();
51 let expanded: SyntaxNode = db.parse_or_expand(new_source.file_id)?; 38 let expanded: SyntaxNode = db.parse_or_expand(macro_file_id)?;
52 39
53 let children = expanded.descendants().filter_map(ast::MacroCall::cast); 40 let children = expanded.descendants().filter_map(ast::MacroCall::cast);
54 let mut replaces = FxHashMap::default(); 41 let mut replaces = FxHashMap::default();
55 42
56 for child in children.into_iter() { 43 for child in children.into_iter() {
57 let source = new_source.with_ast(source.ast); 44 let source = hir::Source::new(macro_file_id, source.ast);
58 let new_node = expand_macro_recur(db, source, &child)?; 45 let new_node = expand_macro_recur(db, source, &child)?;
59 46
60 replaces.insert(child.syntax().clone().into(), new_node.into()); 47 replaces.insert(child.syntax().clone().into(), new_node.into());
@@ -63,21 +50,33 @@ fn expand_macro_recur(
63 Some(replace_descendants(&expanded, &replaces)) 50 Some(replace_descendants(&expanded, &replaces))
64} 51}
65 52
66pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option<(String, String)> { 53fn insert_whitespaces(syn: SyntaxNode) -> String {
67 let parse = db.parse(position.file_id); 54 let mut res = String::new();
68 let file = parse.tree();
69 let name_ref = find_node_at_offset::<ast::NameRef>(file.syntax(), position.offset)?;
70 let mac = name_ref.syntax().ancestors().find_map(ast::MacroCall::cast)?;
71 55
72 let source = hir::Source::new(position.file_id.into(), mac.syntax()); 56 let mut token_iter = syn
57 .preorder_with_tokens()
58 .filter_map(|event| {
59 if let WalkEvent::Enter(NodeOrToken::Token(token)) = event {
60 Some(token)
61 } else {
62 None
63 }
64 })
65 .peekable();
73 66
74 let expanded = expand_macro_recur(db, source, &mac)?; 67 while let Some(token) = token_iter.next() {
68 res += &token.text().to_string();
69 if token.kind().is_keyword()
70 || token.kind().is_literal()
71 || token.kind() == SyntaxKind::IDENT
72 {
73 if !token_iter.peek().map(|it| it.kind().is_punct()).unwrap_or(false) {
74 res += " ";
75 }
76 }
77 }
75 78
76 // FIXME: 79 res
77 // macro expansion may lose all white space information
78 // But we hope someday we can use ra_fmt for that
79 let res = insert_whitespaces(expanded);
80 Some((name_ref.text().to_string(), res))
81} 80}
82 81
83#[cfg(test)] 82#[cfg(test)]