diff options
-rw-r--r-- | crates/ra_ide_api/src/folding_ranges.rs | 15 | ||||
-rw-r--r-- | crates/ra_lsp_server/src/conv.rs | 24 | ||||
-rw-r--r-- | crates/ra_lsp_server/src/main_loop/handlers.rs | 38 | ||||
-rw-r--r-- | crates/ra_mbe/src/tests.rs | 344 |
4 files changed, 202 insertions, 219 deletions
diff --git a/crates/ra_ide_api/src/folding_ranges.rs b/crates/ra_ide_api/src/folding_ranges.rs index 3ab6c195e..79fadcc5d 100644 --- a/crates/ra_ide_api/src/folding_ranges.rs +++ b/crates/ra_ide_api/src/folding_ranges.rs | |||
@@ -87,6 +87,7 @@ fn fold_kind(kind: SyntaxKind) -> Option<FoldKind> { | |||
87 | | EXTERN_ITEM_LIST | 87 | | EXTERN_ITEM_LIST |
88 | | USE_TREE_LIST | 88 | | USE_TREE_LIST |
89 | | BLOCK | 89 | | BLOCK |
90 | | MATCH_ARM_LIST | ||
90 | | ENUM_VARIANT_LIST | 91 | | ENUM_VARIANT_LIST |
91 | | TOKEN_TREE => Some(FoldKind::Block), | 92 | | TOKEN_TREE => Some(FoldKind::Block), |
92 | _ => None, | 93 | _ => None, |
@@ -358,4 +359,18 @@ macro_rules! foo <fold>{ | |||
358 | let folds = &[FoldKind::Block]; | 359 | let folds = &[FoldKind::Block]; |
359 | do_check(text, folds); | 360 | do_check(text, folds); |
360 | } | 361 | } |
362 | |||
363 | #[test] | ||
364 | fn test_fold_match_arms() { | ||
365 | let text = r#" | ||
366 | fn main() <fold>{ | ||
367 | match 0 <fold>{ | ||
368 | 0 => 0, | ||
369 | _ => 1, | ||
370 | }</fold> | ||
371 | }</fold>"#; | ||
372 | |||
373 | let folds = &[FoldKind::Block, FoldKind::Block]; | ||
374 | do_check(text, folds); | ||
375 | } | ||
361 | } | 376 | } |
diff --git a/crates/ra_lsp_server/src/conv.rs b/crates/ra_lsp_server/src/conv.rs index 5fa52ec1b..d78f77925 100644 --- a/crates/ra_lsp_server/src/conv.rs +++ b/crates/ra_lsp_server/src/conv.rs | |||
@@ -6,8 +6,8 @@ use lsp_types::{ | |||
6 | }; | 6 | }; |
7 | use ra_ide_api::{ | 7 | use ra_ide_api::{ |
8 | translate_offset_with_edit, CompletionItem, CompletionItemKind, FileId, FilePosition, | 8 | translate_offset_with_edit, CompletionItem, CompletionItemKind, FileId, FilePosition, |
9 | FileRange, FileSystemEdit, InsertTextFormat, LineCol, LineIndex, NavigationTarget, RangeInfo, | 9 | FileRange, FileSystemEdit, Fold, FoldKind, InsertTextFormat, LineCol, LineIndex, |
10 | Severity, SourceChange, SourceFileEdit, | 10 | NavigationTarget, RangeInfo, Severity, SourceChange, SourceFileEdit, |
11 | }; | 11 | }; |
12 | use ra_syntax::{SyntaxKind, TextRange, TextUnit}; | 12 | use ra_syntax::{SyntaxKind, TextRange, TextUnit}; |
13 | use ra_text_edit::{AtomTextEdit, TextEdit}; | 13 | use ra_text_edit::{AtomTextEdit, TextEdit}; |
@@ -225,6 +225,26 @@ impl ConvWith<(&LineIndex, LineEndings)> for &AtomTextEdit { | |||
225 | } | 225 | } |
226 | } | 226 | } |
227 | 227 | ||
228 | impl ConvWith<&LineIndex> for Fold { | ||
229 | type Output = lsp_types::FoldingRange; | ||
230 | |||
231 | fn conv_with(self, line_index: &LineIndex) -> lsp_types::FoldingRange { | ||
232 | let range = self.range.conv_with(&line_index); | ||
233 | lsp_types::FoldingRange { | ||
234 | start_line: range.start.line, | ||
235 | start_character: Some(range.start.character), | ||
236 | end_line: range.end.line, | ||
237 | end_character: Some(range.end.character), | ||
238 | kind: match self.kind { | ||
239 | FoldKind::Comment => Some(lsp_types::FoldingRangeKind::Comment), | ||
240 | FoldKind::Imports => Some(lsp_types::FoldingRangeKind::Imports), | ||
241 | FoldKind::Mods => None, | ||
242 | FoldKind::Block => None, | ||
243 | }, | ||
244 | } | ||
245 | } | ||
246 | } | ||
247 | |||
228 | impl<T: ConvWith<CTX>, CTX> ConvWith<CTX> for Option<T> { | 248 | impl<T: ConvWith<CTX>, CTX> ConvWith<CTX> for Option<T> { |
229 | type Output = Option<T::Output>; | 249 | type Output = Option<T::Output>; |
230 | 250 | ||
diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs index 948d543ea..ae57e57e9 100644 --- a/crates/ra_lsp_server/src/main_loop/handlers.rs +++ b/crates/ra_lsp_server/src/main_loop/handlers.rs | |||
@@ -3,14 +3,11 @@ use std::{fmt::Write as _, io::Write as _}; | |||
3 | use lsp_server::ErrorCode; | 3 | use lsp_server::ErrorCode; |
4 | use lsp_types::{ | 4 | use lsp_types::{ |
5 | CodeAction, CodeActionResponse, CodeLens, Command, CompletionItem, Diagnostic, | 5 | CodeAction, CodeActionResponse, CodeLens, Command, CompletionItem, Diagnostic, |
6 | DocumentFormattingParams, DocumentHighlight, DocumentSymbol, FoldingRange, FoldingRangeKind, | 6 | DocumentFormattingParams, DocumentHighlight, DocumentSymbol, FoldingRange, FoldingRangeParams, |
7 | FoldingRangeParams, Hover, HoverContents, Location, MarkupContent, MarkupKind, Position, | 7 | Hover, HoverContents, Location, MarkupContent, MarkupKind, Position, PrepareRenameResponse, |
8 | PrepareRenameResponse, Range, RenameParams, SymbolInformation, TextDocumentIdentifier, | 8 | Range, RenameParams, SymbolInformation, TextDocumentIdentifier, TextEdit, WorkspaceEdit, |
9 | TextEdit, WorkspaceEdit, | ||
10 | }; | ||
11 | use ra_ide_api::{ | ||
12 | AssistId, FileId, FilePosition, FileRange, FoldKind, Query, Runnable, RunnableKind, | ||
13 | }; | 9 | }; |
10 | use ra_ide_api::{AssistId, FileId, FilePosition, FileRange, Query, Runnable, RunnableKind}; | ||
14 | use ra_prof::profile; | 11 | use ra_prof::profile; |
15 | use ra_syntax::{AstNode, SyntaxKind, TextRange, TextUnit}; | 12 | use ra_syntax::{AstNode, SyntaxKind, TextRange, TextUnit}; |
16 | use rustc_hash::FxHashMap; | 13 | use rustc_hash::FxHashMap; |
@@ -383,32 +380,9 @@ pub fn handle_folding_range( | |||
383 | params: FoldingRangeParams, | 380 | params: FoldingRangeParams, |
384 | ) -> Result<Option<Vec<FoldingRange>>> { | 381 | ) -> Result<Option<Vec<FoldingRange>>> { |
385 | let file_id = params.text_document.try_conv_with(&world)?; | 382 | let file_id = params.text_document.try_conv_with(&world)?; |
383 | let folds = world.analysis().folding_ranges(file_id)?; | ||
386 | let line_index = world.analysis().file_line_index(file_id)?; | 384 | let line_index = world.analysis().file_line_index(file_id)?; |
387 | 385 | let res = Some(folds.into_iter().map_conv_with(&*line_index).collect()); | |
388 | let res = Some( | ||
389 | world | ||
390 | .analysis() | ||
391 | .folding_ranges(file_id)? | ||
392 | .into_iter() | ||
393 | .map(|fold| { | ||
394 | let kind = match fold.kind { | ||
395 | FoldKind::Comment => Some(FoldingRangeKind::Comment), | ||
396 | FoldKind::Imports => Some(FoldingRangeKind::Imports), | ||
397 | FoldKind::Mods => None, | ||
398 | FoldKind::Block => None, | ||
399 | }; | ||
400 | let range = fold.range.conv_with(&line_index); | ||
401 | FoldingRange { | ||
402 | start_line: range.start.line, | ||
403 | start_character: Some(range.start.character), | ||
404 | end_line: range.end.line, | ||
405 | end_character: Some(range.start.character), | ||
406 | kind, | ||
407 | } | ||
408 | }) | ||
409 | .collect(), | ||
410 | ); | ||
411 | |||
412 | Ok(res) | 386 | Ok(res) |
413 | } | 387 | } |
414 | 388 | ||
diff --git a/crates/ra_mbe/src/tests.rs b/crates/ra_mbe/src/tests.rs index d7482c63d..f34ab52e1 100644 --- a/crates/ra_mbe/src/tests.rs +++ b/crates/ra_mbe/src/tests.rs | |||
@@ -1,4 +1,4 @@ | |||
1 | use ra_syntax::{ast, AstNode, NodeOrToken}; | 1 | use ra_syntax::{ast, AstNode, NodeOrToken, WalkEvent}; |
2 | use test_utils::assert_eq_text; | 2 | use test_utils::assert_eq_text; |
3 | 3 | ||
4 | use super::*; | 4 | use super::*; |
@@ -78,18 +78,8 @@ macro_rules! impl_froms { | |||
78 | impl_froms!(TokenTree: Leaf, Subtree); | 78 | impl_froms!(TokenTree: Leaf, Subtree); |
79 | "#; | 79 | "#; |
80 | 80 | ||
81 | let source_file = ast::SourceFile::parse(macro_definition).ok().unwrap(); | 81 | let rules = create_rules(macro_definition); |
82 | let macro_definition = | 82 | let expansion = expand(&rules, macro_invocation); |
83 | source_file.syntax().descendants().find_map(ast::MacroCall::cast).unwrap(); | ||
84 | |||
85 | let source_file = ast::SourceFile::parse(macro_invocation).ok().unwrap(); | ||
86 | let macro_invocation = | ||
87 | source_file.syntax().descendants().find_map(ast::MacroCall::cast).unwrap(); | ||
88 | |||
89 | let (definition_tt, _) = ast_to_token_tree(¯o_definition.token_tree().unwrap()).unwrap(); | ||
90 | let (invocation_tt, _) = ast_to_token_tree(¯o_invocation.token_tree().unwrap()).unwrap(); | ||
91 | let rules = crate::MacroRules::parse(&definition_tt).unwrap(); | ||
92 | let expansion = rules.expand(&invocation_tt).unwrap(); | ||
93 | assert_eq!( | 83 | assert_eq!( |
94 | expansion.to_string(), | 84 | expansion.to_string(), |
95 | "impl From <Leaf > for TokenTree {fn from (it : Leaf) -> TokenTree {TokenTree ::Leaf (it)}} \ | 85 | "impl From <Leaf > for TokenTree {fn from (it : Leaf) -> TokenTree {TokenTree ::Leaf (it)}} \ |
@@ -97,140 +87,48 @@ impl_froms!(TokenTree: Leaf, Subtree); | |||
97 | ) | 87 | ) |
98 | } | 88 | } |
99 | 89 | ||
100 | pub(crate) fn create_rules(macro_definition: &str) -> MacroRules { | 90 | #[test] |
101 | let source_file = ast::SourceFile::parse(macro_definition).ok().unwrap(); | 91 | fn test_expr_order() { |
102 | let macro_definition = | 92 | let rules = create_rules( |
103 | source_file.syntax().descendants().find_map(ast::MacroCall::cast).unwrap(); | 93 | r#" |
104 | 94 | macro_rules! foo { | |
105 | let (definition_tt, _) = ast_to_token_tree(¯o_definition.token_tree().unwrap()).unwrap(); | 95 | ($ i:expr) => { |
106 | crate::MacroRules::parse(&definition_tt).unwrap() | 96 | fn bar() { $ i * 2; } |
107 | } | ||
108 | |||
109 | pub(crate) fn expand(rules: &MacroRules, invocation: &str) -> tt::Subtree { | ||
110 | let source_file = ast::SourceFile::parse(invocation).ok().unwrap(); | ||
111 | let macro_invocation = | ||
112 | source_file.syntax().descendants().find_map(ast::MacroCall::cast).unwrap(); | ||
113 | |||
114 | let (invocation_tt, _) = ast_to_token_tree(¯o_invocation.token_tree().unwrap()).unwrap(); | ||
115 | |||
116 | rules.expand(&invocation_tt).unwrap() | ||
117 | } | ||
118 | |||
119 | pub(crate) fn expand_to_items(rules: &MacroRules, invocation: &str) -> ast::MacroItems { | ||
120 | let expanded = expand(rules, invocation); | ||
121 | token_tree_to_items(&expanded).unwrap().tree() | ||
122 | } | ||
123 | |||
124 | #[allow(unused)] | ||
125 | pub(crate) fn expand_to_stmts(rules: &MacroRules, invocation: &str) -> ast::MacroStmts { | ||
126 | let expanded = expand(rules, invocation); | ||
127 | token_tree_to_macro_stmts(&expanded).unwrap().tree() | ||
128 | } | ||
129 | |||
130 | pub(crate) fn expand_to_expr(rules: &MacroRules, invocation: &str) -> ast::Expr { | ||
131 | let expanded = expand(rules, invocation); | ||
132 | token_tree_to_expr(&expanded).unwrap().tree() | ||
133 | } | ||
134 | |||
135 | pub(crate) fn text_to_tokentree(text: &str) -> tt::Subtree { | ||
136 | // wrap the given text to a macro call | ||
137 | let wrapped = format!("wrap_macro!( {} )", text); | ||
138 | let wrapped = ast::SourceFile::parse(&wrapped); | ||
139 | let wrapped = wrapped.tree().syntax().descendants().find_map(ast::TokenTree::cast).unwrap(); | ||
140 | let mut wrapped = ast_to_token_tree(&wrapped).unwrap().0; | ||
141 | wrapped.delimiter = tt::Delimiter::None; | ||
142 | |||
143 | wrapped | ||
144 | } | ||
145 | |||
146 | pub(crate) enum MacroKind { | ||
147 | Items, | ||
148 | Stmts, | ||
149 | } | ||
150 | |||
151 | use ra_syntax::WalkEvent; | ||
152 | |||
153 | pub fn debug_dump_ignore_spaces(node: &ra_syntax::SyntaxNode) -> String { | ||
154 | use std::fmt::Write; | ||
155 | |||
156 | let mut level = 0; | ||
157 | let mut buf = String::new(); | ||
158 | macro_rules! indent { | ||
159 | () => { | ||
160 | for _ in 0..level { | ||
161 | buf.push_str(" "); | ||
162 | } | ||
163 | }; | ||
164 | } | ||
165 | |||
166 | for event in node.preorder_with_tokens() { | ||
167 | match event { | ||
168 | WalkEvent::Enter(element) => { | ||
169 | match element { | ||
170 | NodeOrToken::Node(node) => { | ||
171 | indent!(); | ||
172 | writeln!(buf, "{:?}", node.kind()).unwrap(); | ||
173 | } | ||
174 | NodeOrToken::Token(token) => match token.kind() { | ||
175 | ra_syntax::SyntaxKind::WHITESPACE => {} | ||
176 | _ => { | ||
177 | indent!(); | ||
178 | writeln!(buf, "{:?}", token.kind()).unwrap(); | ||
179 | } | ||
180 | }, | ||
181 | } | ||
182 | level += 1; | ||
183 | } | 97 | } |
184 | WalkEvent::Leave(_) => level -= 1, | ||
185 | } | 98 | } |
186 | } | 99 | "#, |
187 | |||
188 | buf | ||
189 | } | ||
190 | |||
191 | pub(crate) fn assert_expansion( | ||
192 | kind: MacroKind, | ||
193 | rules: &MacroRules, | ||
194 | invocation: &str, | ||
195 | expected: &str, | ||
196 | ) -> tt::Subtree { | ||
197 | let expanded = expand(rules, invocation); | ||
198 | assert_eq!(expanded.to_string(), expected); | ||
199 | |||
200 | let expected = expected.replace("$crate", "C_C__C"); | ||
201 | |||
202 | // wrap the given text to a macro call | ||
203 | let expected = text_to_tokentree(&expected); | ||
204 | let (expanded_tree, expected_tree) = match kind { | ||
205 | MacroKind::Items => { | ||
206 | let expanded_tree = token_tree_to_items(&expanded).unwrap().tree(); | ||
207 | let expected_tree = token_tree_to_items(&expected).unwrap().tree(); | ||
208 | |||
209 | ( | ||
210 | debug_dump_ignore_spaces(expanded_tree.syntax()).trim().to_string(), | ||
211 | debug_dump_ignore_spaces(expected_tree.syntax()).trim().to_string(), | ||
212 | ) | ||
213 | } | ||
214 | |||
215 | MacroKind::Stmts => { | ||
216 | let expanded_tree = token_tree_to_macro_stmts(&expanded).unwrap().tree(); | ||
217 | let expected_tree = token_tree_to_macro_stmts(&expected).unwrap().tree(); | ||
218 | |||
219 | ( | ||
220 | debug_dump_ignore_spaces(expanded_tree.syntax()).trim().to_string(), | ||
221 | debug_dump_ignore_spaces(expected_tree.syntax()).trim().to_string(), | ||
222 | ) | ||
223 | } | ||
224 | }; | ||
225 | |||
226 | let expected_tree = expected_tree.replace("C_C__C", "$crate"); | ||
227 | assert_eq!( | ||
228 | expanded_tree, expected_tree, | ||
229 | "\nleft:\n{}\nright:\n{}", | ||
230 | expanded_tree, expected_tree, | ||
231 | ); | 100 | ); |
101 | let expanded = expand(&rules, "foo! { 1 + 1}"); | ||
102 | let tree = token_tree_to_items(&expanded).unwrap().tree(); | ||
232 | 103 | ||
233 | expanded | 104 | let dump = format!("{:#?}", tree.syntax()); |
105 | assert_eq_text!( | ||
106 | dump.trim(), | ||
107 | r#"MACRO_ITEMS@[0; 15) | ||
108 | FN_DEF@[0; 15) | ||
109 | FN_KW@[0; 2) "fn" | ||
110 | NAME@[2; 5) | ||
111 | IDENT@[2; 5) "bar" | ||
112 | PARAM_LIST@[5; 7) | ||
113 | L_PAREN@[5; 6) "(" | ||
114 | R_PAREN@[6; 7) ")" | ||
115 | BLOCK_EXPR@[7; 15) | ||
116 | BLOCK@[7; 15) | ||
117 | L_CURLY@[7; 8) "{" | ||
118 | EXPR_STMT@[8; 14) | ||
119 | BIN_EXPR@[8; 13) | ||
120 | BIN_EXPR@[8; 11) | ||
121 | LITERAL@[8; 9) | ||
122 | INT_NUMBER@[8; 9) "1" | ||
123 | PLUS@[9; 10) "+" | ||
124 | LITERAL@[10; 11) | ||
125 | INT_NUMBER@[10; 11) "1" | ||
126 | STAR@[11; 12) "*" | ||
127 | LITERAL@[12; 13) | ||
128 | INT_NUMBER@[12; 13) "2" | ||
129 | SEMI@[13; 14) ";" | ||
130 | R_CURLY@[14; 15) "}""#, | ||
131 | ); | ||
234 | } | 132 | } |
235 | 133 | ||
236 | #[test] | 134 | #[test] |
@@ -705,47 +603,6 @@ fn test_expr() { | |||
705 | } | 603 | } |
706 | 604 | ||
707 | #[test] | 605 | #[test] |
708 | fn test_expr_order() { | ||
709 | let rules = create_rules( | ||
710 | r#" | ||
711 | macro_rules! foo { | ||
712 | ($ i:expr) => { | ||
713 | fn bar() { $ i * 2; } | ||
714 | } | ||
715 | } | ||
716 | "#, | ||
717 | ); | ||
718 | let dump = format!("{:#?}", expand_to_items(&rules, "foo! { 1 + 1 }").syntax()); | ||
719 | assert_eq_text!( | ||
720 | dump.trim(), | ||
721 | r#"MACRO_ITEMS@[0; 15) | ||
722 | FN_DEF@[0; 15) | ||
723 | FN_KW@[0; 2) "fn" | ||
724 | NAME@[2; 5) | ||
725 | IDENT@[2; 5) "bar" | ||
726 | PARAM_LIST@[5; 7) | ||
727 | L_PAREN@[5; 6) "(" | ||
728 | R_PAREN@[6; 7) ")" | ||
729 | BLOCK_EXPR@[7; 15) | ||
730 | BLOCK@[7; 15) | ||
731 | L_CURLY@[7; 8) "{" | ||
732 | EXPR_STMT@[8; 14) | ||
733 | BIN_EXPR@[8; 13) | ||
734 | BIN_EXPR@[8; 11) | ||
735 | LITERAL@[8; 9) | ||
736 | INT_NUMBER@[8; 9) "1" | ||
737 | PLUS@[9; 10) "+" | ||
738 | LITERAL@[10; 11) | ||
739 | INT_NUMBER@[10; 11) "1" | ||
740 | STAR@[11; 12) "*" | ||
741 | LITERAL@[12; 13) | ||
742 | INT_NUMBER@[12; 13) "2" | ||
743 | SEMI@[13; 14) ";" | ||
744 | R_CURLY@[14; 15) "}""#, | ||
745 | ); | ||
746 | } | ||
747 | |||
748 | #[test] | ||
749 | fn test_last_expr() { | 606 | fn test_last_expr() { |
750 | let rules = create_rules( | 607 | let rules = create_rules( |
751 | r#" | 608 | r#" |
@@ -1061,8 +918,11 @@ fn test_vec() { | |||
1061 | r#"{let mut v = Vec :: new () ; v . push (1u32) ; v . push (2) ; v}"#, | 918 | r#"{let mut v = Vec :: new () ; v . push (1u32) ; v . push (2) ; v}"#, |
1062 | ); | 919 | ); |
1063 | 920 | ||
921 | let expansion = expand(&rules, r#"vec![1u32,2];"#); | ||
922 | let tree = token_tree_to_expr(&expansion).unwrap().tree(); | ||
923 | |||
1064 | assert_eq!( | 924 | assert_eq!( |
1065 | format!("{:#?}", expand_to_expr(&rules, r#"vec![1u32,2];"#).syntax()).trim(), | 925 | format!("{:#?}", tree.syntax()).trim(), |
1066 | r#"BLOCK_EXPR@[0; 45) | 926 | r#"BLOCK_EXPR@[0; 45) |
1067 | BLOCK@[0; 45) | 927 | BLOCK@[0; 45) |
1068 | L_CURLY@[0; 1) "{" | 928 | L_CURLY@[0; 1) "{" |
@@ -1502,3 +1362,117 @@ macro_rules! delegate_impl { | |||
1502 | 1362 | ||
1503 | assert_expansion(MacroKind::Items, &rules, r#"delegate_impl ! {[G , & 'a mut G , deref] pub trait Data : GraphBase {@ section type type NodeWeight ;}}"#, "impl <> Data for & \'a mut G where G : Data {}"); | 1363 | assert_expansion(MacroKind::Items, &rules, r#"delegate_impl ! {[G , & 'a mut G , deref] pub trait Data : GraphBase {@ section type type NodeWeight ;}}"#, "impl <> Data for & \'a mut G where G : Data {}"); |
1504 | } | 1364 | } |
1365 | |||
1366 | pub(crate) fn create_rules(macro_definition: &str) -> MacroRules { | ||
1367 | let source_file = ast::SourceFile::parse(macro_definition).ok().unwrap(); | ||
1368 | let macro_definition = | ||
1369 | source_file.syntax().descendants().find_map(ast::MacroCall::cast).unwrap(); | ||
1370 | |||
1371 | let (definition_tt, _) = ast_to_token_tree(¯o_definition.token_tree().unwrap()).unwrap(); | ||
1372 | crate::MacroRules::parse(&definition_tt).unwrap() | ||
1373 | } | ||
1374 | |||
1375 | pub(crate) fn expand(rules: &MacroRules, invocation: &str) -> tt::Subtree { | ||
1376 | let source_file = ast::SourceFile::parse(invocation).ok().unwrap(); | ||
1377 | let macro_invocation = | ||
1378 | source_file.syntax().descendants().find_map(ast::MacroCall::cast).unwrap(); | ||
1379 | |||
1380 | let (invocation_tt, _) = ast_to_token_tree(¯o_invocation.token_tree().unwrap()).unwrap(); | ||
1381 | |||
1382 | rules.expand(&invocation_tt).unwrap() | ||
1383 | } | ||
1384 | |||
1385 | pub(crate) enum MacroKind { | ||
1386 | Items, | ||
1387 | Stmts, | ||
1388 | } | ||
1389 | |||
1390 | pub(crate) fn assert_expansion( | ||
1391 | kind: MacroKind, | ||
1392 | rules: &MacroRules, | ||
1393 | invocation: &str, | ||
1394 | expected: &str, | ||
1395 | ) -> tt::Subtree { | ||
1396 | let expanded = expand(rules, invocation); | ||
1397 | assert_eq!(expanded.to_string(), expected); | ||
1398 | |||
1399 | let expected = expected.replace("$crate", "C_C__C"); | ||
1400 | |||
1401 | // wrap the given text to a macro call | ||
1402 | let expected = { | ||
1403 | let wrapped = format!("wrap_macro!( {} )", expected); | ||
1404 | let wrapped = ast::SourceFile::parse(&wrapped); | ||
1405 | let wrapped = wrapped.tree().syntax().descendants().find_map(ast::TokenTree::cast).unwrap(); | ||
1406 | let mut wrapped = ast_to_token_tree(&wrapped).unwrap().0; | ||
1407 | wrapped.delimiter = tt::Delimiter::None; | ||
1408 | wrapped | ||
1409 | }; | ||
1410 | let (expanded_tree, expected_tree) = match kind { | ||
1411 | MacroKind::Items => { | ||
1412 | let expanded_tree = token_tree_to_items(&expanded).unwrap().tree(); | ||
1413 | let expected_tree = token_tree_to_items(&expected).unwrap().tree(); | ||
1414 | |||
1415 | ( | ||
1416 | debug_dump_ignore_spaces(expanded_tree.syntax()).trim().to_string(), | ||
1417 | debug_dump_ignore_spaces(expected_tree.syntax()).trim().to_string(), | ||
1418 | ) | ||
1419 | } | ||
1420 | |||
1421 | MacroKind::Stmts => { | ||
1422 | let expanded_tree = token_tree_to_macro_stmts(&expanded).unwrap().tree(); | ||
1423 | let expected_tree = token_tree_to_macro_stmts(&expected).unwrap().tree(); | ||
1424 | |||
1425 | ( | ||
1426 | debug_dump_ignore_spaces(expanded_tree.syntax()).trim().to_string(), | ||
1427 | debug_dump_ignore_spaces(expected_tree.syntax()).trim().to_string(), | ||
1428 | ) | ||
1429 | } | ||
1430 | }; | ||
1431 | |||
1432 | let expected_tree = expected_tree.replace("C_C__C", "$crate"); | ||
1433 | assert_eq!( | ||
1434 | expanded_tree, expected_tree, | ||
1435 | "\nleft:\n{}\nright:\n{}", | ||
1436 | expanded_tree, expected_tree, | ||
1437 | ); | ||
1438 | |||
1439 | expanded | ||
1440 | } | ||
1441 | |||
1442 | pub fn debug_dump_ignore_spaces(node: &ra_syntax::SyntaxNode) -> String { | ||
1443 | use std::fmt::Write; | ||
1444 | |||
1445 | let mut level = 0; | ||
1446 | let mut buf = String::new(); | ||
1447 | macro_rules! indent { | ||
1448 | () => { | ||
1449 | for _ in 0..level { | ||
1450 | buf.push_str(" "); | ||
1451 | } | ||
1452 | }; | ||
1453 | } | ||
1454 | |||
1455 | for event in node.preorder_with_tokens() { | ||
1456 | match event { | ||
1457 | WalkEvent::Enter(element) => { | ||
1458 | match element { | ||
1459 | NodeOrToken::Node(node) => { | ||
1460 | indent!(); | ||
1461 | writeln!(buf, "{:?}", node.kind()).unwrap(); | ||
1462 | } | ||
1463 | NodeOrToken::Token(token) => match token.kind() { | ||
1464 | ra_syntax::SyntaxKind::WHITESPACE => {} | ||
1465 | _ => { | ||
1466 | indent!(); | ||
1467 | writeln!(buf, "{:?}", token.kind()).unwrap(); | ||
1468 | } | ||
1469 | }, | ||
1470 | } | ||
1471 | level += 1; | ||
1472 | } | ||
1473 | WalkEvent::Leave(_) => level -= 1, | ||
1474 | } | ||
1475 | } | ||
1476 | |||
1477 | buf | ||
1478 | } | ||