about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorLukas Wirth <lukastw97@gmail.com>2025-03-22 09:37:59 +0000
committerGitHub <noreply@github.com>2025-03-22 09:37:59 +0000
commiteec37fb8fe56f45073f96ec32b8a4eb879ee37a3 (patch)
treebb4f929aa73153ff6960d5dfdde59b0be45080fb /src
parenteba0d1655207ec3915d1c468e9c671768c67254d (diff)
parent2e3e75fae963910ffa8afebea680408d76f3a75f (diff)
downloadrust-eec37fb8fe56f45073f96ec32b8a4eb879ee37a3.tar.gz
rust-eec37fb8fe56f45073f96ec32b8a4eb879ee37a3.zip
Merge pull request #19362 from nemethf/fix-19322
Speed up resolving a "Generate delegate method" assist
Diffstat (limited to 'src')
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_braces.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_explicit_enum_discriminant.rs8
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_explicit_type.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_label_to_loop.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_lifetime_to_type.rs37
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_return_type.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_turbo_fish.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/apply_demorgan.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/auto_import.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/bind_unused_param.rs8
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/change_visibility.rs8
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_then.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_to_enum.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_closure_to_fn.rs10
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_comment_block.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_comment_from_or_to_doc.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_for_to_while_let.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_from_to_tryfrom.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_integer_literal.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_into_to_from.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_iter_for_each_to_for.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_let_else_to_match.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_match_to_let_else.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_nested_function_to_closure.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_to_guarded_return.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_return_type_to_struct.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_two_arm_bool_match_to_matches_macro.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_while_to_loop.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_tuple_binding.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/desugar_doc_comment.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_glob_import.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_rest_pattern.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_expressions_from_format_string.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_module.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_type_alias.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/fix_visibility.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_binexpr.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_comma.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_or_pattern.rs19
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_trait_bound.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_constant.rs19
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_default_from_enum_variant.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_default_from_new.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_methods.rs5
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_trait.rs8
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_deref.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_derive.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_documentation_template.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_enum_is_method.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_enum_projection_method.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_enum_variant.rs27
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_fn_type_alias.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_from_impl_for_enum.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_getter_or_setter.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_impl.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_is_empty_from_len.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_mut_trait_impl.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_new.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_trait_from_impl.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs29
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_const_as_literal.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_local_variable.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_macro.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_type_alias.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/into_to_qualified_from.rs7
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_lifetime.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_type_parameter.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/invert_if.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_imports.rs87
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_match_arms.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_nested_if.rs37
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_bounds.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_const_to_impl.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_from_mod_rs.rs7
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_guard.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_module_to_file.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_to_mod_rs.rs7
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/normalize_import.rs13
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/number_representation.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/promote_local_to_const.rs7
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/pull_assignment_up.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/qualify_method_call.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/qualify_path.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/raw_string.rs10
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_dbg.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_mut.rs25
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_parentheses.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_param.rs5
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_fields.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_impl_items.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_arith_op.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs157
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_if_let_with_match.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_is_method_with_if_let_method.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_let_with_if_let.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_method_eager_lazy.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_named_generic_with_impl.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_string_with_char.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_try_expr_with_match.rs7
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_turbofish_with_explicit_type.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/sort_items.rs25
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/split_import.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/term_search.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/toggle_async_sugar.rs9
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/toggle_ignore.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/toggle_macro_delimiter.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_match_arm.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_use.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/unnecessary_async.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/unqualify_method_call.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_block.rs5
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_return_type.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_tuple.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/wrap_return_type.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/wrap_unwrap_cfg_attr.rs8
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/tests.rs18
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/assists.rs38
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs10
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unused_variables.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/ssr.rs8
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs12
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs7
137 files changed, 562 insertions, 580 deletions
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_braces.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_braces.rs
index f9124d2d465..d8db7cc761a 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_braces.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_braces.rs
@@ -3,7 +3,7 @@ use syntax::{
     ast::{self, edit_in_place::Indent, syntax_factory::SyntaxFactory},
 };
 
-use crate::{AssistContext, AssistId, AssistKind, Assists};
+use crate::{AssistContext, AssistId, Assists};
 
 // Assist: add_braces
 //
