aboutsummaryrefslogtreecommitdiff
path: root/crates/ide_assists/src/handlers/convert_tuple_struct_to_named_struct.rs
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 /crates/ide_assists/src/handlers/convert_tuple_struct_to_named_struct.rs
parentca9ffba0473cb32b06c01bc5d387e538d379f19e (diff)
Refactor to be just one assist
Diffstat (limited to 'crates/ide_assists/src/handlers/convert_tuple_struct_to_named_struct.rs')
-rw-r--r--crates/ide_assists/src/handlers/convert_tuple_struct_to_named_struct.rs343
1 files changed, 328 insertions, 15 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}