aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/assists/src/handlers/replace_derive_with_manual_impl.rs (renamed from crates/assists/src/handlers/add_custom_impl.rs)103
-rw-r--r--crates/assists/src/lib.rs4
-rw-r--r--crates/assists/src/tests/generated.rs42
-rw-r--r--xtask/tests/tidy.rs8
4 files changed, 88 insertions, 69 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 {}
diff --git a/crates/assists/src/lib.rs b/crates/assists/src/lib.rs
index af88b3437..92f764145 100644
--- a/crates/assists/src/lib.rs
+++ b/crates/assists/src/lib.rs
@@ -120,7 +120,6 @@ mod handlers {
120 120
121 pub(crate) type Handler = fn(&mut Assists, &AssistContext) -> Option<()>; 121 pub(crate) type Handler = fn(&mut Assists, &AssistContext) -> Option<()>;
122 122
123 mod add_custom_impl;
124 mod add_explicit_type; 123 mod add_explicit_type;
125 mod add_missing_impl_members; 124 mod add_missing_impl_members;
126 mod add_turbo_fish; 125 mod add_turbo_fish;
@@ -157,6 +156,7 @@ mod handlers {
157 mod remove_mut; 156 mod remove_mut;
158 mod remove_unused_param; 157 mod remove_unused_param;
159 mod reorder_fields; 158 mod reorder_fields;
159 mod replace_derive_with_manual_impl;
160 mod replace_if_let_with_match; 160 mod replace_if_let_with_match;
161 mod replace_impl_trait_with_generic; 161 mod replace_impl_trait_with_generic;
162 mod replace_let_with_if_let; 162 mod replace_let_with_if_let;
@@ -169,7 +169,6 @@ mod handlers {
169 pub(crate) fn all() -> &'static [Handler] { 169 pub(crate) fn all() -> &'static [Handler] {
170 &[ 170 &[
171 // These are alphabetic for the foolish consistency 171 // These are alphabetic for the foolish consistency
172 add_custom_impl::add_custom_impl,
173 add_explicit_type::add_explicit_type, 172 add_explicit_type::add_explicit_type,
174 add_turbo_fish::add_turbo_fish, 173 add_turbo_fish::add_turbo_fish,
175 apply_demorgan::apply_demorgan, 174 apply_demorgan::apply_demorgan,
@@ -208,6 +207,7 @@ mod handlers {
208 remove_mut::remove_mut, 207 remove_mut::remove_mut,
209 remove_unused_param::remove_unused_param, 208 remove_unused_param::remove_unused_param,
210 reorder_fields::reorder_fields, 209 reorder_fields::reorder_fields,
210 replace_derive_with_manual_impl::replace_derive_with_manual_impl,
211 replace_if_let_with_match::replace_if_let_with_match, 211 replace_if_let_with_match::replace_if_let_with_match,
212 replace_impl_trait_with_generic::replace_impl_trait_with_generic, 212 replace_impl_trait_with_generic::replace_impl_trait_with_generic,
213 replace_let_with_if_let::replace_let_with_if_let, 213 replace_let_with_if_let::replace_let_with_if_let,
diff --git a/crates/assists/src/tests/generated.rs b/crates/assists/src/tests/generated.rs
index 168e1626a..629788f05 100644
--- a/crates/assists/src/tests/generated.rs
+++ b/crates/assists/src/tests/generated.rs
@@ -3,25 +3,6 @@
3use super::check_doc_test; 3use super::check_doc_test;
4 4
5#[test] 5#[test]
6fn doctest_add_custom_impl() {
7 check_doc_test(
8 "add_custom_impl",
9 r#####"
10#[derive(Deb<|>ug, Display)]
11struct S;
12"#####,
13 r#####"
14#[derive(Display)]
15struct S;
16
17impl Debug for S {
18 $0
19}
20"#####,
21 )
22}
23
24#[test]
25fn doctest_add_explicit_type() { 6fn doctest_add_explicit_type() {
26 check_doc_test( 7 check_doc_test(
27 "add_explicit_type", 8 "add_explicit_type",
@@ -832,6 +813,29 @@ const test: Foo = Foo {foo: 1, bar: 0}
832} 813}
833 814
834#[test] 815#[test]
816fn doctest_replace_derive_with_manual_impl() {
817 check_doc_test(
818 "replace_derive_with_manual_impl",
819 r#####"
820trait Debug { fn fmt(&self, f: &mut Formatter) -> Result<()>; }
821#[derive(Deb<|>ug, Display)]
822struct S;
823"#####,
824 r#####"
825trait Debug { fn fmt(&self, f: &mut Formatter) -> Result<()>; }
826#[derive(Display)]
827struct S;
828
829impl Debug for S {
830 fn fmt(&self, f: &mut Formatter) -> Result<()> {
831 ${0:todo!()}
832 }
833}
834"#####,
835 )
836}
837
838#[test]
835fn doctest_replace_if_let_with_match() { 839fn doctest_replace_if_let_with_match() {
836 check_doc_test( 840 check_doc_test(
837 "replace_if_let_with_match", 841 "replace_if_let_with_match",
diff --git a/xtask/tests/tidy.rs b/xtask/tests/tidy.rs
index 4c7db8405..99652e76b 100644
--- a/xtask/tests/tidy.rs
+++ b/xtask/tests/tidy.rs
@@ -214,9 +214,6 @@ fn check_todo(path: &Path, text: &str) {
214 // This file itself obviously needs to use todo (<- like this!). 214 // This file itself obviously needs to use todo (<- like this!).
215 "tests/cli.rs", 215 "tests/cli.rs",
216 // Some of our assists generate `todo!()`. 216 // Some of our assists generate `todo!()`.
217 "tests/generated.rs",
218 "handlers/add_custom_impl.rs",
219 "handlers/add_missing_impl_members.rs",
220 "handlers/add_turbo_fish.rs", 217 "handlers/add_turbo_fish.rs",
221 "handlers/generate_function.rs", 218 "handlers/generate_function.rs",
222 // To support generating `todo!()` in assists, we have `expr_todo()` in 219 // To support generating `todo!()` in assists, we have `expr_todo()` in
@@ -229,6 +226,11 @@ fn check_todo(path: &Path, text: &str) {
229 return; 226 return;
230 } 227 }
231 if text.contains("TODO") || text.contains("TOOD") || text.contains("todo!") { 228 if text.contains("TODO") || text.contains("TOOD") || text.contains("todo!") {
229 // Generated by an assist
230 if text.contains("${0:todo!()}") {
231 return;
232 }
233
232 panic!( 234 panic!(
233 "\nTODO markers or todo! macros should not be committed to the master branch,\n\ 235 "\nTODO markers or todo! macros should not be committed to the master branch,\n\
234 use FIXME instead\n\ 236 use FIXME instead\n\