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.rs332
1 files changed, 332 insertions, 0 deletions
diff --git a/crates/mbe/src/tests.rs b/crates/mbe/src/tests.rs
new file mode 100644
index 0000000000..e63ad113ff
--- /dev/null
+++ b/crates/mbe/src/tests.rs
@@ -0,0 +1,332 @@
+//! 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 tt::{TextRange, TextSize};
+
+use crate::DeclarativeMacro;
+
+#[expect(deprecated)]
+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,
+ "{}",
+ syntax_bridge::prettify_macro_expansion::prettify_macro_expansion(
+ node.syntax_node(),
+ &mut |it| it.clone()
+ )
+ );
+ 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#"
+ IDENT struct 0:[email protected]#0
+ IDENT MyTraitMap2 1:[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
+ 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#"
+ IDENT fn 1:[email protected]#0
+ IDENT main 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
+ 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;
+ }"#]],
+ );
+}
+
+#[test]
+fn expr_2021() {
+ check(
+ Edition::Edition2024,
+ Edition::Edition2024,
+ r#"
+($($e:expr),* $(,)?) => {
+ $($e);* ;
+};
+"#,
+ r#"
+ _,
+ const { 1 },
+"#,
+ expect![[r#"
+ IDENT _ 1:[email protected]#0
+ PUNCH ; [joint] 0:[email protected]#0
+ IDENT const 1:[email protected]#0
+ LITERAL Integer 1 1:[email protected]#0
+ PUNCH ; [alone] 0:[email protected]#0
+
+ _;
+ (const {
+ 1
+ });"#]],
+ );
+ check(
+ Edition::Edition2021,
+ Edition::Edition2024,
+ r#"
+($($e:expr),* $(,)?) => {
+ $($e);* ;
+};
+"#,
+ r#"
+ _,
+"#,
+ expect![[r#"
+ ExpandError {
+ inner: (
+ NoMatchingRule,
+ ),
+ }
+
+ PUNCH ; [alone] 0:[email protected]#0
+
+ ;"#]],
+ );
+ check(
+ Edition::Edition2021,
+ Edition::Edition2024,
+ r#"
+($($e:expr),* $(,)?) => {
+ $($e);* ;
+};
+"#,
+ r#"
+ const { 1 },
+"#,
+ expect![[r#"
+ ExpandError {
+ inner: (
+ NoMatchingRule,
+ ),
+ }
+
+ PUNCH ; [alone] 0:[email protected]#0
+
+ ;"#]],
+ );
+ check(
+ Edition::Edition2024,
+ Edition::Edition2024,
+ r#"
+($($e:expr_2021),* $(,)?) => {
+ $($e);* ;
+};
+"#,
+ r#"
+ 4,
+ "literal",
+ funcall(),
+ future.await,
+ break 'foo bar,
+"#,
+ expect![[r#"
+ LITERAL Integer 4 1:[email protected]#0
+ PUNCH ; [joint] 0:[email protected]#0
+ LITERAL Str literal 1:[email protected]#0
+ PUNCH ; [joint] 0:[email protected]#0
+ IDENT funcall 1:[email protected]#0
+ PUNCH ; [joint] 0:[email protected]#0
+ IDENT future 1:[email protected]#0
+ PUNCH . [alone] 1:[email protected]#0
+ IDENT await 1:[email protected]#0
+ PUNCH ; [joint] 0:[email protected]#0
+ IDENT break 1:[email protected]#0
+ PUNCH ' [joint] 1:[email protected]#0
+ IDENT foo 1:[email protected]#0
+ IDENT bar 1:[email protected]#0
+ PUNCH ; [alone] 0:[email protected]#0
+
+ 4;
+ "literal";
+ (funcall());
+ (future.await);
+ (break 'foo bar);"#]],
+ );
+ check(
+ Edition::Edition2024,
+ Edition::Edition2024,
+ r#"
+($($e:expr_2021),* $(,)?) => {
+ $($e);* ;
+};
+"#,
+ r#"
+ _,
+"#,
+ expect![[r#"
+ ExpandError {
+ inner: (
+ NoMatchingRule,
+ ),
+ }
+
+ PUNCH ; [alone] 0:[email protected]#0
+
+ ;"#]],
+ );
+}