aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_mbe/src/tests.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_mbe/src/tests.rs')
-rw-r--r--crates/ra_mbe/src/tests.rs1897
1 files changed, 0 insertions, 1897 deletions
diff --git a/crates/ra_mbe/src/tests.rs b/crates/ra_mbe/src/tests.rs
deleted file mode 100644
index 286983d60..000000000
--- a/crates/ra_mbe/src/tests.rs
+++ /dev/null
@@ -1,1897 +0,0 @@
1use std::fmt::Write;
2
3use ra_parser::FragmentKind;
4use ra_syntax::{ast, AstNode, NodeOrToken, SyntaxKind::IDENT, SyntaxNode, WalkEvent, T};
5use test_utils::assert_eq_text;
6
7use super::*;
8
9mod rule_parsing {
10 use ra_syntax::{ast, AstNode};
11
12 use super::*;
13 use crate::ast_to_token_tree;
14
15 #[test]
16 fn test_valid_arms() {
17 fn check(macro_body: &str) {
18 let m = parse_macro_arm(macro_body);
19 m.unwrap();
20 }
21
22 check("($i:ident) => ()");
23 check("($($i:ident)*) => ($_)");
24 check("($($true:ident)*) => ($true)");
25 check("($($false:ident)*) => ($false)");
26 check("($) => ($)");
27 }
28
29 #[test]
30 fn test_invalid_arms() {
31 fn check(macro_body: &str, err: &str) {
32 let m = parse_macro_arm(macro_body);
33 assert_eq!(m, Err(ParseError::Expected(String::from(err))));
34 }
35
36 check("invalid", "expected subtree");
37
38 check("$i:ident => ()", "expected subtree");
39 check("($i:ident) ()", "expected `=`");
40 check("($($i:ident)_) => ()", "invalid repeat");
41
42 check("($i) => ($i)", "invalid macro definition");
43 check("($i:) => ($i)", "invalid macro definition");
44 }
45
46 fn parse_macro_arm(arm_definition: &str) -> Result<crate::MacroRules, ParseError> {
47 let macro_definition = format!(" macro_rules! m {{ {} }} ", arm_definition);
48 let source_file = ast::SourceFile::parse(&macro_definition).ok().unwrap();
49 let macro_definition =
50 source_file.syntax().descendants().find_map(ast::MacroCall::cast).unwrap();
51
52 let (definition_tt, _) =
53 ast_to_token_tree(&macro_definition.token_tree().unwrap()).unwrap();
54 crate::MacroRules::parse(&definition_tt)
55 }
56}
57
58// Good first issue (although a slightly challenging one):
59//
60// * Pick a random test from here
61// https://github.com/intellij-rust/intellij-rust/blob/c4e9feee4ad46e7953b1948c112533360b6087bb/src/test/kotlin/org/rust/lang/core/macros/RsMacroExpansionTest.kt
62// * Port the test to rust and add it to this module
63// * Make it pass :-)
64
65#[test]
66fn test_token_id_shift() {
67 let expansion = parse_macro(
68 r#"
69macro_rules! foobar {
70 ($e:ident) => { foo bar $e }
71}
72"#,
73 )
74 .expand_tt("foobar!(baz);");
75
76 fn get_id(t: &tt::TokenTree) -> Option<u32> {
77 if let tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) = t {
78 return Some(ident.id.0);
79 }
80 None
81 }
82
83 assert_eq!(expansion.token_trees.len(), 3);
84 // {($e:ident) => { foo bar $e }}
85 // 012345 67 8 9 T 12
86 assert_eq!(get_id(&expansion.token_trees[0]), Some(9));
87 assert_eq!(get_id(&expansion.token_trees[1]), Some(10));
88
89 // The input args of macro call include parentheses:
90 // (baz)
91 // So baz should be 12+1+1
92 assert_eq!(get_id(&expansion.token_trees[2]), Some(14));
93}
94
95#[test]
96fn test_token_map() {
97 let expanded = parse_macro(
98 r#"
99macro_rules! foobar {
100 ($e:ident) => { fn $e() {} }
101}
102"#,
103 )
104 .expand_tt("foobar!(baz);");
105
106 let (node, token_map) = token_tree_to_syntax_node(&expanded, FragmentKind::Items).unwrap();
107 let content = node.syntax_node().to_string();
108
109 let get_text = |id, kind| -> String {
110 content[token_map.range_by_token(id).unwrap().by_kind(kind).unwrap()].to_string()
111 };
112
113 assert_eq!(expanded.token_trees.len(), 4);
114 // {($e:ident) => { fn $e() {} }}
115 // 012345 67 8 9 T12 3
116
117 assert_eq!(get_text(tt::TokenId(9), IDENT), "fn");
118 assert_eq!(get_text(tt::TokenId(12), T!['(']), "(");
119 assert_eq!(get_text(tt::TokenId(13), T!['{']), "{");
120}
121
122#[test]
123fn test_convert_tt() {
124 parse_macro(r#"
125macro_rules! impl_froms {
126 ($e:ident: $($v:ident),*) => {
127 $(
128 impl From<$v> for $e {
129 fn from(it: $v) -> $e {
130 $e::$v(it)
131 }
132 }
133 )*
134 }
135}
136"#)
137 .assert_expand_tt(
138 "impl_froms!(TokenTree: Leaf, Subtree);",
139 "impl From <Leaf > for TokenTree {fn from (it : Leaf) -> TokenTree {TokenTree ::Leaf (it)}} \
140 impl From <Subtree > for TokenTree {fn from (it : Subtree) -> TokenTree {TokenTree ::Subtree (it)}}"
141 );
142}
143
144#[test]
145fn test_convert_tt2() {
146 parse_macro(
147 r#"
148macro_rules! impl_froms {
149 ($e:ident: $($v:ident),*) => {
150 $(
151 impl From<$v> for $e {
152 fn from(it: $v) -> $e {
153 $e::$v(it)
154 }
155 }
156 )*
157 }
158}
159"#,
160 )
161 .assert_expand(
162 "impl_froms!(TokenTree: Leaf, Subtree);",
163 r#"
164SUBTREE $
165 IDENT impl 20
166 IDENT From 21
167 PUNCH < [joint] 22
168 IDENT Leaf 53
169 PUNCH > [alone] 25
170 IDENT for 26
171 IDENT TokenTree 51
172 SUBTREE {} 29
173 IDENT fn 30
174 IDENT from 31
175 SUBTREE () 32
176 IDENT it 33
177 PUNCH : [alone] 34
178 IDENT Leaf 53
179 PUNCH - [joint] 37
180 PUNCH > [alone] 38
181 IDENT TokenTree 51
182 SUBTREE {} 41
183 IDENT TokenTree 51
184 PUNCH : [joint] 44
185 PUNCH : [joint] 45
186 IDENT Leaf 53
187 SUBTREE () 48
188 IDENT it 49
189 IDENT impl 20
190 IDENT From 21
191 PUNCH < [joint] 22
192 IDENT Subtree 55
193 PUNCH > [alone] 25
194 IDENT for 26
195 IDENT TokenTree 51
196 SUBTREE {} 29
197 IDENT fn 30
198 IDENT from 31
199 SUBTREE () 32
200 IDENT it 33
201 PUNCH : [alone] 34
202 IDENT Subtree 55
203 PUNCH - [joint] 37
204 PUNCH > [alone] 38
205 IDENT TokenTree 51
206 SUBTREE {} 41
207 IDENT TokenTree 51
208 PUNCH : [joint] 44
209 PUNCH : [joint] 45
210 IDENT Subtree 55
211 SUBTREE () 48
212 IDENT it 49
213"#,
214 );
215}
216
217#[test]
218fn test_lifetime_split() {
219 parse_macro(
220 r#"
221macro_rules! foo {
222 ($($t:tt)*) => { $($t)*}
223}
224"#,
225 )
226 .assert_expand(
227 r#"foo!(static bar: &'static str = "hello";);"#,
228 r#"
229SUBTREE $
230 IDENT static 17
231 IDENT bar 18
232 PUNCH : [alone] 19
233 PUNCH & [alone] 20
234 PUNCH ' [joint] 21
235 IDENT static 22
236 IDENT str 23
237 PUNCH = [alone] 24
238 LITERAL "hello" 25
239 PUNCH ; [joint] 26
240"#,
241 );
242}
243
244#[test]
245fn test_expr_order() {
246 let expanded = parse_macro(
247 r#"
248 macro_rules! foo {
249 ($ i:expr) => {
250 fn bar() { $ i * 2; }
251 }
252 }
253"#,
254 )
255 .expand_items("foo! { 1 + 1}");
256
257 let dump = format!("{:#?}", expanded);
258 assert_eq_text!(
259 dump.trim(),
260 r#"[email protected]
261 [email protected]
262 [email protected] "fn"
263 [email protected]
264 [email protected] "bar"
265 [email protected]
266 [email protected] "("
267 [email protected] ")"
268 [email protected]
269 [email protected] "{"
270 [email protected]
271 [email protected]
272 [email protected]
273 [email protected]
274 [email protected] "1"
275 [email protected] "+"
276 [email protected]
277 [email protected] "1"
278 [email protected] "*"
279 [email protected]
280 [email protected] "2"
281 [email protected] ";"
282 [email protected] "}""#,
283 );
284}
285
286#[test]
287fn test_fail_match_pattern_by_first_token() {
288 parse_macro(
289 r#"
290 macro_rules! foo {
291 ($ i:ident) => (
292 mod $ i {}
293 );
294 (= $ i:ident) => (
295 fn $ i() {}
296 );
297 (+ $ i:ident) => (
298 struct $ i;
299 )
300 }
301"#,
302 )
303 .assert_expand_items("foo! { foo }", "mod foo {}")
304 .assert_expand_items("foo! { = bar }", "fn bar () {}")
305 .assert_expand_items("foo! { + Baz }", "struct Baz ;");
306}
307
308#[test]
309fn test_fail_match_pattern_by_last_token() {
310 parse_macro(
311 r#"
312 macro_rules! foo {
313 ($ i:ident) => (
314 mod $ i {}
315 );
316 ($ i:ident =) => (
317 fn $ i() {}
318 );
319 ($ i:ident +) => (
320 struct $ i;
321 )
322 }
323"#,
324 )
325 .assert_expand_items("foo! { foo }", "mod foo {}")
326 .assert_expand_items("foo! { bar = }", "fn bar () {}")
327 .assert_expand_items("foo! { Baz + }", "struct Baz ;");
328}
329
330#[test]
331fn test_fail_match_pattern_by_word_token() {
332 parse_macro(
333 r#"
334 macro_rules! foo {
335 ($ i:ident) => (
336 mod $ i {}
337 );
338 (spam $ i:ident) => (
339 fn $ i() {}
340 );
341 (eggs $ i:ident) => (
342 struct $ i;
343 )
344 }
345"#,
346 )
347 .assert_expand_items("foo! { foo }", "mod foo {}")
348 .assert_expand_items("foo! { spam bar }", "fn bar () {}")
349 .assert_expand_items("foo! { eggs Baz }", "struct Baz ;");
350}
351
352#[test]
353fn test_match_group_pattern_by_separator_token() {
354 parse_macro(
355 r#"
356 macro_rules! foo {
357 ($ ($ i:ident),*) => ($ (
358 mod $ i {}
359 )*);
360 ($ ($ i:ident)#*) => ($ (
361 fn $ i() {}
362 )*);
363 ($ i:ident ,# $ j:ident) => (
364 struct $ i;
365 struct $ j;
366 )
367 }
368"#,
369 )
370 .assert_expand_items("foo! { foo, bar }", "mod foo {} mod bar {}")
371 .assert_expand_items("foo! { foo# bar }", "fn foo () {} fn bar () {}")
372 .assert_expand_items("foo! { Foo,# Bar }", "struct Foo ; struct Bar ;");
373}
374
375#[test]
376fn test_match_group_pattern_with_multiple_defs() {
377 parse_macro(
378 r#"
379 macro_rules! foo {
380 ($ ($ i:ident),*) => ( struct Bar { $ (
381 fn $ i {}
382 )*} );
383 }
384"#,
385 )
386 .assert_expand_items("foo! { foo, bar }", "struct Bar {fn foo {} fn bar {}}");
387}
388
389#[test]
390fn test_match_group_pattern_with_multiple_statement() {
391 parse_macro(
392 r#"
393 macro_rules! foo {
394 ($ ($ i:ident),*) => ( fn baz { $ (
395 $ i ();
396 )*} );
397 }
398"#,
399 )
400 .assert_expand_items("foo! { foo, bar }", "fn baz {foo () ; bar () ;}");
401}
402
403#[test]
404fn test_match_group_pattern_with_multiple_statement_without_semi() {
405 parse_macro(
406 r#"
407 macro_rules! foo {
408 ($ ($ i:ident),*) => ( fn baz { $ (
409 $i()
410 );*} );
411 }
412"#,
413 )
414 .assert_expand_items("foo! { foo, bar }", "fn baz {foo () ;bar ()}");
415}
416
417#[test]
418fn test_match_group_empty_fixed_token() {
419 parse_macro(
420 r#"
421 macro_rules! foo {
422 ($ ($ i:ident)* #abc) => ( fn baz { $ (
423 $ i ();
424 )*} );
425 }
426"#,
427 )
428 .assert_expand_items("foo! {#abc}", "fn baz {}");
429}
430
431#[test]
432fn test_match_group_in_subtree() {
433 parse_macro(
434 r#"
435 macro_rules! foo {
436 (fn $name:ident {$($i:ident)*} ) => ( fn $name() { $ (
437 $ i ();
438 )*} );
439 }"#,
440 )
441 .assert_expand_items("foo! {fn baz {a b} }", "fn baz () {a () ; b () ;}");
442}
443
444#[test]
445fn test_match_group_with_multichar_sep() {
446 parse_macro(
447 r#"
448 macro_rules! foo {
449 (fn $name:ident {$($i:literal)*} ) => ( fn $name() -> bool { $($i)&&*} );
450 }"#,
451 )
452 .assert_expand_items("foo! (fn baz {true true} );", "fn baz () -> bool {true &&true}");
453}
454
455#[test]
456fn test_match_group_zero_match() {
457 parse_macro(
458 r#"
459 macro_rules! foo {
460 ( $($i:ident)* ) => ();
461 }"#,
462 )
463 .assert_expand_items("foo! ();", "");
464}
465
466#[test]
467fn test_match_group_in_group() {
468 parse_macro(
469 r#"
470 macro_rules! foo {
471 { $( ( $($i:ident)* ) )* } => ( $( ( $($i)* ) )* );
472 }"#,
473 )
474 .assert_expand_items("foo! ( (a b) );", "(a b)");
475}
476
477#[test]
478fn test_expand_to_item_list() {
479 let tree = parse_macro(
480 "
481 macro_rules! structs {
482 ($($i:ident),*) => {
483 $(struct $i { field: u32 } )*
484 }
485 }
486 ",
487 )
488 .expand_items("structs!(Foo, Bar);");
489 assert_eq!(
490 format!("{:#?}", tree).trim(),
491 r#"
492[email protected]
493 [email protected]
494 [email protected] "struct"
495 [email protected]
496 [email protected] "Foo"
497 [email protected]
498 [email protected] "{"
499 [email protected]
500 [email protected]
501 [email protected] "field"
502 [email protected] ":"
503 [email protected]
504 [email protected]
505 [email protected]
506 [email protected]
507 [email protected] "u32"
508 [email protected] "}"
509 [email protected]
510 [email protected] "struct"
511 [email protected]
512 [email protected] "Bar"
513 [email protected]
514 [email protected] "{"
515 [email protected]
516 [email protected]
517 [email protected] "field"
518 [email protected] ":"
519 [email protected]
520 [email protected]
521 [email protected]
522 [email protected]
523 [email protected] "u32"
524 [email protected] "}""#
525 .trim()
526 );
527}
528
529fn to_subtree(tt: &tt::TokenTree) -> &tt::Subtree {
530 if let tt::TokenTree::Subtree(subtree) = tt {
531 return &subtree;
532 }
533 unreachable!("It is not a subtree");
534}
535fn to_literal(tt: &tt::TokenTree) -> &tt::Literal {
536 if let tt::TokenTree::Leaf(tt::Leaf::Literal(lit)) = tt {
537 return lit;
538 }
539 unreachable!("It is not a literal");
540}
541
542fn to_punct(tt: &tt::TokenTree) -> &tt::Punct {
543 if let tt::TokenTree::Leaf(tt::Leaf::Punct(lit)) = tt {
544 return lit;
545 }
546 unreachable!("It is not a Punct");
547}
548
549#[test]
550fn test_expand_literals_to_token_tree() {
551 let expansion = parse_macro(
552 r#"
553 macro_rules! literals {
554 ($i:ident) => {
555 {
556 let a = 'c';
557 let c = 1000;
558 let f = 12E+99_f64;
559 let s = "rust1";
560 }
561 }
562 }
563 "#,
564 )
565 .expand_tt("literals!(foo);");
566 let stm_tokens = &to_subtree(&expansion.token_trees[0]).token_trees;
567
568 // [let] [a] [=] ['c'] [;]
569 assert_eq!(to_literal(&stm_tokens[3]).text, "'c'");
570 // [let] [c] [=] [1000] [;]
571 assert_eq!(to_literal(&stm_tokens[5 + 3]).text, "1000");
572 // [let] [f] [=] [12E+99_f64] [;]
573 assert_eq!(to_literal(&stm_tokens[10 + 3]).text, "12E+99_f64");
574 // [let] [s] [=] ["rust1"] [;]
575 assert_eq!(to_literal(&stm_tokens[15 + 3]).text, "\"rust1\"");
576}
577
578#[test]
579fn test_attr_to_token_tree() {
580 let expansion = parse_to_token_tree_by_syntax(
581 r#"
582 #[derive(Copy)]
583 struct Foo;
584 "#,
585 );
586
587 assert_eq!(to_punct(&expansion.token_trees[0]).char, '#');
588 assert_eq!(
589 to_subtree(&expansion.token_trees[1]).delimiter_kind(),
590 Some(tt::DelimiterKind::Bracket)
591 );
592}
593
594#[test]
595fn test_two_idents() {
596 parse_macro(
597 r#"
598 macro_rules! foo {
599 ($ i:ident, $ j:ident) => {
600 fn foo() { let a = $ i; let b = $j; }
601 }
602 }
603"#,
604 )
605 .assert_expand_items("foo! { foo, bar }", "fn foo () {let a = foo ; let b = bar ;}");
606}
607
608#[test]
609fn test_tt_to_stmts() {
610 let stmts = parse_macro(
611 r#"
612 macro_rules! foo {
613 () => {
614 let a = 0;
615 a = 10 + 1;
616 a
617 }
618 }
619"#,
620 )
621 .expand_statements("foo!{}");
622
623 assert_eq!(
624 format!("{:#?}", stmts).trim(),
625 r#"[email protected]
626 [email protected]
627 [email protected] "let"
628 [email protected]
629 [email protected]
630 [email protected] "a"
631 [email protected] "="
632 [email protected]
633 [email protected] "0"
634 [email protected] ";"
635 [email protected]
636 [email protected]
637 [email protected]
638 [email protected]
639 [email protected]
640 [email protected]
641 [email protected] "a"
642 [email protected] "="
643 [email protected]
644 [email protected]
645 [email protected] "10"
646 [email protected] "+"
647 [email protected]
648 [email protected] "1"
649 [email protected] ";"
650 [email protected]
651 [email protected]
652 [email protected]
653 [email protected]
654 [email protected]
655 [email protected] "a""#,
656 );
657}
658
659#[test]
660fn test_match_literal() {
661 parse_macro(
662 r#"
663 macro_rules! foo {
664 ('(') => {
665 fn foo() {}
666 }
667 }
668"#,
669 )
670 .assert_expand_items("foo! ['('];", "fn foo () {}");
671}
672
673// The following tests are port from intellij-rust directly
674// https://github.com/intellij-rust/intellij-rust/blob/c4e9feee4ad46e7953b1948c112533360b6087bb/src/test/kotlin/org/rust/lang/core/macros/RsMacroExpansionTest.kt
675
676#[test]
677fn test_path() {
678 parse_macro(
679 r#"
680 macro_rules! foo {
681 ($ i:path) => {
682 fn foo() { let a = $ i; }
683 }
684 }
685"#,
686 )
687 .assert_expand_items("foo! { foo }", "fn foo () {let a = foo ;}")
688 .assert_expand_items(
689 "foo! { bar::<u8>::baz::<u8> }",
690 "fn foo () {let a = bar ::< u8 >:: baz ::< u8 > ;}",
691 );
692}
693
694#[test]
695fn test_two_paths() {
696 parse_macro(
697 r#"
698 macro_rules! foo {
699 ($ i:path, $ j:path) => {
700 fn foo() { let a = $ i; let b = $j; }
701 }
702 }
703"#,
704 )
705 .assert_expand_items("foo! { foo, bar }", "fn foo () {let a = foo ; let b = bar ;}");
706}
707
708#[test]
709fn test_path_with_path() {
710 parse_macro(
711 r#"
712 macro_rules! foo {
713 ($ i:path) => {
714 fn foo() { let a = $ i :: bar; }
715 }
716 }
717"#,
718 )
719 .assert_expand_items("foo! { foo }", "fn foo () {let a = foo :: bar ;}");
720}
721
722#[test]
723fn test_expr() {
724 parse_macro(
725 r#"
726 macro_rules! foo {
727 ($ i:expr) => {
728 fn bar() { $ i; }
729 }
730 }
731"#,
732 )
733 .assert_expand_items(
734 "foo! { 2 + 2 * baz(3).quux() }",
735 "fn bar () {2 + 2 * baz (3) . quux () ;}",
736 );
737}
738
739#[test]
740fn test_last_expr() {
741 parse_macro(
742 r#"
743 macro_rules! vec {
744 ($($item:expr),*) => {
745 {
746 let mut v = Vec::new();
747 $(
748 v.push($item);
749 )*
750 v
751 }
752 };
753 }
754"#,
755 )
756 .assert_expand_items(
757 "vec!(1,2,3);",
758 "{let mut v = Vec :: new () ; v . push (1) ; v . push (2) ; v . push (3) ; v}",
759 );
760}
761
762#[test]
763fn test_ty() {
764 parse_macro(
765 r#"
766 macro_rules! foo {
767 ($ i:ty) => (
768 fn bar() -> $ i { unimplemented!() }
769 )
770 }
771"#,
772 )
773 .assert_expand_items("foo! { Baz<u8> }", "fn bar () -> Baz < u8 > {unimplemented ! ()}");
774}
775
776#[test]
777fn test_ty_with_complex_type() {
778 parse_macro(
779 r#"
780 macro_rules! foo {
781 ($ i:ty) => (
782 fn bar() -> $ i { unimplemented!() }
783 )
784 }
785"#,
786 )
787 // Reference lifetime struct with generic type
788 .assert_expand_items(
789 "foo! { &'a Baz<u8> }",
790 "fn bar () -> & 'a Baz < u8 > {unimplemented ! ()}",
791 )
792 // extern "Rust" func type
793 .assert_expand_items(
794 r#"foo! { extern "Rust" fn() -> Ret }"#,
795 r#"fn bar () -> extern "Rust" fn () -> Ret {unimplemented ! ()}"#,
796 );
797}
798
799#[test]
800fn test_pat_() {
801 parse_macro(
802 r#"
803 macro_rules! foo {
804 ($ i:pat) => { fn foo() { let $ i; } }
805 }
806"#,
807 )
808 .assert_expand_items("foo! { (a, b) }", "fn foo () {let (a , b) ;}");
809}
810
811#[test]
812fn test_stmt() {
813 parse_macro(
814 r#"
815 macro_rules! foo {
816 ($ i:stmt) => (
817 fn bar() { $ i; }
818 )
819 }
820"#,
821 )
822 .assert_expand_items("foo! { 2 }", "fn bar () {2 ;}")
823 .assert_expand_items("foo! { let a = 0 }", "fn bar () {let a = 0 ;}");
824}
825
826#[test]
827fn test_single_item() {
828 parse_macro(
829 r#"
830 macro_rules! foo {
831 ($ i:item) => (
832 $ i
833 )
834 }
835"#,
836 )
837 .assert_expand_items("foo! {mod c {}}", "mod c {}");
838}
839
840#[test]
841fn test_all_items() {
842 parse_macro(
843 r#"
844 macro_rules! foo {
845 ($ ($ i:item)*) => ($ (
846 $ i
847 )*)
848 }
849"#,
850 ).
851 assert_expand_items(
852 r#"
853 foo! {
854 extern crate a;
855 mod b;
856 mod c {}
857 use d;
858 const E: i32 = 0;
859 static F: i32 = 0;
860 impl G {}
861 struct H;
862 enum I { Foo }
863 trait J {}
864 fn h() {}
865 extern {}
866 type T = u8;
867 }
868"#,
869 r#"extern crate a ; mod b ; mod c {} use d ; const E : i32 = 0 ; static F : i32 = 0 ; impl G {} struct H ; enum I {Foo} trait J {} fn h () {} extern {} type T = u8 ;"#,
870 );
871}
872
873#[test]
874fn test_block() {
875 parse_macro(
876 r#"
877 macro_rules! foo {
878 ($ i:block) => { fn foo() $ i }
879 }
880"#,
881 )
882 .assert_expand_statements("foo! { { 1; } }", "fn foo () {1 ;}");
883}
884
885#[test]
886fn test_meta() {
887 parse_macro(
888 r#"
889 macro_rules! foo {
890 ($ i:meta) => (
891 #[$ i]
892 fn bar() {}
893 )
894 }
895"#,
896 )
897 .assert_expand_items(
898 r#"foo! { cfg(target_os = "windows") }"#,
899 r#"# [cfg (target_os = "windows")] fn bar () {}"#,
900 );
901}
902
903#[test]
904fn test_meta_doc_comments() {
905 parse_macro(
906 r#"
907 macro_rules! foo {
908 ($(#[$ i:meta])+) => (
909 $(#[$ i])+
910 fn bar() {}
911 )
912 }
913"#,
914 ).
915 assert_expand_items(
916 r#"foo! {
917 /// Single Line Doc 1
918 /**
919 MultiLines Doc
920 */
921 }"#,
922 "# [doc = \" Single Line Doc 1\"] # [doc = \"\\\\n MultiLines Doc\\\\n \"] fn bar () {}",
923 );
924}
925
926#[test]
927fn test_tt_block() {
928 parse_macro(
929 r#"
930 macro_rules! foo {
931 ($ i:tt) => { fn foo() $ i }
932 }
933 "#,
934 )
935 .assert_expand_items(r#"foo! { { 1; } }"#, r#"fn foo () {1 ;}"#);
936}
937
938#[test]
939fn test_tt_group() {
940 parse_macro(
941 r#"
942 macro_rules! foo {
943 ($($ i:tt)*) => { $($ i)* }
944 }
945 "#,
946 )
947 .assert_expand_items(r#"foo! { fn foo() {} }"#, r#"fn foo () {}"#);
948}
949
950#[test]
951fn test_tt_composite() {
952 parse_macro(
953 r#"
954 macro_rules! foo {
955 ($i:tt) => { 0 }
956 }
957 "#,
958 )
959 .assert_expand_items(r#"foo! { => }"#, r#"0"#);
960}
961
962#[test]
963fn test_tt_composite2() {
964 let node = parse_macro(
965 r#"
966 macro_rules! foo {
967 ($($tt:tt)*) => { abs!(=> $($tt)*) }
968 }
969 "#,
970 )
971 .expand_items(r#"foo!{#}"#);
972
973 let res = format!("{:#?}", &node);
974 assert_eq_text!(
975 res.trim(),
976 r###"[email protected]
977 [email protected]
978 [email protected]
979 [email protected]
980 [email protected]
981 [email protected] "abs"
982 [email protected] "!"
983 [email protected]
984 [email protected] "("
985 [email protected] "="
986 [email protected] ">"
987 [email protected] " "
988 [email protected] "#"
989 [email protected] ")""###
990 );
991}
992
993#[test]
994fn test_lifetime() {
995 parse_macro(
996 r#"
997 macro_rules! foo {
998 ($ lt:lifetime) => { struct Ref<$ lt>{ s: &$ lt str } }
999 }
1000"#,
1001 )
1002 .assert_expand_items(r#"foo!{'a}"#, r#"struct Ref <'a > {s : &'a str}"#);
1003}
1004
1005#[test]
1006fn test_literal() {
1007 parse_macro(
1008 r#"
1009 macro_rules! foo {
1010 ($ type:ty $ lit:literal) => { const VALUE: $ type = $ lit;};
1011 }
1012"#,
1013 )
1014 .assert_expand_items(r#"foo!(u8 0);"#, r#"const VALUE : u8 = 0 ;"#);
1015}
1016
1017#[test]
1018fn test_boolean_is_ident() {
1019 parse_macro(
1020 r#"
1021 macro_rules! foo {
1022 ($lit0:literal, $lit1:literal) => { const VALUE: (bool,bool) = ($lit0,$lit1); };
1023 }
1024"#,
1025 )
1026 .assert_expand(
1027 r#"foo!(true,false);"#,
1028 r#"
1029SUBTREE $
1030 IDENT const 14
1031 IDENT VALUE 15
1032 PUNCH : [alone] 16
1033 SUBTREE () 17
1034 IDENT bool 18
1035 PUNCH , [alone] 19
1036 IDENT bool 20
1037 PUNCH = [alone] 21
1038 SUBTREE () 22
1039 IDENT true 29
1040 PUNCH , [joint] 25
1041 IDENT false 31
1042 PUNCH ; [alone] 28
1043"#,
1044 );
1045}
1046
1047#[test]
1048fn test_vis() {
1049 parse_macro(
1050 r#"
1051 macro_rules! foo {
1052 ($ vis:vis $ name:ident) => { $ vis fn $ name() {}};
1053 }
1054"#,
1055 )
1056 .assert_expand_items(r#"foo!(pub foo);"#, r#"pub fn foo () {}"#)
1057 // test optional cases
1058 .assert_expand_items(r#"foo!(foo);"#, r#"fn foo () {}"#);
1059}
1060
1061#[test]
1062fn test_inner_macro_rules() {
1063 parse_macro(
1064 r#"
1065macro_rules! foo {
1066 ($a:ident, $b:ident, $c:tt) => {
1067
1068 macro_rules! bar {
1069 ($bi:ident) => {
1070 fn $bi() -> u8 {$c}
1071 }
1072 }
1073
1074 bar!($a);
1075 fn $b() -> u8 {$c}
1076 }
1077}
1078"#,
1079 ).
1080 assert_expand_items(
1081 r#"foo!(x,y, 1);"#,
1082 r#"macro_rules ! bar {($ bi : ident) => {fn $ bi () -> u8 {1}}} bar ! (x) ; fn y () -> u8 {1}"#,
1083 );
1084}
1085
1086// The following tests are based on real world situations
1087#[test]
1088fn test_vec() {
1089 let fixture = parse_macro(
1090 r#"
1091 macro_rules! vec {
1092 ($($item:expr),*) => {
1093 {
1094 let mut v = Vec::new();
1095 $(
1096 v.push($item);
1097 )*
1098 v
1099 }
1100 };
1101}
1102"#,
1103 );
1104 fixture
1105 .assert_expand_items(r#"vec!();"#, r#"{let mut v = Vec :: new () ; v}"#)
1106 .assert_expand_items(
1107 r#"vec![1u32,2];"#,
1108 r#"{let mut v = Vec :: new () ; v . push (1u32) ; v . push (2) ; v}"#,
1109 );
1110
1111 let tree = fixture.expand_expr(r#"vec![1u32,2];"#);
1112
1113 assert_eq!(
1114 format!("{:#?}", tree).trim(),
1115 r#"[email protected]
1116 [email protected] "{"
1117 [email protected]
1118 [email protected] "let"
1119 [email protected]
1120 [email protected] "mut"
1121 [email protected]
1122 [email protected] "v"
1123 [email protected] "="
1124 [email protected]
1125 [email protected]
1126 [email protected]
1127 [email protected]
1128 [email protected]
1129 [email protected]
1130 [email protected] "Vec"
1131 [email protected] "::"
1132 [email protected]
1133 [email protected]
1134 [email protected] "new"
1135 [email protected]
1136 [email protected] "("
1137 [email protected] ")"
1138 [email protected] ";"
1139 [email protected]
1140 [email protected]
1141 [email protected]
1142 [email protected]
1143 [email protected]
1144 [email protected]
1145 [email protected] "v"
1146 [email protected] "."
1147 [email protected]
1148 [email protected] "push"
1149 [email protected]
1150 [email protected] "("
1151 [email protected]
1152 [email protected] "1u32"
1153 [email protected] ")"
1154 [email protected] ";"
1155 [email protected]
1156 [email protected]
1157 [email protected]
1158 [email protected]
1159 [email protected]
1160 [email protected]
1161 [email protected] "v"
1162 [email protected] "."
1163 [email protected]
1164 [email protected] "push"
1165 [email protected]
1166 [email protected] "("
1167 [email protected]
1168 [email protected] "2"
1169 [email protected] ")"
1170 [email protected] ";"
1171 [email protected]
1172 [email protected]
1173 [email protected]
1174 [email protected]
1175 [email protected] "v"
1176 [email protected] "}""#
1177 );
1178}
1179
1180#[test]
1181fn test_winapi_struct() {
1182 // from https://github.com/retep998/winapi-rs/blob/a7ef2bca086aae76cf6c4ce4c2552988ed9798ad/src/macros.rs#L366
1183
1184 parse_macro(
1185 r#"
1186macro_rules! STRUCT {
1187 ($(#[$attrs:meta])* struct $name:ident {
1188 $($field:ident: $ftype:ty,)+
1189 }) => (
1190 #[repr(C)] #[derive(Copy)] $(#[$attrs])*
1191 pub struct $name {
1192 $(pub $field: $ftype,)+
1193 }
1194 impl Clone for $name {
1195 #[inline]
1196 fn clone(&self) -> $name { *self }
1197 }
1198 #[cfg(feature = "impl-default")]
1199 impl Default for $name {
1200 #[inline]
1201 fn default() -> $name { unsafe { $crate::_core::mem::zeroed() } }
1202 }
1203 );
1204}
1205"#,
1206 ).
1207 // from https://github.com/retep998/winapi-rs/blob/a7ef2bca086aae76cf6c4ce4c2552988ed9798ad/src/shared/d3d9caps.rs
1208 assert_expand_items(r#"STRUCT!{struct D3DVSHADERCAPS2_0 {Caps: u8,}}"#,
1209 "# [repr (C)] # [derive (Copy)] pub struct D3DVSHADERCAPS2_0 {pub Caps : u8 ,} impl Clone for D3DVSHADERCAPS2_0 {# [inline] fn clone (& self) -> D3DVSHADERCAPS2_0 {* self}} # [cfg (feature = \"impl-default\")] impl Default for D3DVSHADERCAPS2_0 {# [inline] fn default () -> D3DVSHADERCAPS2_0 {unsafe {$crate :: _core :: mem :: zeroed ()}}}"
1210 )
1211 .assert_expand_items(r#"STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct D3DCONTENTPROTECTIONCAPS {Caps : u8 ,}}"#,
1212 "# [repr (C)] # [derive (Copy)] # [cfg_attr (target_arch = \"x86\" , repr (packed))] pub struct D3DCONTENTPROTECTIONCAPS {pub Caps : u8 ,} impl Clone for D3DCONTENTPROTECTIONCAPS {# [inline] fn clone (& self) -> D3DCONTENTPROTECTIONCAPS {* self}} # [cfg (feature = \"impl-default\")] impl Default for D3DCONTENTPROTECTIONCAPS {# [inline] fn default () -> D3DCONTENTPROTECTIONCAPS {unsafe {$crate :: _core :: mem :: zeroed ()}}}"
1213 );
1214}
1215
1216#[test]
1217fn test_int_base() {
1218 parse_macro(
1219 r#"
1220macro_rules! int_base {
1221 ($Trait:ident for $T:ident as $U:ident -> $Radix:ident) => {
1222 #[stable(feature = "rust1", since = "1.0.0")]
1223 impl fmt::$Trait for $T {
1224 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1225 $Radix.fmt_int(*self as $U, f)
1226 }
1227 }
1228 }
1229}
1230"#,
1231 ).assert_expand_items(r#" int_base!{Binary for isize as usize -> Binary}"#,
1232 "# [stable (feature = \"rust1\" , since = \"1.0.0\")] impl fmt ::Binary for isize {fn fmt (& self , f : & mut fmt :: Formatter < \'_ >) -> fmt :: Result {Binary . fmt_int (* self as usize , f)}}"
1233 );
1234}
1235
1236#[test]
1237fn test_generate_pattern_iterators() {
1238 // from https://github.com/rust-lang/rust/blob/316a391dcb7d66dc25f1f9a4ec9d368ef7615005/src/libcore/str/mod.rs
1239 parse_macro(
1240 r#"
1241macro_rules! generate_pattern_iterators {
1242 { double ended; with $(#[$common_stability_attribute:meta])*,
1243 $forward_iterator:ident,
1244 $reverse_iterator:ident, $iterty:ty
1245 } => {
1246 fn foo(){}
1247 }
1248}
1249"#,
1250 ).assert_expand_items(
1251 r#"generate_pattern_iterators ! ( double ended ; with # [ stable ( feature = "rust1" , since = "1.0.0" ) ] , Split , RSplit , & 'a str );"#,
1252 "fn foo () {}",
1253 );
1254}
1255
1256#[test]
1257fn test_impl_fn_for_zst() {
1258 // from https://github.com/rust-lang/rust/blob/5d20ff4d2718c820632b38c1e49d4de648a9810b/src/libcore/internal_macros.rs
1259 parse_macro(
1260 r#"
1261macro_rules! impl_fn_for_zst {
1262 { $( $( #[$attr: meta] )*
1263 struct $Name: ident impl$( <$( $lifetime : lifetime ),+> )? Fn =
1264 |$( $arg: ident: $ArgTy: ty ),*| -> $ReturnTy: ty
1265$body: block; )+
1266 } => {
1267 $(
1268 $( #[$attr] )*
1269 struct $Name;
1270
1271 impl $( <$( $lifetime ),+> )? Fn<($( $ArgTy, )*)> for $Name {
1272 #[inline]
1273 extern "rust-call" fn call(&self, ($( $arg, )*): ($( $ArgTy, )*)) -> $ReturnTy {
1274 $body
1275 }
1276 }
1277
1278 impl $( <$( $lifetime ),+> )? FnMut<($( $ArgTy, )*)> for $Name {
1279 #[inline]
1280 extern "rust-call" fn call_mut(
1281 &mut self,
1282 ($( $arg, )*): ($( $ArgTy, )*)
1283 ) -> $ReturnTy {
1284 Fn::call(&*self, ($( $arg, )*))
1285 }
1286 }
1287
1288 impl $( <$( $lifetime ),+> )? FnOnce<($( $ArgTy, )*)> for $Name {
1289 type Output = $ReturnTy;
1290
1291 #[inline]
1292 extern "rust-call" fn call_once(self, ($( $arg, )*): ($( $ArgTy, )*)) -> $ReturnTy {
1293 Fn::call(&self, ($( $arg, )*))
1294 }
1295 }
1296 )+
1297}
1298 }
1299"#,
1300 ).assert_expand_items(r#"
1301impl_fn_for_zst ! {
1302 # [ derive ( Clone ) ]
1303 struct CharEscapeDebugContinue impl Fn = | c : char | -> char :: EscapeDebug {
1304 c . escape_debug_ext ( false )
1305 } ;
1306
1307 # [ derive ( Clone ) ]
1308 struct CharEscapeUnicode impl Fn = | c : char | -> char :: EscapeUnicode {
1309 c . escape_unicode ( )
1310 } ;
1311 # [ derive ( Clone ) ]
1312 struct CharEscapeDefault impl Fn = | c : char | -> char :: EscapeDefault {
1313 c . escape_default ( )
1314 } ;
1315 }
1316"#,
1317 "# [derive (Clone)] struct CharEscapeDebugContinue ; impl Fn < (char ,) > for CharEscapeDebugContinue {# [inline] extern \"rust-call\" fn call (& self , (c ,) : (char ,)) -> char :: EscapeDebug {{c . escape_debug_ext (false)}}} impl FnMut < (char ,) > for CharEscapeDebugContinue {# [inline] extern \"rust-call\" fn call_mut (& mut self , (c ,) : (char ,)) -> char :: EscapeDebug {Fn :: call (&* self , (c ,))}} impl FnOnce < (char ,) > for CharEscapeDebugContinue {type Output = char :: EscapeDebug ; # [inline] extern \"rust-call\" fn call_once (self , (c ,) : (char ,)) -> char :: EscapeDebug {Fn :: call (& self , (c ,))}} # [derive (Clone)] struct CharEscapeUnicode ; impl Fn < (char ,) > for CharEscapeUnicode {# [inline] extern \"rust-call\" fn call (& self , (c ,) : (char ,)) -> char :: EscapeUnicode {{c . escape_unicode ()}}} impl FnMut < (char ,) > for CharEscapeUnicode {# [inline] extern \"rust-call\" fn call_mut (& mut self , (c ,) : (char ,)) -> char :: EscapeUnicode {Fn :: call (&* self , (c ,))}} impl FnOnce < (char ,) > for CharEscapeUnicode {type Output = char :: EscapeUnicode ; # [inline] extern \"rust-call\" fn call_once (self , (c ,) : (char ,)) -> char :: EscapeUnicode {Fn :: call (& self , (c ,))}} # [derive (Clone)] struct CharEscapeDefault ; impl Fn < (char ,) > for CharEscapeDefault {# [inline] extern \"rust-call\" fn call (& self , (c ,) : (char ,)) -> char :: EscapeDefault {{c . escape_default ()}}} impl FnMut < (char ,) > for CharEscapeDefault {# [inline] extern \"rust-call\" fn call_mut (& mut self , (c ,) : (char ,)) -> char :: EscapeDefault {Fn :: call (&* self , (c ,))}} impl FnOnce < (char ,) > for CharEscapeDefault {type Output = char :: EscapeDefault ; # [inline] extern \"rust-call\" fn call_once (self , (c ,) : (char ,)) -> char :: EscapeDefault {Fn :: call (& self , (c ,))}}"
1318 );
1319}
1320
1321#[test]
1322fn test_impl_nonzero_fmt() {
1323 // from https://github.com/rust-lang/rust/blob/316a391dcb7d66dc25f1f9a4ec9d368ef7615005/src/libcore/num/mod.rs#L12
1324 parse_macro(
1325 r#"
1326 macro_rules! impl_nonzero_fmt {
1327 ( #[$stability: meta] ( $( $Trait: ident ),+ ) for $Ty: ident ) => {
1328 fn foo () {}
1329 }
1330 }
1331"#,
1332 ).assert_expand_items(
1333 r#"impl_nonzero_fmt! { # [stable(feature= "nonzero",since="1.28.0")] (Debug,Display,Binary,Octal,LowerHex,UpperHex) for NonZeroU8}"#,
1334 "fn foo () {}",
1335 );
1336}
1337
1338#[test]
1339fn test_cfg_if_items() {
1340 // from https://github.com/rust-lang/rust/blob/33fe1131cadba69d317156847be9a402b89f11bb/src/libstd/macros.rs#L986
1341 parse_macro(
1342 r#"
1343 macro_rules! __cfg_if_items {
1344 (($($not:meta,)*) ; ) => {};
1345 (($($not:meta,)*) ; ( ($($m:meta),*) ($($it:item)*) ), $($rest:tt)*) => {
1346 __cfg_if_items! { ($($not,)* $($m,)*) ; $($rest)* }
1347 }
1348 }
1349"#,
1350 ).assert_expand_items(
1351 r#"__cfg_if_items ! { ( rustdoc , ) ; ( ( ) ( # [ cfg ( any ( target_os = "redox" , unix ) ) ] # [ stable ( feature = "rust1" , since = "1.0.0" ) ] pub use sys :: ext as unix ; # [ cfg ( windows ) ] # [ stable ( feature = "rust1" , since = "1.0.0" ) ] pub use sys :: ext as windows ; # [ cfg ( any ( target_os = "linux" , target_os = "l4re" ) ) ] pub mod linux ; ) ) , }"#,
1352 "__cfg_if_items ! {(rustdoc ,) ;}",
1353 );
1354}
1355
1356#[test]
1357fn test_cfg_if_main() {
1358 // from https://github.com/rust-lang/rust/blob/3d211248393686e0f73851fc7548f6605220fbe1/src/libpanic_unwind/macros.rs#L9
1359 parse_macro(
1360 r#"
1361 macro_rules! cfg_if {
1362 ($(
1363 if #[cfg($($meta:meta),*)] { $($it:item)* }
1364 ) else * else {
1365 $($it2:item)*
1366 }) => {
1367 __cfg_if_items! {
1368 () ;
1369 $( ( ($($meta),*) ($($it)*) ), )*
1370 ( () ($($it2)*) ),
1371 }
1372 };
1373
1374 // Internal macro to Apply a cfg attribute to a list of items
1375 (@__apply $m:meta, $($it:item)*) => {
1376 $(#[$m] $it)*
1377 };
1378 }
1379"#,
1380 ).assert_expand_items(r#"
1381cfg_if ! {
1382 if # [ cfg ( target_env = "msvc" ) ] {
1383 // no extra unwinder support needed
1384 } else if # [ cfg ( all ( target_arch = "wasm32" , not ( target_os = "emscripten" ) ) ) ] {
1385 // no unwinder on the system!
1386 } else {
1387 mod libunwind ;
1388 pub use libunwind :: * ;
1389 }
1390 }
1391"#,
1392 "__cfg_if_items ! {() ; ((target_env = \"msvc\") ()) , ((all (target_arch = \"wasm32\" , not (target_os = \"emscripten\"))) ()) , (() (mod libunwind ; pub use libunwind :: * ;)) ,}"
1393 ).assert_expand_items(
1394 r#"
1395cfg_if ! { @ __apply cfg ( all ( not ( any ( not ( any ( target_os = "solaris" , target_os = "illumos" ) ) ) ) ) ) , }
1396"#,
1397 "",
1398 );
1399}
1400
1401#[test]
1402fn test_proptest_arbitrary() {
1403 // from https://github.com/AltSysrq/proptest/blob/d1c4b049337d2f75dd6f49a095115f7c532e5129/proptest/src/arbitrary/macros.rs#L16
1404 parse_macro(
1405 r#"
1406macro_rules! arbitrary {
1407 ([$($bounds : tt)*] $typ: ty, $strat: ty, $params: ty;
1408 $args: ident => $logic: expr) => {
1409 impl<$($bounds)*> $crate::arbitrary::Arbitrary for $typ {
1410 type Parameters = $params;
1411 type Strategy = $strat;
1412 fn arbitrary_with($args: Self::Parameters) -> Self::Strategy {
1413 $logic
1414 }
1415 }
1416 };
1417
1418}"#,
1419 ).assert_expand_items(r#"arbitrary ! ( [ A : Arbitrary ]
1420 Vec < A > ,
1421 VecStrategy < A :: Strategy > ,
1422 RangedParams1 < A :: Parameters > ;
1423 args => { let product_unpack ! [ range , a ] = args ; vec ( any_with :: < A > ( a ) , range ) }
1424 ) ;"#,
1425 "impl <A : Arbitrary > $crate :: arbitrary :: Arbitrary for Vec < A > {type Parameters = RangedParams1 < A :: Parameters > ; type Strategy = VecStrategy < A :: Strategy > ; fn arbitrary_with (args : Self :: Parameters) -> Self :: Strategy {{let product_unpack ! [range , a] = args ; vec (any_with :: < A > (a) , range)}}}"
1426 );
1427}
1428
1429#[test]
1430fn test_old_ridl() {
1431 // This is from winapi 2.8, which do not have a link from github
1432 //
1433 let expanded = parse_macro(
1434 r#"
1435#[macro_export]
1436macro_rules! RIDL {
1437 (interface $interface:ident ($vtbl:ident) : $pinterface:ident ($pvtbl:ident)
1438 {$(
1439 fn $method:ident(&mut self $(,$p:ident : $t:ty)*) -> $rtr:ty
1440 ),+}
1441 ) => {
1442 impl $interface {
1443 $(pub unsafe fn $method(&mut self) -> $rtr {
1444 ((*self.lpVtbl).$method)(self $(,$p)*)
1445 })+
1446 }
1447 };
1448}"#,
1449 ).expand_tt(r#"
1450 RIDL!{interface ID3D11Asynchronous(ID3D11AsynchronousVtbl): ID3D11DeviceChild(ID3D11DeviceChildVtbl) {
1451 fn GetDataSize(&mut self) -> UINT
1452 }}"#);
1453
1454 assert_eq!(expanded.to_string(), "impl ID3D11Asynchronous {pub unsafe fn GetDataSize (& mut self) -> UINT {((* self . lpVtbl) .GetDataSize) (self)}}");
1455}
1456
1457#[test]
1458fn test_quick_error() {
1459 let expanded = parse_macro(
1460 r#"
1461macro_rules! quick_error {
1462
1463 (SORT [enum $name:ident $( #[$meta:meta] )*]
1464 items [$($( #[$imeta:meta] )*
1465 => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*]
1466 {$( $ifuncs:tt )*} )* ]
1467 buf [ ]
1468 queue [ ]
1469 ) => {
1470 quick_error!(ENUMINITION [enum $name $( #[$meta] )*]
1471 body []
1472 queue [$(
1473 $( #[$imeta] )*
1474 =>
1475 $iitem: $imode [$( $ivar: $ityp ),*]
1476 )*]
1477 );
1478};
1479
1480}
1481"#,
1482 )
1483 .expand_tt(
1484 r#"
1485quick_error ! (SORT [enum Wrapped # [derive (Debug)]] items [
1486 => One : UNIT [] {}
1487 => Two : TUPLE [s :String] {display ("two: {}" , s) from ()}
1488 ] buf [] queue []) ;
1489"#,
1490 );
1491
1492 assert_eq!(expanded.to_string(), "quick_error ! (ENUMINITION [enum Wrapped # [derive (Debug)]] body [] queue [=> One : UNIT [] => Two : TUPLE [s : String]]) ;");
1493}
1494
1495#[test]
1496fn test_empty_repeat_vars_in_empty_repeat_vars() {
1497 parse_macro(
1498 r#"
1499macro_rules! delegate_impl {
1500 ([$self_type:ident, $self_wrap:ty, $self_map:ident]
1501 pub trait $name:ident $(: $sup:ident)* $(+ $more_sup:ident)* {
1502
1503 // "Escaped" associated types. Stripped before making the `trait`
1504 // itself, but forwarded when delegating impls.
1505 $(
1506 @escape [type $assoc_name_ext:ident]
1507 // Associated types. Forwarded.
1508 )*
1509 $(
1510 @section type
1511 $(
1512 $(#[$_assoc_attr:meta])*
1513 type $assoc_name:ident $(: $assoc_bound:ty)*;
1514 )+
1515 )*
1516 // Methods. Forwarded. Using $self_map!(self) around the self argument.
1517 // Methods must use receiver `self` or explicit type like `self: &Self`
1518 // &self and &mut self are _not_ supported.
1519 $(
1520 @section self
1521 $(
1522 $(#[$_method_attr:meta])*
1523 fn $method_name:ident(self $(: $self_selftype:ty)* $(,$marg:ident : $marg_ty:ty)*) -> $mret:ty;
1524 )+
1525 )*
1526 // Arbitrary tail that is ignored when forwarding.
1527 $(
1528 @section nodelegate
1529 $($tail:tt)*
1530 )*
1531 }) => {
1532 impl<> $name for $self_wrap where $self_type: $name {
1533 $(
1534 $(
1535 fn $method_name(self $(: $self_selftype)* $(,$marg: $marg_ty)*) -> $mret {
1536 $self_map!(self).$method_name($($marg),*)
1537 }
1538 )*
1539 )*
1540 }
1541 }
1542}
1543"#,
1544 ).assert_expand_items(
1545 r#"delegate_impl ! {[G , & 'a mut G , deref] pub trait Data : GraphBase {@ section type type NodeWeight ;}}"#,
1546 "impl <> Data for & \'a mut G where G : Data {}",
1547 );
1548}
1549
1550#[test]
1551fn expr_interpolation() {
1552 let expanded = parse_macro(
1553 r#"
1554 macro_rules! id {
1555 ($expr:expr) => {
1556 map($expr)
1557 }
1558 }
1559 "#,
1560 )
1561 .expand_expr("id!(x + foo);");
1562
1563 assert_eq!(expanded.to_string(), "map(x+foo)");
1564}
1565
1566pub(crate) struct MacroFixture {
1567 rules: MacroRules,
1568}
1569
1570impl MacroFixture {
1571 pub(crate) fn expand_tt(&self, invocation: &str) -> tt::Subtree {
1572 self.try_expand_tt(invocation).unwrap()
1573 }
1574
1575 fn try_expand_tt(&self, invocation: &str) -> Result<tt::Subtree, ExpandError> {
1576 let source_file = ast::SourceFile::parse(invocation).tree();
1577 let macro_invocation =
1578 source_file.syntax().descendants().find_map(ast::MacroCall::cast).unwrap();
1579
1580 let (invocation_tt, _) = ast_to_token_tree(&macro_invocation.token_tree().unwrap())
1581 .ok_or_else(|| ExpandError::ConversionError)?;
1582
1583 self.rules.expand(&invocation_tt).result()
1584 }
1585
1586 fn assert_expand_err(&self, invocation: &str, err: &ExpandError) {
1587 assert_eq!(self.try_expand_tt(invocation).as_ref(), Err(err));
1588 }
1589
1590 fn expand_items(&self, invocation: &str) -> SyntaxNode {
1591 let expanded = self.expand_tt(invocation);
1592 token_tree_to_syntax_node(&expanded, FragmentKind::Items).unwrap().0.syntax_node()
1593 }
1594
1595 fn expand_statements(&self, invocation: &str) -> SyntaxNode {
1596 let expanded = self.expand_tt(invocation);
1597 token_tree_to_syntax_node(&expanded, FragmentKind::Statements).unwrap().0.syntax_node()
1598 }
1599
1600 fn expand_expr(&self, invocation: &str) -> SyntaxNode {
1601 let expanded = self.expand_tt(invocation);
1602 token_tree_to_syntax_node(&expanded, FragmentKind::Expr).unwrap().0.syntax_node()
1603 }
1604
1605 fn assert_expand_tt(&self, invocation: &str, expected: &str) {
1606 let expansion = self.expand_tt(invocation);
1607 assert_eq!(expansion.to_string(), expected);
1608 }
1609
1610 fn assert_expand(&self, invocation: &str, expected: &str) {
1611 let expansion = self.expand_tt(invocation);
1612 let actual = format!("{:?}", expansion);
1613 test_utils::assert_eq_text!(&actual.trim(), &expected.trim());
1614 }
1615
1616 fn assert_expand_items(&self, invocation: &str, expected: &str) -> &MacroFixture {
1617 self.assert_expansion(FragmentKind::Items, invocation, expected);
1618 self
1619 }
1620
1621 fn assert_expand_statements(&self, invocation: &str, expected: &str) -> &MacroFixture {
1622 self.assert_expansion(FragmentKind::Statements, invocation, expected);
1623 self
1624 }
1625
1626 fn assert_expansion(&self, kind: FragmentKind, invocation: &str, expected: &str) {
1627 let expanded = self.expand_tt(invocation);
1628 assert_eq!(expanded.to_string(), expected);
1629
1630 let expected = expected.replace("$crate", "C_C__C");
1631
1632 // wrap the given text to a macro call
1633 let expected = {
1634 let wrapped = format!("wrap_macro!( {} )", expected);
1635 let wrapped = ast::SourceFile::parse(&wrapped);
1636 let wrapped =
1637 wrapped.tree().syntax().descendants().find_map(ast::TokenTree::cast).unwrap();
1638 let mut wrapped = ast_to_token_tree(&wrapped).unwrap().0;
1639 wrapped.delimiter = None;
1640 wrapped
1641 };
1642
1643 let expanded_tree = token_tree_to_syntax_node(&expanded, kind).unwrap().0.syntax_node();
1644 let expanded_tree = debug_dump_ignore_spaces(&expanded_tree).trim().to_string();
1645
1646 let expected_tree = token_tree_to_syntax_node(&expected, kind).unwrap().0.syntax_node();
1647 let expected_tree = debug_dump_ignore_spaces(&expected_tree).trim().to_string();
1648
1649 let expected_tree = expected_tree.replace("C_C__C", "$crate");
1650 assert_eq!(
1651 expanded_tree, expected_tree,
1652 "\nleft:\n{}\nright:\n{}",
1653 expanded_tree, expected_tree,
1654 );
1655 }
1656}
1657
1658fn parse_macro_to_tt(ra_fixture: &str) -> tt::Subtree {
1659 let source_file = ast::SourceFile::parse(ra_fixture).ok().unwrap();
1660 let macro_definition =
1661 source_file.syntax().descendants().find_map(ast::MacroCall::cast).unwrap();
1662
1663 let (definition_tt, _) = ast_to_token_tree(&macro_definition.token_tree().unwrap()).unwrap();
1664
1665 let parsed = parse_to_token_tree(
1666 &ra_fixture[macro_definition.token_tree().unwrap().syntax().text_range()],
1667 )
1668 .unwrap()
1669 .0;
1670 assert_eq!(definition_tt, parsed);
1671
1672 definition_tt
1673}
1674
1675pub(crate) fn parse_macro(ra_fixture: &str) -> MacroFixture {
1676 let definition_tt = parse_macro_to_tt(ra_fixture);
1677 let rules = MacroRules::parse(&definition_tt).unwrap();
1678 MacroFixture { rules }
1679}
1680
1681pub(crate) fn parse_macro_error(ra_fixture: &str) -> ParseError {
1682 let definition_tt = parse_macro_to_tt(ra_fixture);
1683
1684 match MacroRules::parse(&definition_tt) {
1685 Ok(_) => panic!("Expect error"),
1686 Err(err) => err,
1687 }
1688}
1689
1690pub(crate) fn parse_to_token_tree_by_syntax(ra_fixture: &str) -> tt::Subtree {
1691 let source_file = ast::SourceFile::parse(ra_fixture).ok().unwrap();
1692 let tt = syntax_node_to_token_tree(source_file.syntax()).unwrap().0;
1693
1694 let parsed = parse_to_token_tree(ra_fixture).unwrap().0;
1695 assert_eq!(tt, parsed);
1696
1697 parsed
1698}
1699
1700fn debug_dump_ignore_spaces(node: &ra_syntax::SyntaxNode) -> String {
1701 let mut level = 0;
1702 let mut buf = String::new();
1703 macro_rules! indent {
1704 () => {
1705 for _ in 0..level {
1706 buf.push_str(" ");
1707 }
1708 };
1709 }
1710
1711 for event in node.preorder_with_tokens() {
1712 match event {
1713 WalkEvent::Enter(element) => {
1714 match element {
1715 NodeOrToken::Node(node) => {
1716 indent!();
1717 writeln!(buf, "{:?}", node.kind()).unwrap();
1718 }
1719 NodeOrToken::Token(token) => match token.kind() {
1720 ra_syntax::SyntaxKind::WHITESPACE => {}
1721 _ => {
1722 indent!();
1723 writeln!(buf, "{:?}", token.kind()).unwrap();
1724 }
1725 },
1726 }
1727 level += 1;
1728 }
1729 WalkEvent::Leave(_) => level -= 1,
1730 }
1731 }
1732
1733 buf
1734}
1735
1736#[test]
1737fn test_issue_2520() {
1738 let macro_fixture = parse_macro(
1739 r#"
1740 macro_rules! my_macro {
1741 {
1742 ( $(
1743 $( [] $sname:ident : $stype:ty )?
1744 $( [$expr:expr] $nname:ident : $ntype:ty )?
1745 ),* )
1746 } => {
1747 Test {
1748 $(
1749 $( $sname, )?
1750 )*
1751 }
1752 };
1753 }
1754 "#,
1755 );
1756
1757 macro_fixture.assert_expand_items(
1758 r#"my_macro ! {
1759 ([] p1 : u32 , [|_| S0K0] s : S0K0 , [] k0 : i32)
1760 }"#,
1761 "Test {p1 , k0 ,}",
1762 );
1763}
1764
1765#[test]
1766fn test_issue_3861() {
1767 let macro_fixture = parse_macro(
1768 r#"
1769 macro_rules! rgb_color {
1770 ($p:expr, $t: ty) => {
1771 pub fn new() {
1772 let _ = 0 as $t << $p;
1773 }
1774 };
1775 }
1776 "#,
1777 );
1778
1779 macro_fixture.expand_items(r#"rgb_color!(8 + 8, u32);"#);
1780}
1781
1782#[test]
1783fn test_repeat_bad_var() {
1784 // FIXME: the second rule of the macro should be removed and an error about
1785 // `$( $c )+` raised
1786 parse_macro(
1787 r#"
1788 macro_rules! foo {
1789 ($( $b:ident )+) => {
1790 $( $c )+
1791 };
1792 ($( $b:ident )+) => {
1793 $( $b )+
1794 }
1795 }
1796 "#,
1797 )
1798 .assert_expand_items("foo!(b0 b1);", "b0 b1");
1799}
1800
1801#[test]
1802fn test_no_space_after_semi_colon() {
1803 let expanded = parse_macro(
1804 r#"
1805 macro_rules! with_std { ($($i:item)*) => ($(#[cfg(feature = "std")]$i)*) }
1806 "#,
1807 )
1808 .expand_items(r#"with_std! {mod m;mod f;}"#);
1809
1810 let dump = format!("{:#?}", expanded);
1811 assert_eq_text!(
1812 dump.trim(),
1813 r###"[email protected]
1814 [email protected]
1815 [email protected]
1816 [email protected] "#"
1817 [email protected] "["
1818 [email protected]
1819 [email protected]
1820 [email protected]
1821 [email protected] "cfg"
1822 [email protected]
1823 [email protected] "("
1824 [email protected] "feature"
1825 [email protected] "="
1826 [email protected] "\"std\""
1827 [email protected] ")"
1828 [email protected] "]"
1829 [email protected] "mod"
1830 [email protected]
1831 [email protected] "m"
1832 [email protected] ";"
1833 [email protected]
1834 [email protected]
1835 [email protected] "#"
1836 [email protected] "["
1837 [email protected]
1838 [email protected]
1839 [email protected]
1840 [email protected] "cfg"
1841 [email protected]
1842 [email protected] "("
1843 [email protected] "feature"
1844 [email protected] "="
1845 [email protected] "\"std\""
1846 [email protected] ")"
1847 [email protected] "]"
1848 [email protected] "mod"
1849 [email protected]
1850 [email protected] "f"
1851 [email protected] ";""###,
1852 );
1853}
1854
1855// https://github.com/rust-lang/rust/blob/master/src/test/ui/issues/issue-57597.rs
1856#[test]
1857fn test_rustc_issue_57597() {
1858 fn test_error(fixture: &str) {
1859 assert_eq!(parse_macro_error(fixture), ParseError::RepetitionEmtpyTokenTree);
1860 }
1861
1862 test_error("macro_rules! foo { ($($($i:ident)?)+) => {}; }");
1863 test_error("macro_rules! foo { ($($($i:ident)?)*) => {}; }");
1864 test_error("macro_rules! foo { ($($($i:ident)?)?) => {}; }");
1865 test_error("macro_rules! foo { ($($($($i:ident)?)?)?) => {}; }");
1866 test_error("macro_rules! foo { ($($($($i:ident)*)?)?) => {}; }");
1867 test_error("macro_rules! foo { ($($($($i:ident)?)*)?) => {}; }");
1868 test_error("macro_rules! foo { ($($($($i:ident)?)?)*) => {}; }");
1869 test_error("macro_rules! foo { ($($($($i:ident)*)*)?) => {}; }");
1870 test_error("macro_rules! foo { ($($($($i:ident)?)*)*) => {}; }");
1871 test_error("macro_rules! foo { ($($($($i:ident)?)*)+) => {}; }");
1872 test_error("macro_rules! foo { ($($($($i:ident)+)?)*) => {}; }");
1873 test_error("macro_rules! foo { ($($($($i:ident)+)*)?) => {}; }");
1874}
1875
1876#[test]
1877fn test_expand_bad_literal() {
1878 parse_macro(
1879 r#"
1880 macro_rules! foo { ($i:literal) => {}; }
1881 "#,
1882 )
1883 .assert_expand_err(r#"foo!(&k");"#, &ExpandError::BindingError("".into()));
1884}
1885
1886#[test]
1887fn test_empty_comments() {
1888 parse_macro(
1889 r#"
1890 macro_rules! one_arg_macro { ($fmt:expr) => (); }
1891 "#,
1892 )
1893 .assert_expand_err(
1894 r#"one_arg_macro!(/**/)"#,
1895 &ExpandError::BindingError("expected Expr".into()),
1896 );
1897}