Repository: rust-analyzer/rust-analyzer
Pull request #11871 (2022-04-01 15:14:25)

internal: Move `rust.ungram` into `rust-analyzer/crates/syntax`
This makes updating the grammar a lot simpler for us. Though removing it from ungrammar can't be done without bumping it to 2.0 so I'll leave it in there for the time being.
cc https://github.com/rust-analyzer/ungrammar/pull/47


Patch:
diff --git a/crates/ide/src/runnables.rs b/crates/ide/src/runnables.rs
index 1c455c5f30..bcb2c8797d 100644
--- a/crates/ide/src/runnables.rs
+++ b/crates/ide/src/runnables.rs
@@ -474,7 +474,7 @@ impl TestAttr {
     }
 }
 
-const RUSTDOC_FENCES: [&str; 2] = ["```", "~~~"];
+const RUSTDOC_FENCE: &str = "```";
 const RUSTDOC_CODE_BLOCK_ATTRIBUTES_RUNNABLE: &[&str] =
     &["", "rust", "should_panic", "edition2015", "edition2018", "edition2021"];
 
@@ -483,9 +483,7 @@ fn has_runnable_doc_test(attrs: &hir::Attrs) -> bool {
         let mut in_code_block = false;
 
         for line in String::from(doc).lines() {
-            if let Some(header) =
-                RUSTDOC_FENCES.into_iter().find_map(|fence| line.strip_prefix(fence))
-            {
+            if let Some(header) = line.strip_prefix(RUSTDOC_FENCE) {
                 in_code_block = !in_code_block;
 
                 if in_code_block
diff --git a/crates/ide/src/syntax_highlighting/inject.rs b/crates/ide/src/syntax_highlighting/inject.rs
index 8ac3c2da50..8af0d8007d 100644
--- a/crates/ide/src/syntax_highlighting/inject.rs
+++ b/crates/ide/src/syntax_highlighting/inject.rs
@@ -78,8 +78,7 @@ pub(super) fn ra_fixture(
     Some(())
 }
 
-const RUSTDOC_FENCE_LENGTH: usize = 3;
-const RUSTDOC_FENCES: [&str; 2] = ["```", "~~~"];
+const RUSTDOC_FENCE: &str = "```";
 
 /// Injection of syntax highlighting of doctests.
 pub(super) fn doc_comment(
@@ -167,11 +166,11 @@ pub(super) fn doc_comment(
             };
             let mut pos = TextSize::from(0);
 
-            match RUSTDOC_FENCES.into_iter().find_map(|fence| line.find(fence)) {
+            match line.find(RUSTDOC_FENCE) {
                 Some(idx) => {
                     is_codeblock = !is_codeblock;
                     // Check whether code is rust by inspecting fence guards
-                    let guards = &line[idx + RUSTDOC_FENCE_LENGTH..];
+                    let guards = &line[idx + RUSTDOC_FENCE.len()..];
                     let is_rust = is_rust_fence(guards);
                     is_doctest = is_codeblock && is_rust;
                     continue;
diff --git a/crates/ide_assists/src/handlers/generate_enum_is_method.rs b/crates/ide_assists/src/handlers/generate_enum_is_method.rs
index 7dc1e4df28..863ada79ba 100644
--- a/crates/ide_assists/src/handlers/generate_enum_is_method.rs
+++ b/crates/ide_assists/src/handlers/generate_enum_is_method.rs
@@ -1,4 +1,3 @@
-use ide_db::assists::GroupLabel;
 use stdx::to_lower_snake_case;
 use syntax::ast::HasVisibility;
 use syntax::ast::{self, AstNode, HasName};
@@ -55,8 +54,7 @@ pub(crate) fn generate_enum_is_method(acc: &mut Assists, ctx: &AssistContext) ->
     let impl_def = find_struct_impl(ctx, &parent_enum, &fn_name)?;
 
     let target = variant.syntax().text_range();
-    acc.add_group(
-        &GroupLabel("Generate `is_`,`as_`,`try_into_`".to_owned()),
+    acc.add(
         AssistId("generate_enum_is_method", AssistKind::Generate),
         "Generate an `is_` method for an enum variant",
         target,
diff --git a/crates/ide_assists/src/handlers/generate_enum_projection_method.rs b/crates/ide_assists/src/handlers/generate_enum_projection_method.rs
index fdaa791340..a9116be67c 100644
--- a/crates/ide_assists/src/handlers/generate_enum_projection_method.rs
+++ b/crates/ide_assists/src/handlers/generate_enum_projection_method.rs
@@ -1,4 +1,3 @@
-use ide_db::assists::GroupLabel;
 use itertools::Itertools;
 use stdx::to_lower_snake_case;
 use syntax::ast::HasVisibility;
@@ -140,37 +139,31 @@ fn generate_enum_projection_method(
     let impl_def = find_struct_impl(ctx, &parent_enum, &fn_name)?;
 
     let target = variant.syntax().text_range();
-    acc.add_group(
-        &GroupLabel("Generate `is_`,`as_`,`try_into_`".to_owned()),
-        AssistId(assist_id, AssistKind::Generate),
-        assist_description,
-        target,
-        |builder| {
-            let vis = parent_enum.visibility().map_or(String::new(), |v| format!("{} ", v));
-            let method = format!(
-                "    {0}fn {1}({2}) -> {3}{4}{5} {{
+    acc.add(AssistId(assist_id, AssistKind::Generate), assist_description, target, |builder| {
+        let vis = parent_enum.visibility().map_or(String::new(), |v| format!("{} ", v));
+        let method = format!(
+            "    {0}fn {1}({2}) -> {3}{4}{5} {{
         if let Self::{6}{7} = self {{
             {8}({9})
         }} else {{
             {10}
         }}
     }}",
-                vis,
-                fn_name,
-                props.self_param,
-                props.return_prefix,
-                field_type.syntax(),
-                props.return_suffix,
-                variant_name,
-                pattern_suffix,
-                props.happy_case,
-                bound_name,
-                props.sad_case,
-            );
+            vis,
+            fn_name,
+            props.self_param,
+            props.return_prefix,
+            field_type.syntax(),
+            props.return_suffix,
+            variant_name,
+            pattern_suffix,
+            props.happy_case,
+            bound_name,
+            props.sad_case,
+        );
 
-            add_method_to_adt(builder, &parent_enum, impl_def, &method);
-        },
-    )
+        add_method_to_adt(builder, &parent_enum, impl_def, &method);
+    })
 }
 
 #[cfg(test)]
diff --git a/crates/rust-analyzer/src/markdown.rs b/crates/rust-analyzer/src/markdown.rs
index 912ed1e764..e1ff0f0178 100644
--- a/crates/rust-analyzer/src/markdown.rs
+++ b/crates/rust-analyzer/src/markdown.rs
@@ -1,7 +1,7 @@
 //! Transforms markdown
 use ide_db::rust_doc::is_rust_fence;
 
-const RUSTDOC_FENCES: [&str; 2] = ["```", "~~~"];
+const RUSTDOC_FENCE: &str = "```";
 
 pub(crate) fn format_docs(src: &str) -> String {
     let mut processed_lines = Vec::new();
@@ -13,8 +13,7 @@ pub(crate) fn format_docs(src: &str) -> String {
             continue;
         }
 
-        if let Some(header) = RUSTDOC_FENCES.into_iter().find_map(|fence| line.strip_prefix(fence))
-        {
+        if let Some(header) = line.strip_prefix(RUSTDOC_FENCE) {
             in_code_block ^= true;
 
             if in_code_block {
diff --git a/crates/syntax/Cargo.toml b/crates/syntax/Cargo.toml
index 4a454cb8b7..bb4d10207d 100644
--- a/crates/syntax/Cargo.toml
+++ b/crates/syntax/Cargo.toml
@@ -30,7 +30,7 @@ rayon = "1.5.1"
 expect-test = "1.2.2"
 proc-macro2 = "1.0.36"
 quote = "1.0.16"
-ungrammar = "=1.16.1"
+ungrammar = "1.16.1"
 
 test_utils = { path = "../test_utils" }
 sourcegen = { path = "../sourcegen" }
diff --git a/crates/syntax/rust.ungram b/crates/syntax/rust.ungram
new file mode 100644
index 0000000000..cb58486eff
--- /dev/null
+++ b/crates/syntax/rust.ungram
@@ -0,0 +1,664 @@
+// Rust Un-Grammar.
+//
+// This grammar specifies the structure of Rust's concrete syntax tree.
+// It does not specify parsing rules (ambiguities, precedence, etc are out of scope).
+// Tokens are processed -- contextual keywords are recognised, compound operators glued.
+//
+// Legend:
+//
+//   //          -- comment
+//   Name =      -- non-terminal definition
+//   'ident'     -- token (terminal)
+//   A B         -- sequence
+//   A | B       -- alternation
+//   A*          -- zero or more repetition
+//   A?          -- zero or one repetition
+//   (A)         -- same as A
+//   label:A     -- suggested name for field of AST node
+
+//*************************//
+// Names, Paths and Macros //
+//*************************//
+
+Name =
+  'ident' | 'self'
+
+NameRef =
+  'ident' | 'int_number' | 'self' | 'super' | 'crate' | 'Self'
+
+Lifetime =
+  'lifetime_ident'
+
+Path =
+  (qualifier:Path '::')? segment:PathSegment
+
+PathSegment =
+  '::'? NameRef
+| NameRef GenericArgList?
+| NameRef ParamList RetType?
+| '<' PathType ('as' PathType)? '>'
+
+GenericArgList =
+  '::'? '<' (GenericArg (',' GenericArg)* ','?)? '>'
+
+GenericArg =
+  TypeArg
+| AssocTypeArg
+| LifetimeArg
+| ConstArg
+
+TypeArg =
+  Type
+
+AssocTypeArg =
+  NameRef GenericParamList? (':' TypeBoundList | '=' Type)
+
+LifetimeArg =
+  Lifetime
+
+ConstArg =
+  Expr
+
+MacroCall =
+  Attr* Path '!' TokenTree ';'?
+
+TokenTree =
+  '(' ')'
+| '{' '}'
+| '[' ']'
+
+MacroItems =
+  Item*
+
+MacroStmts =
+  statements:Stmt*
+  Expr?
+
+//*************************//
+//          Items          //
+//*************************//
+
+SourceFile =
+  'shebang'?
+  Attr*
+  Item*
+
+Item =
+  Const
+| Enum
+| ExternBlock
+| ExternCrate
+| Fn
+| Impl
+| MacroCall
+| MacroRules
+| MacroDef
+| Module
+| Static
+| Struct
+| Trait
+| TypeAlias
+| Union
+| Use
+
+MacroRules =
+  Attr* Visibility?
+  'macro_rules' '!' Name
+  TokenTree
+
+MacroDef =
+  Attr* Visibility?
+  'macro' Name args:TokenTree?
+  body:TokenTree
+
+Module =
+  Attr* Visibility?
+  'mod' Name
+  (ItemList | ';')
+
+ItemList =
+  '{' Attr* Item* '}'
+
+ExternCrate =
+  Attr* Visibility?
+  'extern' 'crate' NameRef Rename? ';'
+
+Rename =
+  'as' (Name | '_')
+
+Use =
+  Attr* Visibility?
+  'use' UseTree ';'
+
+UseTree =
+  (Path? '::')? ('*' | UseTreeList)
+| Path Rename?
+
+UseTreeList =
+  '{' (UseTree (',' UseTree)* ','?)? '}'
+
+Fn =
+ Attr* Visibility?
+ 'default'? 'const'? 'async'? 'unsafe'? Abi?
+ 'fn' Name GenericParamList? ParamList RetType? WhereClause?
+ (body:BlockExpr | ';')
+
+Abi =
+  'extern' 'string'?
+
+ParamList =
+  '('(
+    SelfParam
+  | (SelfParam ',')? (Param (',' Param)* ','?)?
+  )')'
+| '|' (Param (',' Param)* ','?)? '|'
+
+SelfParam =
+  Attr* (
+    ('&' Lifetime?)? 'mut'? Name
+  | 'mut'? Name ':' Type
+  )
+
+Param =
+  Attr* (
+    Pat (':' Type)?
+  | Type
+  | '...'
+  )
+
+RetType =
+  '->' Type
+
+TypeAlias =
+  Attr* Visibility?
+  'default'?
+  'type' Name GenericParamList? (':' TypeBoundList?)? WhereClause?
+  ('=' Type)? ';'
+
+Struct =
+  Attr* Visibility?
+  'struct' Name GenericParamList? (
+    WhereClause? (RecordFieldList | ';')
+  | TupleFieldList WhereClause? ';'
+  )
+
+RecordFieldList =
+ '{' fields:(RecordField (',' RecordField)* ','?)? '}'
+
+RecordField =
+  Attr* Visibility?
+  Name ':' Type
+
+TupleFieldList =
+  '(' fields:(TupleField (',' TupleField)* ','?)? ')'
+
+TupleField =
+  Attr* Visibility?
+  Type
+
+FieldList =
+  RecordFieldList
+| TupleFieldList
+
+Enum =
+  Attr* Visibility?
+  'enum' Name GenericParamList? WhereClause?
+  VariantList
+
+VariantList =
+ '{' (Variant (',' Variant)* ','?)? '}'
+
+Variant =
+  Attr* Visibility?
+  Name FieldList? ('=' Expr)?
+
+Union =
+  Attr* Visibility?
+  'union' Name GenericParamList? WhereClause?
+  RecordFieldList
+
+// A Data Type.
+//
+// Not used directly in the grammar, but handy to have anyway.
+Adt =
+  Enum
+| Struct
+| Union
+
+Const =
+  Attr* Visibility?
+  'default'?
+  'const' (Name | '_') ':' Type
+  ('=' body:Expr)? ';'
+
+Static =
+  Attr* Visibility?
+  'static' 'mut'? Name ':' Type
+  ('=' body:Expr)? ';'
+
+Trait =
+  Attr* Visibility?
+  'unsafe'? 'auto'?
+  'trait' Name GenericParamList? (':' TypeBoundList?)? WhereClause?
+  AssocItemList
+
+AssocItemList =
+  '{' Attr* AssocItem* '}'
+
+AssocItem =
+  Const
+| Fn
+| MacroCall
+| TypeAlias
+
+Impl =
+  Attr* Visibility?
+  'default'? 'unsafe'?
+  'impl' GenericParamList? ('const'? '!'? trait:Type 'for')? self_ty:Type WhereClause?
+  AssocItemList
+
+ExternBlock =
+  Attr* 'unsafe'? Abi ExternItemList
+
+ExternItemList =
+  '{' Attr* ExternItem* '}'
+
+ExternItem =
+  Fn
+| MacroCall
+| Static
+| TypeAlias
+
+GenericParamList =
+  '<' (GenericParam (',' GenericParam)* ','?)? '>'
+
+GenericParam =
+  ConstParam
+| LifetimeParam
+| TypeParam
+
+TypeParam =
+  Attr* Name (':' TypeBoundList?)?
+  ('=' default_type:Type)?
+
+ConstParam =
+  Attr* 'const' Name ':' Type
+  ('=' default_val:Expr)?
+
+LifetimeParam =
+  Attr* Lifetime (':' TypeBoundList?)?
+
+WhereClause =
+  'where' predicates:(WherePred (',' WherePred)* ','?)
+
+WherePred =
+  ('for' GenericParamList)?  (Lifetime | Type) ':' TypeBoundList?
+
+Visibility =
+  'pub' ('(' 'in'? Path ')')?
+
+Attr =
+  '#' '!'? '[' Meta ']'
+
+Meta =
+  Path ('=' Expr | TokenTree)?
+
+//****************************//
+// Statements and Expressions //
+//****************************//
+
+Stmt =
+  ';'
+| ExprStmt
+| Item
+| LetStmt
+
+LetStmt =
+  Attr* 'let' Pat (':' Type)?
+  '=' initializer:Expr
+  LetElse?
+  ';'
+
+LetElse =
+  'else' BlockExpr
+
+ExprStmt =
+  Expr ';'?
+
+Expr =
+  ArrayExpr
+| AwaitExpr
+| BinExpr
+| BlockExpr
+| BoxExpr
+| BreakExpr
+| CallExpr
+| CastExpr
+| ClosureExpr
+| ContinueExpr
+| FieldExpr
+| ForExpr
+| IfExpr
+| IndexExpr
+| Literal
+| LoopExpr
+| MacroCall
+| MacroStmts
+| MatchExpr
+| MethodCallExpr
+| ParenExpr
+| PathExpr
+| PrefixExpr
+| RangeExpr
+| RecordExpr
+| RefExpr
+| ReturnExpr
+| TryExpr
+| TupleExpr
+| WhileExpr
+| YieldExpr
+| LetExpr
+| UnderscoreExpr
+
+Literal =
+  Attr* value:(
+    'int_number' | 'float_number'
+  | 'string' | 'raw_string'
+  | 'byte_string' | 'raw_byte_string'
+  | 'true' | 'false'
+  | 'char' | 'byte'
+  )
+
+PathExpr =
+  Attr* Path
+
+StmtList =
+  '{'
+    Attr*
+    statements:Stmt*
+    tail_expr:Expr?
+  '}'
+
+RefExpr =
+  Attr* '&' ('raw' | 'mut' | 'const') Expr
+
+TryExpr =
+  Attr* Expr '?'
+
+BlockExpr =
+  Attr* Label? ('try' | 'unsafe' | 'async' | 'const') StmtList
+
+PrefixExpr =
+  Attr* op:('-' | '!' | '*') Expr
+
+BinExpr =
+  Attr*
+  lhs:Expr
+  op:(
+    '||' | '&&'
+  | '==' | '!=' | '<=' | '>=' | '<' | '>'
+  | '+' | '*' | '-' | '/' | '%' | '<<' | '>>' | '^' | '|' | '&'
+  | '=' | '+=' | '/=' | '*=' | '%=' | '>>=' | '<<=' | '-=' | '|=' | '&=' | '^='
+  )
+  rhs:Expr
+
+CastExpr =
+  Attr* Expr 'as' Type
+
+ParenExpr =
+  Attr* '(' Attr* Expr ')'
+
+ArrayExpr =
+  Attr* '[' Attr* (
+    (Expr (',' Expr)* ','?)?
+  | Expr ';' Expr
+  ) ']'
+
+IndexExpr =
+  Attr* base:Expr '[' index:Expr ']'
+
+TupleExpr =
+  Attr* '(' Attr* fields:(Expr (',' Expr)* ','?)? ')'
+
+RecordExpr =
+  Path RecordExprFieldList
+
+RecordExprFieldList =
+  '{'
+    Attr*
+    fields:(RecordExprField (',' RecordExprField)* ','?)?
+    ('..' spread:Expr?)?
+  '}'
+
+RecordExprField =
+  Attr* (NameRef ':')? Expr
+
+CallExpr =
+  Attr* Expr ArgList
+
+ArgList =
+  '(' args:(Expr (',' Expr)* ','?)? ')'
+
+MethodCallExpr =
+  Attr* receiver:Expr '.' NameRef GenericArgList? ArgList
+
+FieldExpr =
+  Attr* Expr '.' NameRef
+
+ClosureExpr =
+  Attr* 'static'? 'async'? 'move'?  ParamList RetType?
+  body:Expr
+
+IfExpr =
+  Attr* 'if' condition:Expr then_branch:BlockExpr
+  ('else' else_branch:(IfExpr | BlockExpr))?
+
+LoopExpr =
+  Attr* Label? 'loop'
+  loop_body:BlockExpr
+
+ForExpr =
+  Attr* Label? 'for' Pat 'in' iterable:Expr
+  loop_body:BlockExpr
+
+WhileExpr =
+  Attr* Label? 'while' condition:Expr
+  loop_body:BlockExpr
+
+Label =
+  Lifetime ':'
+
+BreakExpr =
+  Attr* 'break' Lifetime? Expr?
+
+ContinueExpr =
+  Attr* 'continue' Lifetime?
+
+RangeExpr =
+  Attr* start:Expr? op:('..' | '..=') end:Expr?
+
+MatchExpr =
+  Attr* 'match' Expr MatchArmList
+
+MatchArmList =
+  '{'
+    Attr*
+    arms:MatchArm*
+  '}'
+
+MatchArm =
+  Attr* Pat guard:MatchGuard? '=>' Expr ','?
+
+MatchGuard =
+  'if' condition:Expr
+
+ReturnExpr =
+  Attr* 'return' Expr?
+
+YieldExpr =
+  Attr* 'yield' Expr?
+
+LetExpr =
+  Attr* 'let' Pat '=' Expr
+
+UnderscoreExpr =
+  Attr* '_'
+
+AwaitExpr =
+  Attr* Expr '.' 'await'
+
+BoxExpr =
+  Attr* 'box' Expr
+
+//*************************//
+//          Types          //
+//*************************//
+
+Type =
+  ArrayType
+| DynTraitType
+| FnPtrType
+| ForType
+| ImplTraitType
+| InferType
+| MacroType
+| NeverType
+| ParenType
+| PathType
+| PtrType
+| RefType
+| SliceType
+| TupleType
+
+ParenType =
+  '(' Type ')'
+
+NeverType =
+  '!'
+
+MacroType =
+  MacroCall
+
+PathType =
+  Path
+
+TupleType =
+  '(' fields:(Type (',' Type)* ','?)? ')'
+
+PtrType =
+  '*' ('const' | 'mut') Type
+
+RefType =
+  '&' Lifetime? 'mut'? Type
+
+ArrayType =
+  '[' Type ';' Expr ']'
+
+SliceType =
+  '[' Type ']'
+
+InferType =
+  '_'
+
+FnPtrType =
+  'const'? 'async'? 'unsafe'? Abi? 'fn' ParamList RetType?
+
+ForType =
+  'for' GenericParamList Type
+
+ImplTraitType =
+  'impl' TypeBoundList
+
+DynTraitType =
+  'dyn' TypeBoundList
+
+TypeBoundList =
+  bounds:(TypeBound ('+' TypeBound)* '+'?)
+
+TypeBound =
+  Lifetime
+| ('?' | '~' 'const')? Type
+
+//************************//
+//        Patterns        //
+//************************//
+
+Pat =
+  IdentPat
+| BoxPat
+| RestPat
+| LiteralPat
+| MacroPat
+| OrPat
+| ParenPat
+| PathPat
+| WildcardPat
+| RangePat
+| RecordPat
+| RefPat
+| SlicePat
+| TuplePat
+| TupleStructPat
+| ConstBlockPat
+
+LiteralPat =
+  Literal
+
+IdentPat =
+  Attr* 'ref'? 'mut'? Name ('@' Pat)?
+
+WildcardPat =
+  '_'
+
+RangePat =
+  // 1..
+  start:Pat op:('..' | '..=')
+  // 1..2
+  | start:Pat op:('..' | '..=') end:Pat
+  // ..2
+  | op:('..' | '..=') end:Pat
+
+RefPat =
+  '&' 'mut'? Pat
+
+RecordPat =
+  Path RecordPatFieldList
+
+RecordPatFieldList =
+  '{'
+    fields:(RecordPatField (',' RecordPatField)* ','?)?
+    RestPat?
+  '}'
+
+RecordPatField =
+  Attr* (NameRef ':')? Pat
+
+TupleStructPat =
+   Path '(' fields:(Pat (',' Pat)* ','?)? ')'
+
+TuplePat =
+   '(' fields:(Pat (',' Pat)* ','?)? ')'
+
+ParenPat =
+  '(' Pat ')'
+
+SlicePat =
+  '[' (Pat (',' Pat)* ','?)? ']'
+
+PathPat =
+  Path
+
+OrPat =
+  (Pat ('|' Pat)* '|'?)
+
+BoxPat =
+  'box' Pat
+
+RestPat =
+  Attr* '..'
+
+MacroPat =
+  MacroCall
+
+ConstBlockPat =
+  'const' BlockExpr


Test patch:
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html b/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html
index 36e9ec6333..d9126421cd 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html
@@ -110,11 +110,6 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
     <span class="comment documentation">///</span><span class="comment documentation"> </span><span class="keyword injected">let</span><span class="none injected"> </span><span class="variable declaration injected">foobar</span><span class="none injected"> </span><span class="operator injected">=</span><span class="none injected"> </span><span class="struct injected">Foo</span><span class="operator injected">::</span><span class="function injected">new</span><span class="parenthesis injected">(</span><span class="parenthesis injected">)</span><span class="operator injected">.</span><span class="function injected">bar</span><span class="parenthesis injected">(</span><span class="parenthesis injected">)</span><span class="semicolon injected">;</span>
     <span class="comment documentation">/// ```</span>
     <span class="comment documentation">///</span>
-    <span class="comment documentation">/// ~~~rust,no_run</span>
-    <span class="comment documentation">///</span><span class="comment documentation"> </span><span class="comment injected">// code block with tilde.</span>
-    <span class="comment documentation">///</span><span class="comment documentation"> </span><span class="keyword injected">let</span><span class="none injected"> </span><span class="variable declaration injected">foobar</span><span class="none injected"> </span><span class="operator injected">=</span><span class="none injected"> </span><span class="struct injected">Foo</span><span class="operator injected">::</span><span class="function injected">new</span><span class="parenthesis injected">(</span><span class="parenthesis injected">)</span><span class="operator injected">.</span><span class="function injected">bar</span><span class="parenthesis injected">(</span><span class="parenthesis injected">)</span><span class="semicolon injected">;</span>
-    <span class="comment documentation">/// ~~~</span>
-    <span class="comment documentation">///</span>
     <span class="comment documentation">/// ```</span>
     <span class="comment documentation">///</span><span class="comment documentation"> </span><span class="comment injected">// functions</span>
     <span class="comment documentation">///</span><span class="comment documentation"> </span><span class="keyword injected">fn</span><span class="none injected"> </span><span class="function declaration injected">foo</span><span class="angle injected">&lt;</span><span class="type_param declaration injected">T</span><span class="comma injected">,</span><span class="none injected"> </span><span class="keyword injected">const</span><span class="none injected"> </span><span class="const_param declaration injected">X</span><span class="colon injected">:</span><span class="none injected"> </span><span class="builtin_type injected">usize</span><span class="angle injected">&gt;</span><span class="parenthesis injected">(</span><span class="value_param declaration injected">arg</span><span class="colon injected">:</span><span class="none injected"> </span><span class="builtin_type injected">i32</span><span class="parenthesis injected">)</span><span class="none injected"> </span><span class="brace injected">{</span>
diff --git a/crates/ide/src/syntax_highlighting/tests.rs b/crates/ide/src/syntax_highlighting/tests.rs
index fdfe347a32..2cd4fa809a 100644
--- a/crates/ide/src/syntax_highlighting/tests.rs
+++ b/crates/ide/src/syntax_highlighting/tests.rs
@@ -644,11 +644,6 @@ impl Foo {
     /// let foobar = Foo::new().bar();
     /// ```
     ///
-    /// ~~~rust,no_run
-    /// // code block with tilde.
-    /// let foobar = Foo::new().bar();
-    /// ~~~
-    ///
     /// ```
     /// // functions
     /// fn foo<T, const X: usize>(arg: i32) {
diff --git a/crates/syntax/src/tests/sourcegen_ast.rs b/crates/syntax/src/tests/sourcegen_ast.rs
index cb38abfe89..c2ed3eab0a 100644
--- a/crates/syntax/src/tests/sourcegen_ast.rs
+++ b/crates/syntax/src/tests/sourcegen_ast.rs
@@ -11,7 +11,7 @@ use std::{
 use itertools::Itertools;
 use proc_macro2::{Punct, Spacing};
 use quote::{format_ident, quote};
-use ungrammar::{rust_grammar, Grammar, Rule};
+use ungrammar::{Grammar, Rule};
 
 use crate::tests::ast_src::{
     AstEnumSrc, AstNodeSrc, AstSrc, Cardinality, Field, KindsSrc, KINDS_SRC,
@@ -24,7 +24,8 @@ fn sourcegen_ast() {
         sourcegen::project_root().join("crates/parser/src/syntax_kind/generated.rs");
     sourcegen::ensure_file_contents(syntax_kinds_file.as_path(), &syntax_kinds);
 
-    let grammar = rust_grammar();
+    let grammar =
+        include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/rust.ungram")).parse().unwrap();
     let ast = lower(&grammar);
 
     let ast_tokens = generate_tokens(&ast);