aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2021-02-13 21:37:35 +0000
committerGitHub <[email protected]>2021-02-13 21:37:35 +0000
commit84c9970db5056738995b0979cda8249c2314c6ee (patch)
tree30e71296bfdc89448256cc4987ac06f18c32758f /crates
parent7f751d6413aaaf7b36c02a76ac99077da529db75 (diff)
parent7f100fff92ab4944f3d49cf7ffdcd91fc3578936 (diff)
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 <[email protected]>
Diffstat (limited to 'crates')
-rw-r--r--crates/assists/src/handlers/generate_from_impl_for_enum.rs61
-rw-r--r--crates/assists/src/handlers/generate_impl.rs46
-rw-r--r--crates/assists/src/handlers/replace_derive_with_manual_impl.rs26
-rw-r--r--crates/assists/src/utils.rs20
4 files changed, 55 insertions, 98 deletions
diff --git a/crates/assists/src/handlers/generate_from_impl_for_enum.rs b/crates/assists/src/handlers/generate_from_impl_for_enum.rs
index f6febd3aa..d9388a737 100644
--- a/crates/assists/src/handlers/generate_from_impl_for_enum.rs
+++ b/crates/assists/src/handlers/generate_from_impl_for_enum.rs
@@ -1,15 +1,9 @@
1use ast::GenericParamsOwner;
2use ide_db::helpers::FamousDefs; 1use ide_db::helpers::FamousDefs;
3use ide_db::RootDatabase; 2use ide_db::RootDatabase;
4use itertools::Itertools; 3use syntax::ast::{self, AstNode, NameOwner};
5use stdx::format_to;
6use syntax::{
7 ast::{self, AstNode, NameOwner},
8 SmolStr,
9};
10use test_utils::mark; 4use test_utils::mark;
11 5
12use crate::{AssistContext, AssistId, AssistKind, Assists}; 6use crate::{utils::generate_trait_impl_text, AssistContext, AssistId, AssistKind, Assists};
13 7
14// Assist: generate_from_impl_for_enum 8// Assist: generate_from_impl_for_enum
15// 9//
@@ -31,8 +25,7 @@ use crate::{AssistContext, AssistId, AssistKind, Assists};
31pub(crate) fn generate_from_impl_for_enum(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { 25pub(crate) fn generate_from_impl_for_enum(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
32 let variant = ctx.find_node_at_offset::<ast::Variant>()?; 26 let variant = ctx.find_node_at_offset::<ast::Variant>()?;
33 let variant_name = variant.name()?; 27 let variant_name = variant.name()?;
34 let enum_name = variant.parent_enum().name()?; 28 let enum_ = ast::Adt::Enum(variant.parent_enum());
35 let enum_type_params = variant.parent_enum().generic_param_list();
36 let (field_name, field_type) = match variant.kind() { 29 let (field_name, field_type) = match variant.kind() {
37 ast::StructKind::Tuple(field_list) => { 30 ast::StructKind::Tuple(field_list) => {
38 if field_list.fields().count() != 1 { 31 if field_list.fields().count() != 1 {
@@ -62,49 +55,27 @@ pub(crate) fn generate_from_impl_for_enum(acc: &mut Assists, ctx: &AssistContext
62 target, 55 target,
63 |edit| { 56 |edit| {
64 let start_offset = variant.parent_enum().syntax().text_range().end(); 57 let start_offset = variant.parent_enum().syntax().text_range().end();
65 let mut buf = String::from("\n\nimpl"); 58 let from_trait = format!("From<{}>", field_type.syntax());
66 if let Some(type_params) = &enum_type_params { 59 let impl_code = if let Some(name) = field_name {
67 format_to!(buf, "{}", type_params.syntax()); 60 format!(
68 } 61 r#" fn from({0}: {1}) -> Self {{
69 format_to!(buf, " From<{}> for {}", field_type.syntax(), enum_name);
70 if let Some(type_params) = enum_type_params {
71 let lifetime_params = type_params
72 .lifetime_params()
73 .filter_map(|it| it.lifetime())
74 .map(|it| SmolStr::from(it.text()));
75 let type_params = type_params
76 .type_params()
77 .filter_map(|it| it.name())
78 .map(|it| SmolStr::from(it.text()));
79
80 let generic_params = lifetime_params.chain(type_params).format(", ");
81 format_to!(buf, "<{}>", generic_params)
82 }
83 if let Some(name) = field_name {
84 format_to!(
85 buf,
86 r#" {{
87 fn from({0}: {1}) -> Self {{
88 Self::{2} {{ {0} }} 62 Self::{2} {{ {0} }}
89 }} 63 }}"#,
90}}"#,
91 name.text(), 64 name.text(),
92 field_type.syntax(), 65 field_type.syntax(),
93 variant_name, 66 variant_name,
94 ); 67 )
95 } else { 68 } else {
96 format_to!( 69 format!(
97 buf, 70 r#" fn from(v: {}) -> Self {{
98 r#" {{
99 fn from(v: {}) -> Self {{
100 Self::{}(v) 71 Self::{}(v)
101 }} 72 }}"#,
102}}"#,
103 field_type.syntax(), 73 field_type.syntax(),
104 variant_name, 74 variant_name,
105 ); 75 )
106 } 76 };
107 edit.insert(start_offset, buf); 77 let from_impl = generate_trait_impl_text(&enum_, &from_trait, &impl_code);
78 edit.insert(start_offset, from_impl);
108 }, 79 },
109 ) 80 )
110} 81}
diff --git a/crates/assists/src/handlers/generate_impl.rs b/crates/assists/src/handlers/generate_impl.rs
index 61d1bd25c..050bcd4e2 100644
--- a/crates/assists/src/handlers/generate_impl.rs
+++ b/crates/assists/src/handlers/generate_impl.rs
@@ -1,11 +1,6 @@
1use itertools::Itertools; 1use syntax::ast::{self, AstNode, NameOwner};
2use stdx::format_to;
3use syntax::{
4 ast::{self, AstNode, AttrsOwner, GenericParamsOwner, NameOwner},
5 SmolStr,
6};
7 2
8use crate::{AssistContext, AssistId, AssistKind, Assists}; 3use crate::{utils::generate_impl_text, AssistContext, AssistId, AssistKind, Assists};
9 4
10// Assist: generate_impl 5// Assist: generate_impl
11// 6//
@@ -36,44 +31,15 @@ pub(crate) fn generate_impl(acc: &mut Assists, ctx: &AssistContext) -> Option<()
36 format!("Generate impl for `{}`", name), 31 format!("Generate impl for `{}`", name),
37 target, 32 target,
38 |edit| { 33 |edit| {
39 let type_params = nominal.generic_param_list();
40 let start_offset = nominal.syntax().text_range().end(); 34 let start_offset = nominal.syntax().text_range().end();
41 let mut buf = String::new();
42 buf.push_str("\n\n");
43 nominal
44 .attrs()
45 .filter(|attr| {
46 attr.as_simple_call().map(|(name, _arg)| name == "cfg").unwrap_or(false)
47 })
48 .for_each(|attr| buf.push_str(format!("{}\n", attr.to_string()).as_str()));
49
50 buf.push_str("impl");
51 if let Some(type_params) = &type_params {
52 format_to!(buf, "{}", type_params.syntax());
53 }
54 buf.push_str(" ");
55 buf.push_str(name.text());
56 if let Some(type_params) = type_params {
57 let lifetime_params = type_params
58 .lifetime_params()
59 .filter_map(|it| it.lifetime())
60 .map(|it| SmolStr::from(it.text()));
61 let type_params = type_params
62 .type_params()
63 .filter_map(|it| it.name())
64 .map(|it| SmolStr::from(it.text()));
65
66 let generic_params = lifetime_params.chain(type_params).format(", ");
67 format_to!(buf, "<{}>", generic_params)
68 }
69 match ctx.config.snippet_cap { 35 match ctx.config.snippet_cap {
70 Some(cap) => { 36 Some(cap) => {
71 buf.push_str(" {\n $0\n}"); 37 let snippet = generate_impl_text(&nominal, " $0");
72 edit.insert_snippet(cap, start_offset, buf); 38 edit.insert_snippet(cap, start_offset, snippet);
73 } 39 }
74 None => { 40 None => {
75 buf.push_str(" {\n}"); 41 let snippet = generate_impl_text(&nominal, "");
76 edit.insert(start_offset, buf); 42 edit.insert(start_offset, snippet);
77 } 43 }
78 } 44 }
79 }, 45 },
diff --git a/crates/assists/src/handlers/replace_derive_with_manual_impl.rs b/crates/assists/src/handlers/replace_derive_with_manual_impl.rs
index 6aa9d2f2c..c69bc5cac 100644
--- a/crates/assists/src/handlers/replace_derive_with_manual_impl.rs
+++ b/crates/assists/src/handlers/replace_derive_with_manual_impl.rs
@@ -2,8 +2,7 @@ use ide_db::helpers::mod_path_to_ast;
2use ide_db::imports_locator; 2use ide_db::imports_locator;
3use itertools::Itertools; 3use itertools::Itertools;
4use syntax::{ 4use syntax::{
5 ast::{self, make, AstNode}, 5 ast::{self, make, AstNode, NameOwner},
6 Direction,
7 SyntaxKind::{IDENT, WHITESPACE}, 6 SyntaxKind::{IDENT, WHITESPACE},
8 TextSize, 7 TextSize,
9}; 8};
@@ -11,7 +10,8 @@ use syntax::{
11use crate::{ 10use crate::{
12 assist_context::{AssistBuilder, AssistContext, Assists}, 11 assist_context::{AssistBuilder, AssistContext, Assists},
13 utils::{ 12 utils::{
14 add_trait_assoc_items_to_impl, filter_assoc_items, render_snippet, Cursor, DefaultMethods, 13 add_trait_assoc_items_to_impl, filter_assoc_items, generate_trait_impl_text,
14 render_snippet, Cursor, DefaultMethods,
15 }, 15 },
16 AssistId, AssistKind, 16 AssistId, AssistKind,
17}; 17};
@@ -57,8 +57,9 @@ pub(crate) fn replace_derive_with_manual_impl(
57 let trait_token = ctx.token_at_offset().find(|t| t.kind() == IDENT && t.text() != "derive")?; 57 let trait_token = ctx.token_at_offset().find(|t| t.kind() == IDENT && t.text() != "derive")?;
58 let trait_path = make::path_unqualified(make::path_segment(make::name_ref(trait_token.text()))); 58 let trait_path = make::path_unqualified(make::path_segment(make::name_ref(trait_token.text())));
59 59
60 let annotated_name = attr.syntax().siblings(Direction::Next).find_map(ast::Name::cast)?; 60 let adt = attr.syntax().parent().and_then(ast::Adt::cast)?;
61 let insert_pos = annotated_name.syntax().parent()?.text_range().end(); 61 let annotated_name = adt.name()?;
62 let insert_pos = adt.syntax().text_range().end();
62 63
63 let current_module = ctx.sema.scope(annotated_name.syntax()).module()?; 64 let current_module = ctx.sema.scope(annotated_name.syntax()).module()?;
64 let current_crate = current_module.krate(); 65 let current_crate = current_module.krate();
@@ -82,10 +83,10 @@ pub(crate) fn replace_derive_with_manual_impl(
82 83
83 let mut no_traits_found = true; 84 let mut no_traits_found = true;
84 for (trait_path, trait_) in found_traits.inspect(|_| no_traits_found = false) { 85 for (trait_path, trait_) in found_traits.inspect(|_| no_traits_found = false) {
85 add_assist(acc, ctx, &attr, &trait_path, Some(trait_), &annotated_name, insert_pos)?; 86 add_assist(acc, ctx, &attr, &trait_path, Some(trait_), &adt, &annotated_name, insert_pos)?;
86 } 87 }
87 if no_traits_found { 88 if no_traits_found {
88 add_assist(acc, ctx, &attr, &trait_path, None, &annotated_name, insert_pos)?; 89 add_assist(acc, ctx, &attr, &trait_path, None, &adt, &annotated_name, insert_pos)?;
89 } 90 }
90 Some(()) 91 Some(())
91} 92}
@@ -96,6 +97,7 @@ fn add_assist(
96 attr: &ast::Attr, 97 attr: &ast::Attr,
97 trait_path: &ast::Path, 98 trait_path: &ast::Path,
98 trait_: Option<hir::Trait>, 99 trait_: Option<hir::Trait>,
100 adt: &ast::Adt,
99 annotated_name: &ast::Name, 101 annotated_name: &ast::Name,
100 insert_pos: TextSize, 102 insert_pos: TextSize,
101) -> Option<()> { 103) -> Option<()> {
@@ -112,15 +114,15 @@ fn add_assist(
112 let impl_def_with_items = 114 let impl_def_with_items =
113 impl_def_from_trait(&ctx.sema, annotated_name, trait_, trait_path); 115 impl_def_from_trait(&ctx.sema, annotated_name, trait_, trait_path);
114 update_attribute(builder, &input, &trait_name, &attr); 116 update_attribute(builder, &input, &trait_name, &attr);
117 let trait_path = format!("{}", trait_path);
115 match (ctx.config.snippet_cap, impl_def_with_items) { 118 match (ctx.config.snippet_cap, impl_def_with_items) {
116 (None, _) => builder.insert( 119 (None, _) => {
117 insert_pos, 120 builder.insert(insert_pos, generate_trait_impl_text(adt, &trait_path, ""))
118 format!("\n\nimpl {} for {} {{\n\n}}", trait_path, annotated_name), 121 }
119 ),
120 (Some(cap), None) => builder.insert_snippet( 122 (Some(cap), None) => builder.insert_snippet(
121 cap, 123 cap,
122 insert_pos, 124 insert_pos,
123 format!("\n\nimpl {} for {} {{\n $0\n}}", trait_path, annotated_name), 125 generate_trait_impl_text(adt, &trait_path, " $0"),
124 ), 126 ),
125 (Some(cap), Some((impl_def, first_assoc_item))) => { 127 (Some(cap), Some((impl_def, first_assoc_item))) => {
126 let mut cursor = Cursor::Before(first_assoc_item.syntax()); 128 let mut cursor = Cursor::Before(first_assoc_item.syntax());
diff --git a/crates/assists/src/utils.rs b/crates/assists/src/utils.rs
index 5dd32aef1..98c4462bb 100644
--- a/crates/assists/src/utils.rs
+++ b/crates/assists/src/utils.rs
@@ -367,13 +367,31 @@ pub(crate) fn find_impl_block_end(impl_def: ast::Impl, buf: &mut String) -> Opti
367// Generates the surrounding `impl Type { <code> }` including type and lifetime 367// Generates the surrounding `impl Type { <code> }` including type and lifetime
368// parameters 368// parameters
369pub(crate) fn generate_impl_text(adt: &ast::Adt, code: &str) -> String { 369pub(crate) fn generate_impl_text(adt: &ast::Adt, code: &str) -> String {
370 generate_impl_text_inner(adt, None, code)
371}
372
373// Generates the surrounding `impl <trait> for Type { <code> }` including type
374// and lifetime parameters
375pub(crate) fn generate_trait_impl_text(adt: &ast::Adt, trait_text: &str, code: &str) -> String {
376 generate_impl_text_inner(adt, Some(trait_text), code)
377}
378
379fn generate_impl_text_inner(adt: &ast::Adt, trait_text: Option<&str>, code: &str) -> String {
370 let type_params = adt.generic_param_list(); 380 let type_params = adt.generic_param_list();
371 let mut buf = String::with_capacity(code.len()); 381 let mut buf = String::with_capacity(code.len());
372 buf.push_str("\n\nimpl"); 382 buf.push_str("\n\n");
383 adt.attrs()
384 .filter(|attr| attr.as_simple_call().map(|(name, _arg)| name == "cfg").unwrap_or(false))
385 .for_each(|attr| buf.push_str(format!("{}\n", attr.to_string()).as_str()));
386 buf.push_str("impl");
373 if let Some(type_params) = &type_params { 387 if let Some(type_params) = &type_params {
374 format_to!(buf, "{}", type_params.syntax()); 388 format_to!(buf, "{}", type_params.syntax());
375 } 389 }
376 buf.push(' '); 390 buf.push(' ');
391 if let Some(trait_text) = trait_text {
392 buf.push_str(trait_text);
393 buf.push_str(" for ");
394 }
377 buf.push_str(adt.name().unwrap().text()); 395 buf.push_str(adt.name().unwrap().text());
378 if let Some(type_params) = type_params { 396 if let Some(type_params) = type_params {
379 let lifetime_params = type_params 397 let lifetime_params = type_params