aboutsummaryrefslogtreecommitdiff
path: root/crates/assists/src/handlers
diff options
context:
space:
mode:
Diffstat (limited to 'crates/assists/src/handlers')
-rw-r--r--crates/assists/src/handlers/replace_derive_with_manual_impl.rs (renamed from crates/assists/src/handlers/add_custom_impl.rs)103
1 files changed, 58 insertions, 45 deletions
diff --git a/crates/assists/src/handlers/add_custom_impl.rs b/crates/assists/src/handlers/replace_derive_with_manual_impl.rs
index c13493fd8..82625516c 100644
--- a/crates/assists/src/handlers/add_custom_impl.rs
+++ b/crates/assists/src/handlers/replace_derive_with_manual_impl.rs
@@ -16,24 +16,31 @@ use crate::{
16 AssistId, AssistKind, 16 AssistId, AssistKind,
17}; 17};
18 18
19// Assist: add_custom_impl 19// Assist: replace_derive_with_manual_impl
20// 20//
21// Adds impl block for derived trait. 21// Converts a `derive` impl into a manual one.
22// 22//
23// ``` 23// ```
24// # trait Debug { fn fmt(&self, f: &mut Formatter) -> Result<()>; }
24// #[derive(Deb<|>ug, Display)] 25// #[derive(Deb<|>ug, Display)]
25// struct S; 26// struct S;
26// ``` 27// ```
27// -> 28// ->
28// ``` 29// ```
30// # trait Debug { fn fmt(&self, f: &mut Formatter) -> Result<()>; }
29// #[derive(Display)] 31// #[derive(Display)]
30// struct S; 32// struct S;
31// 33//
32// impl Debug for S { 34// impl Debug for S {
33// $0 35// fn fmt(&self, f: &mut Formatter) -> Result<()> {
36// ${0:todo!()}
37// }
34// } 38// }
35// ``` 39// ```
36pub(crate) fn add_custom_impl(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { 40pub(crate) fn replace_derive_with_manual_impl(
41 acc: &mut Assists,
42 ctx: &AssistContext,
43) -> Option<()> {
37 let attr = ctx.find_node_at_offset::<ast::Attr>()?; 44 let attr = ctx.find_node_at_offset::<ast::Attr>()?;
38 45
39 let attr_name = attr 46 let attr_name = attr
@@ -90,43 +97,49 @@ fn add_assist(
90) -> Option<()> { 97) -> Option<()> {
91 let target = attr.syntax().text_range(); 98 let target = attr.syntax().text_range();
92 let input = attr.token_tree()?; 99 let input = attr.token_tree()?;
93 let label = format!("Add custom impl `{}` for `{}`", trait_path, annotated_name); 100 let label = format!("Convert to manual `impl {} for {}`", trait_path, annotated_name);
94 let trait_name = trait_path.segment().and_then(|seg| seg.name_ref())?; 101 let trait_name = trait_path.segment().and_then(|seg| seg.name_ref())?;
95 102
96 acc.add(AssistId("add_custom_impl", AssistKind::Refactor), label, target, |builder| { 103 acc.add(
97 let impl_def_with_items = 104 AssistId("replace_derive_with_manual_impl", AssistKind::Refactor),
98 impl_def_from_trait(&ctx.sema, annotated_name, trait_, trait_path); 105 label,
99 update_attribute(builder, &input, &trait_name, &attr); 106 target,
100 match (ctx.config.snippet_cap, impl_def_with_items) { 107 |builder| {
101 (None, _) => builder.insert( 108 let impl_def_with_items =
102 insert_pos, 109 impl_def_from_trait(&ctx.sema, annotated_name, trait_, trait_path);
103 format!("\n\nimpl {} for {} {{\n\n}}", trait_path, annotated_name), 110 update_attribute(builder, &input, &trait_name, &attr);
104 ), 111 match (ctx.config.snippet_cap, impl_def_with_items) {
105 (Some(cap), None) => builder.insert_snippet( 112 (None, _) => builder.insert(
106 cap, 113 insert_pos,
107 insert_pos, 114 format!("\n\nimpl {} for {} {{\n\n}}", trait_path, annotated_name),
108 format!("\n\nimpl {} for {} {{\n $0\n}}", trait_path, annotated_name), 115 ),
109 ), 116 (Some(cap), None) => builder.insert_snippet(
110 (Some(cap), Some((impl_def, first_assoc_item))) => { 117 cap,
111 let mut cursor = Cursor::Before(first_assoc_item.syntax()); 118 insert_pos,
112 let placeholder; 119 format!("\n\nimpl {} for {} {{\n $0\n}}", trait_path, annotated_name),
113 if let ast::AssocItem::Fn(ref func) = first_assoc_item { 120 ),
114 if let Some(m) = func.syntax().descendants().find_map(ast::MacroCall::cast) { 121 (Some(cap), Some((impl_def, first_assoc_item))) => {
115 if m.syntax().text() == "todo!()" { 122 let mut cursor = Cursor::Before(first_assoc_item.syntax());
116 placeholder = m; 123 let placeholder;
117 cursor = Cursor::Replace(placeholder.syntax()); 124 if let ast::AssocItem::Fn(ref func) = first_assoc_item {
125 if let Some(m) = func.syntax().descendants().find_map(ast::MacroCall::cast)
126 {
127 if m.syntax().text() == "todo!()" {
128 placeholder = m;
129 cursor = Cursor::Replace(placeholder.syntax());
130 }
118 } 131 }
119 } 132 }
120 }
121 133
122 builder.insert_snippet( 134 builder.insert_snippet(
123 cap, 135 cap,
124 insert_pos, 136 insert_pos,
125 format!("\n\n{}", render_snippet(cap, impl_def.syntax(), cursor)), 137 format!("\n\n{}", render_snippet(cap, impl_def.syntax(), cursor)),
126 ) 138 )
127 } 139 }
128 }; 140 };
129 }) 141 },
142 )
130} 143}
131 144
132fn impl_def_from_trait( 145fn impl_def_from_trait(
@@ -192,7 +205,7 @@ mod tests {
192 #[test] 205 #[test]
193 fn add_custom_impl_debug() { 206 fn add_custom_impl_debug() {
194 check_assist( 207 check_assist(
195 add_custom_impl, 208 replace_derive_with_manual_impl,
196 " 209 "
197mod fmt { 210mod fmt {
198 pub struct Error; 211 pub struct Error;
@@ -233,7 +246,7 @@ impl fmt::Debug for Foo {
233 #[test] 246 #[test]
234 fn add_custom_impl_all() { 247 fn add_custom_impl_all() {
235 check_assist( 248 check_assist(
236 add_custom_impl, 249 replace_derive_with_manual_impl,
237 " 250 "
238mod foo { 251mod foo {
239 pub trait Bar { 252 pub trait Bar {
@@ -282,7 +295,7 @@ impl foo::Bar for Foo {
282 #[test] 295 #[test]
283 fn add_custom_impl_for_unique_input() { 296 fn add_custom_impl_for_unique_input() {
284 check_assist( 297 check_assist(
285 add_custom_impl, 298 replace_derive_with_manual_impl,
286 " 299 "
287#[derive(Debu<|>g)] 300#[derive(Debu<|>g)]
288struct Foo { 301struct Foo {
@@ -304,7 +317,7 @@ impl Debug for Foo {
304 #[test] 317 #[test]
305 fn add_custom_impl_for_with_visibility_modifier() { 318 fn add_custom_impl_for_with_visibility_modifier() {
306 check_assist( 319 check_assist(
307 add_custom_impl, 320 replace_derive_with_manual_impl,
308 " 321 "
309#[derive(Debug<|>)] 322#[derive(Debug<|>)]
310pub struct Foo { 323pub struct Foo {
@@ -326,7 +339,7 @@ impl Debug for Foo {
326 #[test] 339 #[test]
327 fn add_custom_impl_when_multiple_inputs() { 340 fn add_custom_impl_when_multiple_inputs() {
328 check_assist( 341 check_assist(
329 add_custom_impl, 342 replace_derive_with_manual_impl,
330 " 343 "
331#[derive(Display, Debug<|>, Serialize)] 344#[derive(Display, Debug<|>, Serialize)]
332struct Foo {} 345struct Foo {}
@@ -345,7 +358,7 @@ impl Debug for Foo {
345 #[test] 358 #[test]
346 fn test_ignore_derive_macro_without_input() { 359 fn test_ignore_derive_macro_without_input() {
347 check_assist_not_applicable( 360 check_assist_not_applicable(
348 add_custom_impl, 361 replace_derive_with_manual_impl,
349 " 362 "
350#[derive(<|>)] 363#[derive(<|>)]
351struct Foo {} 364struct Foo {}
@@ -356,7 +369,7 @@ struct Foo {}
356 #[test] 369 #[test]
357 fn test_ignore_if_cursor_on_param() { 370 fn test_ignore_if_cursor_on_param() {
358 check_assist_not_applicable( 371 check_assist_not_applicable(
359 add_custom_impl, 372 replace_derive_with_manual_impl,
360 " 373 "
361#[derive<|>(Debug)] 374#[derive<|>(Debug)]
362struct Foo {} 375struct Foo {}
@@ -364,7 +377,7 @@ struct Foo {}
364 ); 377 );
365 378
366 check_assist_not_applicable( 379 check_assist_not_applicable(
367 add_custom_impl, 380 replace_derive_with_manual_impl,
368 " 381 "
369#[derive(Debug)<|>] 382#[derive(Debug)<|>]
370struct Foo {} 383struct Foo {}
@@ -375,7 +388,7 @@ struct Foo {}
375 #[test] 388 #[test]
376 fn test_ignore_if_not_derive() { 389 fn test_ignore_if_not_derive() {
377 check_assist_not_applicable( 390 check_assist_not_applicable(
378 add_custom_impl, 391 replace_derive_with_manual_impl,
379 " 392 "
380#[allow(non_camel_<|>case_types)] 393#[allow(non_camel_<|>case_types)]
381struct Foo {} 394struct Foo {}