Repository: rust-analyzer/rust-analyzer
Pull request #5213 (2020-07-03 17:15:41)

Add AssistKind::Generate


bors r+
🤖

bors[bot]: Canceled.
matklad: bors r+
bors[bot]: Build failed:
  * [Rust (ubuntu-latest)](https://github.com/rust-analyzer/rust-analyzer/runs/835144740)
matklad: bors r+

Patch:
diff --git a/crates/ra_assists/src/handlers/add_derive.rs b/crates/ra_assists/src/handlers/generate_derive.rs
similarity index 66%
rename from crates/ra_assists/src/handlers/add_derive.rs
rename to crates/ra_assists/src/handlers/generate_derive.rs
index e2b94e7f89..6ccf39900b 100644
--- a/crates/ra_assists/src/handlers/add_derive.rs
+++ b/crates/ra_assists/src/handlers/generate_derive.rs
@@ -6,7 +6,7 @@ use ra_syntax::{
 
 use crate::{AssistContext, AssistId, AssistKind, Assists};
 
-// Assist: add_derive
+// Assist: generate_derive
 //
 // Adds a new `#[derive()]` clause to a struct or enum.
 //
@@ -24,32 +24,37 @@ use crate::{AssistContext, AssistId, AssistKind, Assists};
 //     y: u32,
 // }
 // ```
-pub(crate) fn add_derive(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
+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::NominalDef>()?;
     let node_start = derive_insertion_offset(&nominal)?;
     let target = nominal.syntax().text_range();
-    acc.add(AssistId("add_derive", AssistKind::None), "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",
-                )
-            }
-        };
-    })
+    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.
@@ -70,12 +75,12 @@ mod tests {
     #[test]
     fn add_derive_new() {
         check_assist(
-            add_derive,
+            generate_derive,
             "struct Foo { a: i32, <|>}",
             "#[derive($0)]\nstruct Foo { a: i32, }",
         );
         check_assist(
-            add_derive,
+            generate_derive,
             "struct Foo { <|> a: i32, }",
             "#[derive($0)]\nstruct Foo {  a: i32, }",
         );
@@ -84,7 +89,7 @@ mod tests {
     #[test]
     fn add_derive_existing() {
         check_assist(
-            add_derive,
+            generate_derive,
             "#[derive(Clone)]\nstruct Foo { a: i32<|>, }",
             "#[derive(Clone$0)]\nstruct Foo { a: i32, }",
         );
@@ -93,7 +98,7 @@ mod tests {
     #[test]
     fn add_derive_new_with_doc_comment() {
         check_assist(
-            add_derive,
+            generate_derive,
             "
 /// `Foo` is a pretty important struct.
 /// It does stuff.
@@ -111,7 +116,7 @@ struct Foo { a: i32, }
     #[test]
     fn add_derive_target() {
         check_assist_target(
-            add_derive,
+            generate_derive,
             "
 struct SomeThingIrrelevant;
 /// `Foo` is a pretty important struct.
diff --git a/crates/ra_assists/src/handlers/add_from_impl_for_enum.rs b/crates/ra_assists/src/handlers/generate_from_impl_for_enum.rs
similarity index 88%
rename from crates/ra_assists/src/handlers/add_from_impl_for_enum.rs
rename to crates/ra_assists/src/handlers/generate_from_impl_for_enum.rs
index a324670ed1..a347e3c2ef 100644
--- a/crates/ra_assists/src/handlers/add_from_impl_for_enum.rs
+++ b/crates/ra_assists/src/handlers/generate_from_impl_for_enum.rs
@@ -4,7 +4,7 @@ use test_utils::mark;
 
 use crate::{utils::FamousDefs, AssistContext, AssistId, AssistKind, Assists};
 
-// Assist: add_from_impl_for_enum
+// Assist: generate_from_impl_for_enum
 //
 // Adds a From impl for an enum variant with one tuple field.
 //
@@ -21,7 +21,7 @@ use crate::{utils::FamousDefs, AssistContext, AssistId, AssistKind, Assists};
 //     }
 // }
 // ```
-pub(crate) fn add_from_impl_for_enum(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
+pub(crate) fn generate_from_impl_for_enum(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
     let variant = ctx.find_node_at_offset::<ast::EnumVariant>()?;
     let variant_name = variant.name()?;
     let enum_name = variant.parent_enum().name()?;
@@ -45,8 +45,8 @@ pub(crate) fn add_from_impl_for_enum(acc: &mut Assists, ctx: &AssistContext) ->
 
     let target = variant.syntax().text_range();
     acc.add(
-        AssistId("add_from_impl_for_enum", AssistKind::Refactor),
-        "Add From impl for this enum variant",
+        AssistId("generate_from_impl_for_enum", AssistKind::Generate),
+        "Generate `From` impl for this enum variant",
         target,
         |edit| {
             let start_offset = variant.parent_enum().syntax().text_range().end();
@@ -97,9 +97,9 @@ mod tests {
     use super::*;
 
     #[test]
-    fn test_add_from_impl_for_enum() {
+    fn test_generate_from_impl_for_enum() {
         check_assist(
-            add_from_impl_for_enum,
+            generate_from_impl_for_enum,
             "enum A { <|>One(u32) }",
             r#"enum A { One(u32) }
 
@@ -112,9 +112,9 @@ impl From<u32> for A {
     }
 
     #[test]
-    fn test_add_from_impl_for_enum_complicated_path() {
+    fn test_generate_from_impl_for_enum_complicated_path() {
         check_assist(
-            add_from_impl_for_enum,
+            generate_from_impl_for_enum,
             r#"enum A { <|>One(foo::bar::baz::Boo) }"#,
             r#"enum A { One(foo::bar::baz::Boo) }
 
@@ -129,7 +129,7 @@ impl From<foo::bar::baz::Boo> for A {
     fn check_not_applicable(ra_fixture: &str) {
         let fixture =
             format!("//- /main.rs crate:main deps:core\n{}\n{}", ra_fixture, FamousDefs::FIXTURE);
-        check_assist_not_applicable(add_from_impl_for_enum, &fixture)
+        check_assist_not_applicable(generate_from_impl_for_enum, &fixture)
     }
 
     #[test]
@@ -166,7 +166,7 @@ impl From<u32> for A {
     #[test]
     fn test_add_from_impl_different_variant_impl_exists() {
         check_assist(
-            add_from_impl_for_enum,
+            generate_from_impl_for_enum,
             r#"enum A { <|>One(u32), Two(String), }
 
 impl From<String> for A {
diff --git a/crates/ra_assists/src/handlers/add_function.rs b/crates/ra_assists/src/handlers/generate_function.rs
similarity index 92%
rename from crates/ra_assists/src/handlers/add_function.rs
rename to crates/ra_assists/src/handlers/generate_function.rs
index 7150eb53a5..b721b96bbb 100644
--- a/crates/ra_assists/src/handlers/add_function.rs
+++ b/crates/ra_assists/src/handlers/generate_function.rs
@@ -16,7 +16,7 @@ use crate::{
     AssistContext, AssistId, AssistKind, Assists,
 };
 
-// Assist: add_function
+// Assist: generate_function
 //
 // Adds a stub function with a signature matching the function under the cursor.
 //
@@ -41,7 +41,7 @@ use crate::{
 // }
 //
 // ```
-pub(crate) fn add_function(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
+pub(crate) fn generate_function(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
     let path_expr: ast::PathExpr = ctx.find_node_at_offset()?;
     let call = path_expr.syntax().parent().and_then(ast::CallExpr::cast)?;
     let path = path_expr.path()?;
@@ -62,15 +62,20 @@ pub(crate) fn add_function(acc: &mut Assists, ctx: &AssistContext) -> Option<()>
     let function_builder = FunctionBuilder::from_call(&ctx, &call, &path, target_module)?;
 
     let target = call.syntax().text_range();
-    acc.add(AssistId("add_function", AssistKind::None), "Add function", target, |builder| {
-        let function_template = function_builder.render();
-        builder.edit_file(function_template.file);
-        let new_fn = function_template.to_string(ctx.config.snippet_cap);
-        match ctx.config.snippet_cap {
-            Some(cap) => builder.insert_snippet(cap, function_template.insert_offset, new_fn),
-            None => builder.insert(function_template.insert_offset, new_fn),
-        }
-    })
+    acc.add(
+        AssistId("generate_function", AssistKind::Generate),
+        format!("Generate `{}` function", function_builder.fn_name),
+        target,
+        |builder| {
+            let function_template = function_builder.render();
+            builder.edit_file(function_template.file);
+            let new_fn = function_template.to_string(ctx.config.snippet_cap);
+            match ctx.config.snippet_cap {
+                Some(cap) => builder.insert_snippet(cap, function_template.insert_offset, new_fn),
+                None => builder.insert(function_template.insert_offset, new_fn),
+            }
+        },
+    )
 }
 
 struct FunctionTemplate {
@@ -333,7 +338,7 @@ mod tests {
     #[test]
     fn add_function_with_no_args() {
         check_assist(
-            add_function,
+            generate_function,
             r"
 fn foo() {
     bar<|>();
@@ -356,7 +361,7 @@ fn bar() {
         // This ensures that the function is correctly generated
         // in the next outer mod or file
         check_assist(
-            add_function,
+            generate_function,
             r"
 impl Foo {
     fn foo() {
@@ -382,7 +387,7 @@ fn bar() {
     fn add_function_directly_after_current_block() {
         // The new fn should not be created at the end of the file or module
         check_assist(
-            add_function,
+            generate_function,
             r"
 fn foo1() {
     bar<|>();
@@ -407,7 +412,7 @@ fn foo2() {}
     #[test]
     fn add_function_with_no_args_in_same_module() {
         check_assist(
-            add_function,
+            generate_function,
             r"
 mod baz {
     fn foo() {
@@ -432,7 +437,7 @@ mod baz {
     #[test]
     fn add_function_with_function_call_arg() {
         check_assist(
-            add_function,
+            generate_function,
             r"
 struct Baz;
 fn baz() -> Baz { todo!() }
@@ -457,7 +462,7 @@ fn bar(baz: Baz) {
     #[test]
     fn add_function_with_method_call_arg() {
         check_assist(
-            add_function,
+            generate_function,
             r"
 struct Baz;
 impl Baz {
@@ -490,7 +495,7 @@ fn bar(baz: Baz) {
     #[test]
     fn add_function_with_string_literal_arg() {
         check_assist(
-            add_function,
+            generate_function,
             r#"
 fn foo() {
     <|>bar("bar")
@@ -511,7 +516,7 @@ fn bar(arg: &str) {
     #[test]
     fn add_function_with_char_literal_arg() {
         check_assist(
-            add_function,
+            generate_function,
             r#"
 fn foo() {
     <|>bar('x')
@@ -532,7 +537,7 @@ fn bar(arg: char) {
     #[test]
     fn add_function_with_int_literal_arg() {
         check_assist(
-            add_function,
+            generate_function,
             r"
 fn foo() {
     <|>bar(42)
@@ -553,7 +558,7 @@ fn bar(arg: i32) {
     #[test]
     fn add_function_with_cast_int_literal_arg() {
         check_assist(
-            add_function,
+            generate_function,
             r"
 fn foo() {
     <|>bar(42 as u8)
@@ -576,7 +581,7 @@ fn bar(arg: u8) {
         // Ensures that the name of the cast type isn't used
         // in the generated function signature.
         check_assist(
-            add_function,
+            generate_function,
             r"
 fn foo() {
     let x = 42;
@@ -599,7 +604,7 @@ fn bar(x: u8) {
     #[test]
     fn add_function_with_variable_arg() {
         check_assist(
-            add_function,
+            generate_function,
             r"
 fn foo() {
     let worble = ();
@@ -622,7 +627,7 @@ fn bar(worble: ()) {
     #[test]
     fn add_function_with_impl_trait_arg() {
         check_assist(
-            add_function,
+            generate_function,
             r"
 trait Foo {}
 fn foo() -> impl Foo {
@@ -651,7 +656,7 @@ fn bar(foo: impl Foo) {
     #[test]
     fn borrowed_arg() {
         check_assist(
-            add_function,
+            generate_function,
             r"
 struct Baz;
 fn baz() -> Baz { todo!() }
@@ -678,7 +683,7 @@ fn bar(baz: &Baz) {
     #[test]
     fn add_function_with_qualified_path_arg() {
         check_assist(
-            add_function,
+            generate_function,
             r"
 mod Baz {
     pub struct Bof;
@@ -709,7 +714,7 @@ fn bar(baz: Baz::Bof) {
     // FIXME fix printing the generics of a `Ty` to make this test pass
     fn add_function_with_generic_arg() {
         check_assist(
-            add_function,
+            generate_function,
             r"
 fn foo<T>(t: T) {
     <|>bar(t)
@@ -732,7 +737,7 @@ fn bar<T>(t: T) {
     // FIXME Fix function type printing to make this test pass
     fn add_function_with_fn_arg() {
         check_assist(
-            add_function,
+            generate_function,
             r"
 struct Baz;
 impl Baz {
@@ -763,7 +768,7 @@ fn bar(arg: fn() -> Baz) {
     // FIXME Fix closure type printing to make this test pass
     fn add_function_with_closure_arg() {
         check_assist(
-            add_function,
+            generate_function,
             r"
 fn foo() {
     let closure = |x: i64| x - 1;
@@ -786,7 +791,7 @@ fn bar(closure: impl Fn(i64) -> i64) {
     #[test]
     fn unresolveable_types_default_to_unit() {
         check_assist(
-            add_function,
+            generate_function,
             r"
 fn foo() {
     <|>bar(baz)
@@ -807,7 +812,7 @@ fn bar(baz: ()) {
     #[test]
     fn arg_names_dont_overlap() {
         check_assist(
-            add_function,
+            generate_function,
             r"
 struct Baz;
 fn baz() -> Baz { Baz }
@@ -832,7 +837,7 @@ fn bar(baz_1: Baz, baz_2: Baz) {
     #[test]
     fn arg_name_counters_start_at_1_per_name() {
         check_assist(
-            add_function,
+            generate_function,
             r#"
 struct Baz;
 fn baz() -> Baz { Baz }
@@ -857,7 +862,7 @@ fn bar(baz_1: Baz, baz_2: Baz, arg_1: &str, arg_2: &str) {
     #[test]
     fn add_function_in_module() {
         check_assist(
-            add_function,
+            generate_function,
             r"
 mod bar {}
 
@@ -885,7 +890,7 @@ fn foo() {
     // See https://github.com/rust-analyzer/rust-analyzer/issues/1165
     fn qualified_path_uses_correct_scope() {
         check_assist(
-            add_function,
+            generate_function,
             "
 mod foo {
     pub struct Foo;
@@ -916,7 +921,7 @@ fn baz(foo: foo::Foo) {
     #[test]
     fn add_function_in_module_containing_other_items() {
         check_assist(
-            add_function,
+            generate_function,
             r"
 mod bar {
     fn something_else() {}
@@ -945,7 +950,7 @@ fn foo() {
     #[test]
     fn add_function_in_nested_module() {
         check_assist(
-            add_function,
+            generate_function,
             r"
 mod bar {
     mod baz {}
@@ -974,7 +979,7 @@ fn foo() {
     #[test]
     fn add_function_in_another_file() {
         check_assist(
-            add_function,
+            generate_function,
             r"
 //- /main.rs
 mod foo;
@@ -996,7 +1001,7 @@ pub(crate) fn bar() {
     #[test]
     fn add_function_not_applicable_if_function_already_exists() {
         check_assist_not_applicable(
-            add_function,
+            generate_function,
             r"
 fn foo() {
     bar<|>();
@@ -1013,7 +1018,7 @@ fn bar() {}
             // bar is resolved, but baz isn't.
             // The assist is only active if the cursor is on an unresolved path,
             // but the assist should only be offered if the path is a function call.
-            add_function,
+            generate_function,
             r"
 fn foo() {
     bar(b<|>az);
@@ -1028,7 +1033,7 @@ fn bar(baz: ()) {}
     #[ignore]
     fn create_method_with_no_args() {
         check_assist(
-            add_function,
+            generate_function,
             r"
 struct Foo;
 impl Foo {
diff --git a/crates/ra_assists/src/handlers/add_impl.rs b/crates/ra_assists/src/handlers/generate_impl.rs
similarity index 85%
rename from crates/ra_assists/src/handlers/add_impl.rs
rename to crates/ra_assists/src/handlers/generate_impl.rs
index 2f603ef9cf..cbbac1d7ff 100644
--- a/crates/ra_assists/src/handlers/add_impl.rs
+++ b/crates/ra_assists/src/handlers/generate_impl.rs
@@ -3,7 +3,7 @@ use stdx::{format_to, SepBy};
 
 use crate::{AssistContext, AssistId, AssistKind, Assists};
 
-// Assist: add_impl
+// Assist: generate_impl
 //
 // Adds a new inherent impl for a type.
 //
@@ -22,13 +22,13 @@ use crate::{AssistContext, AssistId, AssistKind, Assists};
 //     $0
 // }
 // ```
-pub(crate) fn add_impl(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
+pub(crate) fn generate_impl(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
     let nominal = ctx.find_node_at_offset::<ast::NominalDef>()?;
     let name = nominal.name()?;
     let target = nominal.syntax().text_range();
     acc.add(
-        AssistId("add_impl", AssistKind::Refactor),
-        format!("Implement {}", name.text().as_str()),
+        AssistId("generate_impl", AssistKind::Generate),
+        format!("Generate impl for `{}`", name),
         target,
         |edit| {
             let type_params = nominal.type_param_list();
@@ -75,14 +75,18 @@ mod tests {
 
     #[test]
     fn test_add_impl() {
-        check_assist(add_impl, "struct Foo {<|>}\n", "struct Foo {}\n\nimpl Foo {\n    $0\n}\n");
         check_assist(
-            add_impl,
+            generate_impl,
+            "struct Foo {<|>}\n",
+            "struct Foo {}\n\nimpl Foo {\n    $0\n}\n",
+        );
+        check_assist(
+            generate_impl,
             "struct Foo<T: Clone> {<|>}",
             "struct Foo<T: Clone> {}\n\nimpl<T: Clone> Foo<T> {\n    $0\n}",
         );
         check_assist(
-            add_impl,
+            generate_impl,
             "struct Foo<'a, T: Foo<'a>> {<|>}",
             "struct Foo<'a, T: Foo<'a>> {}\n\nimpl<'a, T: Foo<'a>> Foo<'a, T> {\n    $0\n}",
         );
@@ -91,7 +95,7 @@ mod tests {
     #[test]
     fn add_impl_target() {
         check_assist_target(
-            add_impl,
+            generate_impl,
             "
 struct SomeThingIrrelevant;
 /// Has a lifetime parameter
diff --git a/crates/ra_assists/src/handlers/add_new.rs b/crates/ra_assists/src/handlers/generate_new.rs
similarity index 92%
rename from crates/ra_assists/src/handlers/add_new.rs
rename to crates/ra_assists/src/handlers/generate_new.rs
index 0b3d29c7c5..e27def1d8a 100644
--- a/crates/ra_assists/src/handlers/add_new.rs
+++ b/crates/ra_assists/src/handlers/generate_new.rs
@@ -9,7 +9,7 @@ use stdx::{format_to, SepBy};
 
 use crate::{AssistContext, AssistId, AssistKind, Assists};
 
-// Assist: add_new
+// Assist: generate_new
 //
 // Adds a new inherent impl for a type.
 //
@@ -29,7 +29,7 @@ use crate::{AssistContext, AssistId, AssistKind, Assists};
 // }
 //
 // ```
-pub(crate) fn add_new(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
+pub(crate) fn generate_new(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
     let strukt = ctx.find_node_at_offset::<ast::StructDef>()?;
 
     // We want to only apply this to non-union structs with named fields
@@ -42,7 +42,7 @@ pub(crate) fn add_new(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
     let impl_def = find_struct_impl(&ctx, &strukt)?;
 
     let target = strukt.syntax().text_range();
-    acc.add(AssistId("add_new", AssistKind::None), "Add default constructor", target, |builder| {
+    acc.add(AssistId("generate_new", AssistKind::Generate), "Generate `new`", target, |builder| {
         let mut buf = String::with_capacity(512);
 
         if impl_def.is_some() {
@@ -181,10 +181,10 @@ mod tests {
 
     #[test]
     #[rustfmt::skip]
-    fn test_add_new() {
+    fn test_generate_new() {
         // Check output of generation
         check_assist(
-            add_new,
+            generate_new,
 "struct Foo {<|>}",
 "struct Foo {}
 
@@ -194,7 +194,7 @@ impl Foo {
 ",
         );
         check_assist(
-            add_new,
+            generate_new,
 "struct Foo<T: Clone> {<|>}",
 "struct Foo<T: Clone> {}
 
@@ -204,7 +204,7 @@ impl<T: Clone> Foo<T> {
 ",
         );
         check_assist(
-            add_new,
+            generate_new,
 "struct Foo<'a, T: Foo<'a>> {<|>}",
 "struct Foo<'a, T: Foo<'a>> {}
 
@@ -214,7 +214,7 @@ impl<'a, T: Foo<'a>> Foo<'a, T> {
 ",
         );
         check_assist(
-            add_new,
+            generate_new,
 "struct Foo { baz: String <|>}",
 "struct Foo { baz: String }
 
@@ -224,7 +224,7 @@ impl Foo {
 ",
         );
         check_assist(
-            add_new,
+            generate_new,
 "struct Foo { baz: String, qux: Vec<i32> <|>}",
 "struct Foo { baz: String, qux: Vec<i32> }
 
@@ -236,7 +236,7 @@ impl Foo {
 
         // Check that visibility modifiers don't get brought in for fields
         check_assist(
-            add_new,
+            generate_new,
 "struct Foo { pub baz: String, pub qux: Vec<i32> <|>}",
 "struct Foo { pub baz: String, pub qux: Vec<i32> }
 
@@ -248,7 +248,7 @@ impl Foo {
 
         // Check that it reuses existing impls
         check_assist(
-            add_new,
+            generate_new,
 "struct Foo {<|>}
 
 impl Foo {}
@@ -261,7 +261,7 @@ impl Foo {
 ",
         );
         check_assist(
-            add_new,
+            generate_new,
 "struct Foo {<|>}
 
 impl Foo {
@@ -279,7 +279,7 @@ impl Foo {
         );
 
         check_assist(
-            add_new,
+            generate_new,
 "struct Foo {<|>}
 
 impl Foo {
@@ -304,7 +304,7 @@ impl Foo {
 
         // Check visibility of new fn based on struct
         check_assist(
-            add_new,
+            generate_new,
 "pub struct Foo {<|>}",
 "pub struct Foo {}
 
@@ -314,7 +314,7 @@ impl Foo {
 ",
         );
         check_assist(
-            add_new,
+            generate_new,
 "pub(crate) struct Foo {<|>}",
 "pub(crate) struct Foo {}
 
@@ -326,9 +326,9 @@ impl Foo {
     }
 
     #[test]
-    fn add_new_not_applicable_if_fn_exists() {
+    fn generate_new_not_applicable_if_fn_exists() {
         check_assist_not_applicable(
-            add_new,
+            generate_new,
             "
 struct Foo {<|>}
 
@@ -340,7 +340,7 @@ impl Foo {
         );
 
         check_assist_not_applicable(
-            add_new,
+            generate_new,
             "
 struct Foo {<|>}
 
@@ -353,9 +353,9 @@ impl Foo {
     }
 
     #[test]
-    fn add_new_target() {
+    fn generate_new_target() {
         check_assist_target(
-            add_new,
+            generate_new,
             "
 struct SomeThingIrrelevant;
 /// Has a lifetime parameter
@@ -370,7 +370,7 @@ struct Foo<'a, T: Foo<'a>> {}",
     #[test]
     fn test_unrelated_new() {
         check_assist(
-            add_new,
+            generate_new,
             r##"
 pub struct AstId<N: AstNode> {
     file_id: HirFileId,
diff --git a/crates/ra_assists/src/lib.rs b/crates/ra_assists/src/lib.rs
index 65cda95ee2..3d61fbdedf 100644
--- a/crates/ra_assists/src/lib.rs
+++ b/crates/ra_assists/src/lib.rs
@@ -30,6 +30,7 @@ pub use assist_config::AssistConfig;
 pub enum AssistKind {
     None,
     QuickFix,
+    Generate,
     Refactor,
     RefactorExtract,
     RefactorInline,
@@ -112,13 +113,8 @@ mod handlers {
     pub(crate) type Handler = fn(&mut Assists, &AssistContext) -> Option<()>;
 
     mod add_custom_impl;
-    mod add_derive;
     mod add_explicit_type;
-    mod add_from_impl_for_enum;
-    mod add_function;
-    mod add_impl;
     mod add_missing_impl_members;
-    mod add_new;
     mod add_turbo_fish;
     mod apply_demorgan;
     mod auto_import;
@@ -132,6 +128,11 @@ mod handlers {
     mod flip_binexpr;
     mod flip_comma;
     mod flip_trait_bound;
+    mod generate_derive;
+    mod generate_from_impl_for_enum;
+    mod generate_function;
+    mod generate_impl;
+    mod generate_new;
     mod inline_local_variable;
     mod introduce_named_lifetime;
     mod invert_if;
@@ -154,12 +155,7 @@ mod handlers {
         &[
             // These are alphabetic for the foolish consistency
             add_custom_impl::add_custom_impl,
-            add_derive::add_derive,
             add_explicit_type::add_explicit_type,
-            add_from_impl_for_enum::add_from_impl_for_enum,
-            add_function::add_function,
-            add_impl::add_impl,
-            add_new::add_new,
             add_turbo_fish::add_turbo_fish,
             apply_demorgan::apply_demorgan,
             auto_import::auto_import,
@@ -173,6 +169,11 @@ mod handlers {
             flip_binexpr::flip_binexpr,
             flip_comma::flip_comma,
             flip_trait_bound::flip_trait_bound,
+            generate_derive::generate_derive,
+            generate_from_impl_for_enum::generate_from_impl_for_enum,
+            generate_function::generate_function,
+            generate_impl::generate_impl,
+            generate_new::generate_new,
             inline_local_variable::inline_local_variable,
             introduce_named_lifetime::introduce_named_lifetime,
             invert_if::invert_if,
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs
index 2312a6e4d5..83c9ac35c8 100644
--- a/crates/rust-analyzer/src/to_proto.rs
+++ b/crates/rust-analyzer/src/to_proto.rs
@@ -629,7 +629,7 @@ pub(crate) fn call_hierarchy_item(
 
 pub(crate) fn code_action_kind(kind: AssistKind) -> String {
     match kind {
-        AssistKind::None => lsp_types::code_action_kind::EMPTY,
+        AssistKind::None | AssistKind::Generate => lsp_types::code_action_kind::EMPTY,
         AssistKind::QuickFix => lsp_types::code_action_kind::QUICKFIX,
         AssistKind::Refactor => lsp_types::code_action_kind::REFACTOR,
         AssistKind::RefactorExtract => lsp_types::code_action_kind::REFACTOR_EXTRACT,


Test patch:
diff --git a/crates/ra_assists/src/tests/generated.rs b/crates/ra_assists/src/tests/generated.rs
index 31ea888c5d..eff7feded6 100644
--- a/crates/ra_assists/src/tests/generated.rs
+++ b/crates/ra_assists/src/tests/generated.rs
@@ -21,26 +21,6 @@ impl Debug for S {
     )
 }
 
-#[test]
-fn doctest_add_derive() {
-    check_doc_test(
-        "add_derive",
-        r#####"
-struct Point {
-    x: u32,
-    y: u32,<|>
-}
-"#####,
-        r#####"
-#[derive($0)]
-struct Point {
-    x: u32,
-    y: u32,
-}
-"#####,
-    )
-}
-
 #[test]
 fn doctest_add_explicit_type() {
     check_doc_test(
@@ -58,52 +38,6 @@ fn main() {
     )
 }
 
-#[test]
-fn doctest_add_from_impl_for_enum() {
-    check_doc_test(
-        "add_from_impl_for_enum",
-        r#####"
-enum A { <|>One(u32) }
-"#####,
-        r#####"
-enum A { One(u32) }
-
-impl From<u32> for A {
-    fn from(v: u32) -> Self {
-        A::One(v)
-    }
-}
-"#####,
-    )
-}
-
-#[test]
-fn doctest_add_function() {
-    check_doc_test(
-        "add_function",
-        r#####"
-struct Baz;
-fn baz() -> Baz { Baz }
-fn foo() {
-    bar<|>("", baz());
-}
-
-"#####,
-        r#####"
-struct Baz;
-fn baz() -> Baz { Baz }
-fn foo() {
-    bar("", baz());
-}
-
-fn bar(arg: &str, baz: Baz) {
-    ${0:todo!()}
-}
-
-"#####,
-    )
-}
-
 #[test]
 fn doctest_add_hash() {
     check_doc_test(
@@ -121,27 +55,6 @@ fn main() {
     )
 }
 
-#[test]
-fn doctest_add_impl() {
-    check_doc_test(
-        "add_impl",
-        r#####"
-struct Ctx<T: Clone> {
-    data: T,<|>
-}
-"#####,
-        r#####"
-struct Ctx<T: Clone> {
-    data: T,
-}
-
-impl<T: Clone> Ctx<T> {
-    $0
-}
-"#####,
-    )
-}
-
 #[test]
 fn doctest_add_impl_default_members() {
     check_doc_test(
@@ -208,28 +121,6 @@ impl Trait<u32> for () {
     )
 }
 
-#[test]
-fn doctest_add_new() {
-    check_doc_test(
-        "add_new",
-        r#####"
-struct Ctx<T: Clone> {
-     data: T,<|>
-}
-"#####,
-        r#####"
-struct Ctx<T: Clone> {
-     data: T,
-}
-
-impl<T: Clone> Ctx<T> {
-    fn $0new(data: T) -> Self { Self { data } }
-}
-
-"#####,
-    )
-}
-
 #[test]
 fn doctest_add_turbo_fish() {
     check_doc_test(
@@ -466,6 +357,115 @@ fn foo<T: Copy + Clone>() { }
     )
 }
 
+#[test]
+fn doctest_generate_derive() {
+    check_doc_test(
+        "generate_derive",
+        r#####"
+struct Point {
+    x: u32,
+    y: u32,<|>
+}
+"#####,
+        r#####"
+#[derive($0)]
+struct Point {
+    x: u32,
+    y: u32,
+}
+"#####,
+    )
+}
+
+#[test]
+fn doctest_generate_from_impl_for_enum() {
+    check_doc_test(
+        "generate_from_impl_for_enum",
+        r#####"
+enum A { <|>One(u32) }
+"#####,
+        r#####"
+enum A { One(u32) }
+
+impl From<u32> for A {
+    fn from(v: u32) -> Self {
+        A::One(v)
+    }
+}
+"#####,
+    )
+}
+
+#[test]
+fn doctest_generate_function() {
+    check_doc_test(
+        "generate_function",
+        r#####"
+struct Baz;
+fn baz() -> Baz { Baz }
+fn foo() {
+    bar<|>("", baz());
+}
+
+"#####,
+        r#####"
+struct Baz;
+fn baz() -> Baz { Baz }
+fn foo() {
+    bar("", baz());
+}
+
+fn bar(arg: &str, baz: Baz) {
+    ${0:todo!()}
+}
+
+"#####,
+    )
+}
+
+#[test]
+fn doctest_generate_impl() {
+    check_doc_test(
+        "generate_impl",
+        r#####"
+struct Ctx<T: Clone> {
+    data: T,<|>
+}
+"#####,
+        r#####"
+struct Ctx<T: Clone> {
+    data: T,
+}
+
+impl<T: Clone> Ctx<T> {
+    $0
+}
+"#####,
+    )
+}
+
+#[test]
+fn doctest_generate_new() {
+    check_doc_test(
+        "generate_new",
+        r#####"
+struct Ctx<T: Clone> {
+     data: T,<|>
+}
+"#####,
+        r#####"
+struct Ctx<T: Clone> {
+     data: T,
+}
+
+impl<T: Clone> Ctx<T> {
+    fn $0new(data: T) -> Self { Self { data } }
+}
+
+"#####,
+    )
+}
+
 #[test]
 fn doctest_inline_local_variable() {
     check_doc_test(
diff --git a/xtask/tests/tidy.rs b/xtask/tests/tidy.rs
index d38ac7f17e..f999351706 100644
--- a/xtask/tests/tidy.rs
+++ b/xtask/tests/tidy.rs
@@ -56,8 +56,8 @@ fn check_todo(path: &Path, text: &str) {
         // Some of our assists generate `todo!()` so those files are whitelisted.
         "tests/generated.rs",
         "handlers/add_missing_impl_members.rs",
-        "handlers/add_function.rs",
         "handlers/add_turbo_fish.rs",
+        "handlers/generate_function.rs",
         // To support generating `todo!()` in assists, we have `expr_todo()` in ast::make.
         "ast/make.rs",
     ];