mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-11-16 09:48:10 +00:00
Merge #7664
7664: refactor impl generation in assists r=Veykril a=jDomantas Follow-up to #7659: all impl generation in assists (at least what I found) is now done through `utils::{generate_impl_text, generate_trait_impl_text}`. Co-authored-by: Domantas Jadenkus <djadenkus@gmail.com>
This commit is contained in:
commit
84c9970db5
4 changed files with 55 additions and 98 deletions
|
@ -1,15 +1,9 @@
|
|||
use ast::GenericParamsOwner;
|
||||
use ide_db::helpers::FamousDefs;
|
||||
use ide_db::RootDatabase;
|
||||
use itertools::Itertools;
|
||||
use stdx::format_to;
|
||||
use syntax::{
|
||||
ast::{self, AstNode, NameOwner},
|
||||
SmolStr,
|
||||
};
|
||||
use syntax::ast::{self, AstNode, NameOwner};
|
||||
use test_utils::mark;
|
||||
|
||||
use crate::{AssistContext, AssistId, AssistKind, Assists};
|
||||
use crate::{utils::generate_trait_impl_text, AssistContext, AssistId, AssistKind, Assists};
|
||||
|
||||
// Assist: generate_from_impl_for_enum
|
||||
//
|
||||
|
@ -31,8 +25,7 @@ use crate::{AssistContext, AssistId, AssistKind, Assists};
|
|||
pub(crate) fn generate_from_impl_for_enum(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
|
||||
let variant = ctx.find_node_at_offset::<ast::Variant>()?;
|
||||
let variant_name = variant.name()?;
|
||||
let enum_name = variant.parent_enum().name()?;
|
||||
let enum_type_params = variant.parent_enum().generic_param_list();
|
||||
let enum_ = ast::Adt::Enum(variant.parent_enum());
|
||||
let (field_name, field_type) = match variant.kind() {
|
||||
ast::StructKind::Tuple(field_list) => {
|
||||
if field_list.fields().count() != 1 {
|
||||
|
@ -62,49 +55,27 @@ pub(crate) fn generate_from_impl_for_enum(acc: &mut Assists, ctx: &AssistContext
|
|||
target,
|
||||
|edit| {
|
||||
let start_offset = variant.parent_enum().syntax().text_range().end();
|
||||
let mut buf = String::from("\n\nimpl");
|
||||
if let Some(type_params) = &enum_type_params {
|
||||
format_to!(buf, "{}", type_params.syntax());
|
||||
}
|
||||
format_to!(buf, " From<{}> for {}", field_type.syntax(), enum_name);
|
||||
if let Some(type_params) = enum_type_params {
|
||||
let lifetime_params = type_params
|
||||
.lifetime_params()
|
||||
.filter_map(|it| it.lifetime())
|
||||
.map(|it| SmolStr::from(it.text()));
|
||||
let type_params = type_params
|
||||
.type_params()
|
||||
.filter_map(|it| it.name())
|
||||
.map(|it| SmolStr::from(it.text()));
|
||||
|
||||
let generic_params = lifetime_params.chain(type_params).format(", ");
|
||||
format_to!(buf, "<{}>", generic_params)
|
||||
}
|
||||
if let Some(name) = field_name {
|
||||
format_to!(
|
||||
buf,
|
||||
r#" {{
|
||||
fn from({0}: {1}) -> Self {{
|
||||
let from_trait = format!("From<{}>", field_type.syntax());
|
||||
let impl_code = if let Some(name) = field_name {
|
||||
format!(
|
||||
r#" fn from({0}: {1}) -> Self {{
|
||||
Self::{2} {{ {0} }}
|
||||
}}
|
||||
}}"#,
|
||||
}}"#,
|
||||
name.text(),
|
||||
field_type.syntax(),
|
||||
variant_name,
|
||||
);
|
||||
)
|
||||
} else {
|
||||
format_to!(
|
||||
buf,
|
||||
r#" {{
|
||||
fn from(v: {}) -> Self {{
|
||||
format!(
|
||||
r#" fn from(v: {}) -> Self {{
|
||||
Self::{}(v)
|
||||
}}
|
||||
}}"#,
|
||||
}}"#,
|
||||
field_type.syntax(),
|
||||
variant_name,
|
||||
);
|
||||
}
|
||||
edit.insert(start_offset, buf);
|
||||
)
|
||||
};
|
||||
let from_impl = generate_trait_impl_text(&enum_, &from_trait, &impl_code);
|
||||
edit.insert(start_offset, from_impl);
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,11 +1,6 @@
|
|||
use itertools::Itertools;
|
||||
use stdx::format_to;
|
||||
use syntax::{
|
||||
ast::{self, AstNode, AttrsOwner, GenericParamsOwner, NameOwner},
|
||||
SmolStr,
|
||||
};
|
||||
use syntax::ast::{self, AstNode, NameOwner};
|
||||
|
||||
use crate::{AssistContext, AssistId, AssistKind, Assists};
|
||||
use crate::{utils::generate_impl_text, AssistContext, AssistId, AssistKind, Assists};
|
||||
|
||||
// Assist: generate_impl
|
||||
//
|
||||
|
@ -36,44 +31,15 @@ pub(crate) fn generate_impl(acc: &mut Assists, ctx: &AssistContext) -> Option<()
|
|||
format!("Generate impl for `{}`", name),
|
||||
target,
|
||||
|edit| {
|
||||
let type_params = nominal.generic_param_list();
|
||||
let start_offset = nominal.syntax().text_range().end();
|
||||
let mut buf = String::new();
|
||||
buf.push_str("\n\n");
|
||||
nominal
|
||||
.attrs()
|
||||
.filter(|attr| {
|
||||
attr.as_simple_call().map(|(name, _arg)| name == "cfg").unwrap_or(false)
|
||||
})
|
||||
.for_each(|attr| buf.push_str(format!("{}\n", attr.to_string()).as_str()));
|
||||
|
||||
buf.push_str("impl");
|
||||
if let Some(type_params) = &type_params {
|
||||
format_to!(buf, "{}", type_params.syntax());
|
||||
}
|
||||
buf.push_str(" ");
|
||||
buf.push_str(name.text());
|
||||
if let Some(type_params) = type_params {
|
||||
let lifetime_params = type_params
|
||||
.lifetime_params()
|
||||
.filter_map(|it| it.lifetime())
|
||||
.map(|it| SmolStr::from(it.text()));
|
||||
let type_params = type_params
|
||||
.type_params()
|
||||
.filter_map(|it| it.name())
|
||||
.map(|it| SmolStr::from(it.text()));
|
||||
|
||||
let generic_params = lifetime_params.chain(type_params).format(", ");
|
||||
format_to!(buf, "<{}>", generic_params)
|
||||
}
|
||||
match ctx.config.snippet_cap {
|
||||
Some(cap) => {
|
||||
buf.push_str(" {\n $0\n}");
|
||||
edit.insert_snippet(cap, start_offset, buf);
|
||||
let snippet = generate_impl_text(&nominal, " $0");
|
||||
edit.insert_snippet(cap, start_offset, snippet);
|
||||
}
|
||||
None => {
|
||||
buf.push_str(" {\n}");
|
||||
edit.insert(start_offset, buf);
|
||||
let snippet = generate_impl_text(&nominal, "");
|
||||
edit.insert(start_offset, snippet);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -2,8 +2,7 @@ use ide_db::helpers::mod_path_to_ast;
|
|||
use ide_db::imports_locator;
|
||||
use itertools::Itertools;
|
||||
use syntax::{
|
||||
ast::{self, make, AstNode},
|
||||
Direction,
|
||||
ast::{self, make, AstNode, NameOwner},
|
||||
SyntaxKind::{IDENT, WHITESPACE},
|
||||
TextSize,
|
||||
};
|
||||
|
@ -11,7 +10,8 @@ use syntax::{
|
|||
use crate::{
|
||||
assist_context::{AssistBuilder, AssistContext, Assists},
|
||||
utils::{
|
||||
add_trait_assoc_items_to_impl, filter_assoc_items, render_snippet, Cursor, DefaultMethods,
|
||||
add_trait_assoc_items_to_impl, filter_assoc_items, generate_trait_impl_text,
|
||||
render_snippet, Cursor, DefaultMethods,
|
||||
},
|
||||
AssistId, AssistKind,
|
||||
};
|
||||
|
@ -57,8 +57,9 @@ pub(crate) fn replace_derive_with_manual_impl(
|
|||
let trait_token = ctx.token_at_offset().find(|t| t.kind() == IDENT && t.text() != "derive")?;
|
||||
let trait_path = make::path_unqualified(make::path_segment(make::name_ref(trait_token.text())));
|
||||
|
||||
let annotated_name = attr.syntax().siblings(Direction::Next).find_map(ast::Name::cast)?;
|
||||
let insert_pos = annotated_name.syntax().parent()?.text_range().end();
|
||||
let adt = attr.syntax().parent().and_then(ast::Adt::cast)?;
|
||||
let annotated_name = adt.name()?;
|
||||
let insert_pos = adt.syntax().text_range().end();
|
||||
|
||||
let current_module = ctx.sema.scope(annotated_name.syntax()).module()?;
|
||||
let current_crate = current_module.krate();
|
||||
|
@ -82,10 +83,10 @@ pub(crate) fn replace_derive_with_manual_impl(
|
|||
|
||||
let mut no_traits_found = true;
|
||||
for (trait_path, trait_) in found_traits.inspect(|_| no_traits_found = false) {
|
||||
add_assist(acc, ctx, &attr, &trait_path, Some(trait_), &annotated_name, insert_pos)?;
|
||||
add_assist(acc, ctx, &attr, &trait_path, Some(trait_), &adt, &annotated_name, insert_pos)?;
|
||||
}
|
||||
if no_traits_found {
|
||||
add_assist(acc, ctx, &attr, &trait_path, None, &annotated_name, insert_pos)?;
|
||||
add_assist(acc, ctx, &attr, &trait_path, None, &adt, &annotated_name, insert_pos)?;
|
||||
}
|
||||
Some(())
|
||||
}
|
||||
|
@ -96,6 +97,7 @@ fn add_assist(
|
|||
attr: &ast::Attr,
|
||||
trait_path: &ast::Path,
|
||||
trait_: Option<hir::Trait>,
|
||||
adt: &ast::Adt,
|
||||
annotated_name: &ast::Name,
|
||||
insert_pos: TextSize,
|
||||
) -> Option<()> {
|
||||
|
@ -112,15 +114,15 @@ fn add_assist(
|
|||
let impl_def_with_items =
|
||||
impl_def_from_trait(&ctx.sema, annotated_name, trait_, trait_path);
|
||||
update_attribute(builder, &input, &trait_name, &attr);
|
||||
let trait_path = format!("{}", trait_path);
|
||||
match (ctx.config.snippet_cap, impl_def_with_items) {
|
||||
(None, _) => builder.insert(
|
||||
insert_pos,
|
||||
format!("\n\nimpl {} for {} {{\n\n}}", trait_path, annotated_name),
|
||||
),
|
||||
(None, _) => {
|
||||
builder.insert(insert_pos, generate_trait_impl_text(adt, &trait_path, ""))
|
||||
}
|
||||
(Some(cap), None) => builder.insert_snippet(
|
||||
cap,
|
||||
insert_pos,
|
||||
format!("\n\nimpl {} for {} {{\n $0\n}}", trait_path, annotated_name),
|
||||
generate_trait_impl_text(adt, &trait_path, " $0"),
|
||||
),
|
||||
(Some(cap), Some((impl_def, first_assoc_item))) => {
|
||||
let mut cursor = Cursor::Before(first_assoc_item.syntax());
|
||||
|
|
|
@ -367,13 +367,31 @@ pub(crate) fn find_impl_block_end(impl_def: ast::Impl, buf: &mut String) -> Opti
|
|||
// Generates the surrounding `impl Type { <code> }` including type and lifetime
|
||||
// parameters
|
||||
pub(crate) fn generate_impl_text(adt: &ast::Adt, code: &str) -> String {
|
||||
generate_impl_text_inner(adt, None, code)
|
||||
}
|
||||
|
||||
// Generates the surrounding `impl <trait> for Type { <code> }` including type
|
||||
// and lifetime parameters
|
||||
pub(crate) fn generate_trait_impl_text(adt: &ast::Adt, trait_text: &str, code: &str) -> String {
|
||||
generate_impl_text_inner(adt, Some(trait_text), code)
|
||||
}
|
||||
|
||||
fn generate_impl_text_inner(adt: &ast::Adt, trait_text: Option<&str>, code: &str) -> String {
|
||||
let type_params = adt.generic_param_list();
|
||||
let mut buf = String::with_capacity(code.len());
|
||||
buf.push_str("\n\nimpl");
|
||||
buf.push_str("\n\n");
|
||||
adt.attrs()
|
||||
.filter(|attr| attr.as_simple_call().map(|(name, _arg)| name == "cfg").unwrap_or(false))
|
||||
.for_each(|attr| buf.push_str(format!("{}\n", attr.to_string()).as_str()));
|
||||
buf.push_str("impl");
|
||||
if let Some(type_params) = &type_params {
|
||||
format_to!(buf, "{}", type_params.syntax());
|
||||
}
|
||||
buf.push(' ');
|
||||
if let Some(trait_text) = trait_text {
|
||||
buf.push_str(trait_text);
|
||||
buf.push_str(" for ");
|
||||
}
|
||||
buf.push_str(adt.name().unwrap().text());
|
||||
if let Some(type_params) = type_params {
|
||||
let lifetime_params = type_params
|
||||
|
|
Loading…
Reference in a new issue