Repository: rust-lang/rust-analyzer
Pull request #12324 (2022-05-20 12:44:36)

feat: Revert the "Add attribute" assist
Reverts https://github.com/rust-lang/rust-analyzer/pull/12296, as the added indirection and "assist noise" (the assist has to trigger inside the body of an item to match what the "Add `#[derive]`" does) makes this not really pull its weight over just using attribute completions.

Keeps the changes to "Add getter". `#[must_use]` can be applied using the attribute completions.


Patch:
diff --git a/crates/ide-assists/src/handlers/add_attribute.rs b/crates/ide-assists/src/handlers/add_attribute.rs
deleted file mode 100644
index dcb52b151d..0000000000
--- a/crates/ide-assists/src/handlers/add_attribute.rs
+++ /dev/null
@@ -1,196 +0,0 @@
-use ide_db::assists::{AssistId, AssistKind, GroupLabel};
-use syntax::{
-    ast::{self, HasAttrs},
-    match_ast, AstNode, SyntaxKind, TextSize,
-};
-
-use crate::assist_context::{AssistContext, Assists};
-
-// Assist: add_attribute
-//
-// Adds commonly used attributes to items.
-//
-// ```
-// struct Point {
-//     x: u32,
-//     y: u32,$0
-// }
-// ```
-// ->add_derive
-// ```
-// #[derive($0)]
-// struct Point {
-//     x: u32,
-//     y: u32,
-// }
-// ```
-pub(crate) fn add_attribute(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
-    let cap = ctx.config.snippet_cap?;
-
-    let (attr_owner, attrs) = ctx
-        .find_node_at_offset::<ast::AnyHasAttrs>()?
-        .syntax()
-        .ancestors()
-        .filter_map(ast::AnyHasAttrs::cast)
-        .find_map(|attr_owner| {
-            let node = attr_owner.syntax();
-            match_ast! {
-                match node {
-                    ast::Adt(_) => Some((attr_owner, ADT_ATTRS)),
-                    ast::Fn(_) => Some((attr_owner, FN_ATTRS)),
-                    _ => None,
-                }
-            }
-        })?;
-
-    let offset = attr_insertion_offset(&attr_owner)?;
-
-    for tpl in attrs {
-        let existing_offset = attr_owner.attrs().find_map(|attr| {
-            if attr.simple_name()? == tpl.name {
-                match attr.token_tree() {
-                    Some(tt) => {
-                        // Attribute like `#[derive(...)]`, position cursor right before the `)`
-                        return Some(tt.syntax().text_range().end() - TextSize::of(')'));
-                    }
-                    None => {
-                        // `#[key = value]`
-                        let tok = attr.syntax().last_token()?;
-                        if tok.kind() == SyntaxKind::R_BRACK {
-                            return Some(tok.text_range().end() - TextSize::of(']'));
-                        }
-                    }
-                }
-            }
-            None
-        });
-        acc.add_group(
-            &GroupLabel("Add attribute".into()),
-            AssistId(tpl.id, AssistKind::Generate),
-            format!("Add `#[{}]`", tpl.name),
-            attr_owner.syntax().text_range(),
-            |b| match existing_offset {
-                Some(offset) => {
-                    b.insert_snippet(cap, offset, "$0");
-                }
-                None => {
-                    b.insert_snippet(cap, offset, format!("#[{}]\n", tpl.snippet));
-                }
-            },
-        );
-    }
-
-    Some(())
-}
-
-fn attr_insertion_offset(nominal: &ast::AnyHasAttrs) -> Option<TextSize> {
-    let non_ws_child = nominal
-        .syntax()
-        .children_with_tokens()
-        .find(|it| it.kind() != SyntaxKind::COMMENT && it.kind() != SyntaxKind::WHITESPACE)?;
-    Some(non_ws_child.text_range().start())
-}
-
-static ADT_ATTRS: &[AttrTemplate] = &[
-    AttrTemplate { id: "add_derive", name: "derive", snippet: "derive($0)" },
-    AttrTemplate { id: "add_must_use", name: "must_use", snippet: "must_use$0" },
-];
-
-static FN_ATTRS: &[AttrTemplate] = &[
-    AttrTemplate { id: "add_inline", name: "inline", snippet: "inline$0" },
-    AttrTemplate { id: "add_must_use", name: "must_use", snippet: "must_use$0" },
-];
-
-struct AttrTemplate {
-    /// Assist ID.
-    id: &'static str,
-    /// User-facing attribute name.
-    name: &'static str,
-    /// Snippet to insert.
-    snippet: &'static str,
-}
-
-#[cfg(test)]
-mod tests {
-    use crate::tests::{check_assist_by_label, check_assist_target};
-
-    use super::add_attribute;
-
-    fn check_derive(ra_fixture_before: &str, ra_fixture_after: &str) {
-        check_assist_by_label(
-            add_attribute,
-            ra_fixture_before,
-            ra_fixture_after,
-            "Add `#[derive]`",
-        );
-    }
-
-    fn check_must_use(ra_fixture_before: &str, ra_fixture_after: &str) {
-        check_assist_by_label(
-            add_attribute,
-            ra_fixture_before,
-            ra_fixture_after,
-            "Add `#[must_use]`",
-        );
-    }
-
-    #[test]
-    fn add_derive_new() {
-        check_derive("struct Foo { a: i32, $0}", "#[derive($0)]\nstruct Foo { a: i32, }");
-        check_derive("struct Foo { $0 a: i32, }", "#[derive($0)]\nstruct Foo {  a: i32, }");
-    }
-
-    #[test]
-    fn add_derive_existing() {
-        check_derive(
-            "#[derive(Clone)]\nstruct Foo { a: i32$0, }",
-            "#[derive(Clone$0)]\nstruct Foo { a: i32, }",
-        );
-    }
-
-    #[test]
-    fn add_derive_new_with_doc_comment() {
-        check_derive(
-            "
-/// `Foo` is a pretty important struct.
-/// It does stuff.
-struct Foo { a: i32$0, }
-            ",
-            "
-/// `Foo` is a pretty important struct.
-/// It does stuff.
-#[derive($0)]
-struct Foo { a: i32, }
-            ",
-        );
-    }
-
-    #[test]
-    fn add_derive_target() {
-        check_assist_target(
-            add_attribute,
-            r#"
-struct SomeThingIrrelevant;
-/// `Foo` is a pretty important struct.
-/// It does stuff.
-struct Foo { a: i32$0, }
-struct EvenMoreIrrelevant;
-            "#,
-            "/// `Foo` is a pretty important struct.
-/// It does stuff.
-struct Foo { a: i32, }",
-        );
-    }
-
-    #[test]
-    fn insert_must_use() {
-        check_must_use("struct S$0;", "#[must_use$0]\nstruct S;");
-        check_must_use("$0fn f() {}", "#[must_use$0]\nfn f() {}");
-
-        check_must_use(r#"#[must_use = "bla"] struct S$0;"#, r#"#[must_use = "bla"$0] struct S;"#);
-        check_must_use(r#"#[must_use = ] struct S$0;"#, r#"#[must_use = $0] struct S;"#);
-
-        check_must_use(r#"#[must_use = "bla"] $0fn f() {}"#, r#"#[must_use = "bla"$0] fn f() {}"#);
-        check_must_use(r#"#[must_use = ] $0fn f() {}"#, r#"#[must_use = $0] fn f() {}"#);
-    }
-}
diff --git a/crates/ide-assists/src/handlers/generate_derive.rs b/crates/ide-assists/src/handlers/generate_derive.rs
new file mode 100644
index 0000000000..28483f795e
--- /dev/null
+++ b/crates/ide-assists/src/handlers/generate_derive.rs
@@ -0,0 +1,132 @@
+use syntax::{
+    ast::{self, AstNode, HasAttrs},
+    SyntaxKind::{COMMENT, WHITESPACE},
+    TextSize,
+};
+
+use crate::{AssistContext, AssistId, AssistKind, Assists};
+
+// Assist: generate_derive
+//
+// Adds a new `#[derive()]` clause to a struct or enum.
+//
+// ```
+// struct Point {
+//     x: u32,
+//     y: u32,$0
+// }
+// ```
+// ->
+// ```
+// #[derive($0)]
+// struct Point {
+//     x: u32,
+//     y: u32,
+// }
+// ```
+pub(crate) fn generate_derive(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
+    let cap = ctx.config.snippet_cap?;
+    let nominal = ctx.find_node_at_offset::<ast::Adt>()?;
+    let node_start = derive_insertion_offset(&nominal)?;
+    let target = nominal.syntax().text_range();
+    acc.add(
+        AssistId("generate_derive", AssistKind::Generate),
+        "Add `#[derive]`",
+        target,
+        |builder| {
+            let derive_attr = nominal
+                .attrs()
+                .filter_map(|x| x.as_simple_call())
+                .filter(|(name, _arg)| name == "derive")
+                .map(|(_name, arg)| arg)
+                .next();
+            match derive_attr {
+                None => {
+                    builder.insert_snippet(cap, node_start, "#[derive($0)]\n");
+                }
+                Some(tt) => {
+                    // Just move the cursor.
+                    builder.insert_snippet(
+                        cap,
+                        tt.syntax().text_range().end() - TextSize::of(')'),
+                        "$0",
+                    )
+                }
+            };
+        },
+    )
+}
+
+// Insert `derive` after doc comments.
+fn derive_insertion_offset(nominal: &ast::Adt) -> Option<TextSize> {
+    let non_ws_child = nominal
+        .syntax()
+        .children_with_tokens()
+        .find(|it| it.kind() != COMMENT && it.kind() != WHITESPACE)?;
+    Some(non_ws_child.text_range().start())
+}
+
+#[cfg(test)]
+mod tests {
+    use crate::tests::{check_assist, check_assist_target};
+
+    use super::*;
+
+    #[test]
+    fn add_derive_new() {
+        check_assist(
+            generate_derive,
+            "struct Foo { a: i32, $0}",
+            "#[derive($0)]\nstruct Foo { a: i32, }",
+        );
+        check_assist(
+            generate_derive,
+            "struct Foo { $0 a: i32, }",
+            "#[derive($0)]\nstruct Foo {  a: i32, }",
+        );
+    }
+
+    #[test]
+    fn add_derive_existing() {
+        check_assist(
+            generate_derive,
+            "#[derive(Clone)]\nstruct Foo { a: i32$0, }",
+            "#[derive(Clone$0)]\nstruct Foo { a: i32, }",
+        );
+    }
+
+    #[test]
+    fn add_derive_new_with_doc_comment() {
+        check_assist(
+            generate_derive,
+            "
+/// `Foo` is a pretty important struct.
+/// It does stuff.
+struct Foo { a: i32$0, }
+            ",
+            "
+/// `Foo` is a pretty important struct.
+/// It does stuff.
+#[derive($0)]
+struct Foo { a: i32, }
+            ",
+        );
+    }
+
+    #[test]
+    fn add_derive_target() {
+        check_assist_target(
+            generate_derive,
+            "
+struct SomeThingIrrelevant;
+/// `Foo` is a pretty important struct.
+/// It does stuff.
+struct Foo { a: i32$0, }
+struct EvenMoreIrrelevant;
+            ",
+            "/// `Foo` is a pretty important struct.
+/// It does stuff.
+struct Foo { a: i32, }",
+        );
+    }
+}
diff --git a/crates/ide-assists/src/lib.rs b/crates/ide-assists/src/lib.rs
index f78dbf2ab8..b8607579a3 100644
--- a/crates/ide-assists/src/lib.rs
+++ b/crates/ide-assists/src/lib.rs
@@ -106,8 +106,6 @@ mod handlers {
     mod add_explicit_type;
     mod add_lifetime_to_type;
     mod add_missing_impl_members;
-    mod add_missing_match_arms;
-    mod add_attribute;
     mod add_turbo_fish;
     mod apply_demorgan;
     mod auto_import;
@@ -128,6 +126,7 @@ mod handlers {
     mod extract_struct_from_enum_variant;
     mod extract_type_alias;
     mod extract_variable;
+    mod add_missing_match_arms;
     mod fix_visibility;
     mod flip_binexpr;
     mod flip_comma;
@@ -136,6 +135,7 @@ mod handlers {
     mod generate_default_from_enum_variant;
     mod generate_default_from_new;
     mod generate_deref;
+    mod generate_derive;
     mod generate_documentation_template;
     mod generate_enum_is_method;
     mod generate_enum_projection_method;
@@ -191,7 +191,6 @@ mod handlers {
     pub(crate) fn all() -> &'static [Handler] {
         &[
             // These are alphabetic for the foolish consistency
-            add_attribute::add_attribute,
             add_explicit_type::add_explicit_type,
             add_missing_match_arms::add_missing_match_arms,
             add_lifetime_to_type::add_lifetime_to_type,
@@ -222,6 +221,7 @@ mod handlers {
             generate_constant::generate_constant,
             generate_default_from_enum_variant::generate_default_from_enum_variant,
             generate_default_from_new::generate_default_from_new,
+            generate_derive::generate_derive,
             generate_documentation_template::generate_documentation_template,
             generate_documentation_template::generate_doc_example,
             generate_enum_is_method::generate_enum_is_method,
diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs
index 3689bd5a42..5eb63a42ad 100644
--- a/crates/ide/src/inlay_hints.rs
+++ b/crates/ide/src/inlay_hints.rs
@@ -26,7 +26,6 @@ pub struct InlayHintsConfig {
     pub lifetime_elision_hints: LifetimeElisionHints,
     pub param_names_for_lifetime_elision_hints: bool,
     pub hide_named_constructor_hints: bool,
-    pub hide_closure_initialization_hints: bool,
     pub max_length: Option<usize>,
     pub closing_brace_hints_min_lines: Option<usize>,
 }
@@ -468,11 +467,10 @@ fn closure_ret_hints(
         return None;
     }
 
-    if !closure_has_block_body(&closure) {
-        return None;
-    }
-
-    let param_list = closure.param_list()?;
+    let param_list = match closure.body() {
+        Some(ast::Expr::BlockExpr(_)) => closure.param_list()?,
+        _ => return None,
+    };
 
     let closure = sema.descend_node_into_attributes(closure.clone()).pop()?;
     let ty = sema.type_of_expr(&ast::Expr::ClosureExpr(closure))?.adjusted();
@@ -695,7 +693,7 @@ fn bind_pat_hints(
     let desc_pat = descended.as_ref().unwrap_or(pat);
     let ty = sema.type_of_pat(&desc_pat.clone().into())?.original;
 
-    if should_not_display_type_hint(sema, config, pat, &ty) {
+    if should_not_display_type_hint(sema, pat, &ty) {
         return None;
     }
 
@@ -850,7 +848,6 @@ fn pat_is_enum_variant(db: &RootDatabase, bind_pat: &ast::IdentPat, pat_ty: &hir
 
 fn should_not_display_type_hint(
     sema: &Semantics<RootDatabase>,
-    config: &InlayHintsConfig,
     bind_pat: &ast::IdentPat,
     pat_ty: &hir::Type,
 ) -> bool {
@@ -866,18 +863,6 @@ fn should_not_display_type_hint(
         }
     }
 
-    if config.hide_closure_initialization_hints {
-        if let Some(parent) = bind_pat.syntax().parent() {
-            if let Some(it) = ast::LetStmt::cast(parent.clone()) {
-                if let Some(ast::Expr::ClosureExpr(closure)) = it.initializer() {
-                    if closure_has_block_body(&closure) {
-                        return true;
-                    }
-                }
-            }
-        }
-    }
-
     for node in bind_pat.syntax().ancestors() {
         match_ast! {
             match node {
@@ -904,10 +889,6 @@ fn should_not_display_type_hint(
     false
 }
 
-fn closure_has_block_body(closure: &ast::ClosureExpr) -> bool {
-    matches!(closure.body(), Some(ast::Expr::BlockExpr(_)))
-}
-
 fn should_hide_param_name_hint(
     sema: &Semantics<RootDatabase>,
     callable: &hir::Callable,
@@ -1102,7 +1083,6 @@ mod tests {
         reborrow_hints: ReborrowHints::Always,
         binding_mode_hints: false,
         hide_named_constructor_hints: false,
-        hide_closure_initialization_hints: false,
         param_names_for_lifetime_elision_hints: false,
         max_length: None,
         closing_brace_hints_min_lines: None,
@@ -2054,53 +2034,6 @@ fn main() {
         );
     }
 
-    #[test]
-    fn skip_closure_type_hints() {
-        check_with_config(
-            InlayHintsConfig {
-                type_hints: true,
-                hide_closure_initialization_hints: true,
-                ..DISABLED_CONFIG
-            },
-            r#"
-//- minicore: fn
-fn main() {
-    let multiple_2 = |x: i32| { x * 2 };
-
-    let multiple_2 = |x: i32| x * 2;
-    //  ^^^^^^^^^^ |i32| -> i32
-
-    let (not) = (|x: bool| { !x });
-    //   ^^^ |bool| -> bool
-
-    let (is_zero, _b) = (|x: usize| { x == 0 }, false);
-    //   ^^^^^^^ |usize| -> bool
-    //            ^^ bool
-
-    let plus_one = |x| { x + 1 };
-    //              ^ u8
-    foo(plus_one);
-
-    let add_mul = bar(|x: u8| { x + 1 });
-    //  ^^^^^^^ impl FnOnce(u8) -> u8 + ?Sized
-
-    let closure = if let Some(6) = add_mul(2).checked_sub(1) {
-    //  ^^^^^^^ fn(i32) -> i32
-        |x: i32| { x * 2 }
-    } else {
-        |x: i32| { x * 3 }
-    };
-}
-
-fn foo(f: impl FnOnce(u8) -> u8) {}
-
-fn bar(f: impl FnOnce(u8) -> u8) -> impl FnOnce(u8) -> u8 {
-    move |x: u8| f(x) * 2
-}
-"#,
-        );
-    }
-
     #[test]
     fn hint_truncation() {
         check_with_config(
diff --git a/crates/ide/src/static_index.rs b/crates/ide/src/static_index.rs
index 006b18b7fd..01d7213630 100644
--- a/crates/ide/src/static_index.rs
+++ b/crates/ide/src/static_index.rs
@@ -113,7 +113,6 @@ impl StaticIndex<'_> {
                     lifetime_elision_hints: crate::LifetimeElisionHints::Never,
                     reborrow_hints: crate::ReborrowHints::Never,
                     hide_named_constructor_hints: false,
-                    hide_closure_initialization_hints: false,
                     param_names_for_lifetime_elision_hints: false,
                     binding_mode_hints: false,
                     max_length: Some(25),
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index d7ae4c72f5..afa83e6206 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/crates/rust-analyzer/src/config.rs
@@ -281,9 +281,6 @@ config_data! {
         inlayHints_renderColons: bool                              = "true",
         /// Whether to show inlay type hints for variables.
         inlayHints_typeHints_enable: bool                          = "true",
-        /// Whether to hide inlay type hints for `let` statements that initialize to a closure.
-        /// Only applies to closures with blocks, same as `#rust-analyzer.inlayHints.closureReturnTypeHints.enable#`.
-        inlayHints_typeHints_hideClosureInitialization: bool       = "false",
         /// Whether to hide inlay type hints for constructors.
         inlayHints_typeHints_hideNamedConstructor: bool            = "false",
 
@@ -1003,9 +1000,6 @@ impl Config {
                 LifetimeElisionDef::SkipTrivial => ide::LifetimeElisionHints::SkipTrivial,
             },
             hide_named_constructor_hints: self.data.inlayHints_typeHints_hideNamedConstructor,
-            hide_closure_initialization_hints: self
-                .data
-                .inlayHints_typeHints_hideClosureInitialization,
             reborrow_hints: match self.data.inlayHints_reborrowHints_enable {
                 ReborrowHintsDef::Always => ide::ReborrowHints::Always,
                 ReborrowHintsDef::Never => ide::ReborrowHints::Never,
diff --git a/docs/user/generated_config.adoc b/docs/user/generated_config.adoc
index 955f085d3f..30722af08c 100644
--- a/docs/user/generated_config.adoc
+++ b/docs/user/generated_config.adoc
@@ -407,12 +407,6 @@ Whether to render leading colons for type hints, and trailing colons for paramet
 --
 Whether to show inlay type hints for variables.
 --
-[[rust-analyzer.inlayHints.typeHints.hideClosureInitialization]]rust-analyzer.inlayHints.typeHints.hideClosureInitialization (default: `false`)::
-+
---
-Whether to hide inlay type hints for `let` statements that initialize to a closure.
-Only applies to closures with blocks, same as `#rust-analyzer.inlayHints.closureReturnTypeHints.enable#`.
---
 [[rust-analyzer.inlayHints.typeHints.hideNamedConstructor]]rust-analyzer.inlayHints.typeHints.hideNamedConstructor (default: `false`)::
 +
 --
diff --git a/editors/code/package.json b/editors/code/package.json
index f46c7ea92d..e81dfff278 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -868,11 +868,6 @@
                     "default": true,
                     "type": "boolean"
                 },
-                "rust-analyzer.inlayHints.typeHints.hideClosureInitialization": {
-                    "markdownDescription": "Whether to hide inlay type hints for `let` statements that initialize to a closure.\nOnly applies to closures with blocks, same as `#rust-analyzer.inlayHints.closureReturnTypeHints.enable#`.",
-                    "default": false,
-                    "type": "boolean"
-                },
                 "rust-analyzer.inlayHints.typeHints.hideNamedConstructor": {
                     "markdownDescription": "Whether to hide inlay type hints for constructors.",
                     "default": false,


Test patch:
diff --git a/crates/ide-assists/src/tests.rs b/crates/ide-assists/src/tests.rs
index ad2066a2ac..a8d5f85ba6 100644
--- a/crates/ide-assists/src/tests.rs
+++ b/crates/ide-assists/src/tests.rs
@@ -251,7 +251,6 @@ pub fn test_some_range(a: int) -> bool {
         Extract into variable
         Extract into function
         Replace if let with match
-        Add attribute
     "#]]
     .assert_eq(&expected);
 }
diff --git a/crates/ide-assists/src/tests/generated.rs b/crates/ide-assists/src/tests/generated.rs
index 69d754d4f7..c9b0b1ce82 100644
--- a/crates/ide-assists/src/tests/generated.rs
+++ b/crates/ide-assists/src/tests/generated.rs
@@ -2,26 +2,6 @@
 
 use super::check_doc_test;
 
-#[test]
-fn doctest_add_attribute() {
-    check_doc_test(
-        "add_derive",
-        r#####"
-struct Point {
-    x: u32,
-    y: u32,$0
-}
-"#####,
-        r#####"
-#[derive($0)]
-struct Point {
-    x: u32,
-    y: u32,
-}
-"#####,
-    )
-}
-
 #[test]
 fn doctest_add_explicit_type() {
     check_doc_test(
@@ -862,6 +842,26 @@ impl core::ops::Deref for B {
     )
 }
 
+#[test]
+fn doctest_generate_derive() {
+    check_doc_test(
+        "generate_derive",
+        r#####"
+struct Point {
+    x: u32,
+    y: u32,$0
+}
+"#####,
+        r#####"
+#[derive($0)]
+struct Point {
+    x: u32,
+    y: u32,
+}
+"#####,
+    )
+}
+
 #[test]
 fn doctest_generate_doc_example() {
     check_doc_test(
diff --git a/crates/ide-assists/src/tests/sourcegen.rs b/crates/ide-assists/src/tests/sourcegen.rs
index 577bc0894e..d45e54186b 100644
--- a/crates/ide-assists/src/tests/sourcegen.rs
+++ b/crates/ide-assists/src/tests/sourcegen.rs
@@ -31,7 +31,7 @@ r#####"
 }}
 "######,
                     &test_id,
-                    &section.assist_id,
+                    &assist.id,
                     reveal_hash_comments(&section.before),
                     reveal_hash_comments(&section.after)
                 );
@@ -61,7 +61,6 @@ r#####"
 }
 #[derive(Debug)]
 struct Section {
-    assist_id: String,
     doc: String,
     before: String,
     after: String,
@@ -112,13 +111,11 @@ impl Assist {
 
                     let before = take_until(lines.by_ref(), "```");
 
-                    let arrow = lines.next().unwrap();
-                    assert!(arrow.starts_with("->"));
-                    let id = if arrow[2..].is_empty() { &assist.id } else { &arrow[2..] };
+                    assert_eq!(lines.next().unwrap().as_str(), "->");
                     assert_eq!(lines.next().unwrap().as_str(), "```");
                     let after = take_until(lines.by_ref(), "```");
 
-                    assist.sections.push(Section { assist_id: id.to_string(), doc, before, after });
+                    assist.sections.push(Section { doc, before, after });
                 }
 
                 acc.push(assist)