aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoshua Warner <[email protected]>2021-06-05 23:29:29 +0100
committerJoshua Warner <[email protected]>2021-06-05 23:29:29 +0100
commit18f796a728806e5138708a7af00d6064ec251382 (patch)
treebfbdb2c523b82928d17d918fc1a6dbbb616c54b0
parentca9ffba0473cb32b06c01bc5d387e538d379f19e (diff)
Refactor to be just one assist
-rw-r--r--crates/ide_assists/src/handlers/convert_tuple_struct_to_named_struct.rs343
-rw-r--r--crates/ide_assists/src/handlers/convert_tuple_variant_to_named_variant.rs515
-rw-r--r--crates/ide_assists/src/lib.rs2
3 files changed, 328 insertions, 532 deletions
diff --git a/crates/ide_assists/src/handlers/convert_tuple_struct_to_named_struct.rs b/crates/ide_assists/src/handlers/convert_tuple_struct_to_named_struct.rs
index 70949ca35..53709e31f 100644
--- a/crates/ide_assists/src/handlers/convert_tuple_struct_to_named_struct.rs
+++ b/crates/ide_assists/src/handlers/convert_tuple_struct_to_named_struct.rs
@@ -1,3 +1,4 @@
1use either::Either;
1use ide_db::defs::{Definition, NameRefClass}; 2use ide_db::defs::{Definition, NameRefClass};
2use syntax::{ 3use syntax::{
3 ast::{self, AstNode, GenericParamsOwner, VisibilityOwner}, 4 ast::{self, AstNode, GenericParamsOwner, VisibilityOwner},
@@ -8,7 +9,7 @@ use crate::{assist_context::AssistBuilder, AssistContext, AssistId, AssistKind,
8 9
9// Assist: convert_tuple_struct_to_named_struct 10// Assist: convert_tuple_struct_to_named_struct
10// 11//
11// Converts tuple struct to struct with named fields. 12// Converts tuple struct to struct with named fields, and analogously for tuple enum variants.
12// 13//
13// ``` 14// ```
14// struct Point$0(f32, f32); 15// struct Point$0(f32, f32);
@@ -49,14 +50,21 @@ pub(crate) fn convert_tuple_struct_to_named_struct(
49 acc: &mut Assists, 50 acc: &mut Assists,
50 ctx: &AssistContext, 51 ctx: &AssistContext,
51) -> Option<()> { 52) -> Option<()> {
52 let strukt = ctx.find_node_at_offset::<ast::Struct>()?; 53 let strukt = ctx
53 let tuple_fields = match strukt.field_list()? { 54 .find_node_at_offset::<ast::Struct>()
55 .map(Either::Left)
56 .or_else(|| ctx.find_node_at_offset::<ast::Variant>().map(Either::Right))?;
57 let field_list = strukt.as_ref().either(|s| s.field_list(), |v| v.field_list())?;
58 let tuple_fields = match field_list {
54 ast::FieldList::TupleFieldList(it) => it, 59 ast::FieldList::TupleFieldList(it) => it,
55 ast::FieldList::RecordFieldList(_) => return None, 60 ast::FieldList::RecordFieldList(_) => return None,
56 }; 61 };
57 let strukt_def = ctx.sema.to_def(&strukt)?; 62 let strukt_def = match &strukt {
63 Either::Left(s) => Either::Left(ctx.sema.to_def(s)?),
64 Either::Right(v) => Either::Right(ctx.sema.to_def(v)?),
65 };
66 let target = strukt.as_ref().either(|s| s.syntax(), |v| v.syntax()).text_range();
58 67
59 let target = strukt.syntax().text_range();
60 acc.add( 68 acc.add(
61 AssistId("convert_tuple_struct_to_named_struct", AssistKind::RefactorRewrite), 69 AssistId("convert_tuple_struct_to_named_struct", AssistKind::RefactorRewrite),
62 "Convert to named struct", 70 "Convert to named struct",
@@ -73,7 +81,7 @@ pub(crate) fn convert_tuple_struct_to_named_struct(
73fn edit_struct_def( 81fn edit_struct_def(
74 ctx: &AssistContext, 82 ctx: &AssistContext,
75 edit: &mut AssistBuilder, 83 edit: &mut AssistBuilder,
76 strukt: &ast::Struct, 84 strukt: &Either<ast::Struct, ast::Variant>,
77 tuple_fields: ast::TupleFieldList, 85 tuple_fields: ast::TupleFieldList,
78 names: Vec<ast::Name>, 86 names: Vec<ast::Name>,
79) { 87) {
@@ -86,27 +94,34 @@ fn edit_struct_def(
86 94
87 edit.edit_file(ctx.frange.file_id); 95 edit.edit_file(ctx.frange.file_id);
88 96
89 if let Some(w) = strukt.where_clause() { 97 if let Either::Left(strukt) = strukt {
90 edit.delete(w.syntax().text_range()); 98 if let Some(w) = strukt.where_clause() {
91 edit.insert(tuple_fields_text_range.start(), ast::make::tokens::single_newline().text()); 99 edit.delete(w.syntax().text_range());
92 edit.insert(tuple_fields_text_range.start(), w.syntax().text()); 100 edit.insert(tuple_fields_text_range.start(), ast::make::tokens::single_newline().text());
93 edit.insert(tuple_fields_text_range.start(), ","); 101 edit.insert(tuple_fields_text_range.start(), w.syntax().text());
94 edit.insert(tuple_fields_text_range.start(), ast::make::tokens::single_newline().text()); 102 edit.insert(tuple_fields_text_range.start(), ",");
103 edit.insert(tuple_fields_text_range.start(), ast::make::tokens::single_newline().text());
104 } else {
105 edit.insert(tuple_fields_text_range.start(), ast::make::tokens::single_space().text());
106 }
107 strukt.semicolon_token().map(|t| edit.delete(t.text_range()));
95 } else { 108 } else {
96 edit.insert(tuple_fields_text_range.start(), ast::make::tokens::single_space().text()); 109 edit.insert(tuple_fields_text_range.start(), ast::make::tokens::single_space().text());
97 } 110 }
98 111
99 edit.replace(tuple_fields_text_range, record_fields.to_string()); 112 edit.replace(tuple_fields_text_range, record_fields.to_string());
100 strukt.semicolon_token().map(|t| edit.delete(t.text_range()));
101} 113}
102 114
103fn edit_struct_references( 115fn edit_struct_references(
104 ctx: &AssistContext, 116 ctx: &AssistContext,
105 edit: &mut AssistBuilder, 117 edit: &mut AssistBuilder,
106 strukt: hir::Struct, 118 strukt: Either<hir::Struct, hir::Variant>,
107 names: &[ast::Name], 119 names: &[ast::Name],
108) { 120) {
109 let strukt_def = Definition::ModuleDef(hir::ModuleDef::Adt(hir::Adt::Struct(strukt))); 121 let strukt_def = match strukt {
122 Either::Left(s) => Definition::ModuleDef(hir::ModuleDef::Adt(hir::Adt::Struct(s))),
123 Either::Right(v) => Definition::ModuleDef(hir::ModuleDef::Variant(v)),
124 };
110 let usages = strukt_def.usages(&ctx.sema).include_self_refs().all(); 125 let usages = strukt_def.usages(&ctx.sema).include_self_refs().all();
111 126
112 let edit_node = |edit: &mut AssistBuilder, node: SyntaxNode| -> Option<()> { 127 let edit_node = |edit: &mut AssistBuilder, node: SyntaxNode| -> Option<()> {
@@ -513,4 +528,302 @@ where
513"#, 528"#,
514 ); 529 );
515 } 530 }
531 #[test]
532 fn not_applicable_other_than_tuple_variant() {
533 check_assist_not_applicable(
534 convert_tuple_struct_to_named_struct,
535 r#"enum Enum { Variant$0 { value: usize } };"#,
536 );
537 check_assist_not_applicable(convert_tuple_struct_to_named_struct, r#"enum Enum { Variant$0 }"#);
538 }
539
540 #[test]
541 fn convert_simple_variant() {
542 check_assist(
543 convert_tuple_struct_to_named_struct,
544 r#"
545enum A {
546 $0Variant(usize),
547}
548
549impl A {
550 fn new(value: usize) -> A {
551 A::Variant(value)
552 }
553
554 fn new_with_default() -> A {
555 A::new(Default::default())
556 }
557
558 fn value(self) -> usize {
559 match self {
560 A::Variant(value) => value,
561 }
562 }
563}"#,
564 r#"
565enum A {
566 Variant { field1: usize },
567}
568
569impl A {
570 fn new(value: usize) -> A {
571 A::Variant { field1: value }
572 }
573
574 fn new_with_default() -> A {
575 A::new(Default::default())
576 }
577
578 fn value(self) -> usize {
579 match self {
580 A::Variant { field1: value } => value,
581 }
582 }
583}"#,
584 );
585 }
586
587 #[test]
588 fn convert_variant_referenced_via_self_kw() {
589 check_assist(
590 convert_tuple_struct_to_named_struct,
591 r#"
592enum A {
593 $0Variant(usize),
594}
595
596impl A {
597 fn new(value: usize) -> A {
598 Self::Variant(value)
599 }
600
601 fn new_with_default() -> A {
602 Self::new(Default::default())
603 }
604
605 fn value(self) -> usize {
606 match self {
607 Self::Variant(value) => value,
608 }
609 }
610}"#,
611 r#"
612enum A {
613 Variant { field1: usize },
614}
615
616impl A {
617 fn new(value: usize) -> A {
618 Self::Variant { field1: value }
619 }
620
621 fn new_with_default() -> A {
622 Self::new(Default::default())
623 }
624
625 fn value(self) -> usize {
626 match self {
627 Self::Variant { field1: value } => value,
628 }
629 }
630}"#,
631 );
632 }
633
634 #[test]
635 fn convert_destructured_variant() {
636 check_assist(
637 convert_tuple_struct_to_named_struct,
638 r#"
639enum A {
640 $0Variant(usize),
641}
642
643impl A {
644 fn into_inner(self) -> usize {
645 let A::Variant(first) = self;
646 first
647 }
648
649 fn into_inner_via_self(self) -> usize {
650 let Self::Variant(first) = self;
651 first
652 }
653}"#,
654 r#"
655enum A {
656 Variant { field1: usize },
657}
658
659impl A {
660 fn into_inner(self) -> usize {
661 let A::Variant { field1: first } = self;
662 first
663 }
664
665 fn into_inner_via_self(self) -> usize {
666 let Self::Variant { field1: first } = self;
667 first
668 }
669}"#,
670 );
671 }
672
673 #[test]
674 fn convert_variant_with_wrapped_references() {
675 check_assist(
676 convert_tuple_struct_to_named_struct,
677 r#"
678enum Inner {
679 $0Variant(usize),
680}
681enum Outer {
682 Variant(Inner),
683}
684
685impl Outer {
686 fn new() -> Self {
687 Self::Variant(Inner::Variant(42))
688 }
689
690 fn into_inner_destructed(self) -> u32 {
691 let Outer::Variant(Inner::Variant(x)) = self;
692 x
693 }
694}"#,
695 r#"
696enum Inner {
697 Variant { field1: usize },
698}
699enum Outer {
700 Variant(Inner),
701}
702
703impl Outer {
704 fn new() -> Self {
705 Self::Variant(Inner::Variant { field1: 42 })
706 }
707
708 fn into_inner_destructed(self) -> u32 {
709 let Outer::Variant(Inner::Variant { field1: x }) = self;
710 x
711 }
712}"#,
713 );
714
715 check_assist(
716 convert_tuple_struct_to_named_struct,
717 r#"
718enum Inner {
719 Variant(usize),
720}
721enum Outer {
722 $0Variant(Inner),
723}
724
725impl Outer {
726 fn new() -> Self {
727 Self::Variant(Inner::Variant(42))
728 }
729
730 fn into_inner_destructed(self) -> u32 {
731 let Outer::Variant(Inner::Variant(x)) = self;
732 x
733 }
734}"#,
735 r#"
736enum Inner {
737 Variant(usize),
738}
739enum Outer {
740 Variant { field1: Inner },
741}
742
743impl Outer {
744 fn new() -> Self {
745 Self::Variant { field1: Inner::Variant(42) }
746 }
747
748 fn into_inner_destructed(self) -> u32 {
749 let Outer::Variant { field1: Inner::Variant(x) } = self;
750 x
751 }
752}"#,
753 );
754 }
755
756 #[test]
757 fn convert_variant_with_multi_file_references() {
758 check_assist(
759 convert_tuple_struct_to_named_struct,
760 r#"
761//- /main.rs
762struct Inner;
763enum A {
764 $0Variant(Inner),
765}
766
767mod foo;
768
769//- /foo.rs
770use crate::{A, Inner};
771fn f() {
772 let a = A::Variant(Inner);
773}
774"#,
775 r#"
776//- /main.rs
777struct Inner;
778enum A {
779 Variant { field1: Inner },
780}
781
782mod foo;
783
784//- /foo.rs
785use crate::{A, Inner};
786fn f() {
787 let a = A::Variant { field1: Inner };
788}
789"#,
790 );
791 }
792
793 #[test]
794 fn convert_directly_used_variant() {
795 check_assist(
796 convert_tuple_struct_to_named_struct,
797 r#"
798//- /main.rs
799struct Inner;
800enum A {
801 $0Variant(Inner),
802}
803
804mod foo;
805
806//- /foo.rs
807use crate::{A::Variant, Inner};
808fn f() {
809 let a = Variant(Inner);
810}
811"#,
812 r#"
813//- /main.rs
814struct Inner;
815enum A {
816 Variant { field1: Inner },
817}
818
819mod foo;
820
821//- /foo.rs
822use crate::{A::Variant, Inner};
823fn f() {
824 let a = Variant { field1: Inner };
825}
826"#,
827 );
828 }
516} 829}
diff --git a/crates/ide_assists/src/handlers/convert_tuple_variant_to_named_variant.rs b/crates/ide_assists/src/handlers/convert_tuple_variant_to_named_variant.rs
deleted file mode 100644
index 586ad9809..000000000
--- a/crates/ide_assists/src/handlers/convert_tuple_variant_to_named_variant.rs
+++ /dev/null
@@ -1,515 +0,0 @@
1use ide_db::defs::{Definition, NameRefClass};
2use syntax::{
3 ast::{self, AstNode, VisibilityOwner},
4 match_ast, SyntaxNode,
5};
6
7use crate::{assist_context::AssistBuilder, AssistContext, AssistId, AssistKind, Assists};
8
9// Assist: convert_tuple_variant_to_named_variant
10//
11// Converts tuple variant to variant with named fields.
12//
13// ```
14// enum A {
15// Variant(usize),
16// }
17//
18// impl A {
19// fn new(value: usize) -> A {
20// A::Variant(value)
21// }
22//
23// fn new_with_default() -> A {
24// A::new(Default::default())
25// }
26//
27// fn value(self) -> usize {
28// match self {
29// A::Variant(value) => value,
30// }
31// }
32// }
33// ```
34// ->
35// ```
36// enum A {
37// Variant {
38// field1: usize
39// },
40// }
41//
42// impl A {
43// fn new(value: usize) -> A {
44// A::Variant {
45// field1: value,
46// }
47// }
48//
49// fn new_with_default() -> A {
50// A::new(Default::default())
51// }
52//
53// fn value(self) -> usize {
54// match self {
55// A::Variant { field1: value } => value,
56// }
57// }
58// }
59// ```
60pub(crate) fn convert_tuple_variant_to_named_variant(
61 acc: &mut Assists,
62 ctx: &AssistContext,
63) -> Option<()> {
64 let variant = ctx.find_node_at_offset::<ast::Variant>()?;
65 let tuple_fields = match variant.field_list()? {
66 ast::FieldList::TupleFieldList(it) => it,
67 ast::FieldList::RecordFieldList(_) => return None,
68 };
69 let variant_def = ctx.sema.to_def(&variant)?;
70
71 let target = variant.syntax().text_range();
72 acc.add(
73 AssistId("convert_tuple_variant_to_named_variant", AssistKind::RefactorRewrite),
74 "Convert to named struct",
75 target,
76 |edit| {
77 let names = generate_names(tuple_fields.fields());
78 edit_field_references(ctx, edit, tuple_fields.fields(), &names); // TODO: is this needed?
79 edit_variant_references(ctx, edit, variant_def, &names);
80 edit_variant_def(ctx, edit, tuple_fields, names);
81 },
82 )
83}
84
85fn edit_variant_def(
86 ctx: &AssistContext,
87 edit: &mut AssistBuilder,
88 tuple_fields: ast::TupleFieldList,
89 names: Vec<ast::Name>,
90) {
91 let record_fields = tuple_fields
92 .fields()
93 .zip(names)
94 .filter_map(|(f, name)| Some(ast::make::record_field(f.visibility(), name, f.ty()?)));
95 let record_fields = ast::make::record_field_list(record_fields);
96 let tuple_fields_text_range = tuple_fields.syntax().text_range();
97
98 edit.edit_file(ctx.frange.file_id);
99
100 edit.insert(tuple_fields_text_range.start(), ast::make::tokens::single_space().text());
101
102 edit.replace(tuple_fields_text_range, record_fields.to_string());
103}
104
105fn edit_variant_references(
106 ctx: &AssistContext,
107 edit: &mut AssistBuilder,
108 variant: hir::Variant,
109 names: &[ast::Name],
110) {
111 let variant_def = Definition::ModuleDef(hir::ModuleDef::Variant(variant));
112 let usages = variant_def.usages(&ctx.sema).include_self_refs().all();
113
114 let edit_node = |edit: &mut AssistBuilder, node: SyntaxNode| -> Option<()> {
115 match_ast! {
116 match node {
117 ast::TupleStructPat(tuple_struct_pat) => {
118 edit.replace(
119 tuple_struct_pat.syntax().text_range(),
120 ast::make::record_pat_with_fields(
121 tuple_struct_pat.path()?,
122 ast::make::record_pat_field_list(tuple_struct_pat.fields().zip(names).map(
123 |(pat, name)| {
124 ast::make::record_pat_field(
125 ast::make::name_ref(&name.to_string()),
126 pat,
127 )
128 },
129 )),
130 )
131 .to_string(),
132 );
133 },
134 // for tuple struct creations like Foo(42)
135 ast::CallExpr(call_expr) => {
136 let path = call_expr.syntax().descendants().find_map(ast::PathExpr::cast).and_then(|expr| expr.path())?;
137
138 // this also includes method calls like Foo::new(42), we should skip them
139 if let Some(name_ref) = path.segment().and_then(|s| s.name_ref()) {
140 match NameRefClass::classify(&ctx.sema, &name_ref) {
141 Some(NameRefClass::Definition(Definition::SelfType(_))) => {},
142 Some(NameRefClass::Definition(def)) if def == variant_def => {},
143 _ => return None,
144 };
145 }
146
147 let arg_list = call_expr.syntax().descendants().find_map(ast::ArgList::cast)?;
148
149 edit.replace(
150 call_expr.syntax().text_range(),
151 ast::make::record_expr(
152 path,
153 ast::make::record_expr_field_list(arg_list.args().zip(names).map(
154 |(expr, name)| {
155 ast::make::record_expr_field(
156 ast::make::name_ref(&name.to_string()),
157 Some(expr),
158 )
159 },
160 )),
161 )
162 .to_string(),
163 );
164 },
165 _ => return None,
166 }
167 }
168 Some(())
169 };
170
171 for (file_id, refs) in usages {
172 edit.edit_file(file_id);
173 for r in refs {
174 for node in r.name.syntax().ancestors() {
175 if edit_node(edit, node).is_some() {
176 break;
177 }
178 }
179 }
180 }
181}
182
183fn edit_field_references(
184 ctx: &AssistContext,
185 edit: &mut AssistBuilder,
186 fields: impl Iterator<Item = ast::TupleField>,
187 names: &[ast::Name],
188) {
189 for (field, name) in fields.zip(names) {
190 let field = match ctx.sema.to_def(&field) {
191 Some(it) => it,
192 None => continue,
193 };
194 let def = Definition::Field(field);
195 let usages = def.usages(&ctx.sema).all();
196 for (file_id, refs) in usages {
197 edit.edit_file(file_id);
198 for r in refs {
199 if let Some(name_ref) = r.name.as_name_ref() {
200 edit.replace(name_ref.syntax().text_range(), name.text());
201 }
202 }
203 }
204 }
205}
206
207fn generate_names(fields: impl Iterator<Item = ast::TupleField>) -> Vec<ast::Name> {
208 fields.enumerate().map(|(i, _)| ast::make::name(&format!("field{}", i + 1))).collect()
209}
210
211#[cfg(test)]
212mod tests {
213 use crate::tests::{check_assist, check_assist_not_applicable};
214
215 use super::*;
216
217 #[test]
218 fn not_applicable_other_than_tuple_variant() {
219 check_assist_not_applicable(
220 convert_tuple_variant_to_named_variant,
221 r#"enum Enum { Variant$0 { value: usize } };"#,
222 );
223 check_assist_not_applicable(convert_tuple_variant_to_named_variant, r#"enum Enum { Variant$0 }"#);
224 }
225
226 #[test]
227 fn convert_simple_variant() {
228 check_assist(
229 convert_tuple_variant_to_named_variant,
230 r#"
231enum A {
232 $0Variant(usize),
233}
234
235impl A {
236 fn new(value: usize) -> A {
237 A::Variant(value)
238 }
239
240 fn new_with_default() -> A {
241 A::new(Default::default())
242 }
243
244 fn value(self) -> usize {
245 match self {
246 A::Variant(value) => value,
247 }
248 }
249}"#,
250 r#"
251enum A {
252 Variant { field1: usize },
253}
254
255impl A {
256 fn new(value: usize) -> A {
257 A::Variant { field1: value }
258 }
259
260 fn new_with_default() -> A {
261 A::new(Default::default())
262 }
263
264 fn value(self) -> usize {
265 match self {
266 A::Variant { field1: value } => value,
267 }
268 }
269}"#,
270 );
271 }
272
273 #[test]
274 fn convert_variant_referenced_via_self_kw() {
275 check_assist(
276 convert_tuple_variant_to_named_variant,
277 r#"
278enum A {
279 $0Variant(usize),
280}
281
282impl A {
283 fn new(value: usize) -> A {
284 Self::Variant(value)
285 }
286
287 fn new_with_default() -> A {
288 Self::new(Default::default())
289 }
290
291 fn value(self) -> usize {
292 match self {
293 Self::Variant(value) => value,
294 }
295 }
296}"#,
297 r#"
298enum A {
299 Variant { field1: usize },
300}
301
302impl A {
303 fn new(value: usize) -> A {
304 Self::Variant { field1: value }
305 }
306
307 fn new_with_default() -> A {
308 Self::new(Default::default())
309 }
310
311 fn value(self) -> usize {
312 match self {
313 Self::Variant { field1: value } => value,
314 }
315 }
316}"#,
317 );
318 }
319
320 #[test]
321 fn convert_destructured_variant() {
322 check_assist(
323 convert_tuple_variant_to_named_variant,
324 r#"
325enum A {
326 $0Variant(usize),
327}
328
329impl A {
330 fn into_inner(self) -> usize {
331 let A::Variant(first) = self;
332 first
333 }
334
335 fn into_inner_via_self(self) -> usize {
336 let Self::Variant(first) = self;
337 first
338 }
339}"#,
340 r#"
341enum A {
342 Variant { field1: usize },
343}
344
345impl A {
346 fn into_inner(self) -> usize {
347 let A::Variant { field1: first } = self;
348 first
349 }
350
351 fn into_inner_via_self(self) -> usize {
352 let Self::Variant { field1: first } = self;
353 first
354 }
355}"#,
356 );
357 }
358
359 #[test]
360 fn convert_variant_with_wrapped_references() {
361 check_assist(
362 convert_tuple_variant_to_named_variant,
363 r#"
364enum Inner {
365 $0Variant(usize),
366}
367enum Outer {
368 Variant(Inner),
369}
370
371impl Outer {
372 fn new() -> Self {
373 Self::Variant(Inner::Variant(42))
374 }
375
376 fn into_inner_destructed(self) -> u32 {
377 let Outer::Variant(Inner::Variant(x)) = self;
378 x
379 }
380}"#,
381 r#"
382enum Inner {
383 Variant { field1: usize },
384}
385enum Outer {
386 Variant(Inner),
387}
388
389impl Outer {
390 fn new() -> Self {
391 Self::Variant(Inner::Variant { field1: 42 })
392 }
393
394 fn into_inner_destructed(self) -> u32 {
395 let Outer::Variant(Inner::Variant { field1: x }) = self;
396 x
397 }
398}"#,
399 );
400
401 check_assist(
402 convert_tuple_variant_to_named_variant,
403 r#"
404enum Inner {
405 Variant(usize),
406}
407enum Outer {
408 $0Variant(Inner),
409}
410
411impl Outer {
412 fn new() -> Self {
413 Self::Variant(Inner::Variant(42))
414 }
415
416 fn into_inner_destructed(self) -> u32 {
417 let Outer::Variant(Inner::Variant(x)) = self;
418 x
419 }
420}"#,
421 r#"
422enum Inner {
423 Variant(usize),
424}
425enum Outer {
426 Variant { field1: Inner },
427}
428
429impl Outer {
430 fn new() -> Self {
431 Self::Variant { field1: Inner::Variant(42) }
432 }
433
434 fn into_inner_destructed(self) -> u32 {
435 let Outer::Variant { field1: Inner::Variant(x) } = self;
436 x
437 }
438}"#,
439 );
440 }
441
442 #[test]
443 fn convert_variant_with_multi_file_references() {
444 check_assist(
445 convert_tuple_variant_to_named_variant,
446 r#"
447//- /main.rs
448struct Inner;
449enum A {
450 $0Variant(Inner),
451}
452
453mod foo;
454
455//- /foo.rs
456use crate::{A, Inner};
457fn f() {
458 let a = A::Variant(Inner);
459}
460"#,
461 r#"
462//- /main.rs
463struct Inner;
464enum A {
465 Variant { field1: Inner },
466}
467
468mod foo;
469
470//- /foo.rs
471use crate::{A, Inner};
472fn f() {
473 let a = A::Variant { field1: Inner };
474}
475"#,
476 );
477 }
478
479 #[test]
480 fn convert_directly_used_variant() {
481 check_assist(
482 convert_tuple_variant_to_named_variant,
483 r#"
484//- /main.rs
485struct Inner;
486enum A {
487 $0Variant(Inner),
488}
489
490mod foo;
491
492//- /foo.rs
493use crate::{A::Variant, Inner};
494fn f() {
495 let a = Variant(Inner);
496}
497"#,
498 r#"
499//- /main.rs
500struct Inner;
501enum A {
502 Variant { field1: Inner },
503}
504
505mod foo;
506
507//- /foo.rs
508use crate::{A::Variant, Inner};
509fn f() {
510 let a = Variant { field1: Inner };
511}
512"#,
513 );
514 }
515}
diff --git a/crates/ide_assists/src/lib.rs b/crates/ide_assists/src/lib.rs
index d64233315..16af72927 100644
--- a/crates/ide_assists/src/lib.rs
+++ b/crates/ide_assists/src/lib.rs
@@ -186,7 +186,6 @@ mod handlers {
186 mod convert_iter_for_each_to_for; 186 mod convert_iter_for_each_to_for;
187 mod convert_into_to_from; 187 mod convert_into_to_from;
188 mod convert_tuple_struct_to_named_struct; 188 mod convert_tuple_struct_to_named_struct;
189 mod convert_tuple_variant_to_named_variant;
190 mod early_return; 189 mod early_return;
191 mod expand_glob_import; 190 mod expand_glob_import;
192 mod extract_function; 191 mod extract_function;
@@ -257,7 +256,6 @@ mod handlers {
257 convert_iter_for_each_to_for::convert_iter_for_each_to_for, 256 convert_iter_for_each_to_for::convert_iter_for_each_to_for,
258 convert_into_to_from::convert_into_to_from, 257 convert_into_to_from::convert_into_to_from,
259 convert_tuple_struct_to_named_struct::convert_tuple_struct_to_named_struct, 258 convert_tuple_struct_to_named_struct::convert_tuple_struct_to_named_struct,
260 convert_tuple_variant_to_named_variant::convert_tuple_variant_to_named_variant,
261 early_return::convert_to_guarded_return, 259 early_return::convert_to_guarded_return,
262 expand_glob_import::expand_glob_import, 260 expand_glob_import::expand_glob_import,
263 extract_struct_from_enum_variant::extract_struct_from_enum_variant, 261 extract_struct_from_enum_variant::extract_struct_from_enum_variant,