From 225988b762899ab5e93c8ad028c080fd5c257c84 Mon Sep 17 00:00:00 2001 From: Hmikihiro <34ttrweoewiwe28@gmail.com> Date: Wed, 23 Jul 2025 04:28:49 +0900 Subject: [PATCH] migrate_replace_derive_with_manual_impl --- .../src/handlers/add_missing_impl_members.rs | 13 +-- .../replace_derive_with_manual_impl.rs | 92 ++++++++----------- 2 files changed, 45 insertions(+), 60 deletions(-) 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 d47e4b747e43..7459f37be188 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 @@ -158,7 +158,6 @@ fn add_missing_impl_members_inner( &target_scope, ); - let mut editor = edit.make_editor(impl_def.syntax()); if let Some(cap) = ctx.config.snippet_cap { let mut placeholder = None; if let DefaultMethods::No = mode { @@ -172,13 +171,11 @@ fn add_missing_impl_members_inner( ) && let Some(func_body) = func.body() { ted::replace(func_body.syntax(), body.syntax()); - } else { - if let Some(m) = func.syntax().descendants().find_map(ast::MacroCall::cast) - { - if m.syntax().text() == "todo!()" { - placeholder = Some(m); - } - } + } else if let Some(m) = + func.syntax().descendants().find_map(ast::MacroCall::cast) + && m.syntax().text() == "todo!()" + { + placeholder = Some(m); } } } 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 b7b8ae1d9c06..2f979b7ee07b 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 @@ -5,12 +5,12 @@ use syntax::{ SyntaxKind::WHITESPACE, T, ast::{self, AstNode, HasName, make}, - ted::{self, Position}, + syntax_editor::{Position, SyntaxEditor}, }; use crate::{ AssistConfig, AssistId, - assist_context::{AssistContext, Assists, SourceChangeBuilder}, + assist_context::{AssistContext, Assists}, utils::{ DefaultMethods, IgnoreAssocItems, add_trait_assoc_items_to_impl, filter_assoc_items, gen_trait_fn_body, generate_trait_impl, @@ -126,9 +126,9 @@ fn add_assist( let label = format!("Convert to manual `impl {replace_trait_path} for {annotated_name}`"); 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 insert_after = Position::after(adt.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( + let impl_def = impl_def_from_trait( &ctx.sema, ctx.config, adt, @@ -137,39 +137,23 @@ fn add_assist( replace_trait_path, impl_is_unsafe, ); - update_attribute(builder, old_derives, old_tree, old_trait_path, attr); + + let mut editor = builder.make_editor(attr.syntax()); + update_attribute(&mut editor, 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(impl_is_unsafe, adt, trait_path); + let (impl_def, first_assoc_item) = if let Some(impl_def) = impl_def { + ( + impl_def.clone(), + impl_def.assoc_item_list().and_then(|list| list.assoc_items().next()), + ) + } else { + (generate_trait_impl(impl_is_unsafe, adt, trait_path), None) + }; - ted::insert_all( - insert_after, - vec![make::tokens::blank_line().into(), impl_def.syntax().clone().into()], - ); - } - (None, Some((impl_def, _))) => { - 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(impl_is_unsafe, adt, trait_path); - - 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()], - ); - } - (Some(cap), Some((impl_def, first_assoc_item))) => { + if let Some(cap) = ctx.config.snippet_cap { + if let Some(first_assoc_item) = first_assoc_item { if let ast::AssocItem::Fn(ref func) = first_assoc_item && let Some(m) = func.syntax().descendants().find_map(ast::MacroCall::cast) && m.syntax().text() == "todo!()" @@ -180,13 +164,18 @@ fn add_assist( // 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()], - ); + } else 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); } - }; + } + + editor.insert_all( + insert_after, + vec![make::tokens::blank_line().into(), impl_def.syntax().clone().into()], + ); + builder.add_file_edits(ctx.vfs_file_id(), editor); }) } @@ -198,7 +187,7 @@ fn impl_def_from_trait( trait_: Option, trait_path: &ast::Path, impl_is_unsafe: bool, -) -> Option<(ast::Impl, ast::AssocItem)> { +) -> Option { let trait_ = trait_?; let target_scope = sema.scope(annotated_name.syntax())?; @@ -217,23 +206,25 @@ fn impl_def_from_trait( } let impl_def = generate_trait_impl(impl_is_unsafe, adt, make::ty_path(trait_path.clone())); - let first_assoc_item = + let _ = add_trait_assoc_items_to_impl(sema, config, &trait_items, trait_, &impl_def, &target_scope); - + let impl_def = impl_def.clone_subtree(); + let mut editor = SyntaxEditor::new(impl_def.syntax().clone()); + let first_assoc_item = impl_def.assoc_item_list().and_then(|item| item.assoc_items().next())?; // Generate a default `impl` function body for the derived trait. if let ast::AssocItem::Fn(ref func) = first_assoc_item { if let Some(body) = gen_trait_fn_body(func, trait_path, adt, None) && let Some(func_body) = func.body() { - ted::replace(func_body.syntax(), body.syntax()); + editor.replace(func_body.syntax(), body.syntax()); } }; - - Some((impl_def, first_assoc_item)) + let impl_def = ast::Impl::cast(editor.finish().new_root().clone())?; + Some(impl_def) } fn update_attribute( - builder: &mut SourceChangeBuilder, + editor: &mut SyntaxEditor, old_derives: &[ast::Path], old_tree: &ast::TokenTree, old_trait_path: &ast::Path, @@ -246,8 +237,6 @@ fn update_attribute( let has_more_derives = !new_derives.is_empty(); if has_more_derives { - let old_tree = builder.make_mut(old_tree.clone()); - // Make the paths into flat lists of tokens in a vec let tt = new_derives.iter().map(|path| path.syntax().clone()).map(|node| { node.descendants_with_tokens() @@ -262,18 +251,17 @@ fn update_attribute( let tt = tt.collect::>(); let new_tree = make::token_tree(T!['('], tt).clone_for_update(); - ted::replace(old_tree.syntax(), new_tree.syntax()); + editor.replace(old_tree.syntax(), new_tree.syntax()); } else { // Remove the attr and any trailing whitespace - let attr = builder.make_mut(attr.clone()); if let Some(line_break) = attr.syntax().next_sibling_or_token().filter(|t| t.kind() == WHITESPACE) { - ted::remove(line_break) + editor.delete(line_break) } - ted::remove(attr.syntax()) + editor.delete(attr.syntax()) } }