Repository: rust-analyzer/rust-analyzer
Pull request #11164 (2022-01-02 14:18:53)

internal: more macro tests
bors r+
🤖


Patch:
diff --git a/crates/mbe/src/syntax_bridge.rs b/crates/mbe/src/syntax_bridge.rs
index 8021e63f7f..1141365e82 100644
--- a/crates/mbe/src/syntax_bridge.rs
+++ b/crates/mbe/src/syntax_bridge.rs
@@ -67,6 +67,7 @@ pub fn token_tree_to_syntax_node(
         }
     }
     if tree_sink.roots.len() != 1 {
+        cov_mark::hit!(expansion_does_not_parse_as_expression);
         return Err(ExpandError::ConversionError);
     }
     //FIXME: would be cool to report errors


Test patch:
diff --git a/crates/hir_def/src/macro_expansion_tests/mbe.rs b/crates/hir_def/src/macro_expansion_tests/mbe.rs
index 466c85fc5b..2cd70a84c5 100644
--- a/crates/hir_def/src/macro_expansion_tests/mbe.rs
+++ b/crates/hir_def/src/macro_expansion_tests/mbe.rs
@@ -85,26 +85,6 @@ impl From<Subtree> for TokenTree {
     );
 }
 
-#[test]
-fn expansion_does_not_parse_as_expression() {
-    check(
-        r#"
-macro_rules! stmts {
-    () => { let _ = 0; }
-}
-
-fn f() { let _ = stmts!(); }
-"#,
-        expect![[r#"
-macro_rules! stmts {
-    () => { let _ = 0; }
-}
-
-fn f() { let _ = /* error: could not convert tokens */; }
-"#]],
-    )
-}
-
 #[test]
 fn wrong_nesting_level() {
     check(
diff --git a/crates/hir_def/src/macro_expansion_tests/mbe/tt_conversion.rs b/crates/hir_def/src/macro_expansion_tests/mbe/tt_conversion.rs
index 291f99330f..97c27c453b 100644
--- a/crates/hir_def/src/macro_expansion_tests/mbe/tt_conversion.rs
+++ b/crates/hir_def/src/macro_expansion_tests/mbe/tt_conversion.rs
@@ -2,7 +2,9 @@
 //! Rather, token trees are an explicit bridge between the parser and
 //! (procedural or declarative) macros.
 //!
-//! This module tests tt <-> syntax tree conversion specifically
+//! This module tests tt <-> syntax tree conversion specifically. In particular,
+//! it, among other things, check that we convert `tt` to the right kind of
+//! syntax node depending on the macro call-site.
 use expect_test::expect;
 
 use crate::macro_expansion_tests::check;
@@ -100,3 +102,49 @@ macro_rules! m2 { ($x:ident) => {} }
 "#]],
     )
 }
+
+#[test]
+fn expansion_does_not_parse_as_expression() {
+    cov_mark::check!(expansion_does_not_parse_as_expression);
+    check(
+        r#"
+macro_rules! stmts {
+    () => { let _ = 0; }
+}
+
+fn f() { let _ = stmts!(); }
+"#,
+        expect![[r#"
+macro_rules! stmts {
+    () => { let _ = 0; }
+}
+
+fn f() { let _ = /* error: could not convert tokens */; }
+"#]],
+    )
+}
+
+#[test]
+fn broken_pat() {
+    check(
+        r#"
+macro_rules! m1 { () => (Some(x) left overs) }
+macro_rules! m2 { () => ($) }
+
+fn main() {
+    let m1!() = ();
+    let m2!/*+errors*/() = ();
+}
+"#,
+        expect![[r#"
+macro_rules! m1 { () => (Some(x) left overs) }
+macro_rules! m2 { () => ($) }
+
+fn main() {
+    let Some(x) = ();
+    let /* parse error: expected pattern */
+$ = ();
+}
+"#]],
+    )
+}
diff --git a/crates/parser/src/tests.rs b/crates/parser/src/tests.rs
index 52388dacc6..c0437bc3b8 100644
--- a/crates/parser/src/tests.rs
+++ b/crates/parser/src/tests.rs
@@ -114,7 +114,13 @@ fn parse(entry: TopEntryPoint, text: &str) -> (String, bool) {
             errors.push(format!("error {}: {}\n", pos, msg))
         }
     });
-    assert_eq!(len, text.len());
+    assert_eq!(
+        len,
+        text.len(),
+        "didn't parse all text.\nParsed:\n{}\n\nAll:\n{}\n",
+        &text[..len],
+        text
+    );
 
     for (token, msg) in lexed.errors() {
         let pos = lexed.text_start(token);
diff --git a/crates/parser/src/tests/top_entries.rs b/crates/parser/src/tests/top_entries.rs
index 0b77c0a5b9..fa25ffd0a2 100644
--- a/crates/parser/src/tests/top_entries.rs
+++ b/crates/parser/src/tests/top_entries.rs
@@ -92,6 +92,62 @@ fn macro_stmt() {
     );
 }
 
+#[test]
+fn macro_items() {
+    check(
+        TopEntryPoint::MacroItems,
+        "#!/usr/bin/rust",
+        expect![[r##"
+            MACRO_ITEMS
+              ERROR
+                SHEBANG "#!/usr/bin/rust"
+            error 0: expected an item
+        "##]],
+    );
+    check(
+        TopEntryPoint::MacroItems,
+        "struct S; foo!{}",
+        expect![[r#"
+            MACRO_ITEMS
+              STRUCT
+                STRUCT_KW "struct"
+                WHITESPACE " "
+                NAME
+                  IDENT "S"
+                SEMICOLON ";"
+              WHITESPACE " "
+              MACRO_CALL
+                PATH
+                  PATH_SEGMENT
+                    NAME_REF
+                      IDENT "foo"
+                BANG "!"
+                TOKEN_TREE
+                  L_CURLY "{"
+                  R_CURLY "}"
+        "#]],
+    );
+}
+
+#[test]
+fn macro_pattern() {
+    check(
+        TopEntryPoint::Pattern,
+        "Some(_)",
+        expect![[r#"
+            TUPLE_STRUCT_PAT
+              PATH
+                PATH_SEGMENT
+                  NAME_REF
+                    IDENT "Some"
+              L_PAREN "("
+              WILDCARD_PAT
+                UNDERSCORE "_"
+              R_PAREN ")"
+        "#]],
+    );
+}
+
 #[track_caller]
 fn check(entry: TopEntryPoint, input: &str, expect: expect_test::Expect) {
     let (parsed, _errors) = super::parse(entry, input);