@@ -32,7 +32,7 @@ pub(crate) fn add_braces(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<(
     let (expr_type, expr) = get_replacement_node(ctx)?;
 
     acc.add(
-        AssistId("add_braces", AssistKind::RefactorRewrite),
+        AssistId::refactor_rewrite("add_braces"),
         match expr_type {
             ParentType::ClosureExpr => "Add braces to closure body",
             ParentType::MatchArmExpr => "Add braces to arm expression",
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_explicit_enum_discriminant.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_explicit_enum_discriminant.rs
index c8a6f9e65ca..10b0879e636 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_explicit_enum_discriminant.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_explicit_enum_discriminant.rs
@@ -1,9 +1,5 @@
 use hir::Semantics;
-use ide_db::{
-    RootDatabase,
-    assists::{AssistId, AssistKind},
-    source_change::SourceChangeBuilder,
-};
+use ide_db::{RootDatabase, assists::AssistId, source_change::SourceChangeBuilder};
 use syntax::{AstNode, ast};
 
 use crate::{AssistContext, Assists};
@@ -53,7 +49,7 @@ pub(crate) fn add_explicit_enum_discriminant(
     }
 
     acc.add(
-        AssistId("add_explicit_enum_discriminant", AssistKind::RefactorRewrite),
+        AssistId::refactor_rewrite("add_explicit_enum_discriminant"),
         "Add explicit enum discriminants",
         enum_node.syntax().text_range(),
         |builder| {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_explicit_type.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_explicit_type.rs
index 8bc285614e0..35a65cc3091 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_explicit_type.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_explicit_type.rs
@@ -2,7 +2,7 @@ use hir::HirDisplay;
 use ide_db::syntax_helpers::node_ext::walk_ty;
 use syntax::ast::{self, AstNode, LetStmt, Param};
 
-use crate::{AssistContext, AssistId, AssistKind, Assists};
+use crate::{AssistContext, AssistId, Assists};
 
 // Assist: add_explicit_type
 //
@@ -71,7 +71,7 @@ pub(crate) fn add_explicit_type(acc: &mut Assists, ctx: &AssistContext<'_>) -> O
 
     let inferred_type = ty.display_source_code(ctx.db(), module.into(), false).ok()?;
     acc.add(
-        AssistId("add_explicit_type", AssistKind::RefactorRewrite),
+        AssistId::refactor_rewrite("add_explicit_type"),
         format!("Insert explicit type `{inferred_type}`"),
         pat_range,
         |builder| match ascribed_ty {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_label_to_loop.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_label_to_loop.rs
index fc10501543b..d2b90344713 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_label_to_loop.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_label_to_loop.rs
@@ -4,7 +4,7 @@ use syntax::{
     ast::{self, AstNode, HasLoopBody},
 };
 
-use crate::{AssistContext, AssistId, AssistKind, Assists};
+use crate::{AssistContext, AssistId, Assists};
 
 // Assist: add_label_to_loop
 //
@@ -35,7 +35,7 @@ pub(crate) fn add_label_to_loop(acc: &mut Assists, ctx: &AssistContext<'_>) -> O
     }
 
     acc.add(
-        AssistId("add_label_to_loop", AssistKind::Generate),
+        AssistId::generate("add_label_to_loop"),
         "Add Label",
         loop_expr.syntax().text_range(),
         |builder| {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_lifetime_to_type.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_lifetime_to_type.rs
index c3e05b8fb08..dcdc7ea9cdc 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_lifetime_to_type.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_lifetime_to_type.rs
@@ -1,6 +1,6 @@
 use syntax::ast::{self, AstNode, HasGenericParams, HasName};
 
-use crate::{AssistContext, AssistId, AssistKind, Assists};
+use crate::{AssistContext, AssistId, Assists};
 
 // Assist: add_lifetime_to_type
 //
@@ -37,31 +37,26 @@ pub(crate) fn add_lifetime_to_type(acc: &mut Assists, ctx: &AssistContext<'_>) -
     let ref_types = fetch_borrowed_types(&node)?;
     let target = node.syntax().text_range();
 
-    acc.add(
-        AssistId("add_lifetime_to_type", AssistKind::Generate),
-        "Add lifetime",
-        target,
-        |builder| {
-            match node.generic_param_list() {
-                Some(gen_param) => {
-                    if let Some(left_angle) = gen_param.l_angle_token() {
-                        builder.insert(left_angle.text_range().end(), "'a, ");
-                    }
+    acc.add(AssistId::generate("add_lifetime_to_type"), "Add lifetime", target, |builder| {
+        match node.generic_param_list() {
+            Some(gen_param) => {
+                if let Some(left_angle) = gen_param.l_angle_token() {
+                    builder.insert(left_angle.text_range().end(), "'a, ");
                 }
-                None => {
-                    if let Some(name) = node.name() {
-                        builder.insert(name.syntax().text_range().end(), "<'a>");
-                    }
+            }
+            None => {
+                if let Some(name) = node.name() {
+                    builder.insert(name.syntax().text_range().end(), "<'a>");
                 }
             }
+        }
 
-            for ref_type in ref_types {
-                if let Some(amp_token) = ref_type.amp_token() {
-                    builder.insert(amp_token.text_range().end(), "'a ");
-                }
+        for ref_type in ref_types {
+            if let Some(amp_token) = ref_type.amp_token() {
+                builder.insert(amp_token.text_range().end(), "'a ");
             }
-        },
-    )
+        }
+    })
 }
 
 fn fetch_borrowed_types(node: &ast::Adt) -> Option<Vec<ast::RefType>> {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs
index 6b8a8777569..65bd9141bd2 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs
@@ -5,7 +5,7 @@ use syntax::{
 };
 
 use crate::{
-    AssistId, AssistKind,
+    AssistId,
     assist_context::{AssistContext, Assists},
     utils::{
         DefaultMethods, IgnoreAssocItems, add_trait_assoc_items_to_impl, filter_assoc_items,
@@ -146,7 +146,7 @@ fn add_missing_impl_members_inner(
     }
 
     let target = impl_def.syntax().text_range();
-    acc.add(AssistId(assist_id, AssistKind::QuickFix), label, target, |edit| {
+    acc.add(AssistId::quick_fix(assist_id), label, target, |edit| {
         let new_impl_def = edit.make_mut(impl_def.clone());
         let first_new_item = add_trait_assoc_items_to_impl(
             &ctx.sema,
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs
index 78f3e26796d..4cabf4b0048 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs
@@ -12,7 +12,7 @@ use syntax::ast::edit_in_place::Indent;
 use syntax::ast::syntax_factory::SyntaxFactory;
 use syntax::ast::{self, AstNode, MatchArmList, MatchExpr, Pat, make};
 
-use crate::{AssistContext, AssistId, AssistKind, Assists, utils};
+use crate::{AssistContext, AssistId, Assists, utils};
 
 // Assist: add_missing_match_arms
 //
@@ -205,7 +205,7 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>)
     }
 
     acc.add(
-        AssistId("add_missing_match_arms", AssistKind::QuickFix),
+        AssistId::quick_fix("add_missing_match_arms"),
         "Fill match arms",
         ctx.sema.original_range(match_expr.syntax()).range,
         |builder| {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_return_type.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_return_type.rs
index 0c745af0eca..a7104ce068d 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_return_type.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_return_type.rs
@@ -1,7 +1,7 @@
 use hir::HirDisplay;
 use syntax::{AstNode, SyntaxKind, SyntaxToken, TextRange, TextSize, ast, match_ast};
 
-use crate::{AssistContext, AssistId, AssistKind, Assists};
+use crate::{AssistContext, AssistId, Assists};
 
 // Assist: add_return_type
 //
@@ -25,7 +25,7 @@ pub(crate) fn add_return_type(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opt
     let ty = ty.display_source_code(ctx.db(), module.into(), true).ok()?;
 
     acc.add(
-        AssistId("add_return_type", AssistKind::RefactorRewrite),
+        AssistId::refactor_rewrite("add_return_type"),
         match fn_type {
             FnType::Function => "Add this function's return type",
             FnType::Closure { .. } => "Add this closure's return type",
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_turbo_fish.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_turbo_fish.rs
index 372e0dad3cf..49019627601 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_turbo_fish.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_turbo_fish.rs
@@ -7,7 +7,7 @@ use syntax::{
 };
 
 use crate::{
-    AssistId, AssistKind,
+    AssistId,
     assist_context::{AssistContext, Assists},
 };
 
@@ -89,7 +89,7 @@ pub(crate) fn add_turbo_fish(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti
             let_stmt.pat()?;
 
             acc.add(
-                AssistId("add_type_ascription", AssistKind::RefactorRewrite),
+                AssistId::refactor_rewrite("add_type_ascription"),
                 "Add `: _` before assignment operator",
                 ident.text_range(),
                 |builder| {
@@ -135,7 +135,7 @@ pub(crate) fn add_turbo_fish(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti
         .count();
 
     acc.add(
-        AssistId("add_turbo_fish", AssistKind::RefactorRewrite),
+        AssistId::refactor_rewrite("add_turbo_fish"),
         "Add `::<>`",
         ident.text_range(),
         |builder| {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/apply_demorgan.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/apply_demorgan.rs
index e584c709a94..daab9922768 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/apply_demorgan.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/apply_demorgan.rs
@@ -17,7 +17,7 @@ use syntax::{
     syntax_editor::{Position, SyntaxEditor},
 };
 
-use crate::{AssistContext, AssistId, AssistKind, Assists, utils::invert_boolean_expression};
+use crate::{AssistContext, AssistId, Assists, utils::invert_boolean_expression};
 
 // Assist: apply_demorgan
 //
@@ -107,7 +107,7 @@ pub(crate) fn apply_demorgan(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti
 
     acc.add_group(
         &GroupLabel("Apply De Morgan's law".to_owned()),
-        AssistId("apply_demorgan", AssistKind::RefactorRewrite),
+        AssistId::refactor_rewrite("apply_demorgan"),
         "Apply De Morgan's law",
         op_range,
         |builder| {
@@ -190,7 +190,7 @@ pub(crate) fn apply_demorgan_iterator(acc: &mut Assists, ctx: &AssistContext<'_>
     let label = format!("Apply De Morgan's law to `Iterator::{}`", name.text().as_str());
     acc.add_group(
         &GroupLabel("Apply De Morgan's law".to_owned()),
-        AssistId("apply_demorgan_iterator", AssistKind::RefactorRewrite),
+        AssistId::refactor_rewrite("apply_demorgan_iterator"),
         label,
         op_range,
         |builder| {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/auto_import.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/auto_import.rs
index f491b9375c3..2c7532d919a 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/auto_import.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/auto_import.rs
@@ -10,7 +10,7 @@ use ide_db::{
 };
 use syntax::{AstNode, Edition, NodeOrToken, SyntaxElement, ast};
 
-use crate::{AssistContext, AssistId, AssistKind, Assists, GroupLabel};
+use crate::{AssistContext, AssistId, Assists, GroupLabel};
 
 // Feature: Auto Import
 //
@@ -127,7 +127,7 @@ pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<
         let import_path = import.import_path;
 
         let (assist_id, import_name) =
-            (AssistId("auto_import", AssistKind::QuickFix), import_path.display(ctx.db(), edition));
+            (AssistId::quick_fix("auto_import"), import_path.display(ctx.db(), edition));
         acc.add_group(
             &group_label,
             assist_id,
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/bind_unused_param.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/bind_unused_param.rs
index 5048ff5163a..dadc38e6f96 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/bind_unused_param.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/bind_unused_param.rs
@@ -1,9 +1,5 @@
 use crate::assist_context::{AssistContext, Assists};
-use ide_db::{
-    LineIndexDatabase,
-    assists::{AssistId, AssistKind},
-    defs::Definition,
-};
+use ide_db::{LineIndexDatabase, assists::AssistId, defs::Definition};
 use syntax::{
     AstNode,
     ast::{self, edit_in_place::Indent},
@@ -42,7 +38,7 @@ pub(crate) fn bind_unused_param(acc: &mut Assists, ctx: &AssistContext<'_>) -> O
     let r_curly_range = stmt_list.r_curly_token()?.text_range();
 
     acc.add(
-        AssistId("bind_unused_param", AssistKind::QuickFix),
+        AssistId::quick_fix("bind_unused_param"),
         format!("Bind as `let _ = {ident_pat};`"),
         param.syntax().text_range(),
         |builder| {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/change_visibility.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/change_visibility.rs
index 8af9121fc8d..9b9f0c4522e 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/change_visibility.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/change_visibility.rs
@@ -8,7 +8,7 @@ use syntax::{
     ast::{self, HasName, HasVisibility},
 };
 
-use crate::{AssistContext, AssistId, AssistKind, Assists, utils::vis_offset};
+use crate::{AssistContext, AssistId, Assists, utils::vis_offset};
 
 // Assist: change_visibility
 //
@@ -76,7 +76,7 @@ fn add_vis(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
     };
 
     acc.add(
-        AssistId("change_visibility", AssistKind::RefactorRewrite),
+        AssistId::refactor_rewrite("change_visibility"),
         "Change visibility to pub(crate)",
         target,
         |edit| {
@@ -112,7 +112,7 @@ fn change_vis(acc: &mut Assists, vis: ast::Visibility) -> Option<()> {
     if vis.syntax().text() == "pub" {
         let target = vis.syntax().text_range();
         return acc.add(
-            AssistId("change_visibility", AssistKind::RefactorRewrite),
+            AssistId::refactor_rewrite("change_visibility"),
             "Change Visibility to pub(crate)",
             target,
             |edit| {
@@ -123,7 +123,7 @@ fn change_vis(acc: &mut Assists, vis: ast::Visibility) -> Option<()> {
     if vis.syntax().text() == "pub(crate)" {
         let target = vis.syntax().text_range();
         return acc.add(
-            AssistId("change_visibility", AssistKind::RefactorRewrite),
+            AssistId::refactor_rewrite("change_visibility"),
             "Change visibility to pub",
             target,
             |edit| {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_then.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_then.rs
index c4a2189f696..f3210a625b2 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_then.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_then.rs
@@ -14,7 +14,7 @@ use syntax::{
 };
 
 use crate::{
-    AssistContext, AssistId, AssistKind, Assists,
+    AssistContext, AssistId, Assists,
     utils::{invert_boolean_expression, unwrap_trivial_block},
 };
 
@@ -73,7 +73,7 @@ pub(crate) fn convert_if_to_bool_then(acc: &mut Assists, ctx: &AssistContext<'_>
 
     let target = expr.syntax().text_range();
     acc.add(
-        AssistId("convert_if_to_bool_then", AssistKind::RefactorRewrite),
+        AssistId::refactor_rewrite("convert_if_to_bool_then"),
         "Convert `if` expression to `bool::then` call",
         target,
         |builder| {
@@ -181,7 +181,7 @@ pub(crate) fn convert_bool_then_to_if(acc: &mut Assists, ctx: &AssistContext<'_>
 
     let target = mcall.syntax().text_range();
     acc.add(
-        AssistId("convert_bool_then_to_if", AssistKind::RefactorRewrite),
+        AssistId::refactor_rewrite("convert_bool_then_to_if"),
         "Convert `bool::then` call to `if`",
         target,
         |builder| {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_to_enum.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_to_enum.rs
index 8200ad75df5..e3ca28d64d8 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_to_enum.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_to_enum.rs
@@ -3,7 +3,7 @@ use hir::ModuleDef;
 use ide_db::text_edit::TextRange;
 use ide_db::{
     FxHashSet,
-    assists::{AssistId, AssistKind},
+    assists::AssistId,
     defs::Definition,
     helpers::mod_path_to_ast,
     imports::insert_use::{ImportScope, insert_use},
@@ -62,7 +62,7 @@ pub(crate) fn convert_bool_to_enum(acc: &mut Assists, ctx: &AssistContext<'_>) -
 
     let target = name.syntax().text_range();
     acc.add(
-        AssistId("convert_bool_to_enum", AssistKind::RefactorRewrite),
+        AssistId::refactor_rewrite("convert_bool_to_enum"),
         "Convert boolean to enum",
         target,
         |edit| {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_closure_to_fn.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_closure_to_fn.rs
index c11a411fb9c..fbd925e55eb 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_closure_to_fn.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_closure_to_fn.rs
@@ -1,12 +1,8 @@
 use either::Either;
 use hir::{CaptureKind, ClosureCapture, FileRangeWrapper, HirDisplay};
 use ide_db::{
-    FxHashSet,
-    assists::{AssistId, AssistKind},
-    base_db::SourceDatabase,
-    defs::Definition,
-    search::FileReferenceNode,
-    source_change::SourceChangeBuilder,
+    FxHashSet, assists::AssistId, base_db::SourceDatabase, defs::Definition,
+    search::FileReferenceNode, source_change::SourceChangeBuilder,
 };
 use stdx::format_to;
 use syntax::{
@@ -147,7 +143,7 @@ pub(crate) fn convert_closure_to_fn(acc: &mut Assists, ctx: &AssistContext<'_>)
     };
 
     acc.add(
-        AssistId("convert_closure_to_fn", AssistKind::RefactorRewrite),
+        AssistId::refactor_rewrite("convert_closure_to_fn"),
         "Convert closure to fn",
         closure.param_list()?.syntax().text_range(),
         |builder| {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_comment_block.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_comment_block.rs
index 92b86cee356..0d36a5ddb30 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_comment_block.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_comment_block.rs
@@ -4,7 +4,7 @@ use syntax::{
     ast::{self, Comment, CommentKind, CommentShape, Whitespace, edit::IndentLevel},
 };
 
-use crate::{AssistContext, AssistId, AssistKind, Assists};
+use crate::{AssistContext, AssistId, Assists};
 
 // Assist: line_to_block
 //
@@ -38,7 +38,7 @@ fn block_to_line(acc: &mut Assists, comment: ast::Comment) -> Option<()> {
     let target = comment.syntax().text_range();
 
     acc.add(
-        AssistId("block_to_line", AssistKind::RefactorRewrite),
+        AssistId::refactor_rewrite("block_to_line"),
         "Replace block comment with line comments",
         target,
         |edit| {
@@ -80,7 +80,7 @@ fn line_to_block(acc: &mut Assists, comment: ast::Comment) -> Option<()> {
     );
 
     acc.add(
-        AssistId("line_to_block", AssistKind::RefactorRewrite),
+        AssistId::refactor_rewrite("line_to_block"),
         "Replace line comments with a single block comment",
         target,
         |edit| {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_comment_from_or_to_doc.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_comment_from_or_to_doc.rs
index 7b4d27100f1..187cc74306e 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_comment_from_or_to_doc.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_comment_from_or_to_doc.rs
@@ -4,7 +4,7 @@ use syntax::{
     ast::{self, Comment, CommentPlacement, Whitespace, edit::IndentLevel},
 };
 
-use crate::{AssistContext, AssistId, AssistKind, Assists};
+use crate::{AssistContext, AssistId, Assists};
 
 // Assist: comment_to_doc
 //
@@ -39,7 +39,7 @@ fn doc_to_comment(acc: &mut Assists, comment: ast::Comment) -> Option<()> {
     };
 
     acc.add(
-        AssistId("doc_to_comment", AssistKind::RefactorRewrite),
+        AssistId::refactor_rewrite("doc_to_comment"),
         "Replace doc comment with comment",
         target,
         |edit| {
@@ -86,7 +86,7 @@ fn comment_to_doc(acc: &mut Assists, comment: ast::Comment, style: CommentPlacem
     };
 
     acc.add(
-        AssistId("comment_to_doc", AssistKind::RefactorRewrite),
+        AssistId::refactor_rewrite("comment_to_doc"),
         "Replace comment with doc comment",
         target,
         |edit| {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_for_to_while_let.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_for_to_while_let.rs
index 03041f3551d..801a57b3e3f 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_for_to_while_let.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_for_to_while_let.rs
@@ -9,7 +9,7 @@ use syntax::{
     syntax_editor::Position,
 };
 
-use crate::{AssistContext, AssistId, AssistKind, Assists};
+use crate::{AssistContext, AssistId, Assists};
 
 // Assist: convert_for_loop_to_while_let
 //
@@ -47,7 +47,7 @@ pub(crate) fn convert_for_loop_to_while_let(
     }
 
     acc.add(
-        AssistId("convert_for_loop_to_while_let", AssistKind::RefactorRewrite),
+        AssistId::refactor_rewrite("convert_for_loop_to_while_let"),
         "Replace this for loop with `while let`",
         for_loop.syntax().text_range(),
         |builder| {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_from_to_tryfrom.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_from_to_tryfrom.rs
index 07ad5a695b3..ec08eb92463 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_from_to_tryfrom.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_from_to_tryfrom.rs
@@ -5,7 +5,7 @@ use syntax::{
     ted,
 };
 
-use crate::{AssistContext, AssistId, AssistKind, Assists};
+use crate::{AssistContext, AssistId, Assists};
 
 // Assist: convert_from_to_tryfrom
 //
@@ -71,7 +71,7 @@ pub(crate) fn convert_from_to_tryfrom(acc: &mut Assists, ctx: &AssistContext<'_>
     }
 
     acc.add(
-        AssistId("convert_from_to_tryfrom", AssistKind::RefactorRewrite),
+        AssistId::refactor_rewrite("convert_from_to_tryfrom"),
         "Convert From to TryFrom",
         impl_.syntax().text_range(),
         |builder| {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_integer_literal.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_integer_literal.rs
index 270eecd83b0..846f4e9b258 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_integer_literal.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_integer_literal.rs
@@ -1,6 +1,6 @@
 use syntax::{AstToken, ast, ast::Radix};
 
-use crate::{AssistContext, AssistId, AssistKind, Assists, GroupLabel};
+use crate::{AssistContext, AssistId, Assists, GroupLabel};
 
 // Assist: convert_integer_literal
 //
@@ -47,7 +47,7 @@ pub(crate) fn convert_integer_literal(acc: &mut Assists, ctx: &AssistContext<'_>
 
         acc.add_group(
             &group_id,
-            AssistId("convert_integer_literal", AssistKind::RefactorInline),
+            AssistId::refactor_rewrite("convert_integer_literal"),
             label,
             range,
             |builder| builder.replace(range, converted),
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_into_to_from.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_into_to_from.rs
index 8c59ef4314f..b80276a95fb 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_into_to_from.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_into_to_from.rs
@@ -1,7 +1,7 @@
 use ide_db::{famous_defs::FamousDefs, helpers::mod_path_to_ast, traits::resolve_target_trait};
 use syntax::ast::{self, AstNode, HasGenericArgs, HasName};
 
-use crate::{AssistContext, AssistId, AssistKind, Assists};
+use crate::{AssistContext, AssistId, Assists};
 
 // FIXME: this should be a diagnostic
 
@@ -85,7 +85,7 @@ pub(crate) fn convert_into_to_from(acc: &mut Assists, ctx: &AssistContext<'_>) -
         .filter(|name| name.text() == "self" || name.text() == "Self");
 
     acc.add(
-        AssistId("convert_into_to_from", AssistKind::RefactorRewrite),
+        AssistId::refactor_rewrite("convert_into_to_from"),
         "Convert Into to From",
         impl_.syntax().text_range(),
         |builder| {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_iter_for_each_to_for.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_iter_for_each_to_for.rs
index 713d215f120..d7f6594e6d4 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_iter_for_each_to_for.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_iter_for_each_to_for.rs
@@ -6,7 +6,7 @@ use syntax::{
     ast::{self, HasArgList, HasLoopBody, edit_in_place::Indent, make},
 };
 
-use crate::{AssistContext, AssistId, AssistKind, Assists};
+use crate::{AssistContext, AssistId, Assists};
 
 // Assist: convert_iter_for_each_to_for
 //
@@ -53,7 +53,7 @@ pub(crate) fn convert_iter_for_each_to_for(
     let range = stmt.as_ref().map_or(method.syntax(), AstNode::syntax).text_range();
 
     acc.add(
-        AssistId("convert_iter_for_each_to_for", AssistKind::RefactorRewrite),
+        AssistId::refactor_rewrite("convert_iter_for_each_to_for"),
         "Replace this `Iterator::for_each` with a for loop",
         range,
         |builder| {
@@ -108,7 +108,7 @@ pub(crate) fn convert_for_loop_with_for_each(
     }
 
     acc.add(
-        AssistId("convert_for_loop_with_for_each", AssistKind::RefactorRewrite),
+        AssistId::refactor_rewrite("convert_for_loop_with_for_each"),
         "Replace this for loop with `Iterator::for_each`",
         for_loop.syntax().text_range(),
         |builder| {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_let_else_to_match.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_let_else_to_match.rs
index 9f71031a1e6..df92b07cba7 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_let_else_to_match.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_let_else_to_match.rs
@@ -4,7 +4,7 @@ use syntax::T;
 use syntax::ast::RangeItem;
 use syntax::ast::{AstNode, HasName, LetStmt, Name, Pat, edit::AstNodeEdit};
 
-use crate::{AssistContext, AssistId, AssistKind, Assists};
+use crate::{AssistContext, AssistId, Assists};
 
 // Assist: convert_let_else_to_match
 //
@@ -43,7 +43,7 @@ pub(crate) fn convert_let_else_to_match(acc: &mut Assists, ctx: &AssistContext<'
 
     let target = let_stmt.syntax().text_range();
     acc.add(
-        AssistId("convert_let_else_to_match", AssistKind::RefactorRewrite),
+        AssistId::refactor_rewrite("convert_let_else_to_match"),
         "Convert let-else to let and match",
         target,
         |edit| {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_match_to_let_else.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_match_to_let_else.rs
index 2db78f412d7..efcbcef00e9 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_match_to_let_else.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_match_to_let_else.rs
@@ -6,7 +6,7 @@ use syntax::{
 };
 
 use crate::{
-    AssistId, AssistKind,
+    AssistId,
     assist_context::{AssistContext, Assists},
 };
 
@@ -55,7 +55,7 @@ pub(crate) fn convert_match_to_let_else(acc: &mut Assists, ctx: &AssistContext<'
     let extracted_variable_positions = find_extracted_variable(ctx, &extracting_arm)?;
 
     acc.add(
-        AssistId("convert_match_to_let_else", AssistKind::RefactorRewrite),
+        AssistId::refactor_rewrite("convert_match_to_let_else"),
         "Convert match to let-else",
         let_stmt.syntax().text_range(),
         |builder| {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs
index 7b8804e53f0..53a5a9465e0 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs
@@ -7,7 +7,7 @@ use syntax::{
     match_ast, ted,
 };
 
-use crate::{AssistContext, AssistId, AssistKind, Assists, assist_context::SourceChangeBuilder};
+use crate::{AssistContext, AssistId, Assists, assist_context::SourceChangeBuilder};
 
 // Assist: convert_named_struct_to_tuple_struct
 //
@@ -69,7 +69,7 @@ pub(crate) fn convert_named_struct_to_tuple_struct(
     };
 
     acc.add(
-        AssistId("convert_named_struct_to_tuple_struct", AssistKind::RefactorRewrite),
+        AssistId::refactor_rewrite("convert_named_struct_to_tuple_struct"),
         "Convert to tuple struct",
         strukt.syntax().text_range(),
         |edit| {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_nested_function_to_closure.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_nested_function_to_closure.rs
index ea2752b8818..c0fd69779ae 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_nested_function_to_closure.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_nested_function_to_closure.rs
@@ -1,4 +1,4 @@
-use ide_db::assists::{AssistId, AssistKind};
+use ide_db::assists::AssistId;
 use syntax::ast::{self, HasGenericParams, HasName};
 use syntax::{AstNode, SyntaxKind};
 
@@ -44,7 +44,7 @@ pub(crate) fn convert_nested_function_to_closure(
     let param_list = function.param_list()?;
 
     acc.add(
-        AssistId("convert_nested_function_to_closure", AssistKind::RefactorRewrite),
+        AssistId::refactor_rewrite("convert_nested_function_to_closure"),
         "Convert nested function to closure",
         target,
         |edit| {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_to_guarded_return.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_to_guarded_return.rs
index bd829d1e24b..71a61f2db00 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_to_guarded_return.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_to_guarded_return.rs
@@ -17,7 +17,7 @@ use syntax::{
 };
 
 use crate::{
-    AssistId, AssistKind,
+    AssistId,
     assist_context::{AssistContext, Assists},
     utils::invert_boolean_expression_legacy,
 };
@@ -128,7 +128,7 @@ fn if_expr_to_guarded_return(
 
     let target = if_expr.syntax().text_range();
     acc.add(
-        AssistId("convert_to_guarded_return", AssistKind::RefactorRewrite),
+        AssistId::refactor_rewrite("convert_to_guarded_return"),
         "Convert to guarded return",
         target,
         |edit| {
@@ -210,7 +210,7 @@ fn let_stmt_to_guarded_return(
     };
 
     acc.add(
-        AssistId("convert_to_guarded_return", AssistKind::RefactorRewrite),
+        AssistId::refactor_rewrite("convert_to_guarded_return"),
         "Convert to guarded return",
         target,
         |edit| {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_return_type_to_struct.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_return_type_to_struct.rs
index 0d799378857..87eafc39f83 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_return_type_to_struct.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_return_type_to_struct.rs
@@ -2,7 +2,7 @@ use either::Either;
 use hir::ModuleDef;
 use ide_db::{
     FxHashSet,
-    assists::{AssistId, AssistKind},
+    assists::AssistId,
     defs::Definition,
     helpers::mod_path_to_ast,
     imports::insert_use::{ImportScope, insert_use},
@@ -63,7 +63,7 @@ pub(crate) fn convert_tuple_return_type_to_struct(
 
     let target = type_ref.syntax().text_range();
     acc.add(
-        AssistId("convert_tuple_return_type_to_struct", AssistKind::RefactorRewrite),
+        AssistId::refactor_rewrite("convert_tuple_return_type_to_struct"),
         "Convert tuple return type to tuple struct",
         target,
         move |edit| {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs
index 83e4737350c..ae23fa05f9a 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs
@@ -6,7 +6,7 @@ use syntax::{
     match_ast, ted,
 };
 
-use crate::{AssistContext, AssistId, AssistKind, Assists, assist_context::SourceChangeBuilder};
+use crate::{AssistContext, AssistId, Assists, assist_context::SourceChangeBuilder};
 
 // Assist: convert_tuple_struct_to_named_struct
 //
@@ -65,7 +65,7 @@ pub(crate) fn convert_tuple_struct_to_named_struct(
     let target = strukt.as_ref().either(|s| s.syntax(), |v| v.syntax()).text_range();
 
     acc.add(
-        AssistId("convert_tuple_struct_to_named_struct", AssistKind::RefactorRewrite),
+        AssistId::refactor_rewrite("convert_tuple_struct_to_named_struct"),
         "Convert to named struct",
         target,
         |edit| {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_two_arm_bool_match_to_matches_macro.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_two_arm_bool_match_to_matches_macro.rs
index 6a5b11f5425..e582aa814ae 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_two_arm_bool_match_to_matches_macro.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_two_arm_bool_match_to_matches_macro.rs
@@ -3,7 +3,7 @@ use ide_db::RootDatabase;
 use stdx::format_to;
 use syntax::ast::{self, AstNode};
 
-use crate::{AssistContext, AssistId, AssistKind, Assists};
+use crate::{AssistContext, AssistId, Assists};
 
 // Assist: convert_two_arm_bool_match_to_matches_macro
 //
@@ -56,7 +56,7 @@ pub(crate) fn convert_two_arm_bool_match_to_matches_macro(
     let expr = match_expr.expr()?;
 
     acc.add(
-        AssistId("convert_two_arm_bool_match_to_matches_macro", AssistKind::RefactorRewrite),
+        AssistId::refactor_rewrite("convert_two_arm_bool_match_to_matches_macro"),
         "Convert to matches!",
         target_range,
         |builder| {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_while_to_loop.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_while_to_loop.rs
index 724de1969cb..dbe3ee0ed60 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_while_to_loop.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_while_to_loop.rs
@@ -12,7 +12,7 @@ use syntax::{
 };
 
 use crate::{
-    AssistId, AssistKind,
+    AssistId,
     assist_context::{AssistContext, Assists},
     utils::invert_boolean_expression_legacy,
 };
@@ -47,7 +47,7 @@ pub(crate) fn convert_while_to_loop(acc: &mut Assists, ctx: &AssistContext<'_>)
 
     let target = while_expr.syntax().text_range();
     acc.add(
-        AssistId("convert_while_to_loop", AssistKind::RefactorRewrite),
+        AssistId::refactor_rewrite("convert_while_to_loop"),
         "Convert while to loop",
         target,
         |edit| {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs
index a8a3a8c927f..76fb6b6b06a 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs
@@ -2,7 +2,7 @@ use hir::{HasVisibility, sym};
 use ide_db::text_edit::TextRange;
 use ide_db::{
     FxHashMap, FxHashSet,
-    assists::{AssistId, AssistKind},
+    assists::AssistId,
     defs::Definition,
     helpers::mod_path_to_ast,
     search::{FileReference, SearchScope},
@@ -47,7 +47,7 @@ pub(crate) fn destructure_struct_binding(acc: &mut Assists, ctx: &AssistContext<
     let data = collect_data(ident_pat, ctx)?;
 
     acc.add(
-        AssistId("destructure_struct_binding", AssistKind::RefactorRewrite),
+        AssistId::refactor_rewrite("destructure_struct_binding"),
         "Destructure struct binding",
         data.ident_pat.syntax().text_range(),
         |edit| destructure_struct_binding_impl(ctx, edit, &data),
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_tuple_binding.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_tuple_binding.rs
index 95eb88fa868..adf0f0997b3 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_tuple_binding.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_tuple_binding.rs
@@ -1,5 +1,5 @@
 use ide_db::{
-    assists::{AssistId, AssistKind},
+    assists::AssistId,
     defs::Definition,
     search::{FileReference, SearchScope},
     syntax_helpers::suggest_name,
@@ -65,7 +65,7 @@ pub(crate) fn destructure_tuple_binding_impl(
 
     if with_sub_pattern {
         acc.add(
-            AssistId("destructure_tuple_binding_in_sub_pattern", AssistKind::RefactorRewrite),
+            AssistId::refactor_rewrite("destructure_tuple_binding_in_sub_pattern"),
             "Destructure tuple in sub-pattern",
             data.ident_pat.syntax().text_range(),
             |edit| destructure_tuple_edit_impl(ctx, edit, &data, true),
@@ -73,7 +73,7 @@ pub(crate) fn destructure_tuple_binding_impl(
     }
 
     acc.add(
-        AssistId("destructure_tuple_binding", AssistKind::RefactorRewrite),
+        AssistId::refactor_rewrite("destructure_tuple_binding"),
         if with_sub_pattern { "Destructure tuple in place" } else { "Destructure tuple" },
         data.ident_pat.syntax().text_range(),
         |edit| destructure_tuple_edit_impl(ctx, edit, &data, false),
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/desugar_doc_comment.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/desugar_doc_comment.rs
index 9d0797d32a8..74bb0ba3f60 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/desugar_doc_comment.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/desugar_doc_comment.rs
@@ -6,7 +6,7 @@ use syntax::{
 };
 
 use crate::{
-    AssistContext, AssistId, AssistKind, Assists,
+    AssistContext, AssistId, Assists,
     handlers::convert_comment_block::{line_comment_text, relevant_line_comments},
     utils::required_hashes,
 };
@@ -54,7 +54,7 @@ pub(crate) fn desugar_doc_comment(acc: &mut Assists, ctx: &AssistContext<'_>) ->
     };
 
     acc.add(
-        AssistId("desugar_doc_comment", AssistKind::RefactorRewrite),
+        AssistId::refactor_rewrite("desugar_doc_comment"),
         "Desugar doc-comment to attribute macro",
         target,
         |edit| {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_glob_import.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_glob_import.rs
index fae5530f995..307414c7971 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_glob_import.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_glob_import.rs
@@ -13,7 +13,7 @@ use syntax::{
 };
 
 use crate::{
-    AssistId, AssistKind,
+    AssistId,
     assist_context::{AssistContext, Assists},
 };
 
@@ -62,7 +62,7 @@ pub(crate) fn expand_glob_import(acc: &mut Assists, ctx: &AssistContext<'_>) ->
 
     let target = parent.either(|n| n.syntax().clone(), |n| n.syntax().clone());
     acc.add(
-        AssistId("expand_glob_import", AssistKind::RefactorRewrite),
+        AssistId::refactor_rewrite("expand_glob_import"),
         "Expand glob import",
         target.text_range(),
         |builder| {
@@ -123,7 +123,7 @@ pub(crate) fn expand_glob_reexport(acc: &mut Assists, ctx: &AssistContext<'_>) -
 
     let target = parent.either(|n| n.syntax().clone(), |n| n.syntax().clone());
     acc.add(
-        AssistId("expand_glob_reexport", AssistKind::RefactorRewrite),
+        AssistId::refactor_rewrite("expand_glob_reexport"),
         "Expand glob reexport",
         target.text_range(),
         |builder| {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_rest_pattern.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_rest_pattern.rs
index e437e7eb751..ceb13b2f212 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_rest_pattern.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_rest_pattern.rs
@@ -74,7 +74,7 @@ fn expand_record_rest_pattern(
 
     let target_range = rest_pat.syntax().text_range();
     acc.add(
-        AssistId("expand_record_rest_pattern", crate::AssistKind::RefactorRewrite),
+        AssistId::refactor_rewrite("expand_record_rest_pattern"),
         "Fill struct fields",
         target_range,
         move |builder| builder.replace_ast(old_field_list, new_field_list),
@@ -155,7 +155,7 @@ fn expand_tuple_struct_rest_pattern(
 
     let target_range = rest_pat.syntax().text_range();
     acc.add(
-        AssistId("expand_tuple_struct_rest_pattern", crate::AssistKind::RefactorRewrite),
+        AssistId::refactor_rewrite("expand_tuple_struct_rest_pattern"),
         "Fill tuple struct fields",
         target_range,
         move |builder| builder.replace_ast(pat, new_pat),
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_expressions_from_format_string.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_expressions_from_format_string.rs
index c9eb7c52379..1212bb770bb 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_expressions_from_format_string.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_expressions_from_format_string.rs
@@ -53,6 +53,7 @@ pub(crate) fn extract_expressions_from_format_string(
             } else {
                 AssistKind::QuickFix
             },
+            None,
         ),
         "Extract format expressions",
         tt.syntax().text_range(),
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs
index 6b535a28977..abc0698b014 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs
@@ -108,7 +108,7 @@ pub(crate) fn extract_function(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op
 
     acc.add_group(
         &GroupLabel("Extract into...".to_owned()),
-        AssistId("extract_function", crate::AssistKind::RefactorExtract),
+        AssistId::refactor_extract("extract_function"),
         "Extract into function",
         target_range,
         move |builder| {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_module.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_module.rs
index 8a7bb5a1f0d..a77b5e4a1a5 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_module.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_module.rs
@@ -5,7 +5,7 @@ use hir::{HasSource, HirFileIdExt, ModuleSource};
 use ide_db::base_db::salsa::AsDynDatabase;
 use ide_db::{
     FileId, FxHashMap, FxHashSet,
-    assists::{AssistId, AssistKind},
+    assists::AssistId,
     defs::{Definition, NameClass, NameRefClass},
     search::{FileReference, SearchScope},
 };
@@ -92,7 +92,7 @@ pub(crate) fn extract_module(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti
     let old_item_indent = module.body_items[0].indent_level();
 
     acc.add(
-        AssistId("extract_module", AssistKind::RefactorExtract),
+        AssistId::refactor_extract("extract_module"),
         "Extract Module",
         module.text_range,
         |builder| {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs
index 7fba75f9e56..72fdae271da 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs
@@ -22,7 +22,7 @@ use syntax::{
     match_ast, ted,
 };
 
-use crate::{AssistContext, AssistId, AssistKind, Assists, assist_context::SourceChangeBuilder};
+use crate::{AssistContext, AssistId, Assists, assist_context::SourceChangeBuilder};
 
 // Assist: extract_struct_from_enum_variant
 //
@@ -55,7 +55,7 @@ pub(crate) fn extract_struct_from_enum_variant(
     let enum_hir = ctx.sema.to_def(&enum_ast)?;
     let target = variant.syntax().text_range();
     acc.add(
-        AssistId("extract_struct_from_enum_variant", AssistKind::RefactorRewrite),
+        AssistId::refactor_rewrite("extract_struct_from_enum_variant"),
         "Extract struct from enum variant",
         target,
         |builder| {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_type_alias.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_type_alias.rs
index e6fb4d40d46..c1c9a82dd18 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_type_alias.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_type_alias.rs
@@ -5,7 +5,7 @@ use syntax::{
     syntax_editor,
 };
 
-use crate::{AssistContext, AssistId, AssistKind, Assists};
+use crate::{AssistContext, AssistId, Assists};
 
 // Assist: extract_type_alias
 //
@@ -40,7 +40,7 @@ pub(crate) fn extract_type_alias(acc: &mut Assists, ctx: &AssistContext<'_>) ->
     let target = ty.syntax().text_range();
 
     acc.add(
-        AssistId("extract_type_alias", AssistKind::RefactorExtract),
+        AssistId::refactor_extract("extract_type_alias"),
         "Extract type as type alias",
         target,
         |builder| {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs
index 2e58e62ab0c..95ea8b3c8b6 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs
@@ -13,7 +13,7 @@ use syntax::{
     syntax_editor::Position,
 };
 
-use crate::{AssistContext, AssistId, AssistKind, Assists, utils::is_body_const};
+use crate::{AssistContext, AssistId, Assists, utils::is_body_const};
 
 // Assist: extract_variable
 //
@@ -311,7 +311,7 @@ impl ExtractionKind {
             ExtractionKind::Static => "extract_static",
         };
 
-        AssistId(s, AssistKind::RefactorExtract)
+        AssistId::refactor_extract(s)
     }
 
     fn label(&self) -> &'static str {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/fix_visibility.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/fix_visibility.rs
index 51dbce29731..6373699853b 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/fix_visibility.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/fix_visibility.rs
@@ -7,7 +7,7 @@ use syntax::{
     ast::{self, HasVisibility as _, edit_in_place::HasVisibilityEdit, make},
 };
 
-use crate::{AssistContext, AssistId, AssistKind, Assists};
+use crate::{AssistContext, AssistId, Assists};
 
 // FIXME: this really should be a fix for diagnostic, rather than an assist.
 
@@ -78,7 +78,7 @@ fn add_vis_to_referenced_module_def(acc: &mut Assists, ctx: &AssistContext<'_>)
         }
     };
 
-    acc.add(AssistId("fix_visibility", AssistKind::QuickFix), assist_label, target, |edit| {
+    acc.add(AssistId::quick_fix("fix_visibility"), assist_label, target, |edit| {
         edit.edit_file(target_file);
 
         let vis_owner = edit.make_mut(vis_owner);
@@ -131,7 +131,7 @@ fn add_vis_to_referenced_record_field(acc: &mut Assists, ctx: &AssistContext<'_>
         target_name.display(ctx.db(), current_edition)
     );
 
-    acc.add(AssistId("fix_visibility", AssistKind::QuickFix), assist_label, target, |edit| {
+    acc.add(AssistId::quick_fix("fix_visibility"), assist_label, target, |edit| {
         edit.edit_file(target_file.file_id());
 
         let vis_owner = edit.make_mut(vis_owner);
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_binexpr.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_binexpr.rs
index 75133c3a023..94d7b73425d 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_binexpr.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_binexpr.rs
@@ -3,7 +3,7 @@ use syntax::{
     ast::{self, AstNode, BinExpr, syntax_factory::SyntaxFactory},
 };
 
-use crate::{AssistContext, AssistId, AssistKind, Assists};
+use crate::{AssistContext, AssistId, Assists};
 
 // Assist: flip_binexpr
 //
@@ -43,7 +43,7 @@ pub(crate) fn flip_binexpr(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option
     }
 
     acc.add(
-        AssistId("flip_binexpr", AssistKind::RefactorRewrite),
+        AssistId::refactor_rewrite("flip_binexpr"),
         "Flip binary expression",
         op_token.text_range(),
         |builder| {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_comma.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_comma.rs
index 6900e94bdd2..25e514b4980 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_comma.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_comma.rs
@@ -5,7 +5,7 @@ use syntax::{
     syntax_editor::SyntaxMapping,
 };
 
-use crate::{AssistContext, AssistId, AssistKind, Assists};
+use crate::{AssistContext, AssistId, Assists};
 
 // Assist: flip_comma
 //
@@ -40,7 +40,7 @@ pub(crate) fn flip_comma(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<(
     }
 
     let target = comma.text_range();
-    acc.add(AssistId("flip_comma", AssistKind::RefactorRewrite), "Flip comma", target, |builder| {
+    acc.add(AssistId::refactor_rewrite("flip_comma"), "Flip comma", target, |builder| {
         let parent = comma.parent().unwrap();
         let mut editor = builder.make_editor(&parent);
 
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_or_pattern.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_or_pattern.rs
index 6ef8aa6a739..c84d23ffd0e 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_or_pattern.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_or_pattern.rs
@@ -4,7 +4,7 @@ use syntax::{
     ast::{self, AstNode},
 };
 
-use crate::{AssistContext, AssistId, AssistKind, Assists};
+use crate::{AssistContext, AssistId, Assists};
 
 // Assist: flip_or_pattern
 //
@@ -31,17 +31,12 @@ pub(crate) fn flip_or_pattern(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opt
     let after = non_trivia_sibling(pipe.clone().into(), Direction::Next)?.into_node()?;
 
     let target = pipe.text_range();
-    acc.add(
-        AssistId("flip_or_pattern", AssistKind::RefactorRewrite),
-        "Flip patterns",
-        target,
-        |builder| {
-            let mut editor = builder.make_editor(parent.syntax());
-            editor.replace(before.clone(), after.clone());
-            editor.replace(after, before);
-            builder.add_file_edits(ctx.file_id(), editor);
-        },
-    )
+    acc.add(AssistId::refactor_rewrite("flip_or_pattern"), "Flip patterns", target, |builder| {
+        let mut editor = builder.make_editor(parent.syntax());
+        editor.replace(before.clone(), after.clone());
+        editor.replace(after, before);
+        builder.add_file_edits(ctx.file_id(), editor);
+    })
 }
 
 #[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_trait_bound.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_trait_bound.rs
index af40b09643a..2f3b047b278 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_trait_bound.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_trait_bound.rs
@@ -4,7 +4,7 @@ use syntax::{
     ast::{self, AstNode},
 };
 
-use crate::{AssistContext, AssistId, AssistKind, Assists};
+use crate::{AssistContext, AssistId, Assists};
 
 // Assist: flip_trait_bound
 //
@@ -29,7 +29,7 @@ pub(crate) fn flip_trait_bound(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op
 
     let target = plus.text_range();
     acc.add(
-        AssistId("flip_trait_bound", AssistKind::RefactorRewrite),
+        AssistId::refactor_rewrite("flip_trait_bound"),
         "Flip trait bounds",
         target,
         |builder| {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_constant.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_constant.rs
index 2f4b6a0421b..dbf3b6d1f7e 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_constant.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_constant.rs
@@ -2,7 +2,7 @@ use crate::assist_context::{AssistContext, Assists};
 use hir::{HasVisibility, HirDisplay, HirFileIdExt, Module};
 use ide_db::{
     FileId,
-    assists::{AssistId, AssistKind},
+    assists::AssistId,
     base_db::Upcast,
     defs::{Definition, NameRefClass},
 };
@@ -88,17 +88,12 @@ pub(crate) fn generate_constant(acc: &mut Assists, ctx: &AssistContext<'_>) -> O
         );
 
     let text = get_text_for_generate_constant(not_exist_name_ref, indent, outer_exists, type_name)?;
-    acc.add(
-        AssistId("generate_constant", AssistKind::QuickFix),
-        "Generate constant",
-        target,
-        |builder| {
-            if let Some(file_id) = file_id {
-                builder.edit_file(file_id);
-            }
-            builder.insert(offset, format!("{text}{post_string}"));
-        },
-    )
+    acc.add(AssistId::quick_fix("generate_constant"), "Generate constant", target, |builder| {
+        if let Some(file_id) = file_id {
+            builder.edit_file(file_id);
+        }
+        builder.insert(offset, format!("{text}{post_string}"));
+    })
 }
 
 fn get_text_for_generate_constant(
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_default_from_enum_variant.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_default_from_enum_variant.rs
index c6725a013e3..6198dbc4ed9 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_default_from_enum_variant.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_default_from_enum_variant.rs
@@ -1,7 +1,7 @@
 use ide_db::{RootDatabase, famous_defs::FamousDefs};
 use syntax::ast::{self, AstNode, HasName};
 
-use crate::{AssistContext, AssistId, AssistKind, Assists};
+use crate::{AssistContext, AssistId, Assists};
 
 // Assist: generate_default_from_enum_variant
 //
@@ -47,7 +47,7 @@ pub(crate) fn generate_default_from_enum_variant(
 
     let target = variant.syntax().text_range();
     acc.add(
-        AssistId("generate_default_from_enum_variant", AssistKind::Generate),
+        AssistId::generate("generate_default_from_enum_variant"),
         "Generate `Default` impl from this enum variant",
         target,
         |edit| {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_default_from_new.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_default_from_new.rs
index 1a4349cfea9..79a78ab3698 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_default_from_new.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_default_from_new.rs
@@ -65,7 +65,7 @@ pub(crate) fn generate_default_from_new(acc: &mut Assists, ctx: &AssistContext<'
     let insert_location = impl_.syntax().text_range();
 
     acc.add(
-        AssistId("generate_default_from_new", crate::AssistKind::Generate),
+        AssistId::generate("generate_default_from_new"),
         "Generate a Default impl from a new fn",
         insert_location,
         move |builder| {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_methods.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_methods.rs
index 750f160ec2d..4794bf541fa 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_methods.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_methods.rs
@@ -92,19 +92,18 @@ pub(crate) fn generate_delegate_methods(acc: &mut Assists, ctx: &AssistContext<'
         });
     }
     methods.sort_by(|(a, _), (b, _)| a.cmp(b));
-    for (name, method) in methods {
+    for (index, (name, method)) in methods.into_iter().enumerate() {
         let adt = ast::Adt::Struct(strukt.clone());
         let name = name.display(ctx.db(), current_edition).to_string();
         // if `find_struct_impl` returns None, that means that a function named `name` already exists.
         let Some(impl_def) = find_struct_impl(ctx, &adt, std::slice::from_ref(&name)) else {
             continue;
         };
-
         let field = make::ext::field_from_idents(["self", &field_name])?;
 
         acc.add_group(
             &GroupLabel("Generate delegate methods…".to_owned()),
-            AssistId("generate_delegate_methods", AssistKind::Generate),
+            AssistId("generate_delegate_methods", AssistKind::Generate, Some(index)),
             format!("Generate delegate for `{field_name}.{name}()`",),
             target,
             |edit| {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_trait.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_trait.rs
index 5c39214617e..53a06ba1c6c 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_trait.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_trait.rs
@@ -201,7 +201,7 @@ impl Struct {
     pub(crate) fn delegate(&self, field: Field, acc: &mut Assists, ctx: &AssistContext<'_>) {
         let db = ctx.db();
 
-        for delegee in &field.impls {
+        for (index, delegee) in field.impls.iter().enumerate() {
             let trait_ = match delegee {
                 Delegee::Bound(b) => b,
                 Delegee::Impls(i, _) => i,
@@ -229,7 +229,11 @@ impl Struct {
 
             acc.add_group(
                 &GroupLabel(format!("Generate delegate trait impls for field `{}`", field.name)),
-                AssistId("generate_delegate_trait", ide_db::assists::AssistKind::Generate),
+                AssistId(
+                    "generate_delegate_trait",
+                    ide_db::assists::AssistKind::Generate,
+                    Some(index),
+                ),
                 format!("Generate delegate trait impl `{}` for `{}`", signature, field.name),
                 field.range,
                 |builder| {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_deref.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_deref.rs
index 7bf29978128..c7b97dcd231 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_deref.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_deref.rs
@@ -8,7 +8,7 @@ use syntax::{
 };
 
 use crate::{
-    AssistId, AssistKind,
+    AssistId,
     assist_context::{AssistContext, Assists, SourceChangeBuilder},
     utils::generate_trait_impl_text,
 };
@@ -65,7 +65,7 @@ fn generate_record_deref(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<(
     let field_name = field.name()?;
     let target = field.syntax().text_range();
     acc.add(
-        AssistId("generate_deref", AssistKind::Generate),
+        AssistId::generate("generate_deref"),
         format!("Generate `{deref_type_to_generate:?}` impl using `{field_name}`"),
         target,
         |edit| {
@@ -106,7 +106,7 @@ fn generate_tuple_deref(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()
     let field_type = field.ty()?;
     let target = field.syntax().text_range();
     acc.add(
-        AssistId("generate_deref", AssistKind::Generate),
+        AssistId::generate("generate_deref"),
         format!("Generate `{deref_type_to_generate:?}` impl using `{field}`"),
         target,
         |edit| {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_derive.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_derive.rs
index 8b4dbeff7cf..73a69c82fbc 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_derive.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_derive.rs
@@ -3,7 +3,7 @@ use syntax::{
     ast::{self, AstNode, HasAttrs, edit_in_place::AttrsOwnerEdit, make},
 };
 
-use crate::{AssistContext, AssistId, AssistKind, Assists};
+use crate::{AssistContext, AssistId, Assists};
 
 // Assist: generate_derive
 //
@@ -39,7 +39,7 @@ pub(crate) fn generate_derive(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opt
         Some(tt) => Some(tt.right_delimiter_token()?),
     };
 
-    acc.add(AssistId("generate_derive", AssistKind::Generate), "Add `#[derive]`", target, |edit| {
+    acc.add(AssistId::generate("generate_derive"), "Add `#[derive]`", target, |edit| {
         match derive_attr {
             None => {
                 let derive = make::attr_outer(make::meta_token_tree(
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_documentation_template.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_documentation_template.rs
index df05c0d6b2f..d4d1b3490cb 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_documentation_template.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_documentation_template.rs
@@ -1,5 +1,5 @@
 use hir::{AsAssocItem, HasVisibility, ModuleDef, Visibility};
-use ide_db::assists::{AssistId, AssistKind};
+use ide_db::assists::AssistId;
 use itertools::Itertools;
 use stdx::{format_to, to_lower_snake_case};
 use syntax::{
@@ -56,7 +56,7 @@ pub(crate) fn generate_documentation_template(
     let indent_level = IndentLevel::from_node(parent_syntax);
 
     acc.add(
-        AssistId("generate_documentation_template", AssistKind::Generate),
+        AssistId::generate("generate_documentation_template"),
         "Generate a documentation template",
         text_range,
         |builder| {
@@ -115,7 +115,7 @@ pub(crate) fn generate_doc_example(acc: &mut Assists, ctx: &AssistContext<'_>) -
     let indent_level = IndentLevel::from_node(&node);
 
     acc.add(
-        AssistId("generate_doc_example", AssistKind::Generate),
+        AssistId::generate("generate_doc_example"),
         "Generate a documentation example",
         node.text_range(),
         |builder| {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_enum_is_method.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_enum_is_method.rs
index 78fdca910c7..3e6d0bec68a 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_enum_is_method.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_enum_is_method.rs
@@ -4,7 +4,7 @@ use syntax::ast::HasVisibility;
 use syntax::ast::{self, AstNode, HasName};
 
 use crate::{
-    AssistContext, AssistId, AssistKind, Assists,
+    AssistContext, AssistId, Assists,
     utils::{add_method_to_adt, find_struct_impl},
 };
 
@@ -57,7 +57,7 @@ pub(crate) fn generate_enum_is_method(acc: &mut Assists, ctx: &AssistContext<'_>
     let target = variant.syntax().text_range();
     acc.add_group(
         &GroupLabel("Generate an `is_`,`as_`, or `try_into_` for this enum variant".to_owned()),
-        AssistId("generate_enum_is_method", AssistKind::Generate),
+        AssistId::generate("generate_enum_is_method"),
         "Generate an `is_` method for this enum variant",
         target,
         |builder| {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_enum_projection_method.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_enum_projection_method.rs
index e96be673a1b..3974bcf6187 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_enum_projection_method.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_enum_projection_method.rs
@@ -5,7 +5,7 @@ use syntax::ast::HasVisibility;
 use syntax::ast::{self, AstNode, HasName};
 
 use crate::{
-    AssistContext, AssistId, AssistKind, Assists,
+    AssistContext, AssistId, Assists,
     utils::{add_method_to_adt, find_struct_impl},
 };
 
@@ -153,7 +153,7 @@ fn generate_enum_projection_method(
     let target = variant.syntax().text_range();
     acc.add_group(
         &GroupLabel("Generate an `is_`,`as_`, or `try_into_` for this enum variant".to_owned()),
-        AssistId(assist_id, AssistKind::Generate),
+        AssistId::generate(assist_id),
         assist_description,
         target,
         |builder| {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_enum_variant.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_enum_variant.rs
index 51b6a4be019..8a20a2dd59d 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_enum_variant.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_enum_variant.rs
@@ -1,5 +1,5 @@
 use hir::{HasSource, HirDisplay, InRealFile};
-use ide_db::assists::{AssistId, AssistKind};
+use ide_db::assists::AssistId;
 use syntax::{
     AstNode, SyntaxNode,
     ast::{self, HasArgList, syntax_factory::SyntaxFactory},
@@ -58,21 +58,16 @@ pub(crate) fn generate_enum_variant(acc: &mut Assists, ctx: &AssistContext<'_>)
     let db = ctx.db();
     let InRealFile { file_id, value: enum_node } = e.source(db)?.original_ast_node_rooted(db)?;
 
-    acc.add(
-        AssistId("generate_enum_variant", AssistKind::Generate),
-        "Generate variant",
-        target,
-        |builder| {
-            let mut editor = builder.make_editor(enum_node.syntax());
-            let make = SyntaxFactory::new();
-            let field_list = parent.make_field_list(ctx, &make);
-            let variant = make.variant(None, make.name(&name_ref.text()), field_list, None);
-            if let Some(it) = enum_node.variant_list() {
-                it.add_variant(&mut editor, &variant);
-            }
-            builder.add_file_edits(file_id, editor);
-        },
-    )
+    acc.add(AssistId::generate("generate_enum_variant"), "Generate variant", target, |builder| {
+        let mut editor = builder.make_editor(enum_node.syntax());
+        let make = SyntaxFactory::new();
+        let field_list = parent.make_field_list(ctx, &make);
+        let variant = make.variant(None, make.name(&name_ref.text()), field_list, None);
+        if let Some(it) = enum_node.variant_list() {
+            it.add_variant(&mut editor, &variant);
+        }
+        builder.add_file_edits(file_id, editor);
+    })
 }
 
 #[derive(Debug)]
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_fn_type_alias.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_fn_type_alias.rs
index bc890ac53b8..7ece5f8ea5f 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_fn_type_alias.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_fn_type_alias.rs
@@ -1,5 +1,5 @@
 use either::Either;
-use ide_db::assists::{AssistId, AssistKind, GroupLabel};
+use ide_db::assists::{AssistId, GroupLabel};
 use syntax::{
     AstNode,
     ast::{self, HasGenericParams, HasName, edit::IndentLevel, make},
@@ -139,7 +139,7 @@ impl ParamStyle {
             ParamStyle::Unnamed => "generate_fn_type_alias_unnamed",
         };
 
-        AssistId(s, AssistKind::Generate)
+        AssistId::generate(s)
     }
 
     fn label(&self) -> &'static str {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_from_impl_for_enum.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_from_impl_for_enum.rs
index 88226820cf2..af949a06498 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_from_impl_for_enum.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_from_impl_for_enum.rs
@@ -1,9 +1,7 @@
 use ide_db::{RootDatabase, famous_defs::FamousDefs};
 use syntax::ast::{self, AstNode, HasName};
 
-use crate::{
-    AssistContext, AssistId, AssistKind, Assists, utils::generate_trait_impl_text_intransitive,
-};
+use crate::{AssistContext, AssistId, Assists, utils::generate_trait_impl_text_intransitive};
 
 // Assist: generate_from_impl_for_enum
 //
@@ -53,7 +51,7 @@ pub(crate) fn generate_from_impl_for_enum(
 
     let target = variant.syntax().text_range();
     acc.add(
-        AssistId("generate_from_impl_for_enum", AssistKind::Generate),
+        AssistId::generate("generate_from_impl_for_enum"),
         "Generate `From` impl for this enum variant",
         target,
         |edit| {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs
index a74d477ec89..55187c38c17 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs
@@ -23,7 +23,7 @@ use syntax::{
 };
 
 use crate::{
-    AssistContext, AssistId, AssistKind, Assists,
+    AssistContext, AssistId, Assists,
     utils::{convert_reference_type, find_struct_impl},
 };
 
@@ -173,7 +173,7 @@ fn add_func_to_accumulator(
     adt_info: Option<AdtInfo>,
     label: String,
 ) -> Option<()> {
-    acc.add(AssistId("generate_function", AssistKind::Generate), label, text_range, |edit| {
+    acc.add(AssistId::generate("generate_function"), label, text_range, |edit| {
         edit.edit_file(file);
 
         let target = function_builder.target.clone();
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_getter_or_setter.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_getter_or_setter.rs
index 8183a11e1ba..c7e5e41aac4 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_getter_or_setter.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_getter_or_setter.rs
@@ -7,7 +7,7 @@ use syntax::{
 };
 
 use crate::{
-    AssistContext, AssistId, AssistKind, Assists, GroupLabel,
+    AssistContext, AssistId, Assists, GroupLabel,
     utils::{convert_reference_type, find_struct_impl, generate_impl},
 };
 
@@ -63,7 +63,7 @@ pub(crate) fn generate_setter(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opt
 
     acc.add_group(
         &GroupLabel("Generate getter/setter".to_owned()),
-        AssistId("generate_setter", AssistKind::Generate),
+        AssistId::generate("generate_setter"),
         "Generate a setter method",
         target,
         |builder| build_source_change(builder, ctx, info_of_record_fields, setter_info),
@@ -204,7 +204,7 @@ pub(crate) fn generate_getter_impl(
 
     acc.add_group(
         &GroupLabel("Generate getter/setter".to_owned()),
-        AssistId(id, AssistKind::Generate),
+        AssistId::generate(id),
         label,
         target,
         |builder| build_source_change(builder, ctx, info_of_record_fields, getter_info),
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_impl.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_impl.rs
index ff4f388e39c..2862e6d5afb 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_impl.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_impl.rs
@@ -3,7 +3,7 @@ use syntax::{
     ted,
 };
 
-use crate::{AssistContext, AssistId, AssistKind, Assists, utils};
+use crate::{AssistContext, AssistId, Assists, utils};
 
 fn insert_impl(impl_: ast::Impl, nominal: &ast::Adt) {
     let indent = nominal.indent_level();
@@ -44,7 +44,7 @@ pub(crate) fn generate_impl(acc: &mut Assists, ctx: &AssistContext<'_>) -> Optio
     }
 
     acc.add(
-        AssistId("generate_impl", AssistKind::Generate),
+        AssistId::generate("generate_impl"),
         format!("Generate impl for `{name}`"),
         target,
         |edit| {
@@ -90,7 +90,7 @@ pub(crate) fn generate_trait_impl(acc: &mut Assists, ctx: &AssistContext<'_>) ->
     }
 
     acc.add(
-        AssistId("generate_trait_impl", AssistKind::Generate),
+        AssistId::generate("generate_trait_impl"),
         format!("Generate trait impl for `{name}`"),
         target,
         |edit| {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_is_empty_from_len.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_is_empty_from_len.rs
index d9ed8111c6f..f86c717fcce 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_is_empty_from_len.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_is_empty_from_len.rs
@@ -5,7 +5,7 @@ use syntax::{
 };
 
 use crate::{
-    AssistId, AssistKind,
+    AssistId,
     assist_context::{AssistContext, Assists},
 };
 
@@ -69,7 +69,7 @@ pub(crate) fn generate_is_empty_from_len(acc: &mut Assists, ctx: &AssistContext<
     let range = node.syntax().value.text_range();
 
     acc.add(
-        AssistId("generate_is_empty_from_len", AssistKind::Generate),
+        AssistId::generate("generate_is_empty_from_len"),
         "Generate a is_empty impl from a len function",
         range,
         |builder| {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_mut_trait_impl.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_mut_trait_impl.rs
index 8d107e41289..2ac960ed7e1 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_mut_trait_impl.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_mut_trait_impl.rs
@@ -5,7 +5,7 @@ use syntax::{
     ted,
 };
 
-use crate::{AssistContext, AssistId, AssistKind, Assists};
+use crate::{AssistContext, AssistId, Assists};
 
 // FIXME: Generate proper `index_mut` method body refer to `index` method body may impossible due to the unpredictable case [#15581].
 // Here just leave the `index_mut` method body be same as `index` method body, user can modify it manually to meet their need.
@@ -102,7 +102,7 @@ pub(crate) fn generate_mut_trait_impl(acc: &mut Assists, ctx: &AssistContext<'_>
 
     let target = impl_def.syntax().text_range();
     acc.add(
-        AssistId("generate_mut_trait_impl", AssistKind::Generate),
+        AssistId::generate("generate_mut_trait_impl"),
         "Generate `IndexMut` impl from this `Index` trait",
         target,
         |edit| {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_new.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_new.rs
index f14a4c10707..f963f48d62a 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_new.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_new.rs
@@ -7,7 +7,7 @@ use syntax::{
 };
 
 use crate::{
-    AssistContext, AssistId, AssistKind, Assists,
+    AssistContext, AssistId, Assists,
     utils::{find_struct_impl, generate_impl},
 };
 
@@ -48,7 +48,7 @@ pub(crate) fn generate_new(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option
     let current_module = ctx.sema.scope(strukt.syntax())?.module();
 
     let target = strukt.syntax().text_range();
-    acc.add(AssistId("generate_new", AssistKind::Generate), "Generate `new`", target, |builder| {
+    acc.add(AssistId::generate("generate_new"), "Generate `new`", target, |builder| {
         let trivial_constructors = field_list
             .fields()
             .map(|f| {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_trait_from_impl.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_trait_from_impl.rs
index 3470a4d660d..154b502e1bf 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_trait_from_impl.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_trait_from_impl.rs
@@ -95,7 +95,7 @@ pub(crate) fn generate_trait_from_impl(acc: &mut Assists, ctx: &AssistContext<'_
     let impl_name = impl_ast.self_ty()?;
 
     acc.add(
-        AssistId("generate_trait_from_impl", ide_db::assists::AssistKind::Generate),
+        AssistId::generate("generate_trait_from_impl"),
         "Generate trait from impl",
         impl_ast.syntax().text_range(),
         |builder| {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs
index b8381a8cce1..bb445e572be 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs
@@ -27,7 +27,7 @@ use syntax::{
 };
 
 use crate::{
-    AssistId, AssistKind,
+    AssistId,
     assist_context::{AssistContext, Assists},
 };
 
@@ -98,7 +98,7 @@ pub(crate) fn inline_into_callers(acc: &mut Assists, ctx: &AssistContext<'_>) ->
     }
 
     acc.add(
-        AssistId("inline_into_callers", AssistKind::RefactorInline),
+        AssistId::refactor_inline("inline_into_callers"),
         "Inline into all callers",
         name.syntax().text_range(),
         |builder| {
@@ -232,21 +232,16 @@ pub(crate) fn inline_call(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<
     }
 
     let syntax = call_info.node.syntax().clone();
-    acc.add(
-        AssistId("inline_call", AssistKind::RefactorInline),
-        label,
-        syntax.text_range(),
-        |builder| {
-            let replacement = inline(&ctx.sema, file_id, function, &fn_body, &params, &call_info);
-            builder.replace_ast(
-                match call_info.node {
-                    ast::CallableExpr::Call(it) => ast::Expr::CallExpr(it),
-                    ast::CallableExpr::MethodCall(it) => ast::Expr::MethodCallExpr(it),
-                },
-                replacement,
-            );
-        },
-    )
+    acc.add(AssistId::refactor_inline("inline_call"), label, syntax.text_range(), |builder| {
+        let replacement = inline(&ctx.sema, file_id, function, &fn_body, &params, &call_info);
+        builder.replace_ast(
+            match call_info.node {
+                ast::CallableExpr::Call(it) => ast::Expr::CallExpr(it),
+                ast::CallableExpr::MethodCall(it) => ast::Expr::MethodCallExpr(it),
+            },
+            replacement,
+        );
+    })
 }
 
 struct CallInfo {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_const_as_literal.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_const_as_literal.rs
index 10f9652cfe9..e5ed04fdc7c 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_const_as_literal.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_const_as_literal.rs
@@ -1,7 +1,7 @@
 use hir::HasCrate;
 use syntax::{AstNode, ast};
 
-use crate::{AssistContext, AssistId, AssistKind, Assists};
+use crate::{AssistContext, AssistId, Assists};
 
 // Assist: inline_const_as_literal
 //
@@ -44,7 +44,7 @@ pub(crate) fn inline_const_as_literal(acc: &mut Assists, ctx: &AssistContext<'_>
             .ok()?
             .render(ctx.sema.db, konst.krate(ctx.sema.db).to_display_target(ctx.sema.db));
 
-        let id = AssistId("inline_const_as_literal", AssistKind::RefactorInline);
+        let id = AssistId::refactor_inline("inline_const_as_literal");
 
         let label = "Inline const as literal".to_owned();
         let target = variable.syntax().text_range();
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_local_variable.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_local_variable.rs
index 8b7aa8f4af3..f1a3f72f7b9 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_local_variable.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_local_variable.rs
@@ -10,7 +10,7 @@ use syntax::{
 };
 
 use crate::{
-    AssistId, AssistKind,
+    AssistId,
     assist_context::{AssistContext, Assists},
 };
 
@@ -74,7 +74,7 @@ pub(crate) fn inline_local_variable(acc: &mut Assists, ctx: &AssistContext<'_>)
     };
 
     acc.add(
-        AssistId("inline_local_variable", AssistKind::RefactorInline),
+        AssistId::refactor_inline("inline_local_variable"),
         "Inline variable",
         target.text_range(),
         move |builder| {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_macro.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_macro.rs
index cd6f900ba15..37d9b340d08 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_macro.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_macro.rs
@@ -2,7 +2,7 @@ use hir::db::ExpandDatabase;
 use ide_db::syntax_helpers::prettify_macro_expansion;
 use syntax::ast::{self, AstNode};
 
-use crate::{AssistContext, AssistId, AssistKind, Assists};
+use crate::{AssistContext, AssistId, Assists};
 
 // Assist: inline_macro
 //
@@ -42,7 +42,7 @@ pub(crate) fn inline_macro(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option
     let text_range = unexpanded.syntax().text_range();
 
     acc.add(
-        AssistId("inline_macro", AssistKind::RefactorInline),
+        AssistId::refactor_inline("inline_macro"),
         "Inline macro".to_owned(),
         text_range,
         |builder| {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_type_alias.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_type_alias.rs
index 936b09d5a46..6a132e119e7 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_type_alias.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_type_alias.rs
@@ -16,7 +16,7 @@ use syntax::{
 };
 
 use crate::{
-    AssistId, AssistKind,
+    AssistId,
     assist_context::{AssistContext, Assists},
 };
 
@@ -60,7 +60,7 @@ pub(crate) fn inline_type_alias_uses(acc: &mut Assists, ctx: &AssistContext<'_>)
     // until this is ok
 
     acc.add(
-        AssistId("inline_type_alias_uses", AssistKind::RefactorInline),
+        AssistId::refactor_inline("inline_type_alias_uses"),
         "Inline type alias into all uses",
         name.syntax().text_range(),
         |builder| {
@@ -149,7 +149,7 @@ pub(crate) fn inline_type_alias(acc: &mut Assists, ctx: &AssistContext<'_>) -> O
     let target = alias_instance.syntax().text_range();
 
     acc.add(
-        AssistId("inline_type_alias", AssistKind::RefactorInline),
+        AssistId::refactor_inline("inline_type_alias"),
         "Inline type alias",
         target,
         |builder| builder.replace(target, replacement.to_text(&concrete_type)),
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/into_to_qualified_from.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/into_to_qualified_from.rs
index c8ec3da180b..47b273535a8 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/into_to_qualified_from.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/into_to_qualified_from.rs
@@ -1,8 +1,5 @@
 use hir::{AsAssocItem, HirDisplay};
-use ide_db::{
-    assists::{AssistId, AssistKind},
-    famous_defs::FamousDefs,
-};
+use ide_db::{assists::AssistId, famous_defs::FamousDefs};
 use syntax::{AstNode, ast};
 
 use crate::assist_context::{AssistContext, Assists};
@@ -60,7 +57,7 @@ pub(crate) fn into_to_qualified_from(acc: &mut Assists, ctx: &AssistContext<'_>)
 
         let sc = adjusted_tc.display_source_code(db, scope.module().into(), true).ok()?;
         acc.add(
-            AssistId("into_to_qualified_from", AssistKind::Generate),
+            AssistId::generate("into_to_qualified_from"),
             "Convert `into` to fully qualified `from`",
             nameref.syntax().text_range(),
             |edit| {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_lifetime.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_lifetime.rs
index 587e76585f1..264e3767a23 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_lifetime.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_lifetime.rs
@@ -5,7 +5,7 @@ use syntax::{
     ted::{self, Position},
 };
 
-use crate::{AssistContext, AssistId, AssistKind, Assists, assist_context::SourceChangeBuilder};
+use crate::{AssistContext, AssistId, Assists, assist_context::SourceChangeBuilder};
 
 static ASSIST_NAME: &str = "introduce_named_lifetime";
 static ASSIST_LABEL: &str = "Introduce named lifetime";
@@ -83,7 +83,7 @@ fn generate_fn_def_assist(
             _ => return None,
         }
     };
-    acc.add(AssistId(ASSIST_NAME, AssistKind::Refactor), ASSIST_LABEL, lifetime_loc, |builder| {
+    acc.add(AssistId::refactor(ASSIST_NAME), ASSIST_LABEL, lifetime_loc, |builder| {
         let fn_def = builder.make_mut(fn_def);
         let lifetime = builder.make_mut(lifetime);
         let loc_needing_lifetime =
@@ -107,7 +107,7 @@ fn generate_impl_def_assist(
     lifetime: ast::Lifetime,
 ) -> Option<()> {
     let new_lifetime_param = generate_unique_lifetime_param_name(impl_def.generic_param_list())?;
-    acc.add(AssistId(ASSIST_NAME, AssistKind::Refactor), ASSIST_LABEL, lifetime_loc, |builder| {
+    acc.add(AssistId::refactor(ASSIST_NAME), ASSIST_LABEL, lifetime_loc, |builder| {
         let impl_def = builder.make_mut(impl_def);
         let lifetime = builder.make_mut(lifetime);
 
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_type_parameter.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_type_parameter.rs
index d60106cc804..9c39a7aa41e 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_type_parameter.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_type_parameter.rs
@@ -2,7 +2,7 @@ use ide_db::syntax_helpers::suggest_name;
 use itertools::Itertools;
 use syntax::ast::{self, AstNode, HasGenericParams, HasName, syntax_factory::SyntaxFactory};
 
-use crate::{AssistContext, AssistId, AssistKind, Assists};
+use crate::{AssistContext, AssistId, Assists};
 
 // Assist: introduce_named_type_parameter
 //
@@ -27,7 +27,7 @@ pub(crate) fn introduce_named_type_parameter(
     let make = SyntaxFactory::new();
     let target = fn_.syntax().text_range();
     acc.add(
-        AssistId("introduce_named_type_parameter", AssistKind::RefactorRewrite),
+        AssistId::refactor_rewrite("introduce_named_type_parameter"),
         "Replace impl trait with type parameter",
         target,
         |builder| {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/invert_if.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/invert_if.rs
index 4273a85df5a..d198870b023 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/invert_if.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/invert_if.rs
@@ -5,7 +5,7 @@ use syntax::{
 };
 
 use crate::{
-    AssistId, AssistKind,
+    AssistId,
     assist_context::{AssistContext, Assists},
     utils::invert_boolean_expression_legacy,
 };
@@ -47,7 +47,7 @@ pub(crate) fn invert_if(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()
         ast::ElseBranch::IfExpr(_) => return None,
     };
 
-    acc.add(AssistId("invert_if", AssistKind::RefactorRewrite), "Invert if", if_range, |edit| {
+    acc.add(AssistId::refactor_rewrite("invert_if"), "Invert if", if_range, |edit| {
         let flip_cond = invert_boolean_expression_legacy(cond.clone());
         edit.replace_ast(cond, flip_cond);
 
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_imports.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_imports.rs
index aae007577c2..b7f7cb9cb01 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_imports.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_imports.rs
@@ -12,7 +12,7 @@ use syntax::{
 };
 
 use crate::{
-    AssistId, AssistKind,
+    AssistId,
     assist_context::{AssistContext, Assists},
     utils::next_prev,
 };
@@ -69,55 +69,50 @@ pub(crate) fn merge_imports(acc: &mut Assists, ctx: &AssistContext<'_>) -> Optio
         (selection_range, edits?)
     };
 
-    acc.add(
-        AssistId("merge_imports", AssistKind::RefactorRewrite),
-        "Merge imports",
-        target,
-        |builder| {
-            let edits_mut: Vec<Edit> = edits
-                .into_iter()
-                .map(|it| match it {
-                    Remove(Either::Left(it)) => Remove(Either::Left(builder.make_mut(it))),
-                    Remove(Either::Right(it)) => Remove(Either::Right(builder.make_mut(it))),
-                    Replace(old, new) => Replace(builder.make_syntax_mut(old), new),
-                })
-                .collect();
-            for edit in edits_mut {
-                match edit {
-                    Remove(it) => it.as_ref().either(Removable::remove, Removable::remove),
-                    Replace(old, new) => {
-                        ted::replace(old, &new);
-
-                        // If there's a selection and we're replacing a use tree in a tree list,
-                        // normalize the parent use tree if it only contains the merged subtree.
-                        if !ctx.has_empty_selection() {
-                            let normalized_use_tree = ast::UseTree::cast(new)
-                                .as_ref()
-                                .and_then(ast::UseTree::parent_use_tree_list)
-                                .and_then(|use_tree_list| {
-                                    if use_tree_list.use_trees().collect_tuple::<(_,)>().is_some() {
-                                        Some(use_tree_list.parent_use_tree())
-                                    } else {
-                                        None
-                                    }
-                                })
-                                .and_then(|target_tree| {
-                                    try_normalize_use_tree(
-                                        &target_tree,
-                                        ctx.config.insert_use.granularity.into(),
-                                    )
-                                    .map(|top_use_tree_flat| (target_tree, top_use_tree_flat))
-                                });
-                            if let Some((old_tree, new_tree)) = normalized_use_tree {
-                                cov_mark::hit!(replace_parent_with_normalized_use_tree);
-                                ted::replace(old_tree.syntax(), new_tree.syntax());
-                            }
+    acc.add(AssistId::refactor_rewrite("merge_imports"), "Merge imports", target, |builder| {
+        let edits_mut: Vec<Edit> = edits
+            .into_iter()
+            .map(|it| match it {
+                Remove(Either::Left(it)) => Remove(Either::Left(builder.make_mut(it))),
+                Remove(Either::Right(it)) => Remove(Either::Right(builder.make_mut(it))),
+                Replace(old, new) => Replace(builder.make_syntax_mut(old), new),
+            })
+            .collect();
+        for edit in edits_mut {
+            match edit {
+                Remove(it) => it.as_ref().either(Removable::remove, Removable::remove),
+                Replace(old, new) => {
+                    ted::replace(old, &new);
+
+                    // If there's a selection and we're replacing a use tree in a tree list,
+                    // normalize the parent use tree if it only contains the merged subtree.
+                    if !ctx.has_empty_selection() {
+                        let normalized_use_tree = ast::UseTree::cast(new)
+                            .as_ref()
+                            .and_then(ast::UseTree::parent_use_tree_list)
+                            .and_then(|use_tree_list| {
+                                if use_tree_list.use_trees().collect_tuple::<(_,)>().is_some() {
+                                    Some(use_tree_list.parent_use_tree())
+                                } else {
+                                    None
+                                }
+                            })
+                            .and_then(|target_tree| {
+                                try_normalize_use_tree(
+                                    &target_tree,
+                                    ctx.config.insert_use.granularity.into(),
+                                )
+                                .map(|top_use_tree_flat| (target_tree, top_use_tree_flat))
+                            });
+                        if let Some((old_tree, new_tree)) = normalized_use_tree {
+                            cov_mark::hit!(replace_parent_with_normalized_use_tree);
+                            ted::replace(old_tree.syntax(), new_tree.syntax());
                         }
                     }
                 }
             }
-        },
-    )
+        }
+    })
 }
 
 trait Merge: AstNode + Clone {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_match_arms.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_match_arms.rs
index be73377070f..42f35210b49 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_match_arms.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_match_arms.rs
@@ -7,7 +7,7 @@ use syntax::{
     ast::{self, AstNode, HasName},
 };
 
-use crate::{AssistContext, AssistId, AssistKind, Assists, TextRange};
+use crate::{AssistContext, AssistId, Assists, TextRange};
 
 // Assist: merge_match_arms
 //
@@ -73,7 +73,7 @@ pub(crate) fn merge_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op
     }
 
     acc.add(
-        AssistId("merge_match_arms", AssistKind::RefactorRewrite),
+        AssistId::refactor_rewrite("merge_match_arms"),
         "Merge match arms",
         current_text_range,
         |edit| {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_nested_if.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_nested_if.rs
index 89bd62a084a..73cb8204f20 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_nested_if.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_nested_if.rs
@@ -5,7 +5,7 @@ use syntax::{
 };
 
 use crate::{
-    AssistId, AssistKind,
+    AssistId,
     assist_context::{AssistContext, Assists},
 };
 // Assist: merge_nested_if
@@ -69,29 +69,24 @@ pub(crate) fn merge_nested_if(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opt
     let nested_if_then_branch = nested_if_to_merge.then_branch()?;
     let then_branch_range = then_branch.syntax().text_range();
 
-    acc.add(
-        AssistId("merge_nested_if", AssistKind::RefactorRewrite),
-        "Merge nested if",
-        if_range,
-        |edit| {
-            let cond_text = if has_logic_op_or(&cond) {
-                format!("({})", cond.syntax().text())
-            } else {
-                cond.syntax().text().to_string()
-            };
+    acc.add(AssistId::refactor_rewrite("merge_nested_if"), "Merge nested if", if_range, |edit| {
+        let cond_text = if has_logic_op_or(&cond) {
+            format!("({})", cond.syntax().text())
+        } else {
+            cond.syntax().text().to_string()
+        };
 
-            let nested_if_cond_text = if has_logic_op_or(&nested_if_cond) {
-                format!("({})", nested_if_cond.syntax().text())
-            } else {
-                nested_if_cond.syntax().text().to_string()
-            };
+        let nested_if_cond_text = if has_logic_op_or(&nested_if_cond) {
+            format!("({})", nested_if_cond.syntax().text())
+        } else {
+            nested_if_cond.syntax().text().to_string()
+        };
 
-            let replace_cond = format!("{cond_text} && {nested_if_cond_text}");
+        let replace_cond = format!("{cond_text} && {nested_if_cond_text}");
 
-            edit.replace(cond_range, replace_cond);
-            edit.replace(then_branch_range, nested_if_then_branch.syntax().text());
-        },
-    )
+        edit.replace(cond_range, replace_cond);
+        edit.replace(then_branch_range, nested_if_then_branch.syntax().text());
+    })
 }
 
 /// Returns whether the given if condition has logical operators.
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_bounds.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_bounds.rs
index 35571ed8341..7e8735bd7a2 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_bounds.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_bounds.rs
@@ -7,7 +7,7 @@ use syntax::{
     match_ast,
 };
 
-use crate::{AssistContext, AssistId, AssistKind, Assists};
+use crate::{AssistContext, AssistId, Assists};
 
 // Assist: move_bounds_to_where_clause
 //
@@ -42,7 +42,7 @@ pub(crate) fn move_bounds_to_where_clause(
 
     let target = type_param_list.syntax().text_range();
     acc.add(
-        AssistId("move_bounds_to_where_clause", AssistKind::RefactorRewrite),
+        AssistId::refactor_rewrite("move_bounds_to_where_clause"),
         "Move to where clause",
         target,
         |edit| {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_const_to_impl.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_const_to_impl.rs
index 71b1461a6ea..5c9318f5cf5 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_const_to_impl.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_const_to_impl.rs
@@ -83,7 +83,7 @@ pub(crate) fn move_const_to_impl(acc: &mut Assists, ctx: &AssistContext<'_>) ->
     }
 
     acc.add(
-        AssistId("move_const_to_impl", crate::AssistKind::RefactorRewrite),
+        AssistId::refactor_rewrite("move_const_to_impl"),
         "Move const to impl block",
         const_.syntax().text_range(),
         |builder| {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_from_mod_rs.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_from_mod_rs.rs
index 0d6fc49e5fe..00469f07ba7 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_from_mod_rs.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_from_mod_rs.rs
@@ -1,7 +1,4 @@
-use ide_db::{
-    assists::{AssistId, AssistKind},
-    base_db::AnchoredPathBuf,
-};
+use ide_db::{assists::AssistId, base_db::AnchoredPathBuf};
 use syntax::{AstNode, ToSmolStr, ast};
 
 use crate::{
@@ -43,7 +40,7 @@ pub(crate) fn move_from_mod_rs(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op
     let path = format!("../{module_name}.rs");
     let dst = AnchoredPathBuf { anchor: ctx.file_id().into(), path };
     acc.add(
-        AssistId("move_from_mod_rs", AssistKind::Refactor),
+        AssistId::refactor("move_from_mod_rs"),
         format!("Convert {module_name}/mod.rs to {module_name}.rs"),
         target,
         |builder| {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_guard.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_guard.rs
index abba3de4a1f..644d1f6cafe 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_guard.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_guard.rs
@@ -3,7 +3,7 @@ use syntax::{
     ast::{AstNode, BlockExpr, ElseBranch, Expr, IfExpr, MatchArm, Pat, edit::AstNodeEdit, make},
 };
 
-use crate::{AssistContext, AssistId, AssistKind, Assists};
+use crate::{AssistContext, AssistId, Assists};
 
 // Assist: move_guard_to_arm_body
 //
@@ -49,7 +49,7 @@ pub(crate) fn move_guard_to_arm_body(acc: &mut Assists, ctx: &AssistContext<'_>)
 
     let target = guard.syntax().text_range();
     acc.add(
-        AssistId("move_guard_to_arm_body", AssistKind::RefactorRewrite),
+        AssistId::refactor_rewrite("move_guard_to_arm_body"),
         "Move guard to arm body",
         target,
         |edit| {
@@ -118,7 +118,7 @@ pub(crate) fn move_arm_cond_to_match_guard(
     let (conds_blocks, tail) = parse_if_chain(if_expr)?;
 
     acc.add(
-        AssistId("move_arm_cond_to_match_guard", AssistKind::RefactorRewrite),
+        AssistId::refactor_rewrite("move_arm_cond_to_match_guard"),
         "Move condition to match guard",
         replace_node.text_range(),
         |edit| {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_module_to_file.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_module_to_file.rs
index 5f547593b43..cfca89fce46 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_module_to_file.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_module_to_file.rs
@@ -10,7 +10,7 @@ use syntax::{
     ast::{self, HasName, edit::AstNodeEdit},
 };
 
-use crate::{AssistContext, AssistId, AssistKind, Assists};
+use crate::{AssistContext, AssistId, Assists};
 
 // Assist: move_module_to_file
 //
@@ -45,7 +45,7 @@ pub(crate) fn move_module_to_file(acc: &mut Assists, ctx: &AssistContext<'_>) ->
     let parent_module = module_def.parent(ctx.db())?;
 
     acc.add(
-        AssistId("move_module_to_file", AssistKind::RefactorExtract),
+        AssistId::refactor_extract("move_module_to_file"),
         "Extract module to file",
         target,
         |builder| {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_to_mod_rs.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_to_mod_rs.rs
index a19c122ddf0..ffa3894fe5a 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_to_mod_rs.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_to_mod_rs.rs
@@ -1,7 +1,4 @@
-use ide_db::{
-    assists::{AssistId, AssistKind},
-    base_db::AnchoredPathBuf,
-};
+use ide_db::{assists::AssistId, base_db::AnchoredPathBuf};
 use syntax::{AstNode, ToSmolStr, ast};
 
 use crate::{
@@ -43,7 +40,7 @@ pub(crate) fn move_to_mod_rs(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti
     let path = format!("./{module_name}/mod.rs");
     let dst = AnchoredPathBuf { anchor: ctx.file_id().into(), path };
     acc.add(
-        AssistId("move_to_mod_rs", AssistKind::Refactor),
+        AssistId::refactor("move_to_mod_rs"),
         format!("Convert {module_name}.rs to {module_name}/mod.rs"),
         target,
         |builder| {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/normalize_import.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/normalize_import.rs
index 813c2dd191d..bba28b5fc8a 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/normalize_import.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/normalize_import.rs
@@ -2,7 +2,7 @@ use ide_db::imports::merge_imports::try_normalize_import;
 use syntax::{AstNode, ast};
 
 use crate::{
-    AssistId, AssistKind,
+    AssistId,
     assist_context::{AssistContext, Assists},
 };
 
@@ -28,14 +28,9 @@ pub(crate) fn normalize_import(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op
     let normalized_use_item =
         try_normalize_import(&use_item, ctx.config.insert_use.granularity.into())?;
 
-    acc.add(
-        AssistId("normalize_import", AssistKind::RefactorRewrite),
-        "Normalize import",
-        target,
-        |builder| {
-            builder.replace_ast(use_item, normalized_use_item);
-        },
-    )
+    acc.add(AssistId::refactor_rewrite("normalize_import"), "Normalize import", target, |builder| {
+        builder.replace_ast(use_item, normalized_use_item);
+    })
 }
 
 #[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/number_representation.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/number_representation.rs
index 9b81aecd7da..1fe40f8ee83 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/number_representation.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/number_representation.rs
@@ -1,6 +1,6 @@
 use syntax::{AstToken, ast, ast::Radix};
 
-use crate::{AssistContext, AssistId, AssistKind, Assists, GroupLabel};
+use crate::{AssistContext, AssistId, Assists, GroupLabel};
 
 const MIN_NUMBER_OF_DIGITS_TO_FORMAT: usize = 5;
 
@@ -42,7 +42,7 @@ pub(crate) fn reformat_number_literal(acc: &mut Assists, ctx: &AssistContext<'_>
     let range = literal.syntax().text_range();
     acc.add_group(
         &group_id,
-        AssistId("reformat_number_literal", AssistKind::RefactorInline),
+        AssistId::refactor_inline("reformat_number_literal"),
         label,
         range,
         |builder| builder.replace(range, converted),
@@ -54,7 +54,7 @@ fn remove_separators(acc: &mut Assists, literal: ast::IntNumber) -> Option<()> {
     let range = literal.syntax().text_range();
     acc.add_group(
         &group_id,
-        AssistId("reformat_number_literal", AssistKind::RefactorInline),
+        AssistId::refactor_inline("reformat_number_literal"),
         "Remove digit separators",
         range,
         |builder| builder.replace(range, literal.text().replace('_', "")),
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/promote_local_to_const.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/promote_local_to_const.rs
index 04a19d7869c..6316a8f0db2 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/promote_local_to_const.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/promote_local_to_const.rs
@@ -1,8 +1,5 @@
 use hir::HirDisplay;
-use ide_db::{
-    assists::{AssistId, AssistKind},
-    defs::Definition,
-};
+use ide_db::{assists::AssistId, defs::Definition};
 use stdx::to_upper_snake_case;
 use syntax::{
     AstNode,
@@ -68,7 +65,7 @@ pub(crate) fn promote_local_to_const(acc: &mut Assists, ctx: &AssistContext<'_>)
     }
 
     acc.add(
-        AssistId("promote_local_to_const", AssistKind::Refactor),
+        AssistId::refactor("promote_local_to_const"),
         "Promote local to constant",
         let_stmt.syntax().text_range(),
         |edit| {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/pull_assignment_up.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/pull_assignment_up.rs
index d9e71ec763d..5f626d29571 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/pull_assignment_up.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/pull_assignment_up.rs
@@ -5,7 +5,7 @@ use syntax::{
 };
 
 use crate::{
-    AssistId, AssistKind,
+    AssistId,
     assist_context::{AssistContext, Assists},
 };
 
@@ -68,7 +68,7 @@ pub(crate) fn pull_assignment_up(acc: &mut Assists, ctx: &AssistContext<'_>) ->
     }
 
     acc.add(
-        AssistId("pull_assignment_up", AssistKind::RefactorExtract),
+        AssistId::refactor_extract("pull_assignment_up"),
         "Pull assignment up",
         tgt.syntax().text_range(),
         move |edit| {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/qualify_method_call.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/qualify_method_call.rs
index d8ade0eb871..985121780b1 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/qualify_method_call.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/qualify_method_call.rs
@@ -1,5 +1,5 @@
 use hir::{AsAssocItem, AssocItem, AssocItemContainer, ItemInNs, ModuleDef, db::HirDatabase};
-use ide_db::assists::{AssistId, AssistKind};
+use ide_db::assists::AssistId;
 use syntax::{AstNode, ast};
 
 use crate::{
@@ -54,7 +54,7 @@ pub(crate) fn qualify_method_call(acc: &mut Assists, ctx: &AssistContext<'_>) ->
     let qualify_candidate = QualifyCandidate::ImplMethod(ctx.sema.db, call, resolved_call);
 
     acc.add(
-        AssistId("qualify_method_call", AssistKind::RefactorRewrite),
+        AssistId::refactor_rewrite("qualify_method_call"),
         format!("Qualify `{ident}` method call"),
         range,
         |builder| {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/qualify_path.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/qualify_path.rs
index a4f066ad364..4c213a27f4b 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/qualify_path.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/qualify_path.rs
@@ -15,7 +15,7 @@ use syntax::{
 };
 
 use crate::{
-    AssistId, AssistKind, GroupLabel,
+    AssistId, GroupLabel,
     assist_context::{AssistContext, Assists},
     handlers::auto_import::find_importable_node,
 };
@@ -104,7 +104,7 @@ pub(crate) fn qualify_path(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option
     for import in proposed_imports {
         acc.add_group(
             &group_label,
-            AssistId("qualify_path", AssistKind::QuickFix),
+            AssistId::quick_fix("qualify_path"),
             label(ctx.db(), candidate, &import, current_edition),
             range,
             |builder| {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/raw_string.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/raw_string.rs
index 21c697f5386..ed86380a56c 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/raw_string.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/raw_string.rs
@@ -2,7 +2,7 @@ use std::borrow::Cow;
 
 use syntax::{AstToken, TextRange, TextSize, ast, ast::IsString};
 
-use crate::{AssistContext, AssistId, AssistKind, Assists, utils::required_hashes};
+use crate::{AssistContext, AssistId, Assists, utils::required_hashes};
 
 // Assist: make_raw_string
 //
@@ -28,7 +28,7 @@ pub(crate) fn make_raw_string(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opt
     let value = token.value().ok()?;
     let target = token.syntax().text_range();
     acc.add(
-        AssistId("make_raw_string", AssistKind::RefactorRewrite),
+        AssistId::refactor_rewrite("make_raw_string"),
         "Rewrite as raw string",
         target,
         |edit| {
@@ -67,7 +67,7 @@ pub(crate) fn make_usual_string(acc: &mut Assists, ctx: &AssistContext<'_>) -> O
     let value = token.value().ok()?;
     let target = token.syntax().text_range();
     acc.add(
-        AssistId("make_usual_string", AssistKind::RefactorRewrite),
+        AssistId::refactor_rewrite("make_usual_string"),
         "Rewrite as regular string",
         target,
         |edit| {
@@ -108,7 +108,7 @@ pub(crate) fn add_hash(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()>
     }
     let text_range = token.syntax().text_range();
     let target = text_range;
-    acc.add(AssistId("add_hash", AssistKind::Refactor), "Add #", target, |edit| {
+    acc.add(AssistId::refactor("add_hash"), "Add #", target, |edit| {
         edit.insert(text_range.start() + TextSize::of('r'), "#");
         edit.insert(text_range.end(), "#");
     })
@@ -150,7 +150,7 @@ pub(crate) fn remove_hash(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<
         return None;
     }
 
-    acc.add(AssistId("remove_hash", AssistKind::RefactorRewrite), "Remove #", text_range, |edit| {
+    acc.add(AssistId::refactor_rewrite("remove_hash"), "Remove #", text_range, |edit| {
         edit.delete(TextRange::at(text_range.start() + TextSize::of('r'), TextSize::of('#')));
         edit.delete(TextRange::new(text_range.end() - TextSize::of('#'), text_range.end()));
     })
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_dbg.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_dbg.rs
index cbc2e4f0047..809ef6dae31 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_dbg.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_dbg.rs
@@ -5,7 +5,7 @@ use syntax::{
     match_ast, ted,
 };
 
-use crate::{AssistContext, AssistId, AssistKind, Assists};
+use crate::{AssistContext, AssistId, Assists};
 
 // Assist: remove_dbg
 //
@@ -42,7 +42,7 @@ pub(crate) fn remove_dbg(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<(
         macro_calls.into_iter().filter_map(compute_dbg_replacement).collect::<Vec<_>>();
 
     acc.add(
-        AssistId("remove_dbg", AssistKind::QuickFix),
+        AssistId::quick_fix("remove_dbg"),
         "Remove dbg!()",
         replacements.iter().map(|&(range, _)| range).reduce(|acc, range| acc.cover(range))?,
         |builder| {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_mut.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_mut.rs
index 43740a5a6d5..1b2a8336a84 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_mut.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_mut.rs
@@ -1,6 +1,6 @@
 use syntax::{SyntaxKind, T};
 
-use crate::{AssistContext, AssistId, AssistKind, Assists};
+use crate::{AssistContext, AssistId, Assists};
 
 // Assist: remove_mut
 //
@@ -21,18 +21,13 @@ pub(crate) fn remove_mut(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<(
     let mut_token = ctx.find_token_syntax_at_offset(T![mut])?;
 
     let target = mut_token.text_range();
-    acc.add(
-        AssistId("remove_mut", AssistKind::Refactor),
-        "Remove `mut` keyword",
-        target,
-        |builder| {
-            let mut editor = builder.make_editor(&mut_token.parent().unwrap());
-            match mut_token.next_token() {
-                Some(it) if it.kind() == SyntaxKind::WHITESPACE => editor.delete(it),
-                _ => (),
-            }
-            editor.delete(mut_token);
-            builder.add_file_edits(ctx.file_id(), editor);
-        },
-    )
+    acc.add(AssistId::refactor("remove_mut"), "Remove `mut` keyword", target, |builder| {
+        let mut editor = builder.make_editor(&mut_token.parent().unwrap());
+        match mut_token.next_token() {
+            Some(it) if it.kind() == SyntaxKind::WHITESPACE => editor.delete(it),
+            _ => (),
+        }
+        editor.delete(mut_token);
+        builder.add_file_edits(ctx.file_id(), editor);
+    })
 }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_parentheses.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_parentheses.rs
index 9bd8decbedc..f5b3e003be0 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_parentheses.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_parentheses.rs
@@ -4,7 +4,7 @@ use syntax::{
     syntax_editor::Position,
 };
 
-use crate::{AssistContext, AssistId, AssistKind, Assists};
+use crate::{AssistContext, AssistId, Assists};
 
 // Assist: remove_parentheses
 //
@@ -40,7 +40,7 @@ pub(crate) fn remove_parentheses(acc: &mut Assists, ctx: &AssistContext<'_>) ->
 
     let target = parens.syntax().text_range();
     acc.add(
-        AssistId("remove_parentheses", AssistKind::Refactor),
+        AssistId::refactor("remove_parentheses"),
         "Remove redundant parentheses",
         target,
         |builder| {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs
index 01c4eedd3e2..09697eb9b29 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs
@@ -12,7 +12,7 @@ use syntax::{
     ast::{self, Rename},
 };
 
-use crate::{AssistContext, AssistId, AssistKind, Assists};
+use crate::{AssistContext, AssistId, Assists};
 
 // Assist: remove_unused_imports
 //
@@ -126,7 +126,7 @@ pub(crate) fn remove_unused_imports(acc: &mut Assists, ctx: &AssistContext<'_>)
     // Peek so we terminate early if an unused use is found. Only do the rest of the work if the user selects the assist.
     if unused.peek().is_some() {
         acc.add(
-            AssistId("remove_unused_imports", AssistKind::QuickFix),
+            AssistId::quick_fix("remove_unused_imports"),
             "Remove all the unused imports",
             selected_el.text_range(),
             |builder| {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_param.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_param.rs
index 6ebc9007cf1..5ed1efe614b 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_param.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_param.rs
@@ -11,8 +11,7 @@ use syntax::{
 use SyntaxKind::WHITESPACE;
 
 use crate::{
-    AssistContext, AssistId, AssistKind, Assists, assist_context::SourceChangeBuilder,
-    utils::next_prev,
+    AssistContext, AssistId, Assists, assist_context::SourceChangeBuilder, utils::next_prev,
 };
 
 // Assist: remove_unused_param
@@ -79,7 +78,7 @@ pub(crate) fn remove_unused_param(acc: &mut Assists, ctx: &AssistContext<'_>) ->
     }
     let parent = param.syntax().parent()?;
     acc.add(
-        AssistId("remove_unused_param", AssistKind::Refactor),
+        AssistId::refactor("remove_unused_param"),
         "Remove unused parameter",
         param.syntax().text_range(),
         |builder| {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_fields.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_fields.rs
index 410e2bbbdff..1951d007ca4 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_fields.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_fields.rs
@@ -3,7 +3,7 @@ use ide_db::FxHashMap;
 use itertools::Itertools;
 use syntax::{AstNode, SmolStr, SyntaxElement, ToSmolStr, ast, syntax_editor::SyntaxEditor};
 
-use crate::{AssistContext, AssistId, AssistKind, Assists};
+use crate::{AssistContext, AssistId, Assists};
 
 // Assist: reorder_fields
 //
@@ -67,7 +67,7 @@ pub(crate) fn reorder_fields(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti
     }
     let target = record.as_ref().either(AstNode::syntax, AstNode::syntax).text_range();
     acc.add(
-        AssistId("reorder_fields", AssistKind::RefactorRewrite),
+        AssistId::refactor_rewrite("reorder_fields"),
         "Reorder record fields",
         target,
         |builder| {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_impl_items.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_impl_items.rs
index e254fb9949d..1222ba928c8 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_impl_items.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_impl_items.rs
@@ -6,7 +6,7 @@ use syntax::{
     ast::{self, HasName},
 };
 
-use crate::{AssistContext, AssistId, AssistKind, Assists};
+use crate::{AssistContext, AssistId, Assists};
 
 // Assist: reorder_impl_items
 //
@@ -95,7 +95,7 @@ pub(crate) fn reorder_impl_items(acc: &mut Assists, ctx: &AssistContext<'_>) ->
 
     let target = items.syntax().text_range();
     acc.add(
-        AssistId("reorder_impl_items", AssistKind::RefactorRewrite),
+        AssistId::refactor_rewrite("reorder_impl_items"),
         "Sort items by trait definition",
         target,
         |builder| {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_arith_op.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_arith_op.rs
index 39f350fb68d..6b385a03625 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_arith_op.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_arith_op.rs
@@ -1,4 +1,4 @@
-use ide_db::assists::{AssistId, AssistKind, GroupLabel};
+use ide_db::assists::{AssistId, GroupLabel};
 use syntax::{
     AstNode, TextRange,
     ast::{self, ArithOp, BinaryOp},
@@ -132,7 +132,7 @@ impl ArithKind {
             ArithKind::Wrapping => "replace_arith_with_wrapping",
         };
 
-        AssistId(s, AssistKind::RefactorRewrite)
+        AssistId::refactor_rewrite(s)
     }
 
     fn label(&self) -> &'static str {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs
index c5faf6d3e01..691ae931f8a 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs
@@ -9,7 +9,7 @@ use syntax::{
 };
 
 use crate::{
-    AssistId, AssistKind,
+    AssistId,
     assist_context::{AssistContext, Assists, SourceChangeBuilder},
     utils::{
         DefaultMethods, IgnoreAssocItems, add_trait_assoc_items_to_impl, filter_assoc_items,
@@ -125,101 +125,94 @@ fn add_assist(
     let annotated_name = adt.name()?;
     let label = format!("Convert to manual `impl {replace_trait_path} for {annotated_name}`");
 
-    acc.add(
-        AssistId("replace_derive_with_manual_impl", AssistKind::Refactor),
-        label,
-        target,
-        |builder| {
-            let insert_after = ted::Position::after(builder.make_mut(adt.clone()).syntax());
-            let impl_is_unsafe = trait_.map(|s| s.is_unsafe(ctx.db())).unwrap_or(false);
-            let impl_def_with_items =
-                impl_def_from_trait(&ctx.sema, adt, &annotated_name, trait_, replace_trait_path);
-            update_attribute(builder, old_derives, old_tree, old_trait_path, attr);
-
-            let trait_path = make::ty_path(replace_trait_path.clone());
-
-            match (ctx.config.snippet_cap, impl_def_with_items) {
-                (None, None) => {
-                    let impl_def = generate_trait_impl(adt, trait_path);
-                    if impl_is_unsafe {
-                        ted::insert(
-                            Position::first_child_of(impl_def.syntax()),
-                            make::token(T![unsafe]),
-                        );
-                    }
+    acc.add(AssistId::refactor("replace_derive_with_manual_impl"), label, target, |builder| {
+        let insert_after = ted::Position::after(builder.make_mut(adt.clone()).syntax());
+        let impl_is_unsafe = trait_.map(|s| s.is_unsafe(ctx.db())).unwrap_or(false);
+        let impl_def_with_items =
+            impl_def_from_trait(&ctx.sema, adt, &annotated_name, trait_, replace_trait_path);
+        update_attribute(builder, old_derives, old_tree, old_trait_path, attr);
+
+        let trait_path = make::ty_path(replace_trait_path.clone());
+
+        match (ctx.config.snippet_cap, impl_def_with_items) {
+            (None, None) => {
+                let impl_def = generate_trait_impl(adt, trait_path);
+                if impl_is_unsafe {
+                    ted::insert(
+                        Position::first_child_of(impl_def.syntax()),
+                        make::token(T![unsafe]),
+                    );
+                }
 
-                    ted::insert_all(
-                        insert_after,
-                        vec![make::tokens::blank_line().into(), impl_def.syntax().clone().into()],
+                ted::insert_all(
+                    insert_after,
+                    vec![make::tokens::blank_line().into(), impl_def.syntax().clone().into()],
+                );
+            }
+            (None, Some((impl_def, _))) => {
+                if impl_is_unsafe {
+                    ted::insert(
+                        Position::first_child_of(impl_def.syntax()),
+                        make::token(T![unsafe]),
                     );
                 }
-                (None, Some((impl_def, _))) => {
-                    if impl_is_unsafe {
-                        ted::insert(
-                            Position::first_child_of(impl_def.syntax()),
-                            make::token(T![unsafe]),
-                        );
-                    }
-                    ted::insert_all(
-                        insert_after,
-                        vec![make::tokens::blank_line().into(), impl_def.syntax().clone().into()],
+                ted::insert_all(
+                    insert_after,
+                    vec![make::tokens::blank_line().into(), impl_def.syntax().clone().into()],
+                );
+            }
+            (Some(cap), None) => {
+                let impl_def = generate_trait_impl(adt, trait_path);
+
+                if impl_is_unsafe {
+                    ted::insert(
+                        Position::first_child_of(impl_def.syntax()),
+                        make::token(T![unsafe]),
                     );
                 }
-                (Some(cap), None) => {
-                    let impl_def = generate_trait_impl(adt, trait_path);
-
-                    if impl_is_unsafe {
-                        ted::insert(
-                            Position::first_child_of(impl_def.syntax()),
-                            make::token(T![unsafe]),
-                        );
-                    }
 
-                    if let Some(l_curly) =
-                        impl_def.assoc_item_list().and_then(|it| it.l_curly_token())
-                    {
-                        builder.add_tabstop_after_token(cap, l_curly);
-                    }
+                if let Some(l_curly) = impl_def.assoc_item_list().and_then(|it| it.l_curly_token())
+                {
+                    builder.add_tabstop_after_token(cap, l_curly);
+                }
 
-                    ted::insert_all(
-                        insert_after,
-                        vec![make::tokens::blank_line().into(), impl_def.syntax().clone().into()],
+                ted::insert_all(
+                    insert_after,
+                    vec![make::tokens::blank_line().into(), impl_def.syntax().clone().into()],
+                );
+            }
+            (Some(cap), Some((impl_def, first_assoc_item))) => {
+                let mut added_snippet = false;
+
+                if impl_is_unsafe {
+                    ted::insert(
+                        Position::first_child_of(impl_def.syntax()),
+                        make::token(T![unsafe]),
                     );
                 }
-                (Some(cap), Some((impl_def, first_assoc_item))) => {
-                    let mut added_snippet = false;
-
-                    if impl_is_unsafe {
-                        ted::insert(
-                            Position::first_child_of(impl_def.syntax()),
-                            make::token(T![unsafe]),
-                        );
-                    }
 
-                    if let ast::AssocItem::Fn(ref func) = first_assoc_item {
-                        if let Some(m) = func.syntax().descendants().find_map(ast::MacroCall::cast)
-                        {
-                            if m.syntax().text() == "todo!()" {
-                                // Make the `todo!()` a placeholder
-                                builder.add_placeholder_snippet(cap, m);
-                                added_snippet = true;
-                            }
+                if let ast::AssocItem::Fn(ref func) = first_assoc_item {
+                    if let Some(m) = func.syntax().descendants().find_map(ast::MacroCall::cast) {
+                        if m.syntax().text() == "todo!()" {
+                            // Make the `todo!()` a placeholder
+                            builder.add_placeholder_snippet(cap, m);
+                            added_snippet = true;
                         }
                     }
+                }
 
-                    if !added_snippet {
-                        // If we haven't already added a snippet, add a tabstop before the generated function
-                        builder.add_tabstop_before(cap, first_assoc_item);
-                    }
-
-                    ted::insert_all(
-                        insert_after,
-                        vec![make::tokens::blank_line().into(), impl_def.syntax().clone().into()],
-                    );
+                if !added_snippet {
+                    // If we haven't already added a snippet, add a tabstop before the generated function
+                    builder.add_tabstop_before(cap, first_assoc_item);
                 }
-            };
-        },
-    )
+
+                ted::insert_all(
+                    insert_after,
+                    vec![make::tokens::blank_line().into(), impl_def.syntax().clone().into()],
+                );
+            }
+        };
+    })
 }
 
 fn impl_def_from_trait(
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_if_let_with_match.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_if_let_with_match.rs
index c3b753653c2..734bd1786cb 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_if_let_with_match.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_if_let_with_match.rs
@@ -13,7 +13,7 @@ use syntax::{
 };
 
 use crate::{
-    AssistContext, AssistId, AssistKind, Assists,
+    AssistContext, AssistId, Assists,
     utils::{does_pat_match_variant, does_pat_variant_nested_or_literal, unwrap_trivial_block},
 };
 
@@ -101,7 +101,7 @@ pub(crate) fn replace_if_let_with_match(acc: &mut Assists, ctx: &AssistContext<'
     let let_ = if pat_seen { " let" } else { "" };
 
     acc.add(
-        AssistId("replace_if_let_with_match", AssistKind::RefactorRewrite),
+        AssistId::refactor_rewrite("replace_if_let_with_match"),
         format!("Replace if{let_} with match"),
         available_range,
         move |builder| {
@@ -249,7 +249,7 @@ pub(crate) fn replace_match_with_if_let(acc: &mut Assists, ctx: &AssistContext<'
         _ => " let",
     };
     acc.add(
-        AssistId("replace_match_with_if_let", AssistKind::RefactorRewrite),
+        AssistId::refactor_rewrite("replace_match_with_if_let"),
         format!("Replace match with if{let_}"),
         match_expr.syntax().text_range(),
         move |builder| {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_is_method_with_if_let_method.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_is_method_with_if_let_method.rs
index c49f285d8e9..e933bcc40db 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_is_method_with_if_let_method.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_is_method_with_if_let_method.rs
@@ -4,7 +4,7 @@ use syntax::{
     ted,
 };
 
-use crate::{AssistContext, AssistId, AssistKind, Assists};
+use crate::{AssistContext, AssistId, Assists};
 
 // Assist: replace_is_some_with_if_let_some
 //
@@ -56,7 +56,7 @@ pub(crate) fn replace_is_method_with_if_let_method(
             };
 
             acc.add(
-                AssistId(assist_id, AssistKind::RefactorRewrite),
+                AssistId::refactor_rewrite(assist_id),
                 message,
                 call_expr.syntax().text_range(),
                 |edit| {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_let_with_if_let.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_let_with_if_let.rs
index 34bbd6ba5be..a2dcbf948d8 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_let_with_if_let.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_let_with_if_let.rs
@@ -4,7 +4,7 @@ use syntax::{
     ast::{self, edit::IndentLevel, edit_in_place::Indent, syntax_factory::SyntaxFactory},
 };
 
-use crate::{AssistContext, AssistId, AssistKind, Assists};
+use crate::{AssistContext, AssistId, Assists};
 
 // Assist: replace_let_with_if_let
 //
@@ -38,7 +38,7 @@ pub(crate) fn replace_let_with_if_let(acc: &mut Assists, ctx: &AssistContext<'_>
 
     let target = let_kw.text_range();
     acc.add(
-        AssistId("replace_let_with_if_let", AssistKind::RefactorRewrite),
+        AssistId::refactor_rewrite("replace_let_with_if_let"),
         "Replace let with if let",
         target,
         |builder| {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_method_eager_lazy.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_method_eager_lazy.rs
index 88b56ebb4b1..afac6cd724c 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_method_eager_lazy.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_method_eager_lazy.rs
@@ -1,4 +1,4 @@
-use ide_db::assists::{AssistId, AssistKind};
+use ide_db::assists::AssistId;
 use syntax::{
     AstNode,
     ast::{self, Expr, HasArgList, make},
@@ -60,7 +60,7 @@ pub(crate) fn replace_with_lazy_method(acc: &mut Assists, ctx: &AssistContext<'_
     )?;
 
     acc.add(
-        AssistId("replace_with_lazy_method", AssistKind::RefactorRewrite),
+        AssistId::refactor_rewrite("replace_with_lazy_method"),
         format!("Replace {method_name} with {method_name_lazy}"),
         call.syntax().text_range(),
         |builder| {
@@ -136,7 +136,7 @@ pub(crate) fn replace_with_eager_method(acc: &mut Assists, ctx: &AssistContext<'
     )?;
 
     acc.add(
-        AssistId("replace_with_eager_method", AssistKind::RefactorRewrite),
+        AssistId::refactor_rewrite("replace_with_eager_method"),
         format!("Replace {method_name} with {method_name_eager}"),
         call.syntax().text_range(),
         |builder| {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_named_generic_with_impl.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_named_generic_with_impl.rs
index f99394e8775..3cd7b58f4dd 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_named_generic_with_impl.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_named_generic_with_impl.rs
@@ -14,7 +14,7 @@ use syntax::{
     match_ast, ted,
 };
 
-use crate::{AssistContext, AssistId, AssistKind, Assists};
+use crate::{AssistContext, AssistId, Assists};
 
 // Assist: replace_named_generic_with_impl
 //
@@ -70,7 +70,7 @@ pub(crate) fn replace_named_generic_with_impl(
     let target = type_param.syntax().text_range();
 
     acc.add(
-        AssistId("replace_named_generic_with_impl", AssistKind::RefactorRewrite),
+        AssistId::refactor_rewrite("replace_named_generic_with_impl"),
         "Replace named generic with impl trait",
         target,
         |edit| {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs
index 08a4d28e9fe..c067747bc1b 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs
@@ -9,7 +9,7 @@ use syntax::{
     match_ast, ted,
 };
 
-use crate::{AssistContext, AssistId, AssistKind, Assists};
+use crate::{AssistContext, AssistId, Assists};
 
 // Assist: replace_qualified_name_with_use
 //
@@ -75,7 +75,7 @@ pub(crate) fn replace_qualified_name_with_use(
     let scope = ImportScope::find_insert_use_container(original_path.syntax(), &ctx.sema)?;
     let target = original_path.syntax().text_range();
     acc.add(
-        AssistId("replace_qualified_name_with_use", AssistKind::RefactorRewrite),
+        AssistId::refactor_rewrite("replace_qualified_name_with_use"),
         "Replace qualified path with use",
         target,
         |builder| {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_string_with_char.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_string_with_char.rs
index 176b4e4af08..0eab70424a1 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_string_with_char.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_string_with_char.rs
@@ -5,7 +5,7 @@ use syntax::{
     ast::IsString,
 };
 
-use crate::{AssistContext, AssistId, AssistKind, Assists};
+use crate::{AssistContext, AssistId, Assists};
 
 // Assist: replace_string_with_char
 //
@@ -33,7 +33,7 @@ pub(crate) fn replace_string_with_char(acc: &mut Assists, ctx: &AssistContext<'_
     let quote_offsets = token.quote_offsets()?;
 
     acc.add(
-        AssistId("replace_string_with_char", AssistKind::RefactorRewrite),
+        AssistId::refactor_rewrite("replace_string_with_char"),
         "Replace string with char",
         target,
         |edit| {
@@ -67,7 +67,7 @@ pub(crate) fn replace_char_with_string(acc: &mut Assists, ctx: &AssistContext<'_
     let target = token.text_range();
 
     acc.add(
-        AssistId("replace_char_with_string", AssistKind::RefactorRewrite),
+        AssistId::refactor_rewrite("replace_char_with_string"),
         "Replace char with string",
         target,
         |edit| {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_try_expr_with_match.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_try_expr_with_match.rs
index 93dfe48ebca..3fd59f3b69d 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_try_expr_with_match.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_try_expr_with_match.rs
@@ -1,9 +1,6 @@
 use std::iter;
 
-use ide_db::{
-    assists::{AssistId, AssistKind},
-    ty_filter::TryEnum,
-};
+use ide_db::{assists::AssistId, ty_filter::TryEnum};
 use syntax::{
     AstNode, T,
     ast::{
@@ -48,7 +45,7 @@ pub(crate) fn replace_try_expr_with_match(
 
     let target = qm_kw_parent.syntax().text_range();
     acc.add(
-        AssistId("replace_try_expr_with_match", AssistKind::RefactorRewrite),
+        AssistId::refactor_rewrite("replace_try_expr_with_match"),
         "Replace try expression with match",
         target,
         |edit| {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_turbofish_with_explicit_type.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_turbofish_with_explicit_type.rs
index 39ebca25a90..311cbf6ad3f 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_turbofish_with_explicit_type.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_turbofish_with_explicit_type.rs
@@ -5,7 +5,7 @@ use syntax::{
 };
 
 use crate::{
-    AssistId, AssistKind,
+    AssistId,
     assist_context::{AssistContext, Assists},
 };
 
@@ -74,7 +74,7 @@ pub(crate) fn replace_turbofish_with_explicit_type(
         let ident_range = let_stmt.pat()?.syntax().text_range();
 
         return acc.add(
-            AssistId("replace_turbofish_with_explicit_type", AssistKind::RefactorRewrite),
+            AssistId::refactor_rewrite("replace_turbofish_with_explicit_type"),
             "Replace turbofish with explicit type",
             TextRange::new(initializer_start, turbofish_range.end()),
             |builder| {
@@ -89,7 +89,7 @@ pub(crate) fn replace_turbofish_with_explicit_type(
         let underscore_range = t.syntax().text_range();
 
         return acc.add(
-            AssistId("replace_turbofish_with_explicit_type", AssistKind::RefactorRewrite),
+            AssistId::refactor_rewrite("replace_turbofish_with_explicit_type"),
             "Replace `_` with turbofish type",
             turbofish_range,
             |builder| {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/sort_items.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/sort_items.rs
index 73dfbf02379..e973e70345d 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/sort_items.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/sort_items.rs
@@ -7,7 +7,7 @@ use syntax::{
     ast::{self, HasName},
 };
 
-use crate::{AssistContext, AssistId, AssistKind, Assists, utils::get_methods};
+use crate::{AssistContext, AssistId, Assists, utils::get_methods};
 
 // Assist: sort_items
 //
@@ -126,20 +126,15 @@ impl AddRewrite for Assists {
         new: Vec<T>,
         target: &SyntaxNode,
     ) -> Option<()> {
-        self.add(
-            AssistId("sort_items", AssistKind::RefactorRewrite),
-            label,
-            target.text_range(),
-            |builder| {
-                let mut editor = builder.make_editor(target);
-
-                old.into_iter()
-                    .zip(new)
-                    .for_each(|(old, new)| editor.replace(old.syntax(), new.syntax()));
-
-                builder.add_file_edits(builder.file_id, editor)
-            },
-        )
+        self.add(AssistId::refactor_rewrite("sort_items"), label, target.text_range(), |builder| {
+            let mut editor = builder.make_editor(target);
+
+            old.into_iter()
+                .zip(new)
+                .for_each(|(old, new)| editor.replace(old.syntax(), new.syntax()));
+
+            builder.add_file_edits(builder.file_id, editor)
+        })
     }
 }
 
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/split_import.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/split_import.rs
index 63371ddf9fb..1729a0667c0 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/split_import.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/split_import.rs
@@ -1,6 +1,6 @@
 use syntax::{AstNode, T, ast};
 
-use crate::{AssistContext, AssistId, AssistKind, Assists};
+use crate::{AssistContext, AssistId, Assists};
 
 // Assist: split_import
 //
@@ -29,7 +29,7 @@ pub(crate) fn split_import(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option
     }
 
     let target = colon_colon.text_range();
-    acc.add(AssistId("split_import", AssistKind::RefactorRewrite), "Split import", target, |edit| {
+    acc.add(AssistId::refactor_rewrite("split_import"), "Split import", target, |edit| {
         let use_tree = edit.make_mut(use_tree.clone());
         let path = edit.make_mut(path);
         use_tree.split_prefix(&path);
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/term_search.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/term_search.rs
index 7b2598b4557..86121e7fc8c 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/term_search.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/term_search.rs
@@ -1,7 +1,7 @@
 //! Term search assist
 use hir::term_search::{TermSearchConfig, TermSearchCtx};
 use ide_db::{
-    assists::{AssistId, AssistKind, GroupLabel},
+    assists::{AssistId, GroupLabel},
     famous_defs::FamousDefs,
 };
 
@@ -68,7 +68,7 @@ pub(crate) fn term_search(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<
     for code in paths {
         acc.add_group(
             &GroupLabel(String::from("Term search")),
-            AssistId("term_search", AssistKind::Generate),
+            AssistId::generate("term_search"),
             format!("Replace {macro_name}!() with {code}"),
             goal_range,
             |builder| {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/toggle_async_sugar.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/toggle_async_sugar.rs
index 9f45b2898a7..eed070cb07d 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/toggle_async_sugar.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/toggle_async_sugar.rs
@@ -1,8 +1,5 @@
 use hir::ModuleDef;
-use ide_db::{
-    assists::{AssistId, AssistKind},
-    famous_defs::FamousDefs,
-};
+use ide_db::{assists::AssistId, famous_defs::FamousDefs};
 use syntax::{
     AstNode, NodeOrToken, SyntaxKind, SyntaxNode, SyntaxToken, TextRange,
     ast::{self, HasGenericArgs, HasVisibility},
@@ -60,7 +57,7 @@ pub(crate) fn sugar_impl_future_into_async(
     let future_output = unwrap_future_output(main_trait_path)?;
 
     acc.add(
-        AssistId("sugar_impl_future_into_async", AssistKind::RefactorRewrite),
+        AssistId::refactor_rewrite("sugar_impl_future_into_async"),
         "Convert `impl Future` into async",
         function.syntax().text_range(),
         |builder| {
@@ -145,7 +142,7 @@ pub(crate) fn desugar_async_into_impl_future(
     let trait_path = trait_path.display(ctx.db(), edition);
 
     acc.add(
-        AssistId("desugar_async_into_impl_future", AssistKind::RefactorRewrite),
+        AssistId::refactor_rewrite("desugar_async_into_impl_future"),
         "Convert async into `impl Future`",
         function.syntax().text_range(),
         |builder| {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/toggle_ignore.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/toggle_ignore.rs
index c1ea7dc4c78..7a29928af93 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/toggle_ignore.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/toggle_ignore.rs
@@ -3,7 +3,7 @@ use syntax::{
     ast::{self, HasAttrs},
 };
 
-use crate::{AssistContext, AssistId, AssistKind, Assists, utils::test_related_attribute_syn};
+use crate::{AssistContext, AssistId, Assists, utils::test_related_attribute_syn};
 
 // Assist: toggle_ignore
 //
@@ -30,13 +30,13 @@ pub(crate) fn toggle_ignore(acc: &mut Assists, ctx: &AssistContext<'_>) -> Optio
 
     match has_ignore_attribute(&func) {
         None => acc.add(
-            AssistId("toggle_ignore", AssistKind::None),
+            AssistId::none("toggle_ignore"),
             "Ignore this test",
             attr.syntax().text_range(),
             |builder| builder.insert(attr.syntax().text_range().end(), "\n#[ignore]"),
         ),
         Some(ignore_attr) => acc.add(
-            AssistId("toggle_ignore", AssistKind::None),
+            AssistId::none("toggle_ignore"),
             "Re-enable this test",
             ignore_attr.syntax().text_range(),
             |builder| {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/toggle_macro_delimiter.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/toggle_macro_delimiter.rs
index 80834abecc9..109269bd6e6 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/toggle_macro_delimiter.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/toggle_macro_delimiter.rs
@@ -1,4 +1,4 @@
-use ide_db::assists::{AssistId, AssistKind};
+use ide_db::assists::AssistId;
 use syntax::{
     AstNode, T,
     ast::{self, make},
@@ -63,7 +63,7 @@ pub(crate) fn toggle_macro_delimiter(acc: &mut Assists, ctx: &AssistContext<'_>)
     };
 
     acc.add(
-        AssistId("toggle_macro_delimiter", AssistKind::Refactor),
+        AssistId::refactor("toggle_macro_delimiter"),
         match token {
             MacroDelims::LPar | MacroDelims::RPar => "Replace delimiters with braces",
             MacroDelims::LBra | MacroDelims::RBra => "Replace delimiters with parentheses",
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_match_arm.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_match_arm.rs
index 8b6aef02ecc..31ff47a0549 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_match_arm.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_match_arm.rs
@@ -5,7 +5,7 @@ use syntax::{
     ted::{self, Position},
 };
 
-use crate::{AssistContext, AssistId, AssistKind, Assists};
+use crate::{AssistContext, AssistId, Assists};
 
 // Assist: unmerge_match_arm
 //
@@ -47,7 +47,7 @@ pub(crate) fn unmerge_match_arm(acc: &mut Assists, ctx: &AssistContext<'_>) -> O
     let old_parent_range = new_parent.text_range();
 
     acc.add(
-        AssistId("unmerge_match_arm", AssistKind::RefactorRewrite),
+        AssistId::refactor_rewrite("unmerge_match_arm"),
         "Unmerge match arm",
         pipe_token.text_range(),
         |edit| {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_use.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_use.rs
index 7f2dd19ce07..805a7344494 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_use.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_use.rs
@@ -5,7 +5,7 @@ use syntax::{
 };
 
 use crate::{
-    AssistId, AssistKind,
+    AssistId,
     assist_context::{AssistContext, Assists},
 };
 
@@ -43,7 +43,7 @@ pub(crate) fn unmerge_use(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<
     };
 
     let target = tree.syntax().text_range();
-    acc.add(AssistId("unmerge_use", AssistKind::RefactorRewrite), label, target, |builder| {
+    acc.add(AssistId::refactor_rewrite("unmerge_use"), label, target, |builder| {
         let new_use = make::use_(
             use_.visibility(),
             make::use_tree(path, tree.use_tree_list(), tree.rename(), tree.star_token().is_some()),
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unnecessary_async.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unnecessary_async.rs
index f3ae70160bf..ac10a829bbf 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unnecessary_async.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unnecessary_async.rs
@@ -1,6 +1,6 @@
 use ide_db::{
     EditionedFileId,
-    assists::{AssistId, AssistKind},
+    assists::AssistId,
     defs::Definition,
     search::{FileReference, FileReferenceNode},
     syntax_helpers::node_ext::full_path_of_name_ref,
@@ -60,7 +60,7 @@ pub(crate) fn unnecessary_async(acc: &mut Assists, ctx: &AssistContext<'_>) -> O
 
     // Otherwise, we may remove the `async` keyword.
     acc.add(
-        AssistId("unnecessary_async", AssistKind::QuickFix),
+        AssistId::quick_fix("unnecessary_async"),
         "Remove unnecessary async",
         async_range,
         |edit| {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unqualify_method_call.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unqualify_method_call.rs
index 712c8c3d14d..ebb8ef99100 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unqualify_method_call.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unqualify_method_call.rs
@@ -4,7 +4,7 @@ use syntax::{
     ast::{self, AstNode, HasArgList, prec::ExprPrecedence},
 };
 
-use crate::{AssistContext, AssistId, AssistKind, Assists};
+use crate::{AssistContext, AssistId, Assists};
 
 // Assist: unqualify_method_call
 //
@@ -69,7 +69,7 @@ pub(crate) fn unqualify_method_call(acc: &mut Assists, ctx: &AssistContext<'_>)
     );
 
     acc.add(
-        AssistId("unqualify_method_call", AssistKind::RefactorRewrite),
+        AssistId::refactor_rewrite("unqualify_method_call"),
         "Unqualify method call",
         call.syntax().text_range(),
         |edit| {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_block.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_block.rs
index 80d8cebff5b..a83f6835ca6 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_block.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_block.rs
@@ -7,7 +7,7 @@ use syntax::{
     },
 };
 
-use crate::{AssistContext, AssistId, AssistKind, Assists};
+use crate::{AssistContext, AssistId, Assists};
 
 // Assist: unwrap_block
 //
@@ -27,9 +27,8 @@ use crate::{AssistContext, AssistId, AssistKind, Assists};
 // }
 // ```
 pub(crate) fn unwrap_block(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
-    let assist_id = AssistId("unwrap_block", AssistKind::RefactorRewrite);
+    let assist_id = AssistId::refactor_rewrite("unwrap_block");
     let assist_label = "Unwrap block";
-
     let l_curly_token = ctx.find_token_syntax_at_offset(T!['{'])?;
     let mut block = ast::BlockExpr::cast(l_curly_token.parent_ancestors().nth(1)?)?;
     let target = block.syntax().text_range();
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_return_type.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_return_type.rs
index f6eb68524f2..8804fea72f8 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_return_type.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_return_type.rs
@@ -9,7 +9,7 @@ use syntax::{
     match_ast,
 };
 
-use crate::{AssistContext, AssistId, AssistKind, Assists};
+use crate::{AssistContext, AssistId, Assists};
 
 // Assist: unwrap_option_return_type
 //
@@ -187,7 +187,7 @@ impl UnwrapperKind {
             UnwrapperKind::Result => "unwrap_result_return_type",
         };
 
-        AssistId(s, AssistKind::RefactorRewrite)
+        AssistId::refactor_rewrite(s)
     }
 
     fn label(&self) -> &'static str {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_tuple.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_tuple.rs
index 55053ac97dc..ecfecbb04ff 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_tuple.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_tuple.rs
@@ -3,7 +3,7 @@ use syntax::{
     ast::{self, edit::AstNodeEdit},
 };
 
-use crate::{AssistContext, AssistId, AssistKind, Assists};
+use crate::{AssistContext, AssistId, Assists};
 
 // Assist: unwrap_tuple
 //
@@ -56,7 +56,7 @@ pub(crate) fn unwrap_tuple(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option
     let parent = let_kw.parent()?;
 
     acc.add(
-        AssistId("unwrap_tuple", AssistKind::RefactorRewrite),
+        AssistId::refactor_rewrite("unwrap_tuple"),
         "Unwrap tuple",
         let_kw.text_range(),
         |edit| {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/wrap_return_type.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/wrap_return_type.rs
index 8857c446f6d..a0440680d01 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/wrap_return_type.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/wrap_return_type.rs
@@ -12,7 +12,7 @@ use syntax::{
     match_ast,
 };
 
-use crate::{AssistContext, AssistId, AssistKind, Assists};
+use crate::{AssistContext, AssistId, Assists};
 
 // Assist: wrap_return_type_in_option
 //
@@ -155,7 +155,7 @@ impl WrapperKind {
             WrapperKind::Result => "wrap_return_type_in_result",
         };
 
-        AssistId(s, AssistKind::RefactorRewrite)
+        AssistId::refactor_rewrite(s)
     }
 
     fn label(&self) -> &'static str {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/wrap_unwrap_cfg_attr.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/wrap_unwrap_cfg_attr.rs
index 717c68d04e0..1068d5d4cd5 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/wrap_unwrap_cfg_attr.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/wrap_unwrap_cfg_attr.rs
@@ -6,7 +6,7 @@ use syntax::{
     ted::{self, Position},
 };
 
-use crate::{AssistContext, AssistId, AssistKind, Assists};
+use crate::{AssistContext, AssistId, Assists};
 
 // Assist: wrap_unwrap_cfg_attr
 //
@@ -210,7 +210,7 @@ fn wrap_derive(
     };
 
     acc.add(
-        AssistId("wrap_unwrap_cfg_attr", AssistKind::Refactor),
+        AssistId::refactor("wrap_unwrap_cfg_attr"),
         format!("Wrap #[derive({path_text})] in `cfg_attr`",),
         range,
         handle_source_change,
@@ -267,7 +267,7 @@ fn wrap_cfg_attr(acc: &mut Assists, ctx: &AssistContext<'_>, attr: ast::Attr) ->
         }
     };
     acc.add(
-        AssistId("wrap_unwrap_cfg_attr", AssistKind::Refactor),
+        AssistId::refactor("wrap_unwrap_cfg_attr"),
         "Convert to `cfg_attr`",
         range,
         handle_source_change,
@@ -336,7 +336,7 @@ fn unwrap_cfg_attr(acc: &mut Assists, attr: ast::Attr) -> Option<()> {
         f.replace(range, inner_attrs);
     };
     acc.add(
-        AssistId("wrap_unwrap_cfg_attr", AssistKind::Refactor),
+        AssistId::refactor("wrap_unwrap_cfg_attr"),
         "Extract Inner Attributes from `cfg_attr`",
         range,
         handle_source_change,
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs b/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs
index a23461e69a5..13e061724e4 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs
@@ -504,6 +504,7 @@ pub fn test_some_range(a: int) -> bool {
                 id: AssistId(
                     "extract_variable",
                     RefactorExtract,
+                    None,
                 ),
                 label: "Extract into variable",
                 group: Some(
@@ -524,6 +525,7 @@ pub fn test_some_range(a: int) -> bool {
                 id: AssistId(
                     "extract_constant",
                     RefactorExtract,
+                    None,
                 ),
                 label: "Extract into constant",
                 group: Some(
@@ -544,6 +546,7 @@ pub fn test_some_range(a: int) -> bool {
                 id: AssistId(
                     "extract_static",
                     RefactorExtract,
+                    None,
                 ),
                 label: "Extract into static",
                 group: Some(
@@ -564,6 +567,7 @@ pub fn test_some_range(a: int) -> bool {
                 id: AssistId(
                     "extract_function",
                     RefactorExtract,
+                    None,
                 ),
                 label: "Extract into function",
                 group: Some(
@@ -586,6 +590,7 @@ pub fn test_some_range(a: int) -> bool {
             AssistResolveStrategy::Single(SingleResolve {
                 assist_id: "SOMETHING_MISMATCHING".to_owned(),
                 assist_kind: AssistKind::RefactorExtract,
+                assist_subtype: None,
             }),
             frange.into(),
         );
@@ -598,6 +603,7 @@ pub fn test_some_range(a: int) -> bool {
                 id: AssistId(
                     "extract_variable",
                     RefactorExtract,
+                    None,
                 ),
                 label: "Extract into variable",
                 group: Some(
@@ -618,6 +624,7 @@ pub fn test_some_range(a: int) -> bool {
                 id: AssistId(
                     "extract_constant",
                     RefactorExtract,
+                    None,
                 ),
                 label: "Extract into constant",
                 group: Some(
@@ -638,6 +645,7 @@ pub fn test_some_range(a: int) -> bool {
                 id: AssistId(
                     "extract_static",
                     RefactorExtract,
+                    None,
                 ),
                 label: "Extract into static",
                 group: Some(
@@ -658,6 +666,7 @@ pub fn test_some_range(a: int) -> bool {
                 id: AssistId(
                     "extract_function",
                     RefactorExtract,
+                    None,
                 ),
                 label: "Extract into function",
                 group: Some(
@@ -680,6 +689,7 @@ pub fn test_some_range(a: int) -> bool {
             AssistResolveStrategy::Single(SingleResolve {
                 assist_id: "extract_variable".to_owned(),
                 assist_kind: AssistKind::RefactorExtract,
+                assist_subtype: None,
             }),
             frange.into(),
         );
@@ -692,6 +702,7 @@ pub fn test_some_range(a: int) -> bool {
                 id: AssistId(
                     "extract_variable",
                     RefactorExtract,
+                    None,
                 ),
                 label: "Extract into variable",
                 group: Some(
@@ -758,6 +769,7 @@ pub fn test_some_range(a: int) -> bool {
                 id: AssistId(
                     "extract_constant",
                     RefactorExtract,
+                    None,
                 ),
                 label: "Extract into constant",
                 group: Some(
@@ -778,6 +790,7 @@ pub fn test_some_range(a: int) -> bool {
                 id: AssistId(
                     "extract_static",
                     RefactorExtract,
+                    None,
                 ),
                 label: "Extract into static",
                 group: Some(
@@ -798,6 +811,7 @@ pub fn test_some_range(a: int) -> bool {
                 id: AssistId(
                     "extract_function",
                     RefactorExtract,
+                    None,
                 ),
                 label: "Extract into function",
                 group: Some(
@@ -824,6 +838,7 @@ pub fn test_some_range(a: int) -> bool {
                 id: AssistId(
                     "extract_variable",
                     RefactorExtract,
+                    None,
                 ),
                 label: "Extract into variable",
                 group: Some(
@@ -890,6 +905,7 @@ pub fn test_some_range(a: int) -> bool {
                 id: AssistId(
                     "extract_constant",
                     RefactorExtract,
+                    None,
                 ),
                 label: "Extract into constant",
                 group: Some(
@@ -960,6 +976,7 @@ pub fn test_some_range(a: int) -> bool {
                 id: AssistId(
                     "extract_static",
                     RefactorExtract,
+                    None,
                 ),
                 label: "Extract into static",
                 group: Some(
@@ -1030,6 +1047,7 @@ pub fn test_some_range(a: int) -> bool {
                 id: AssistId(
                     "extract_function",
                     RefactorExtract,
+                    None,
                 ),
                 label: "Extract into function",
                 group: Some(
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/assists.rs b/src/tools/rust-analyzer/crates/ide-db/src/assists.rs
index 1c40685ebb1..9ff3e10a1e7 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/assists.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/assists.rs
@@ -105,7 +105,37 @@ impl FromStr for AssistKind {
 /// Unique identifier of the assist, should not be shown to the user
 /// directly.
 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub struct AssistId(pub &'static str, pub AssistKind);
+pub struct AssistId(pub &'static str, pub AssistKind, pub Option<usize>);
+
+impl AssistId {
+    pub fn none(id: &'static str) -> AssistId {
+        AssistId(id, AssistKind::None, None)
+    }
+
+    pub fn quick_fix(id: &'static str) -> AssistId {
+        AssistId(id, AssistKind::QuickFix, None)
+    }
+
+    pub fn generate(id: &'static str) -> AssistId {
+        AssistId(id, AssistKind::Generate, None)
+    }
+
+    pub fn refactor(id: &'static str) -> AssistId {
+        AssistId(id, AssistKind::Refactor, None)
+    }
+
+    pub fn refactor_extract(id: &'static str) -> AssistId {
+        AssistId(id, AssistKind::RefactorExtract, None)
+    }
+
+    pub fn refactor_inline(id: &'static str) -> AssistId {
+        AssistId(id, AssistKind::RefactorInline, None)
+    }
+
+    pub fn refactor_rewrite(id: &'static str) -> AssistId {
+        AssistId(id, AssistKind::RefactorRewrite, None)
+    }
+}
 
 /// A way to control how many assist to resolve during the assist resolution.
 /// When an assist is resolved, its edits are calculated that might be costly to always do by default.
@@ -128,6 +158,8 @@ pub struct SingleResolve {
     pub assist_id: String,
     // The kind of the assist.
     pub assist_kind: AssistKind,
+    /// Subtype of the assist. When many assists have the same id, it differentiates among them.
+    pub assist_subtype: Option<usize>,
 }
 
 impl AssistResolveStrategy {
@@ -136,7 +168,9 @@ impl AssistResolveStrategy {
             AssistResolveStrategy::None => false,
             AssistResolveStrategy::All => true,
             AssistResolveStrategy::Single(single_resolve) => {
-                single_resolve.assist_id == id.0 && single_resolve.assist_kind == id.1
+                single_resolve.assist_id == id.0
+                    && single_resolve.assist_kind == id.1
+                    && single_resolve.assist_subtype == id.2
             }
         }
     }
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs
index 79231685c01..9f1901ff95e 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs
@@ -1,7 +1,7 @@
 use hir::{HasSource, HirDisplay, db::ExpandDatabase};
 use ide_db::text_edit::TextRange;
 use ide_db::{
-    assists::{Assist, AssistId, AssistKind},
+    assists::{Assist, AssistId},
     label::Label,
     source_change::SourceChangeBuilder,
 };
@@ -97,7 +97,7 @@ fn quickfix_for_redundant_assoc_item(
     add_assoc_item_def(&mut source_change_builder)?;
 
     Some(vec![Assist {
-        id: AssistId("add assoc item def into trait def", AssistKind::QuickFix),
+        id: AssistId::quick_fix("add assoc item def into trait def"),
         label: Label::new("Add assoc item def into trait def".to_owned()),
         group: None,
         target: range,
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs
index e8179293902..0bef91f3375 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs
@@ -5,7 +5,7 @@ use hir::{
 };
 use ide_db::text_edit::TextEdit;
 use ide_db::{
-    assists::{Assist, AssistId, AssistKind, GroupLabel},
+    assists::{Assist, AssistId, GroupLabel},
     label::Label,
     source_change::SourceChange,
 };
@@ -78,7 +78,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::TypedHole) -> Option<Vec<Assist>
         })
         .unique()
         .map(|code| Assist {
-            id: AssistId("typed-hole", AssistKind::QuickFix),
+            id: AssistId::quick_fix("typed-hole"),
             label: Label::new(format!("Replace `_` with `{code}`")),
             group: Some(GroupLabel("Replace `_` with a term".to_owned())),
             target: original_range.range,
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs
index 7020fce24ff..986ebb8818f 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs
@@ -4,7 +4,7 @@ use either::Either;
 use hir::{Adt, FileRange, HasSource, HirDisplay, InFile, Struct, Union, db::ExpandDatabase};
 use ide_db::text_edit::TextEdit;
 use ide_db::{
-    assists::{Assist, AssistId, AssistKind},
+    assists::{Assist, AssistId},
     helpers::is_editable_crate,
     label::Label,
     source_change::{SourceChange, SourceChangeBuilder},
@@ -122,7 +122,7 @@ fn add_variant_to_union(
     let mut src_change_builder = SourceChangeBuilder::new(range.file_id);
     src_change_builder.insert(offset, record_field);
     Some(Assist {
-        id: AssistId("add-variant-to-union", AssistKind::QuickFix),
+        id: AssistId::quick_fix("add-variant-to-union"),
         label: Label::new("Add field to union".to_owned()),
         group: None,
         target: error_range.range,
@@ -170,7 +170,7 @@ fn add_field_to_struct_fix(
             // FIXME: Allow for choosing a visibility modifier see https://github.com/rust-lang/rust-analyzer/issues/11563
             src_change_builder.insert(offset, record_field);
             Some(Assist {
-                id: AssistId("add-field-to-record-struct", AssistKind::QuickFix),
+                id: AssistId::quick_fix("add-field-to-record-struct"),
                 label: Label::new("Add field to Record Struct".to_owned()),
                 group: None,
                 target: error_range.range,
@@ -206,7 +206,7 @@ fn add_field_to_struct_fix(
             src_change_builder.replace(semi_colon.text_range(), record_field_list.to_string());
 
             Some(Assist {
-                id: AssistId("convert-unit-struct-to-record-struct", AssistKind::QuickFix),
+                id: AssistId::quick_fix("convert-unit-struct-to-record-struct"),
                 label: Label::new("Convert Unit Struct to Record Struct and add field".to_owned()),
                 group: None,
                 target: error_range.range,
@@ -265,7 +265,7 @@ fn method_fix(
     let expr = expr_ptr.value.to_node(&root);
     let FileRange { range, file_id } = ctx.sema.original_range_opt(expr.syntax())?;
     Some(Assist {
-        id: AssistId("expected-field-found-method-call-fix", AssistKind::QuickFix),
+        id: AssistId::quick_fix("expected-field-found-method-call-fix"),
         label: Label::new("Use parentheses to call the method".to_owned()),
         group: None,
         target: range,
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs
index e6e86214bba..b5d7aa113a1 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs
@@ -1,7 +1,7 @@
 use hir::{FileRange, HirDisplay, InFile, db::ExpandDatabase};
 use ide_db::text_edit::TextEdit;
 use ide_db::{
-    assists::{Assist, AssistId, AssistKind},
+    assists::{Assist, AssistId},
     label::Label,
     source_change::SourceChange,
 };
@@ -96,7 +96,7 @@ fn field_fix(
         _ => return None,
     };
     Some(Assist {
-        id: AssistId("expected-method-found-field-fix", AssistKind::QuickFix),
+        id: AssistId::quick_fix("expected-method-found-field-fix"),
         label: Label::new("Use parentheses to call the value of the field".to_owned()),
         group: None,
         target: range,
@@ -175,7 +175,7 @@ fn assoc_func_fix(ctx: &DiagnosticsContext<'_>, d: &hir::UnresolvedMethodCall) -
         let file_id = ctx.sema.original_range_opt(call.receiver()?.syntax())?.file_id;
 
         Some(Assist {
-            id: AssistId("method_call_to_assoc_func_call_fix", AssistKind::QuickFix),
+            id: AssistId::quick_fix("method_call_to_assoc_func_call_fix"),
             label: Label::new(format!(
                 "Use associated func call instead: `{assoc_func_call_expr_string}`"
             )),
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unused_variables.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unused_variables.rs
index c412536d749..5857b1dab2f 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unused_variables.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unused_variables.rs
@@ -2,7 +2,7 @@ use hir::Name;
 use ide_db::text_edit::TextEdit;
 use ide_db::{
     FileRange, RootDatabase,
-    assists::{Assist, AssistId, AssistKind},
+    assists::{Assist, AssistId},
     label::Label,
     source_change::SourceChange,
 };
@@ -68,7 +68,7 @@ fn fixes(
     }
 
     Some(vec![Assist {
-        id: AssistId("unscore_unused_variable_name", AssistKind::QuickFix),
+        id: AssistId::quick_fix("unscore_unused_variable_name"),
         label: Label::new(format!(
             "Rename unused {} to _{}",
             var_name.display(db, edition),
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs
index 7cba58f66ba..a8d9b67b4ea 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs
@@ -89,7 +89,7 @@ use hir::{
 use ide_db::base_db::salsa::AsDynDatabase;
 use ide_db::{
     EditionedFileId, FileId, FileRange, FxHashMap, FxHashSet, RootDatabase, Severity, SnippetCap,
-    assists::{Assist, AssistId, AssistKind, AssistResolveStrategy},
+    assists::{Assist, AssistId, AssistResolveStrategy},
     base_db::{ReleaseChannel, RootQueryDb as _},
     generated::lints::{CLIPPY_LINT_GROUPS, DEFAULT_LINT_GROUPS, DEFAULT_LINTS, Lint, LintGroup},
     imports::insert_use::InsertUseConfig,
@@ -992,7 +992,7 @@ fn fix(id: &'static str, label: &str, source_change: SourceChange, target: TextR
 fn unresolved_fix(id: &'static str, label: &str, target: TextRange) -> Assist {
     assert!(!id.contains(' '));
     Assist {
-        id: AssistId(id, AssistKind::QuickFix),
+        id: AssistId::quick_fix(id),
         label: Label::new(label.to_owned()),
         group: None,
         target,
diff --git a/src/tools/rust-analyzer/crates/ide/src/ssr.rs b/src/tools/rust-analyzer/crates/ide/src/ssr.rs
index 5e439bd38a5..0e06b8e2dae 100644
--- a/src/tools/rust-analyzer/crates/ide/src/ssr.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/ssr.rs
@@ -2,7 +2,7 @@
 //! assist in ide_assists because that would require the ide_assists crate
 //! depend on the ide_ssr crate.
 
-use ide_assists::{Assist, AssistId, AssistKind, AssistResolveStrategy, GroupLabel};
+use ide_assists::{Assist, AssistId, AssistResolveStrategy, GroupLabel};
 use ide_db::{FileRange, RootDatabase, label::Label, source_change::SourceChange};
 
 pub(crate) fn ssr_assists(
@@ -16,7 +16,7 @@ pub(crate) fn ssr_assists(
         Some(ssr_data) => ssr_data,
         None => return ssr_assists,
     };
-    let id = AssistId("ssr", AssistKind::RefactorRewrite);
+    let id = AssistId::refactor_rewrite("ssr");
 
     let (source_change_for_file, source_change_for_workspace) = if resolve.should_resolve(&id) {
         let edits = match_finder.edits();
@@ -120,6 +120,7 @@ mod tests {
                 id: AssistId(
                     "ssr",
                     RefactorRewrite,
+                    None,
                 ),
                 label: "Apply SSR in file",
                 group: Some(
@@ -163,6 +164,7 @@ mod tests {
                 id: AssistId(
                     "ssr",
                     RefactorRewrite,
+                    None,
                 ),
                 label: "Apply SSR in workspace",
                 group: Some(
@@ -240,6 +242,7 @@ mod tests {
                 id: AssistId(
                     "ssr",
                     RefactorRewrite,
+                    None,
                 ),
                 label: "Apply SSR in file",
                 group: Some(
@@ -260,6 +263,7 @@ mod tests {
                 id: AssistId(
                     "ssr",
                     RefactorRewrite,
+                    None,
                 ),
                 label: "Apply SSR in workspace",
                 group: Some(
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs
index ef1cc28d15a..ec8b324aac3 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs
@@ -1568,13 +1568,21 @@ pub(crate) fn handle_code_action_resolve(
 fn parse_action_id(action_id: &str) -> anyhow::Result<(usize, SingleResolve), String> {
     let id_parts = action_id.split(':').collect::<Vec<_>>();
     match id_parts.as_slice() {
-        [assist_id_string, assist_kind_string, index_string] => {
+        [assist_id_string, assist_kind_string, index_string, subtype_str] => {
             let assist_kind: AssistKind = assist_kind_string.parse()?;
             let index: usize = match index_string.parse() {
                 Ok(index) => index,
                 Err(e) => return Err(format!("Incorrect index string: {e}")),
             };
-            Ok((index, SingleResolve { assist_id: assist_id_string.to_string(), assist_kind }))
+            let assist_subtype = subtype_str.parse::<usize>().ok();
+            Ok((
+                index,
+                SingleResolve {
+                    assist_id: assist_id_string.to_string(),
+                    assist_kind,
+                    assist_subtype,
+                },
+            ))
         }
         _ => Err("Action id contains incorrect number of segments".to_owned()),
     }
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs
index 8ea2d467977..c30ee0fee19 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs
@@ -1514,7 +1514,12 @@ pub(crate) fn code_action(
         (Some(it), _) => res.edit = Some(snippet_workspace_edit(snap, it)?),
         (None, Some((index, code_action_params, version))) => {
             res.data = Some(lsp_ext::CodeActionData {
-                id: format!("{}:{}:{index}", assist.id.0, assist.id.1.name()),
+                id: format!(
+                    "{}:{}:{index}:{}",
+                    assist.id.0,
+                    assist.id.1.name(),
+                    assist.id.2.map(|x| x.to_string()).unwrap_or("".to_owned())
+                ),
                 code_action_params,
                 version,
             });