]> git.lizzy.rs Git - rust.git/blob - crates/mbe/src/tests/expand.rs
7929989442951d129f8c162718146832081dcbfa
[rust.git] / crates / mbe / src / tests / expand.rs
1 use ::parser::ParserEntryPoint;
2 use syntax::{
3     SyntaxKind::{ERROR, IDENT},
4     T,
5 };
6 use test_utils::assert_eq_text;
7
8 use super::*;
9
10 // Good first issue (although a slightly challenging one):
11 //
12 // * Pick a random test from here
13 //   https://github.com/intellij-rust/intellij-rust/blob/c4e9feee4ad46e7953b1948c112533360b6087bb/src/test/kotlin/org/rust/lang/core/macros/RsMacroExpansionTest.kt
14 // * Port the test to rust and add it to this module
15 // * Make it pass :-)
16
17 #[test]
18 fn test_token_id_shift() {
19     let expansion = parse_macro(
20         r#"
21 macro_rules! foobar {
22     ($e:ident) => { foo bar $e }
23 }
24 "#,
25     )
26     .expand_tt("foobar!(baz);");
27
28     fn get_id(t: &tt::TokenTree) -> Option<u32> {
29         if let tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) = t {
30             return Some(ident.id.0);
31         }
32         None
33     }
34
35     assert_eq!(expansion.token_trees.len(), 3);
36     // {($e:ident) => { foo bar $e }}
37     // 012345      67 8 9   T   12
38     assert_eq!(get_id(&expansion.token_trees[0]), Some(9));
39     assert_eq!(get_id(&expansion.token_trees[1]), Some(10));
40
41     // The input args of macro call include parentheses:
42     // (baz)
43     // So baz should be 12+1+1
44     assert_eq!(get_id(&expansion.token_trees[2]), Some(14));
45 }
46
47 #[test]
48 fn test_token_map() {
49     let expanded = parse_macro(
50         r#"
51 macro_rules! foobar {
52     ($e:ident) => { fn $e() {} }
53 }
54 "#,
55     )
56     .expand_tt("foobar!(baz);");
57
58     let (node, token_map) = token_tree_to_syntax_node(&expanded, ParserEntryPoint::Items).unwrap();
59     let content = node.syntax_node().to_string();
60
61     let get_text = |id, kind| -> String {
62         content[token_map.first_range_by_token(id, kind).unwrap()].to_string()
63     };
64
65     assert_eq!(expanded.token_trees.len(), 4);
66     // {($e:ident) => { fn $e() {} }}
67     // 012345      67 8 9  T12  3
68
69     assert_eq!(get_text(tt::TokenId(9), IDENT), "fn");
70     assert_eq!(get_text(tt::TokenId(12), T!['(']), "(");
71     assert_eq!(get_text(tt::TokenId(13), T!['{']), "{");
72 }
73
74 fn to_subtree(tt: &tt::TokenTree) -> &tt::Subtree {
75     if let tt::TokenTree::Subtree(subtree) = tt {
76         return subtree;
77     }
78     unreachable!("It is not a subtree");
79 }
80
81 fn to_punct(tt: &tt::TokenTree) -> &tt::Punct {
82     if let tt::TokenTree::Leaf(tt::Leaf::Punct(lit)) = tt {
83         return lit;
84     }
85     unreachable!("It is not a Punct");
86 }
87
88 #[test]
89 fn test_attr_to_token_tree() {
90     let expansion = parse_to_token_tree_by_syntax(
91         r#"
92             #[derive(Copy)]
93             struct Foo;
94             "#,
95     );
96
97     assert_eq!(to_punct(&expansion.token_trees[0]).char, '#');
98     assert_eq!(
99         to_subtree(&expansion.token_trees[1]).delimiter_kind(),
100         Some(tt::DelimiterKind::Bracket)
101     );
102 }
103
104 #[test]
105 fn test_meta_doc_comments() {
106     parse_macro(
107         r#"
108         macro_rules! foo {
109             ($(#[$ i:meta])+) => (
110                 $(#[$ i])+
111                 fn bar() {}
112             )
113         }
114 "#,
115     ).
116     assert_expand_items(
117         r#"foo! {
118             /// Single Line Doc 1
119             /**
120                 MultiLines Doc
121             */
122         }"#,
123         "# [doc = \" Single Line Doc 1\"] # [doc = \"\\n                MultiLines Doc\\n            \"] fn bar () {}",
124     );
125 }
126
127 #[test]
128 fn test_meta_extended_key_value_attributes() {
129     parse_macro(
130         r#"
131 macro_rules! foo {
132     (#[$i:meta]) => (
133         #[$ i]
134         fn bar() {}
135     )
136 }
137 "#,
138     )
139     .assert_expand_items(
140         r#"foo! { #[doc = concat!("The `", "bla", "` lang item.")] }"#,
141         r#"# [doc = concat ! ("The `" , "bla" , "` lang item.")] fn bar () {}"#,
142     );
143 }
144
145 #[test]
146 fn test_meta_doc_comments_non_latin() {
147     parse_macro(
148         r#"
149         macro_rules! foo {
150             ($(#[$ i:meta])+) => (
151                 $(#[$ i])+
152                 fn bar() {}
153             )
154         }
155 "#,
156     ).
157     assert_expand_items(
158         r#"foo! {
159             /// 錦瑟無端五十弦,一弦一柱思華年。
160             /**
161                 莊生曉夢迷蝴蝶,望帝春心託杜鵑。
162             */
163         }"#,
164         "# [doc = \" 錦瑟無端五十弦,一弦一柱思華年。\"] # [doc = \"\\n                莊生曉夢迷蝴蝶,望帝春心託杜鵑。\\n            \"] fn bar () {}",
165     );
166 }
167
168 #[test]
169 fn test_meta_doc_comments_escaped_characters() {
170     parse_macro(
171         r#"
172         macro_rules! foo {
173             ($(#[$ i:meta])+) => (
174                 $(#[$ i])+
175                 fn bar() {}
176             )
177         }
178 "#,
179     )
180     .assert_expand_items(
181         r#"foo! {
182             /// \ " '
183         }"#,
184         r#"# [doc = " \\ \" \'"] fn bar () {}"#,
185     );
186 }
187
188 #[test]
189 fn test_tt_block() {
190     parse_macro(
191         r#"
192             macro_rules! foo {
193                 ($ i:tt) => { fn foo() $ i }
194             }
195     "#,
196     )
197     .assert_expand_items(r#"foo! { { 1; } }"#, r#"fn foo () {1 ;}"#);
198 }
199
200 #[test]
201 fn test_tt_group() {
202     parse_macro(
203         r#"
204             macro_rules! foo {
205                  ($($ i:tt)*) => { $($ i)* }
206             }
207     "#,
208     )
209     .assert_expand_items(r#"foo! { fn foo() {} }"#, r#"fn foo () {}"#);
210 }
211
212 #[test]
213 fn test_tt_composite() {
214     parse_macro(
215         r#"
216             macro_rules! foo {
217                  ($i:tt) => { 0 }
218             }
219     "#,
220     )
221     .assert_expand_items(r#"foo! { => }"#, r#"0"#);
222 }
223
224 #[test]
225 fn test_tt_composite2() {
226     let node = parse_macro(
227         r#"
228             macro_rules! foo {
229                 ($($tt:tt)*) => { abs!(=> $($tt)*) }
230             }
231     "#,
232     )
233     .expand_items(r#"foo!{#}"#);
234
235     let res = format!("{:#?}", &node);
236     assert_eq_text!(
237         r###"MACRO_ITEMS@0..10
238   MACRO_CALL@0..10
239     PATH@0..3
240       PATH_SEGMENT@0..3
241         NAME_REF@0..3
242           IDENT@0..3 "abs"
243     BANG@3..4 "!"
244     TOKEN_TREE@4..10
245       L_PAREN@4..5 "("
246       EQ@5..6 "="
247       R_ANGLE@6..7 ">"
248       WHITESPACE@7..8 " "
249       POUND@8..9 "#"
250       R_PAREN@9..10 ")""###,
251         res.trim()
252     );
253 }
254
255 #[test]
256 fn test_tt_with_composite_without_space() {
257     parse_macro(
258         r#"
259         macro_rules! foo {
260             ($ op:tt, $j:path) => (
261                 0
262             )
263         }
264 "#,
265     )
266     // Test macro input without any spaces
267     // See https://github.com/rust-analyzer/rust-analyzer/issues/6692
268     .assert_expand_items("foo!(==,Foo::Bool)", "0");
269 }
270
271 #[test]
272 fn test_underscore() {
273     parse_macro(
274         r#"
275             macro_rules! foo {
276                  ($_:tt) => { 0 }
277             }
278     "#,
279     )
280     .assert_expand_items(r#"foo! { => }"#, r#"0"#);
281 }
282
283 #[test]
284 fn test_underscore_not_greedily() {
285     parse_macro(
286         r#"
287 macro_rules! q {
288     ($($a:ident)* _) => {0};
289 }
290 "#,
291     )
292     // `_` overlaps with `$a:ident` but rustc matches it under the `_` token
293     .assert_expand_items(r#"q![a b c d _]"#, r#"0"#);
294
295     parse_macro(
296         r#"
297 macro_rules! q {
298     ($($a:expr => $b:ident)* _ => $c:expr) => {0};
299 }
300 "#,
301     )
302     // `_ => ou` overlaps with `$a:expr => $b:ident` but rustc matches it under `_ => $c:expr`
303     .assert_expand_items(r#"q![a => b c => d _ => ou]"#, r#"0"#);
304 }
305
306 #[test]
307 fn test_underscore_as_type() {
308     parse_macro(
309         r#"
310 macro_rules! q {
311     ($a:ty) => {0};
312 }
313 "#,
314     )
315     // Underscore is a type
316     .assert_expand_items(r#"q![_]"#, r#"0"#);
317 }
318
319 #[test]
320 fn test_underscore_lifetime() {
321     parse_macro(r#"macro_rules! q { ($a:lifetime) => {0}; }"#)
322         .assert_expand_items(r#"q!['_]"#, r#"0"#);
323 }
324
325 #[test]
326 fn test_vertical_bar_with_pat() {
327     parse_macro(
328         r#"
329             macro_rules! foo {
330                  (| $pat:pat | ) => { 0 }
331             }
332     "#,
333     )
334     .assert_expand_items(r#"foo! { | x | }"#, r#"0"#);
335 }
336
337 #[test]
338 fn test_dollar_crate_lhs_is_not_meta() {
339     parse_macro(
340         r#"
341 macro_rules! foo {
342     ($crate) => {};
343     () => {0};
344 }
345     "#,
346     )
347     .assert_expand_items(r#"foo!{}"#, r#"0"#);
348 }
349
350 #[test]
351 fn test_lifetime() {
352     parse_macro(
353         r#"
354         macro_rules! foo {
355               ($ lt:lifetime) => { struct Ref<$ lt>{ s: &$ lt str } }
356         }
357 "#,
358     )
359     .assert_expand_items(r#"foo!{'a}"#, r#"struct Ref <'a > {s : &'a str}"#);
360 }
361
362 #[test]
363 fn test_literal() {
364     parse_macro(
365         r#"
366         macro_rules! foo {
367               ($ type:ty , $ lit:literal) => { const VALUE: $ type = $ lit;};
368         }
369 "#,
370     )
371     .assert_expand_items(r#"foo!(u8,0);"#, r#"const VALUE : u8 = 0 ;"#);
372
373     parse_macro(
374         r#"
375         macro_rules! foo {
376               ($ type:ty , $ lit:literal) => { const VALUE: $ type = $ lit;};
377         }
378 "#,
379     )
380     .assert_expand_items(r#"foo!(i32,-1);"#, r#"const VALUE : i32 = - 1 ;"#);
381 }
382
383 #[test]
384 fn test_boolean_is_ident() {
385     parse_macro(
386         r#"
387         macro_rules! foo {
388               ($lit0:literal, $lit1:literal) => { const VALUE: (bool,bool) = ($lit0,$lit1); };
389         }
390 "#,
391     )
392     .assert_expand(
393         r#"foo!(true,false);"#,
394         r#"
395 SUBTREE $
396   IDENT   const 14
397   IDENT   VALUE 15
398   PUNCH   : [alone] 16
399   SUBTREE () 17
400     IDENT   bool 18
401     PUNCH   , [alone] 19
402     IDENT   bool 20
403   PUNCH   = [alone] 21
404   SUBTREE () 22
405     IDENT   true 29
406     PUNCH   , [joint] 25
407     IDENT   false 31
408   PUNCH   ; [alone] 28
409 "#,
410     );
411 }
412
413 #[test]
414 fn test_vis() {
415     parse_macro(
416         r#"
417         macro_rules! foo {
418               ($ vis:vis $ name:ident) => { $ vis fn $ name() {}};
419         }
420 "#,
421     )
422     .assert_expand_items(r#"foo!(pub foo);"#, r#"pub fn foo () {}"#)
423     // test optional cases
424     .assert_expand_items(r#"foo!(foo);"#, r#"fn foo () {}"#);
425 }
426
427 #[test]
428 fn test_inner_macro_rules() {
429     parse_macro(
430         r#"
431 macro_rules! foo {
432     ($a:ident, $b:ident, $c:tt) => {
433
434         macro_rules! bar {
435             ($bi:ident) => {
436                 fn $bi() -> u8 {$c}
437             }
438         }
439
440         bar!($a);
441         fn $b() -> u8 {$c}
442     }
443 }
444 "#,
445     ).
446     assert_expand_items(
447         r#"foo!(x,y, 1);"#,
448         r#"macro_rules ! bar {($ bi : ident) => {fn $ bi () -> u8 {1}}} bar ! (x) ; fn y () -> u8 {1}"#,
449     );
450 }
451
452 #[test]
453 fn test_expr_after_path_colons() {
454     assert!(parse_macro(
455         r#"
456 macro_rules! m {
457     ($k:expr) => {
458             f(K::$k);
459        }
460 }
461 "#,
462     )
463     .expand_statements(r#"m!(C("0"))"#)
464     .descendants()
465     .any(|token| token.kind() == ERROR));
466 }
467
468 #[test]
469 fn test_match_is_not_greedy() {
470     parse_macro(
471         r#"
472 macro_rules! foo {
473     ($($i:ident $(,)*),*) => {};
474 }
475 "#,
476     )
477     .assert_expand_items(r#"foo!(a,b);"#, r#""#);
478 }
479
480 // The following tests are based on real world situations
481 #[test]
482 fn test_vec() {
483     let fixture = parse_macro(
484         r#"
485          macro_rules! vec {
486             ($($item:expr),*) => {
487                 {
488                     let mut v = Vec::new();
489                     $(
490                         v.push($item);
491                     )*
492                     v
493                 }
494             };
495 }
496 "#,
497     );
498     fixture
499         .assert_expand_items(r#"vec!();"#, r#"{let mut v = Vec :: new () ; v}"#)
500         .assert_expand_items(
501             r#"vec![1u32,2];"#,
502             r#"{let mut v = Vec :: new () ; v . push (1u32) ; v . push (2) ; v}"#,
503         );
504
505     let tree = fixture.expand_expr(r#"vec![1u32,2];"#);
506
507     assert_eq_text!(
508         &format!("{:#?}", tree),
509         r#"BLOCK_EXPR@0..45
510   STMT_LIST@0..45
511     L_CURLY@0..1 "{"
512     LET_STMT@1..20
513       LET_KW@1..4 "let"
514       IDENT_PAT@4..8
515         MUT_KW@4..7 "mut"
516         NAME@7..8
517           IDENT@7..8 "v"
518       EQ@8..9 "="
519       CALL_EXPR@9..19
520         PATH_EXPR@9..17
521           PATH@9..17
522             PATH@9..12
523               PATH_SEGMENT@9..12
524                 NAME_REF@9..12
525                   IDENT@9..12 "Vec"
526             COLON2@12..14 "::"
527             PATH_SEGMENT@14..17
528               NAME_REF@14..17
529                 IDENT@14..17 "new"
530         ARG_LIST@17..19
531           L_PAREN@17..18 "("
532           R_PAREN@18..19 ")"
533       SEMICOLON@19..20 ";"
534     EXPR_STMT@20..33
535       METHOD_CALL_EXPR@20..32
536         PATH_EXPR@20..21
537           PATH@20..21
538             PATH_SEGMENT@20..21
539               NAME_REF@20..21
540                 IDENT@20..21 "v"
541         DOT@21..22 "."
542         NAME_REF@22..26
543           IDENT@22..26 "push"
544         ARG_LIST@26..32
545           L_PAREN@26..27 "("
546           LITERAL@27..31
547             INT_NUMBER@27..31 "1u32"
548           R_PAREN@31..32 ")"
549       SEMICOLON@32..33 ";"
550     EXPR_STMT@33..43
551       METHOD_CALL_EXPR@33..42
552         PATH_EXPR@33..34
553           PATH@33..34
554             PATH_SEGMENT@33..34
555               NAME_REF@33..34
556                 IDENT@33..34 "v"
557         DOT@34..35 "."
558         NAME_REF@35..39
559           IDENT@35..39 "push"
560         ARG_LIST@39..42
561           L_PAREN@39..40 "("
562           LITERAL@40..41
563             INT_NUMBER@40..41 "2"
564           R_PAREN@41..42 ")"
565       SEMICOLON@42..43 ";"
566     PATH_EXPR@43..44
567       PATH@43..44
568         PATH_SEGMENT@43..44
569           NAME_REF@43..44
570             IDENT@43..44 "v"
571     R_CURLY@44..45 "}"
572 "#
573     );
574 }
575
576 #[test]
577 fn test_winapi_struct() {
578     // from https://github.com/retep998/winapi-rs/blob/a7ef2bca086aae76cf6c4ce4c2552988ed9798ad/src/macros.rs#L366
579
580     parse_macro(
581         r#"
582 macro_rules! STRUCT {
583     ($(#[$attrs:meta])* struct $name:ident {
584         $($field:ident: $ftype:ty,)+
585     }) => (
586         #[repr(C)] #[derive(Copy)] $(#[$attrs])*
587         pub struct $name {
588             $(pub $field: $ftype,)+
589         }
590         impl Clone for $name {
591             #[inline]
592             fn clone(&self) -> $name { *self }
593         }
594         #[cfg(feature = "impl-default")]
595         impl Default for $name {
596             #[inline]
597             fn default() -> $name { unsafe { $crate::_core::mem::zeroed() } }
598         }
599     );
600 }
601 "#,
602     ).
603     // from https://github.com/retep998/winapi-rs/blob/a7ef2bca086aae76cf6c4ce4c2552988ed9798ad/src/shared/d3d9caps.rs
604     assert_expand_items(r#"STRUCT!{struct D3DVSHADERCAPS2_0 {Caps: u8,}}"#,
605         "# [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 ()}}}"
606     )
607     .assert_expand_items(r#"STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct D3DCONTENTPROTECTIONCAPS {Caps : u8 ,}}"#,
608         "# [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 ()}}}"
609     );
610 }
611
612 #[test]
613 fn test_int_base() {
614     parse_macro(
615         r#"
616 macro_rules! int_base {
617     ($Trait:ident for $T:ident as $U:ident -> $Radix:ident) => {
618         #[stable(feature = "rust1", since = "1.0.0")]
619         impl fmt::$Trait for $T {
620             fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
621                 $Radix.fmt_int(*self as $U, f)
622             }
623         }
624     }
625 }
626 "#,
627     ).assert_expand_items(r#" int_base!{Binary for isize as usize -> Binary}"#,
628         "# [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)}}"
629     );
630 }
631
632 #[test]
633 fn test_generate_pattern_iterators() {
634     // from https://github.com/rust-lang/rust/blob/316a391dcb7d66dc25f1f9a4ec9d368ef7615005/src/libcore/str/mod.rs
635     parse_macro(
636         r#"
637 macro_rules! generate_pattern_iterators {
638         { double ended; with $(#[$common_stability_attribute:meta])*,
639                            $forward_iterator:ident,
640                            $reverse_iterator:ident, $iterty:ty
641         } => {
642             fn foo(){}
643         }
644 }
645 "#,
646     ).assert_expand_items(
647         r#"generate_pattern_iterators ! ( double ended ; with # [ stable ( feature = "rust1" , since = "1.0.0" ) ] , Split , RSplit , & 'a str );"#,
648         "fn foo () {}",
649     );
650 }
651
652 #[test]
653 fn test_impl_fn_for_zst() {
654     // from https://github.com/rust-lang/rust/blob/5d20ff4d2718c820632b38c1e49d4de648a9810b/src/libcore/internal_macros.rs
655     parse_macro(
656         r#"
657 macro_rules! impl_fn_for_zst  {
658         {  $( $( #[$attr: meta] )*
659         struct $Name: ident impl$( <$( $lifetime : lifetime ),+> )? Fn =
660             |$( $arg: ident: $ArgTy: ty ),*| -> $ReturnTy: ty
661 $body: block; )+
662         } => {
663            $(
664             $( #[$attr] )*
665             struct $Name;
666
667             impl $( <$( $lifetime ),+> )? Fn<($( $ArgTy, )*)> for $Name {
668                 #[inline]
669                 extern "rust-call" fn call(&self, ($( $arg, )*): ($( $ArgTy, )*)) -> $ReturnTy {
670                     $body
671                 }
672             }
673
674             impl $( <$( $lifetime ),+> )? FnMut<($( $ArgTy, )*)> for $Name {
675                 #[inline]
676                 extern "rust-call" fn call_mut(
677                     &mut self,
678                     ($( $arg, )*): ($( $ArgTy, )*)
679                 ) -> $ReturnTy {
680                     Fn::call(&*self, ($( $arg, )*))
681                 }
682             }
683
684             impl $( <$( $lifetime ),+> )? FnOnce<($( $ArgTy, )*)> for $Name {
685                 type Output = $ReturnTy;
686
687                 #[inline]
688                 extern "rust-call" fn call_once(self, ($( $arg, )*): ($( $ArgTy, )*)) -> $ReturnTy {
689                     Fn::call(&self, ($( $arg, )*))
690                 }
691             }
692         )+
693 }
694         }
695 "#,
696     ).assert_expand_items(r#"
697 impl_fn_for_zst !   {
698      # [ derive ( Clone ) ]
699      struct   CharEscapeDebugContinue   impl   Fn   =   | c :   char |   ->   char :: EscapeDebug   {
700          c . escape_debug_ext ( false )
701      } ;
702
703      # [ derive ( Clone ) ]
704      struct   CharEscapeUnicode   impl   Fn   =   | c :   char |   ->   char :: EscapeUnicode   {
705          c . escape_unicode ( )
706      } ;
707      # [ derive ( Clone ) ]
708      struct   CharEscapeDefault   impl   Fn   =   | c :   char |   ->   char :: EscapeDefault   {
709          c . escape_default ( )
710      } ;
711  }
712 "#,
713         "# [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 ,))}}"
714     );
715 }
716
717 #[test]
718 fn test_impl_nonzero_fmt() {
719     // from https://github.com/rust-lang/rust/blob/316a391dcb7d66dc25f1f9a4ec9d368ef7615005/src/libcore/num/mod.rs#L12
720     parse_macro(
721         r#"
722         macro_rules! impl_nonzero_fmt {
723             ( #[$stability: meta] ( $( $Trait: ident ),+ ) for $Ty: ident ) => {
724                 fn foo () {}
725             }
726         }
727 "#,
728     ).assert_expand_items(
729         r#"impl_nonzero_fmt! { # [stable(feature= "nonzero",since="1.28.0")] (Debug,Display,Binary,Octal,LowerHex,UpperHex) for NonZeroU8}"#,
730         "fn foo () {}",
731     );
732 }
733
734 #[test]
735 fn test_cfg_if_items() {
736     // from https://github.com/rust-lang/rust/blob/33fe1131cadba69d317156847be9a402b89f11bb/src/libstd/macros.rs#L986
737     parse_macro(
738         r#"
739         macro_rules! __cfg_if_items {
740             (($($not:meta,)*) ; ) => {};
741             (($($not:meta,)*) ; ( ($($m:meta),*) ($($it:item)*) ), $($rest:tt)*) => {
742                  __cfg_if_items! { ($($not,)* $($m,)*) ; $($rest)* }
743             }
744         }
745 "#,
746     ).assert_expand_items(
747         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 ; ) ) , }"#,
748         "__cfg_if_items ! {(rustdoc ,) ;}",
749     );
750 }
751
752 #[test]
753 fn test_cfg_if_main() {
754     // from https://github.com/rust-lang/rust/blob/3d211248393686e0f73851fc7548f6605220fbe1/src/libpanic_unwind/macros.rs#L9
755     parse_macro(
756         r#"
757         macro_rules! cfg_if {
758             ($(
759                 if #[cfg($($meta:meta),*)] { $($it:item)* }
760             ) else * else {
761                 $($it2:item)*
762             }) => {
763                 __cfg_if_items! {
764                     () ;
765                     $( ( ($($meta),*) ($($it)*) ), )*
766                     ( () ($($it2)*) ),
767                 }
768             };
769
770             // Internal macro to Apply a cfg attribute to a list of items
771             (@__apply $m:meta, $($it:item)*) => {
772                 $(#[$m] $it)*
773             };
774         }
775 "#,
776     ).assert_expand_items(r#"
777 cfg_if !   {
778      if   # [ cfg ( target_env   =   "msvc" ) ]   {
779          // no extra unwinder support needed
780      }   else   if   # [ cfg ( all ( target_arch   =   "wasm32" ,   not ( target_os   =   "emscripten" ) ) ) ]   {
781          // no unwinder on the system!
782      }   else   {
783          mod   libunwind ;
784          pub   use   libunwind :: * ;
785      }
786  }
787 "#,
788         "__cfg_if_items ! {() ; ((target_env = \"msvc\") ()) , ((all (target_arch = \"wasm32\" , not (target_os = \"emscripten\"))) ()) , (() (mod libunwind ; pub use libunwind :: * ;)) ,}"
789     ).assert_expand_items(
790         r#"
791 cfg_if ! { @ __apply cfg ( all ( not ( any ( not ( any ( target_os = "solaris" , target_os = "illumos" ) ) ) ) ) ) , }
792 "#,
793         "",
794     );
795 }
796
797 #[test]
798 fn test_proptest_arbitrary() {
799     // from https://github.com/AltSysrq/proptest/blob/d1c4b049337d2f75dd6f49a095115f7c532e5129/proptest/src/arbitrary/macros.rs#L16
800     parse_macro(
801         r#"
802 macro_rules! arbitrary {
803     ([$($bounds : tt)*] $typ: ty, $strat: ty, $params: ty;
804         $args: ident => $logic: expr) => {
805         impl<$($bounds)*> $crate::arbitrary::Arbitrary for $typ {
806             type Parameters = $params;
807             type Strategy = $strat;
808             fn arbitrary_with($args: Self::Parameters) -> Self::Strategy {
809                 $logic
810             }
811         }
812     };
813
814 }"#,
815     ).assert_expand_items(r#"arbitrary !   ( [ A : Arbitrary ]
816         Vec < A > ,
817         VecStrategy < A :: Strategy > ,
818         RangedParams1 < A :: Parameters > ;
819         args =>   { let product_unpack !   [ range , a ] = args ; vec ( any_with :: < A >   ( a ) , range ) }
820     ) ;"#,
821     "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)}}}"
822     );
823 }
824
825 #[test]
826 fn test_old_ridl() {
827     // This is from winapi 2.8, which do not have a link from github
828     //
829     let expanded = parse_macro(
830         r#"
831 #[macro_export]
832 macro_rules! RIDL {
833     (interface $interface:ident ($vtbl:ident) : $pinterface:ident ($pvtbl:ident)
834         {$(
835             fn $method:ident(&mut self $(,$p:ident : $t:ty)*) -> $rtr:ty
836         ),+}
837     ) => {
838         impl $interface {
839             $(pub unsafe fn $method(&mut self) -> $rtr {
840                 ((*self.lpVtbl).$method)(self $(,$p)*)
841             })+
842         }
843     };
844 }"#,
845     ).expand_tt(r#"
846     RIDL!{interface ID3D11Asynchronous(ID3D11AsynchronousVtbl): ID3D11DeviceChild(ID3D11DeviceChildVtbl) {
847         fn GetDataSize(&mut self) -> UINT
848     }}"#);
849
850     assert_eq!(expanded.to_string(), "impl ID3D11Asynchronous {pub unsafe fn GetDataSize (& mut self) -> UINT {((* self . lpVtbl) .GetDataSize) (self)}}");
851 }
852
853 #[test]
854 fn test_quick_error() {
855     let expanded = parse_macro(
856         r#"
857 macro_rules! quick_error {
858
859  (SORT [enum $name:ident $( #[$meta:meta] )*]
860         items [$($( #[$imeta:meta] )*
861                   => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*]
862                                 {$( $ifuncs:tt )*} )* ]
863         buf [ ]
864         queue [ ]
865     ) => {
866         quick_error!(ENUMINITION [enum $name $( #[$meta] )*]
867             body []
868             queue [$(
869                 $( #[$imeta] )*
870                 =>
871                 $iitem: $imode [$( $ivar: $ityp ),*]
872             )*]
873         );
874 };
875
876 }
877 "#,
878     )
879     .expand_tt(
880         r#"
881 quick_error ! (SORT [enum Wrapped # [derive (Debug)]] items [
882         => One : UNIT [] {}
883         => Two : TUPLE [s :String] {display ("two: {}" , s) from ()}
884     ] buf [] queue []) ;
885 "#,
886     );
887
888     assert_eq!(expanded.to_string(), "quick_error ! (ENUMINITION [enum Wrapped # [derive (Debug)]] body [] queue [=> One : UNIT [] => Two : TUPLE [s : String]]) ;");
889 }
890
891 #[test]
892 fn test_empty_repeat_vars_in_empty_repeat_vars() {
893     parse_macro(
894         r#"
895 macro_rules! delegate_impl {
896     ([$self_type:ident, $self_wrap:ty, $self_map:ident]
897      pub trait $name:ident $(: $sup:ident)* $(+ $more_sup:ident)* {
898
899         $(
900         @escape [type $assoc_name_ext:ident]
901         )*
902         $(
903         @section type
904         $(
905             $(#[$_assoc_attr:meta])*
906             type $assoc_name:ident $(: $assoc_bound:ty)*;
907         )+
908         )*
909         $(
910         @section self
911         $(
912             $(#[$_method_attr:meta])*
913             fn $method_name:ident(self $(: $self_selftype:ty)* $(,$marg:ident : $marg_ty:ty)*) -> $mret:ty;
914         )+
915         )*
916         $(
917         @section nodelegate
918         $($tail:tt)*
919         )*
920     }) => {
921         impl<> $name for $self_wrap where $self_type: $name {
922             $(
923             $(
924                 fn $method_name(self $(: $self_selftype)* $(,$marg: $marg_ty)*) -> $mret {
925                     $self_map!(self).$method_name($($marg),*)
926                 }
927             )*
928             )*
929         }
930     }
931 }
932 "#,
933     ).assert_expand_items(
934         r#"delegate_impl ! {[G , & 'a mut G , deref] pub trait Data : GraphBase {@ section type type NodeWeight ;}}"#,
935         "impl <> Data for & \'a mut G where G : Data {}",
936     );
937 }
938
939 #[test]
940 fn expr_interpolation() {
941     let expanded = parse_macro(
942         r#"
943         macro_rules! id {
944             ($expr:expr) => {
945                 map($expr)
946             }
947         }
948         "#,
949     )
950     .expand_expr("id!(x + foo);");
951
952     assert_eq!(expanded.to_string(), "map(x+foo)");
953 }
954
955 #[test]
956 fn test_issue_2520() {
957     let macro_fixture = parse_macro(
958         r#"
959         macro_rules! my_macro {
960             {
961                 ( $(
962                     $( [] $sname:ident : $stype:ty  )?
963                     $( [$expr:expr] $nname:ident : $ntype:ty  )?
964                 ),* )
965             } => {
966                 Test {
967                     $(
968                         $( $sname, )?
969                     )*
970                 }
971             };
972         }
973     "#,
974     );
975
976     macro_fixture.assert_expand_items(
977         r#"my_macro ! {
978             ([] p1 : u32 , [|_| S0K0] s : S0K0 , [] k0 : i32)
979         }"#,
980         "Test {p1 , k0 ,}",
981     );
982 }
983
984 #[test]
985 fn test_issue_3861() {
986     let macro_fixture = parse_macro(
987         r#"
988         macro_rules! rgb_color {
989             ($p:expr, $t: ty) => {
990                 pub fn new() {
991                     let _ = 0 as $t << $p;
992                 }
993             };
994         }
995     "#,
996     );
997
998     macro_fixture.expand_items(r#"rgb_color!(8 + 8, u32);"#);
999 }
1000
1001 #[test]
1002 fn test_repeat_bad_var() {
1003     // FIXME: the second rule of the macro should be removed and an error about
1004     // `$( $c )+` raised
1005     parse_macro(
1006         r#"
1007         macro_rules! foo {
1008             ($( $b:ident )+) => {
1009                 $( $c )+
1010             };
1011             ($( $b:ident )+) => {
1012                 $( $b )+
1013             }
1014         }
1015     "#,
1016     )
1017     .assert_expand_items("foo!(b0 b1);", "b0 b1");
1018 }
1019
1020 #[test]
1021 fn test_no_space_after_semi_colon() {
1022     let expanded = parse_macro(
1023         r#"
1024         macro_rules! with_std { ($($i:item)*) => ($(#[cfg(feature = "std")]$i)*) }
1025     "#,
1026     )
1027     .expand_items(r#"with_std! {mod m;mod f;}"#);
1028
1029     let dump = format!("{:#?}", expanded);
1030     assert_eq_text!(
1031         r###"MACRO_ITEMS@0..52
1032   MODULE@0..26
1033     ATTR@0..21
1034       POUND@0..1 "#"
1035       L_BRACK@1..2 "["
1036       META@2..20
1037         PATH@2..5
1038           PATH_SEGMENT@2..5
1039             NAME_REF@2..5
1040               IDENT@2..5 "cfg"
1041         TOKEN_TREE@5..20
1042           L_PAREN@5..6 "("
1043           IDENT@6..13 "feature"
1044           EQ@13..14 "="
1045           STRING@14..19 "\"std\""
1046           R_PAREN@19..20 ")"
1047       R_BRACK@20..21 "]"
1048     MOD_KW@21..24 "mod"
1049     NAME@24..25
1050       IDENT@24..25 "m"
1051     SEMICOLON@25..26 ";"
1052   MODULE@26..52
1053     ATTR@26..47
1054       POUND@26..27 "#"
1055       L_BRACK@27..28 "["
1056       META@28..46
1057         PATH@28..31
1058           PATH_SEGMENT@28..31
1059             NAME_REF@28..31
1060               IDENT@28..31 "cfg"
1061         TOKEN_TREE@31..46
1062           L_PAREN@31..32 "("
1063           IDENT@32..39 "feature"
1064           EQ@39..40 "="
1065           STRING@40..45 "\"std\""
1066           R_PAREN@45..46 ")"
1067       R_BRACK@46..47 "]"
1068     MOD_KW@47..50 "mod"
1069     NAME@50..51
1070       IDENT@50..51 "f"
1071     SEMICOLON@51..52 ";""###,
1072         dump.trim()
1073     );
1074 }
1075
1076 // https://github.com/rust-lang/rust/blob/master/src/test/ui/issues/issue-57597.rs
1077 #[test]
1078 fn test_rustc_issue_57597() {
1079     fn test_error(fixture: &str) {
1080         assert_eq!(parse_macro_error(fixture), ParseError::RepetitionEmptyTokenTree);
1081     }
1082
1083     test_error("macro_rules! foo { ($($($i:ident)?)+) => {}; }");
1084     test_error("macro_rules! foo { ($($($i:ident)?)*) => {}; }");
1085     test_error("macro_rules! foo { ($($($i:ident)?)?) => {}; }");
1086     test_error("macro_rules! foo { ($($($($i:ident)?)?)?) => {}; }");
1087     test_error("macro_rules! foo { ($($($($i:ident)*)?)?) => {}; }");
1088     test_error("macro_rules! foo { ($($($($i:ident)?)*)?) => {}; }");
1089     test_error("macro_rules! foo { ($($($($i:ident)?)?)*) => {}; }");
1090     test_error("macro_rules! foo { ($($($($i:ident)*)*)?) => {}; }");
1091     test_error("macro_rules! foo { ($($($($i:ident)?)*)*) => {}; }");
1092     test_error("macro_rules! foo { ($($($($i:ident)?)*)+) => {}; }");
1093     test_error("macro_rules! foo { ($($($($i:ident)+)?)*) => {}; }");
1094     test_error("macro_rules! foo { ($($($($i:ident)+)*)?) => {}; }");
1095 }
1096
1097 #[test]
1098 fn test_expand_bad_literal() {
1099     parse_macro(
1100         r#"
1101         macro_rules! foo { ($i:literal) => {}; }
1102     "#,
1103     )
1104     .assert_expand_err(r#"foo!(&k");"#, &ExpandError::BindingError("".into()));
1105 }
1106
1107 #[test]
1108 fn test_empty_comments() {
1109     parse_macro(
1110         r#"
1111         macro_rules! one_arg_macro { ($fmt:expr) => (); }
1112     "#,
1113     )
1114     .assert_expand_err(
1115         r#"one_arg_macro!(/**/)"#,
1116         &ExpandError::BindingError("expected Expr".into()),
1117     );
1118 }