Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/mbe/src/tests.rs')
| -rw-r--r-- | crates/mbe/src/tests.rs | 179 |
1 files changed, 179 insertions, 0 deletions
diff --git a/crates/mbe/src/tests.rs b/crates/mbe/src/tests.rs new file mode 100644 index 0000000000..5422c9ae64 --- /dev/null +++ b/crates/mbe/src/tests.rs @@ -0,0 +1,179 @@ +//! Tests specific to declarative macros, aka macros by example. This covers +//! both stable `macro_rules!` macros as well as unstable `macro` macros. +// FIXME: Move more of the nameres independent tests from +// crates\hir-def\src\macro_expansion_tests\mod.rs to this +use expect_test::expect; +use span::{Edition, EditionedFileId, ErasedFileAstId, FileId, Span, SpanAnchor, SyntaxContextId}; +use stdx::format_to; +use syntax_bridge::insert_whitespace_into_node::insert_ws_into; +use tt::{TextRange, TextSize}; + +use crate::DeclarativeMacro; + +fn check_( + def_edition: Edition, + call_edition: Edition, + macro2: bool, + decl: &str, + arg: &str, + render_debug: bool, + expect: expect_test::Expect, + parse: parser::TopEntryPoint, +) { + let decl_tt = &syntax_bridge::parse_to_token_tree( + def_edition, + SpanAnchor { + file_id: EditionedFileId::new(FileId::from_raw(0), def_edition), + ast_id: ErasedFileAstId::from_raw(0), + }, + SyntaxContextId::ROOT, + decl, + ) + .unwrap(); + let mac = if macro2 { + DeclarativeMacro::parse_macro2(None, decl_tt, |_| def_edition) + } else { + DeclarativeMacro::parse_macro_rules(decl_tt, |_| def_edition) + }; + let call_anchor = SpanAnchor { + file_id: EditionedFileId::new(FileId::from_raw(1), call_edition), + ast_id: ErasedFileAstId::from_raw(0), + }; + let arg_tt = + syntax_bridge::parse_to_token_tree(call_edition, call_anchor, SyntaxContextId::ROOT, arg) + .unwrap(); + let res = mac.expand( + &arg_tt, + |_| (), + Span { + range: TextRange::up_to(TextSize::of(arg)), + anchor: call_anchor, + ctx: SyntaxContextId::ROOT, + }, + def_edition, + ); + let mut expect_res = String::new(); + if let Some(err) = res.err { + format_to!(expect_res, "{err:#?}\n\n",); + } + if render_debug { + format_to!(expect_res, "{:#?}\n\n", res.value.0); + } + let (node, _) = syntax_bridge::token_tree_to_syntax_node(&res.value.0, parse, def_edition); + format_to!(expect_res, "{}", insert_ws_into(node.syntax_node())); + expect.assert_eq(&expect_res); +} + +fn check( + def_edition: Edition, + call_edition: Edition, + decl: &str, + arg: &str, + expect: expect_test::Expect, +) { + check_( + def_edition, + call_edition, + false, + decl, + arg, + true, + expect, + parser::TopEntryPoint::SourceFile, + ); +} + +#[test] +fn token_mapping_smoke_test() { + check( + Edition::CURRENT, + Edition::CURRENT, + r#" +( struct $ident:ident ) => { + struct $ident { + map: ::std::collections::HashSet<()>, + } +}; +"#, + r#" +struct MyTraitMap2 +"#, + expect![[r#" + SUBTREE $$ 1:[email protected]#0 1:[email protected]#0 + IDENT struct 0:[email protected]#0 + IDENT MyTraitMap2 1:[email protected]#0 + SUBTREE {} 0:[email protected]#0 0:[email protected]#0 + IDENT map 0:[email protected]#0 + PUNCH : [alone] 0:[email protected]#0 + PUNCH : [joint] 0:[email protected]#0 + PUNCH : [alone] 0:[email protected]#0 + IDENT std 0:[email protected]#0 + PUNCH : [joint] 0:[email protected]#0 + PUNCH : [alone] 0:[email protected]#0 + IDENT collections 0:[email protected]#0 + PUNCH : [joint] 0:[email protected]#0 + PUNCH : [alone] 0:[email protected]#0 + IDENT HashSet 0:[email protected]#0 + PUNCH < [alone] 0:[email protected]#0 + SUBTREE () 0:[email protected]#0 0:[email protected]#0 + PUNCH > [joint] 0:[email protected]#0 + PUNCH , [alone] 0:[email protected]#0 + + struct MyTraitMap2 { + map: ::std::collections::HashSet<()>, + }"#]], + ); +} + +#[test] +fn token_mapping_floats() { + // Regression test for https://github.com/rust-lang/rust-analyzer/issues/12216 + // (and related issues) + check( + Edition::CURRENT, + Edition::CURRENT, + r#" +($($tt:tt)*) => { + $($tt)* +}; +"#, + r#" +fn main() { + 1; + 1.0; + ((1,),).0.0; + let x = 1; +} +"#, + expect![[r#" + SUBTREE $$ 1:[email protected]#0 1:[email protected]#0 + IDENT fn 1:[email protected]#0 + IDENT main 1:[email protected]#0 + SUBTREE () 1:[email protected]#0 1:[email protected]#0 + SUBTREE {} 1:[email protected]#0 1:[email protected]#0 + LITERAL Integer 1 1:[email protected]#0 + PUNCH ; [alone] 1:[email protected]#0 + LITERAL Float 1.0 1:[email protected]#0 + PUNCH ; [alone] 1:[email protected]#0 + SUBTREE () 1:[email protected]#0 1:[email protected]#0 + SUBTREE () 1:[email protected]#0 1:[email protected]#0 + LITERAL Integer 1 1:[email protected]#0 + PUNCH , [alone] 1:[email protected]#0 + PUNCH , [alone] 1:[email protected]#0 + PUNCH . [alone] 1:[email protected]#0 + LITERAL Float 0.0 1:[email protected]#0 + PUNCH ; [alone] 1:[email protected]#0 + IDENT let 1:[email protected]#0 + IDENT x 1:[email protected]#0 + PUNCH = [alone] 1:[email protected]#0 + LITERAL Integer 1 1:[email protected]#0 + PUNCH ; [alone] 1:[email protected]#0 + + fn main(){ + 1; + 1.0; + ((1,),).0.0; + let x = 1; + }"#]], + ); +} |