diff options
-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.rs | 4 | ||||
-rw-r--r-- | crates/assists/src/tests/generated.rs | 42 | ||||
-rw-r--r-- | xtask/tests/tidy.rs | 8 |
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 | // ``` |
36 | pub(crate) fn add_custom_impl(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | 40 | pub(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 | ||
132 | fn impl_def_from_trait( | 145 | fn 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 | " |
197 | mod fmt { | 210 | mod 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 | " |
238 | mod foo { | 251 | mod 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)] |
288 | struct Foo { | 301 | struct 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<|>)] |
310 | pub struct Foo { | 323 | pub 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)] |
332 | struct Foo {} | 345 | struct 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(<|>)] |
351 | struct Foo {} | 364 | struct 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)] |
362 | struct Foo {} | 375 | struct 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)<|>] |
370 | struct Foo {} | 383 | struct 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)] |
381 | struct Foo {} | 394 | struct 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 @@ | |||
3 | use super::check_doc_test; | 3 | use super::check_doc_test; |
4 | 4 | ||
5 | #[test] | 5 | #[test] |
6 | fn doctest_add_custom_impl() { | ||
7 | check_doc_test( | ||
8 | "add_custom_impl", | ||
9 | r#####" | ||
10 | #[derive(Deb<|>ug, Display)] | ||
11 | struct S; | ||
12 | "#####, | ||
13 | r#####" | ||
14 | #[derive(Display)] | ||
15 | struct S; | ||
16 | |||
17 | impl Debug for S { | ||
18 | $0 | ||
19 | } | ||
20 | "#####, | ||
21 | ) | ||
22 | } | ||
23 | |||
24 | #[test] | ||
25 | fn doctest_add_explicit_type() { | 6 | fn 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] |
816 | fn doctest_replace_derive_with_manual_impl() { | ||
817 | check_doc_test( | ||
818 | "replace_derive_with_manual_impl", | ||
819 | r#####" | ||
820 | trait Debug { fn fmt(&self, f: &mut Formatter) -> Result<()>; } | ||
821 | #[derive(Deb<|>ug, Display)] | ||
822 | struct S; | ||
823 | "#####, | ||
824 | r#####" | ||
825 | trait Debug { fn fmt(&self, f: &mut Formatter) -> Result<()>; } | ||
826 | #[derive(Display)] | ||
827 | struct S; | ||
828 | |||
829 | impl Debug for S { | ||
830 | fn fmt(&self, f: &mut Formatter) -> Result<()> { | ||
831 | ${0:todo!()} | ||
832 | } | ||
833 | } | ||
834 | "#####, | ||
835 | ) | ||
836 | } | ||
837 | |||
838 | #[test] | ||
835 | fn doctest_replace_if_let_with_match() { | 839 | fn 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\ |