aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_hir/src/source_binder.rs40
-rw-r--r--crates/ra_hir_expand/src/db.rs1
-rw-r--r--crates/ra_hir_expand/src/lib.rs1
-rw-r--r--crates/ra_ide_api/src/expand_macro.rs64
4 files changed, 93 insertions, 13 deletions
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs
index c42ceabdf..797f90d50 100644
--- a/crates/ra_hir/src/source_binder.rs
+++ b/crates/ra_hir/src/source_binder.rs
@@ -131,6 +131,7 @@ pub struct ReferenceDescriptor {
131} 131}
132 132
133pub struct Expansion { 133pub struct Expansion {
134 macro_file_kind: MacroFileKind,
134 macro_call_id: MacroCallId, 135 macro_call_id: MacroCallId,
135} 136}
136 137
@@ -145,7 +146,7 @@ impl Expansion {
145 } 146 }
146 147
147 pub fn file_id(&self) -> HirFileId { 148 pub fn file_id(&self) -> HirFileId {
148 self.macro_call_id.as_file(MacroFileKind::Items) 149 self.macro_call_id.as_file(self.macro_file_kind)
149 } 150 }
150} 151}
151 152
@@ -439,7 +440,10 @@ impl SourceAnalyzer {
439 db.ast_id_map(macro_call.file_id).ast_id(macro_call.value), 440 db.ast_id_map(macro_call.file_id).ast_id(macro_call.value),
440 ); 441 );
441 let macro_call_loc = MacroCallLoc { def, ast_id }; 442 let macro_call_loc = MacroCallLoc { def, ast_id };
442 Some(Expansion { macro_call_id: db.intern_macro(macro_call_loc) }) 443 Some(Expansion {
444 macro_call_id: db.intern_macro(macro_call_loc),
445 macro_file_kind: to_macro_file_kind(macro_call.value),
446 })
443 } 447 }
444 448
445 #[cfg(test)] 449 #[cfg(test)]
@@ -538,3 +542,35 @@ fn adjust(
538 }) 542 })
539 .map(|(_ptr, scope)| *scope) 543 .map(|(_ptr, scope)| *scope)
540} 544}
545
546/// Given a `ast::MacroCall`, return what `MacroKindFile` it belongs to.
547/// FIXME: Not completed
548fn to_macro_file_kind(macro_call: &ast::MacroCall) -> MacroFileKind {
549 let syn = macro_call.syntax();
550 let parent = match syn.parent() {
551 Some(it) => it,
552 None => {
553 // FIXME:
554 // If it is root, which means the parent HirFile
555 // MacroKindFile must be non-items
556 // return expr now.
557 return MacroFileKind::Expr;
558 }
559 };
560
561 match parent.kind() {
562 MACRO_ITEMS | SOURCE_FILE => MacroFileKind::Items,
563 LET_STMT => {
564 // FIXME: Handle Pattern
565 MacroFileKind::Expr
566 }
567 EXPR_STMT => MacroFileKind::Statements,
568 BLOCK => MacroFileKind::Statements,
569 ARG_LIST => MacroFileKind::Expr,
570 TRY_EXPR => MacroFileKind::Expr,
571 _ => {
572 // Unknown , Just guess it is `Items`
573 MacroFileKind::Items
574 }
575 }
576}
diff --git a/crates/ra_hir_expand/src/db.rs b/crates/ra_hir_expand/src/db.rs
index 3c11c8a22..e1d93a8ef 100644
--- a/crates/ra_hir_expand/src/db.rs
+++ b/crates/ra_hir_expand/src/db.rs
@@ -151,6 +151,7 @@ pub(crate) fn parse_macro(
151 let fragment_kind = match macro_file.macro_file_kind { 151 let fragment_kind = match macro_file.macro_file_kind {
152 MacroFileKind::Items => FragmentKind::Items, 152 MacroFileKind::Items => FragmentKind::Items,
153 MacroFileKind::Expr => FragmentKind::Expr, 153 MacroFileKind::Expr => FragmentKind::Expr,
154 MacroFileKind::Statements => FragmentKind::Statements,
154 }; 155 };
155 let (parse, rev_token_map) = mbe::token_tree_to_syntax_node(&tt, fragment_kind).ok()?; 156 let (parse, rev_token_map) = mbe::token_tree_to_syntax_node(&tt, fragment_kind).ok()?;
156 Some((parse, Arc::new(rev_token_map))) 157 Some((parse, Arc::new(rev_token_map)))
diff --git a/crates/ra_hir_expand/src/lib.rs b/crates/ra_hir_expand/src/lib.rs
index 1389f64ce..126d12fbb 100644
--- a/crates/ra_hir_expand/src/lib.rs
+++ b/crates/ra_hir_expand/src/lib.rs
@@ -109,6 +109,7 @@ pub struct MacroFile {
109pub enum MacroFileKind { 109pub enum MacroFileKind {
110 Items, 110 Items,
111 Expr, 111 Expr,
112 Statements,
112} 113}
113 114
114/// `MacroCallId` identifies a particular macro invocation, like 115/// `MacroCallId` identifies a particular macro invocation, like
diff --git a/crates/ra_ide_api/src/expand_macro.rs b/crates/ra_ide_api/src/expand_macro.rs
index 7f39262dc..7dbf33a16 100644
--- a/crates/ra_ide_api/src/expand_macro.rs
+++ b/crates/ra_ide_api/src/expand_macro.rs
@@ -84,24 +84,19 @@ fn insert_whitespaces(syn: SyntaxNode) -> String {
84 }; 84 };
85 85
86 res += &match token.kind() { 86 res += &match token.kind() {
87 k @ _ 87 k @ _ if is_text(k) && is_next(|it| !it.is_punct(), true) => {
88 if (k.is_keyword() || k.is_literal() || k == IDENT)
89 && is_next(|it| !it.is_punct(), true) =>
90 {
91 token.text().to_string() + " " 88 token.text().to_string() + " "
92 } 89 }
93 L_CURLY if is_next(|it| it != R_CURLY, true) => { 90 L_CURLY if is_next(|it| it != R_CURLY, true) => {
94 indent += 1; 91 indent += 1;
95 format!(" {{\n{}", " ".repeat(indent)) 92 let leading_space = if is_last(|it| is_text(it), false) { " " } else { "" };
93 format!("{}{{\n{}", leading_space, " ".repeat(indent))
96 } 94 }
97 R_CURLY if is_last(|it| it != L_CURLY, true) => { 95 R_CURLY if is_last(|it| it != L_CURLY, true) => {
98 indent = indent.checked_sub(1).unwrap_or(0); 96 indent = indent.checked_sub(1).unwrap_or(0);
99 format!("\n}}{}", " ".repeat(indent)) 97 format!("\n{}}}", " ".repeat(indent))
100 }
101 R_CURLY => {
102 indent = indent.checked_sub(1).unwrap_or(0);
103 format!("}}\n{}", " ".repeat(indent))
104 } 98 }
99 R_CURLY => format!("}}\n{}", " ".repeat(indent)),
105 T![;] => format!(";\n{}", " ".repeat(indent)), 100 T![;] => format!(";\n{}", " ".repeat(indent)),
106 T![->] => " -> ".to_string(), 101 T![->] => " -> ".to_string(),
107 T![=] => " = ".to_string(), 102 T![=] => " = ".to_string(),
@@ -112,7 +107,11 @@ fn insert_whitespaces(syn: SyntaxNode) -> String {
112 last = Some(token.kind()); 107 last = Some(token.kind());
113 } 108 }
114 109
115 res 110 return res;
111
112 fn is_text(k: SyntaxKind) -> bool {
113 k.is_keyword() || k.is_literal() || k == IDENT
114 }
116} 115}
117 116
118#[cfg(test)] 117#[cfg(test)]
@@ -175,4 +174,47 @@ fn some_thing() -> u32 {
175} 174}
176"###); 175"###);
177 } 176 }
177
178 #[test]
179 fn macro_expand_match_ast() {
180 let res = check_expand_macro(
181 r#"
182 //- /lib.rs
183 macro_rules! match_ast {
184 (match $node:ident { $($tt:tt)* }) => { match_ast!(match ($node) { $($tt)* }) };
185
186 (match ($node:expr) {
187 $( ast::$ast:ident($it:ident) => $res:block, )*
188 _ => $catch_all:expr $(,)?
189 }) => {{
190 $( if let Some($it) = ast::$ast::cast($node.clone()) $res else )*
191 { $catch_all }
192 }};
193 }
194
195 fn main() {
196 mat<|>ch_ast! {
197 match container {
198 ast::TraitDef(it) => {},
199 ast::ImplBlock(it) => {},
200 _ => { continue },
201 }
202 }
203 }
204 "#,
205 );
206
207 assert_eq!(res.name, "match_ast");
208 assert_snapshot!(res.expansion, @r###"
209{
210 if let Some(it) = ast::TraitDef::cast(container.clone()){}
211 else if let Some(it) = ast::ImplBlock::cast(container.clone()){}
212 else {
213 {
214 continue
215 }
216 }
217}
218"###);
219 }
178} 220}