migrate_replace_derive_with_manual_impl
This commit is contained in:
parent
3c8fdcbed6
commit
225988b762
2 changed files with 45 additions and 60 deletions
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<hir::Trait>,
|
||||
trait_path: &ast::Path,
|
||||
impl_is_unsafe: bool,
|
||||
) -> Option<(ast::Impl, ast::AssocItem)> {
|
||||
) -> Option<ast::Impl> {
|
||||
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::<Vec<_>>();
|
||||
|
||||
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())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue