diff --git a/crates/hir_def/src/macro_expansion_tests.rs b/crates/hir_def/src/macro_expansion_tests.rs index d113a2f504..f9527a4135 100644 --- a/crates/hir_def/src/macro_expansion_tests.rs +++ b/crates/hir_def/src/macro_expansion_tests.rs @@ -20,7 +20,7 @@ use stdx::format_to; use syntax::{ ast::{self, edit::IndentLevel}, AstNode, - SyntaxKind::{EOF, IDENT, LIFETIME_IDENT}, + SyntaxKind::{COMMENT, EOF, IDENT, LIFETIME_IDENT}, SyntaxNode, T, }; @@ -60,21 +60,36 @@ fn check(ra_fixture: &str, mut expect: Expect) { let mut expanded_text = source_file.to_string(); for (call, exp) in expansions.into_iter().rev() { + let mut tree = false; + let mut expect_errors = false; + for comment in call.syntax().children_with_tokens().filter(|it| it.kind() == COMMENT) { + tree |= comment.to_string().contains("+tree"); + expect_errors |= comment.to_string().contains("+errors"); + } + let mut expn_text = String::new(); if let Some(err) = exp.err { format_to!(expn_text, "/* error: {} */", err); } if let Some((parse, _token_map)) = exp.value { - assert!( - parse.errors().is_empty(), - "parse errors in expansion: \n{:#?}", - parse.errors() - ); + if expect_errors { + assert!(!parse.errors().is_empty(), "no parse errors in expansion"); + for e in parse.errors() { + format_to!(expn_text, "/* parse error: {} */\n", e); + } + } else { + assert!( + parse.errors().is_empty(), + "parse errors in expansion: \n{:#?}", + parse.errors() + ); + } let pp = pretty_print_macro_expansion(parse.syntax_node()); let indent = IndentLevel::from_node(call.syntax()); let pp = reindent(indent, pp); format_to!(expn_text, "{}", pp); - if call.to_string().contains("// +tree") { + + if tree { let tree = format!("{:#?}", parse.syntax_node()) .split_inclusive("\n") .map(|line| format!("// {}", line)) diff --git a/crates/hir_def/src/macro_expansion_tests/mbe.rs b/crates/hir_def/src/macro_expansion_tests/mbe.rs index 4ed46a1325..7600b16ded 100644 --- a/crates/hir_def/src/macro_expansion_tests/mbe.rs +++ b/crates/hir_def/src/macro_expansion_tests/mbe.rs @@ -1310,3 +1310,120 @@ fn foo() {} "#]], ); } + +#[test] +fn test_inner_macro_rules() { + check( + r#" +macro_rules! m { + ($a:ident, $b:ident, $c:tt) => { + macro_rules! inner { + ($bi:ident) => { fn $bi() -> u8 { $c } } + } + + inner!($a); + fn $b() -> u8 { $c } + } +} +m!(x, y, 1); +"#, + expect![[r#" +macro_rules! m { + ($a:ident, $b:ident, $c:tt) => { + macro_rules! inner { + ($bi:ident) => { fn $bi() -> u8 { $c } } + } + + inner!($a); + fn $b() -> u8 { $c } + } +} +macro_rules !inner { + ($bi: ident) = > { + fn $bi()-> u8 { + 1 + } + } +} +inner!(x); +fn y() -> u8 { + 1 +} +"#]], + ); +} + +#[test] +fn test_expr_after_path_colons() { + check( + r#" +macro_rules! m { + ($k:expr) => { fn f() { K::$k; } } +} +// +tree +errors +m!(C("0")); +"#, + expect![[r#" +macro_rules! m { + ($k:expr) => { fn f() { K::$k; } } +} +/* parse error: expected identifier */ +/* parse error: expected SEMICOLON */ +fn f() { + K::C("0"); +} +// MACRO_ITEMS@0..17 +// FN@0..17 +// FN_KW@0..2 "fn" +// NAME@2..3 +// IDENT@2..3 "f" +// PARAM_LIST@3..5 +// L_PAREN@3..4 "(" +// R_PAREN@4..5 ")" +// BLOCK_EXPR@5..17 +// STMT_LIST@5..17 +// L_CURLY@5..6 "{" +// EXPR_STMT@6..9 +// PATH_EXPR@6..9 +// PATH@6..9 +// PATH@6..7 +// PATH_SEGMENT@6..7 +// NAME_REF@6..7 +// IDENT@6..7 "K" +// COLON2@7..9 "::" +// EXPR_STMT@9..16 +// CALL_EXPR@9..15 +// PATH_EXPR@9..10 +// PATH@9..10 +// PATH_SEGMENT@9..10 +// NAME_REF@9..10 +// IDENT@9..10 "C" +// ARG_LIST@10..15 +// L_PAREN@10..11 "(" +// LITERAL@11..14 +// STRING@11..14 "\"0\"" +// R_PAREN@14..15 ")" +// SEMICOLON@15..16 ";" +// R_CURLY@16..17 "}" + +"#]], + ); +} + +#[test] +fn test_match_is_not_greedy() { + check( + r#" +macro_rules! foo { + ($($i:ident $(,)*),*) => {}; +} +foo!(a,b); +"#, + expect![[r#" +macro_rules! foo { + ($($i:ident $(,)*),*) => {}; +} + +"#]], + ); +} diff --git a/crates/mbe/src/tests/expand.rs b/crates/mbe/src/tests/expand.rs index 51c3ba10da..79f0824b59 100644 --- a/crates/mbe/src/tests/expand.rs +++ b/crates/mbe/src/tests/expand.rs @@ -1,8 +1,5 @@ use ::parser::ParserEntryPoint; -use syntax::{ - SyntaxKind::{ERROR, IDENT}, - T, -}; +use syntax::{SyntaxKind::IDENT, T}; use test_utils::assert_eq_text; use super::*; @@ -101,59 +98,6 @@ fn test_attr_to_token_tree() { ); } -#[test] -fn test_inner_macro_rules() { - parse_macro( - r#" -macro_rules! foo { - ($a:ident, $b:ident, $c:tt) => { - - macro_rules! bar { - ($bi:ident) => { - fn $bi() -> u8 {$c} - } - } - - bar!($a); - fn $b() -> u8 {$c} - } -} -"#, - ). - assert_expand_items( - r#"foo!(x,y, 1);"#, - r#"macro_rules ! bar {($ bi : ident) => {fn $ bi () -> u8 {1}}} bar ! (x) ; fn y () -> u8 {1}"#, - ); -} - -#[test] -fn test_expr_after_path_colons() { - assert!(parse_macro( - r#" -macro_rules! m { - ($k:expr) => { - f(K::$k); - } -} -"#, - ) - .expand_statements(r#"m!(C("0"))"#) - .descendants() - .any(|token| token.kind() == ERROR)); -} - -#[test] -fn test_match_is_not_greedy() { - parse_macro( - r#" -macro_rules! foo { - ($($i:ident $(,)*),*) => {}; -} -"#, - ) - .assert_expand_items(r#"foo!(a,b);"#, r#""#); -} - // The following tests are based on real world situations #[test] fn test_vec() {