diff options
Diffstat (limited to 'crates/ide_assists/src')
29 files changed, 641 insertions, 114 deletions
diff --git a/crates/ide_assists/src/assist_context.rs b/crates/ide_assists/src/assist_context.rs index 8fc40f9bd..36a2bf89a 100644 --- a/crates/ide_assists/src/assist_context.rs +++ b/crates/ide_assists/src/assist_context.rs | |||
@@ -291,8 +291,7 @@ impl AssistBuilder { | |||
291 | algo::diff(old.syntax(), new.syntax()).into_text_edit(&mut self.edit) | 291 | algo::diff(old.syntax(), new.syntax()).into_text_edit(&mut self.edit) |
292 | } | 292 | } |
293 | pub(crate) fn create_file(&mut self, dst: AnchoredPathBuf, content: impl Into<String>) { | 293 | pub(crate) fn create_file(&mut self, dst: AnchoredPathBuf, content: impl Into<String>) { |
294 | let file_system_edit = | 294 | let file_system_edit = FileSystemEdit::CreateFile { dst, initial_contents: content.into() }; |
295 | FileSystemEdit::CreateFile { dst: dst, initial_contents: content.into() }; | ||
296 | self.source_change.push_file_system_edit(file_system_edit); | 295 | self.source_change.push_file_system_edit(file_system_edit); |
297 | } | 296 | } |
298 | 297 | ||
diff --git a/crates/ide_assists/src/handlers/apply_demorgan.rs b/crates/ide_assists/src/handlers/apply_demorgan.rs index 5c936a510..c93959e66 100644 --- a/crates/ide_assists/src/handlers/apply_demorgan.rs +++ b/crates/ide_assists/src/handlers/apply_demorgan.rs | |||
@@ -78,12 +78,12 @@ pub(crate) fn apply_demorgan(acc: &mut Assists, ctx: &AssistContext) -> Option<( | |||
78 | terms.sort_by_key(|t| t.syntax().text_range().start()); | 78 | terms.sort_by_key(|t| t.syntax().text_range().start()); |
79 | let mut terms = VecDeque::from(terms); | 79 | let mut terms = VecDeque::from(terms); |
80 | 80 | ||
81 | let paren_expr = expr.syntax().parent().and_then(|parent| ast::ParenExpr::cast(parent)); | 81 | let paren_expr = expr.syntax().parent().and_then(ast::ParenExpr::cast); |
82 | 82 | ||
83 | let neg_expr = paren_expr | 83 | let neg_expr = paren_expr |
84 | .clone() | 84 | .clone() |
85 | .and_then(|paren_expr| paren_expr.syntax().parent()) | 85 | .and_then(|paren_expr| paren_expr.syntax().parent()) |
86 | .and_then(|parent| ast::PrefixExpr::cast(parent)) | 86 | .and_then(ast::PrefixExpr::cast) |
87 | .and_then(|prefix_expr| { | 87 | .and_then(|prefix_expr| { |
88 | if prefix_expr.op_kind().unwrap() == ast::PrefixOp::Not { | 88 | if prefix_expr.op_kind().unwrap() == ast::PrefixOp::Not { |
89 | Some(prefix_expr) | 89 | Some(prefix_expr) |
diff --git a/crates/ide_assists/src/handlers/change_visibility.rs b/crates/ide_assists/src/handlers/change_visibility.rs index d7e39b2ae..ed936667f 100644 --- a/crates/ide_assists/src/handlers/change_visibility.rs +++ b/crates/ide_assists/src/handlers/change_visibility.rs | |||
@@ -1,7 +1,9 @@ | |||
1 | use syntax::{ | 1 | use syntax::{ |
2 | ast::{self, NameOwner, VisibilityOwner}, | 2 | ast::{self, NameOwner, VisibilityOwner}, |
3 | AstNode, | 3 | AstNode, |
4 | SyntaxKind::{CONST, ENUM, FN, MODULE, STATIC, STRUCT, TRAIT, TYPE_ALIAS, VISIBILITY}, | 4 | SyntaxKind::{ |
5 | CONST, ENUM, FN, MACRO_DEF, MODULE, STATIC, STRUCT, TRAIT, TYPE_ALIAS, USE, VISIBILITY, | ||
6 | }, | ||
5 | T, | 7 | T, |
6 | }; | 8 | }; |
7 | 9 | ||
@@ -37,12 +39,15 @@ fn add_vis(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | |||
37 | | T![enum] | 39 | | T![enum] |
38 | | T![trait] | 40 | | T![trait] |
39 | | T![type] | 41 | | T![type] |
42 | | T![use] | ||
43 | | T![macro] | ||
40 | ) | 44 | ) |
41 | }); | 45 | }); |
42 | 46 | ||
43 | let (offset, target) = if let Some(keyword) = item_keyword { | 47 | let (offset, target) = if let Some(keyword) = item_keyword { |
44 | let parent = keyword.parent()?; | 48 | let parent = keyword.parent()?; |
45 | let def_kws = vec![CONST, STATIC, TYPE_ALIAS, FN, MODULE, STRUCT, ENUM, TRAIT]; | 49 | let def_kws = |
50 | vec![CONST, STATIC, TYPE_ALIAS, FN, MODULE, STRUCT, ENUM, TRAIT, USE, MACRO_DEF]; | ||
46 | // Parent is not a definition, can't add visibility | 51 | // Parent is not a definition, can't add visibility |
47 | if !def_kws.iter().any(|&def_kw| def_kw == parent.kind()) { | 52 | if !def_kws.iter().any(|&def_kw| def_kw == parent.kind()) { |
48 | return None; | 53 | return None; |
@@ -122,6 +127,8 @@ mod tests { | |||
122 | check_assist(change_visibility, "$0trait Foo {}", "pub(crate) trait Foo {}"); | 127 | check_assist(change_visibility, "$0trait Foo {}", "pub(crate) trait Foo {}"); |
123 | check_assist(change_visibility, "m$0od {}", "pub(crate) mod {}"); | 128 | check_assist(change_visibility, "m$0od {}", "pub(crate) mod {}"); |
124 | check_assist(change_visibility, "unsafe f$0n foo() {}", "pub(crate) unsafe fn foo() {}"); | 129 | check_assist(change_visibility, "unsafe f$0n foo() {}", "pub(crate) unsafe fn foo() {}"); |
130 | check_assist(change_visibility, "$0macro foo() {}", "pub(crate) macro foo() {}"); | ||
131 | check_assist(change_visibility, "$0use foo;", "pub(crate) use foo;"); | ||
125 | } | 132 | } |
126 | 133 | ||
127 | #[test] | 134 | #[test] |
diff --git a/crates/ide_assists/src/handlers/convert_comment_block.rs b/crates/ide_assists/src/handlers/convert_comment_block.rs index d202a85f9..749e8685b 100644 --- a/crates/ide_assists/src/handlers/convert_comment_block.rs +++ b/crates/ide_assists/src/handlers/convert_comment_block.rs | |||
@@ -88,7 +88,7 @@ fn line_to_block(acc: &mut Assists, comment: ast::Comment) -> Option<()> { | |||
88 | // We pick a single indentation level for the whole block comment based on the | 88 | // We pick a single indentation level for the whole block comment based on the |
89 | // comment where the assist was invoked. This will be prepended to the | 89 | // comment where the assist was invoked. This will be prepended to the |
90 | // contents of each line comment when they're put into the block comment. | 90 | // contents of each line comment when they're put into the block comment. |
91 | let indentation = IndentLevel::from_token(&comment.syntax()); | 91 | let indentation = IndentLevel::from_token(comment.syntax()); |
92 | 92 | ||
93 | let block_comment_body = | 93 | let block_comment_body = |
94 | comments.into_iter().map(|c| line_comment_text(indentation, c)).join("\n"); | 94 | comments.into_iter().map(|c| line_comment_text(indentation, c)).join("\n"); |
@@ -167,7 +167,7 @@ fn line_comment_text(indentation: IndentLevel, comm: ast::Comment) -> String { | |||
167 | if contents.is_empty() { | 167 | if contents.is_empty() { |
168 | contents.to_owned() | 168 | contents.to_owned() |
169 | } else { | 169 | } else { |
170 | indentation.to_string() + &contents | 170 | indentation.to_string() + contents |
171 | } | 171 | } |
172 | } | 172 | } |
173 | 173 | ||
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..fc5a17f05 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 @@ | |||
1 | use either::Either; | ||
1 | use ide_db::defs::{Definition, NameRefClass}; | 2 | use ide_db::defs::{Definition, NameRefClass}; |
2 | use syntax::{ | 3 | use 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( | |||
73 | fn edit_struct_def( | 81 | fn 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,40 @@ 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( |
93 | edit.insert(tuple_fields_text_range.start(), ","); | 101 | tuple_fields_text_range.start(), |
94 | edit.insert(tuple_fields_text_range.start(), ast::make::tokens::single_newline().text()); | 102 | ast::make::tokens::single_newline().text(), |
103 | ); | ||
104 | edit.insert(tuple_fields_text_range.start(), w.syntax().text()); | ||
105 | edit.insert(tuple_fields_text_range.start(), ","); | ||
106 | edit.insert( | ||
107 | tuple_fields_text_range.start(), | ||
108 | ast::make::tokens::single_newline().text(), | ||
109 | ); | ||
110 | } else { | ||
111 | edit.insert(tuple_fields_text_range.start(), ast::make::tokens::single_space().text()); | ||
112 | } | ||
113 | strukt.semicolon_token().map(|t| edit.delete(t.text_range())); | ||
95 | } else { | 114 | } else { |
96 | edit.insert(tuple_fields_text_range.start(), ast::make::tokens::single_space().text()); | 115 | edit.insert(tuple_fields_text_range.start(), ast::make::tokens::single_space().text()); |
97 | } | 116 | } |
98 | 117 | ||
99 | edit.replace(tuple_fields_text_range, record_fields.to_string()); | 118 | edit.replace(tuple_fields_text_range, record_fields.to_string()); |
100 | strukt.semicolon_token().map(|t| edit.delete(t.text_range())); | ||
101 | } | 119 | } |
102 | 120 | ||
103 | fn edit_struct_references( | 121 | fn edit_struct_references( |
104 | ctx: &AssistContext, | 122 | ctx: &AssistContext, |
105 | edit: &mut AssistBuilder, | 123 | edit: &mut AssistBuilder, |
106 | strukt: hir::Struct, | 124 | strukt: Either<hir::Struct, hir::Variant>, |
107 | names: &[ast::Name], | 125 | names: &[ast::Name], |
108 | ) { | 126 | ) { |
109 | let strukt_def = Definition::ModuleDef(hir::ModuleDef::Adt(hir::Adt::Struct(strukt))); | 127 | let strukt_def = match strukt { |
128 | Either::Left(s) => Definition::ModuleDef(hir::ModuleDef::Adt(hir::Adt::Struct(s))), | ||
129 | Either::Right(v) => Definition::ModuleDef(hir::ModuleDef::Variant(v)), | ||
130 | }; | ||
110 | let usages = strukt_def.usages(&ctx.sema).include_self_refs().all(); | 131 | let usages = strukt_def.usages(&ctx.sema).include_self_refs().all(); |
111 | 132 | ||
112 | let edit_node = |edit: &mut AssistBuilder, node: SyntaxNode| -> Option<()> { | 133 | let edit_node = |edit: &mut AssistBuilder, node: SyntaxNode| -> Option<()> { |
@@ -513,4 +534,305 @@ where | |||
513 | "#, | 534 | "#, |
514 | ); | 535 | ); |
515 | } | 536 | } |
537 | #[test] | ||
538 | fn not_applicable_other_than_tuple_variant() { | ||
539 | check_assist_not_applicable( | ||
540 | convert_tuple_struct_to_named_struct, | ||
541 | r#"enum Enum { Variant$0 { value: usize } };"#, | ||
542 | ); | ||
543 | check_assist_not_applicable( | ||
544 | convert_tuple_struct_to_named_struct, | ||
545 | r#"enum Enum { Variant$0 }"#, | ||
546 | ); | ||
547 | } | ||
548 | |||
549 | #[test] | ||
550 | fn convert_simple_variant() { | ||
551 | check_assist( | ||
552 | convert_tuple_struct_to_named_struct, | ||
553 | r#" | ||
554 | enum A { | ||
555 | $0Variant(usize), | ||
556 | } | ||
557 | |||
558 | impl A { | ||
559 | fn new(value: usize) -> A { | ||
560 | A::Variant(value) | ||
561 | } | ||
562 | |||
563 | fn new_with_default() -> A { | ||
564 | A::new(Default::default()) | ||
565 | } | ||
566 | |||
567 | fn value(self) -> usize { | ||
568 | match self { | ||
569 | A::Variant(value) => value, | ||
570 | } | ||
571 | } | ||
572 | }"#, | ||
573 | r#" | ||
574 | enum A { | ||
575 | Variant { field1: usize }, | ||
576 | } | ||
577 | |||
578 | impl A { | ||
579 | fn new(value: usize) -> A { | ||
580 | A::Variant { field1: value } | ||
581 | } | ||
582 | |||
583 | fn new_with_default() -> A { | ||
584 | A::new(Default::default()) | ||
585 | } | ||
586 | |||
587 | fn value(self) -> usize { | ||
588 | match self { | ||
589 | A::Variant { field1: value } => value, | ||
590 | } | ||
591 | } | ||
592 | }"#, | ||
593 | ); | ||
594 | } | ||
595 | |||
596 | #[test] | ||
597 | fn convert_variant_referenced_via_self_kw() { | ||
598 | check_assist( | ||
599 | convert_tuple_struct_to_named_struct, | ||
600 | r#" | ||
601 | enum A { | ||
602 | $0Variant(usize), | ||
603 | } | ||
604 | |||
605 | impl A { | ||
606 | fn new(value: usize) -> A { | ||
607 | Self::Variant(value) | ||
608 | } | ||
609 | |||
610 | fn new_with_default() -> A { | ||
611 | Self::new(Default::default()) | ||
612 | } | ||
613 | |||
614 | fn value(self) -> usize { | ||
615 | match self { | ||
616 | Self::Variant(value) => value, | ||
617 | } | ||
618 | } | ||
619 | }"#, | ||
620 | r#" | ||
621 | enum A { | ||
622 | Variant { field1: usize }, | ||
623 | } | ||
624 | |||
625 | impl A { | ||
626 | fn new(value: usize) -> A { | ||
627 | Self::Variant { field1: value } | ||
628 | } | ||
629 | |||
630 | fn new_with_default() -> A { | ||
631 | Self::new(Default::default()) | ||
632 | } | ||
633 | |||
634 | fn value(self) -> usize { | ||
635 | match self { | ||
636 | Self::Variant { field1: value } => value, | ||
637 | } | ||
638 | } | ||
639 | }"#, | ||
640 | ); | ||
641 | } | ||
642 | |||
643 | #[test] | ||
644 | fn convert_destructured_variant() { | ||
645 | check_assist( | ||
646 | convert_tuple_struct_to_named_struct, | ||
647 | r#" | ||
648 | enum A { | ||
649 | $0Variant(usize), | ||
650 | } | ||
651 | |||
652 | impl A { | ||
653 | fn into_inner(self) -> usize { | ||
654 | let A::Variant(first) = self; | ||
655 | first | ||
656 | } | ||
657 | |||
658 | fn into_inner_via_self(self) -> usize { | ||
659 | let Self::Variant(first) = self; | ||
660 | first | ||
661 | } | ||
662 | }"#, | ||
663 | r#" | ||
664 | enum A { | ||
665 | Variant { field1: usize }, | ||
666 | } | ||
667 | |||
668 | impl A { | ||
669 | fn into_inner(self) -> usize { | ||
670 | let A::Variant { field1: first } = self; | ||
671 | first | ||
672 | } | ||
673 | |||
674 | fn into_inner_via_self(self) -> usize { | ||
675 | let Self::Variant { field1: first } = self; | ||
676 | first | ||
677 | } | ||
678 | }"#, | ||
679 | ); | ||
680 | } | ||
681 | |||
682 | #[test] | ||
683 | fn convert_variant_with_wrapped_references() { | ||
684 | check_assist( | ||
685 | convert_tuple_struct_to_named_struct, | ||
686 | r#" | ||
687 | enum Inner { | ||
688 | $0Variant(usize), | ||
689 | } | ||
690 | enum Outer { | ||
691 | Variant(Inner), | ||
692 | } | ||
693 | |||
694 | impl Outer { | ||
695 | fn new() -> Self { | ||
696 | Self::Variant(Inner::Variant(42)) | ||
697 | } | ||
698 | |||
699 | fn into_inner_destructed(self) -> u32 { | ||
700 | let Outer::Variant(Inner::Variant(x)) = self; | ||
701 | x | ||
702 | } | ||
703 | }"#, | ||
704 | r#" | ||
705 | enum Inner { | ||
706 | Variant { field1: usize }, | ||
707 | } | ||
708 | enum Outer { | ||
709 | Variant(Inner), | ||
710 | } | ||
711 | |||
712 | impl Outer { | ||
713 | fn new() -> Self { | ||
714 | Self::Variant(Inner::Variant { field1: 42 }) | ||
715 | } | ||
716 | |||
717 | fn into_inner_destructed(self) -> u32 { | ||
718 | let Outer::Variant(Inner::Variant { field1: x }) = self; | ||
719 | x | ||
720 | } | ||
721 | }"#, | ||
722 | ); | ||
723 | |||
724 | check_assist( | ||
725 | convert_tuple_struct_to_named_struct, | ||
726 | r#" | ||
727 | enum Inner { | ||
728 | Variant(usize), | ||
729 | } | ||
730 | enum Outer { | ||
731 | $0Variant(Inner), | ||
732 | } | ||
733 | |||
734 | impl Outer { | ||
735 | fn new() -> Self { | ||
736 | Self::Variant(Inner::Variant(42)) | ||
737 | } | ||
738 | |||
739 | fn into_inner_destructed(self) -> u32 { | ||
740 | let Outer::Variant(Inner::Variant(x)) = self; | ||
741 | x | ||
742 | } | ||
743 | }"#, | ||
744 | r#" | ||
745 | enum Inner { | ||
746 | Variant(usize), | ||
747 | } | ||
748 | enum Outer { | ||
749 | Variant { field1: Inner }, | ||
750 | } | ||
751 | |||
752 | impl Outer { | ||
753 | fn new() -> Self { | ||
754 | Self::Variant { field1: Inner::Variant(42) } | ||
755 | } | ||
756 | |||
757 | fn into_inner_destructed(self) -> u32 { | ||
758 | let Outer::Variant { field1: Inner::Variant(x) } = self; | ||
759 | x | ||
760 | } | ||
761 | }"#, | ||
762 | ); | ||
763 | } | ||
764 | |||
765 | #[test] | ||
766 | fn convert_variant_with_multi_file_references() { | ||
767 | check_assist( | ||
768 | convert_tuple_struct_to_named_struct, | ||
769 | r#" | ||
770 | //- /main.rs | ||
771 | struct Inner; | ||
772 | enum A { | ||
773 | $0Variant(Inner), | ||
774 | } | ||
775 | |||
776 | mod foo; | ||
777 | |||
778 | //- /foo.rs | ||
779 | use crate::{A, Inner}; | ||
780 | fn f() { | ||
781 | let a = A::Variant(Inner); | ||
782 | } | ||
783 | "#, | ||
784 | r#" | ||
785 | //- /main.rs | ||
786 | struct Inner; | ||
787 | enum A { | ||
788 | Variant { field1: Inner }, | ||
789 | } | ||
790 | |||
791 | mod foo; | ||
792 | |||
793 | //- /foo.rs | ||
794 | use crate::{A, Inner}; | ||
795 | fn f() { | ||
796 | let a = A::Variant { field1: Inner }; | ||
797 | } | ||
798 | "#, | ||
799 | ); | ||
800 | } | ||
801 | |||
802 | #[test] | ||
803 | fn convert_directly_used_variant() { | ||
804 | check_assist( | ||
805 | convert_tuple_struct_to_named_struct, | ||
806 | r#" | ||
807 | //- /main.rs | ||
808 | struct Inner; | ||
809 | enum A { | ||
810 | $0Variant(Inner), | ||
811 | } | ||
812 | |||
813 | mod foo; | ||
814 | |||
815 | //- /foo.rs | ||
816 | use crate::{A::Variant, Inner}; | ||
817 | fn f() { | ||
818 | let a = Variant(Inner); | ||
819 | } | ||
820 | "#, | ||
821 | r#" | ||
822 | //- /main.rs | ||
823 | struct Inner; | ||
824 | enum A { | ||
825 | Variant { field1: Inner }, | ||
826 | } | ||
827 | |||
828 | mod foo; | ||
829 | |||
830 | //- /foo.rs | ||
831 | use crate::{A::Variant, Inner}; | ||
832 | fn f() { | ||
833 | let a = Variant { field1: Inner }; | ||
834 | } | ||
835 | "#, | ||
836 | ); | ||
837 | } | ||
516 | } | 838 | } |
diff --git a/crates/ide_assists/src/handlers/early_return.rs b/crates/ide_assists/src/handlers/early_return.rs index 5eb6a57f0..ef4a7cb50 100644 --- a/crates/ide_assists/src/handlers/early_return.rs +++ b/crates/ide_assists/src/handlers/early_return.rs | |||
@@ -108,7 +108,7 @@ pub(crate) fn convert_to_guarded_return(acc: &mut Assists, ctx: &AssistContext) | |||
108 | "Convert to guarded return", | 108 | "Convert to guarded return", |
109 | target, | 109 | target, |
110 | |edit| { | 110 | |edit| { |
111 | let if_indent_level = IndentLevel::from_node(&if_expr.syntax()); | 111 | let if_indent_level = IndentLevel::from_node(if_expr.syntax()); |
112 | let new_block = match if_let_pat { | 112 | let new_block = match if_let_pat { |
113 | None => { | 113 | None => { |
114 | // If. | 114 | // If. |
@@ -174,7 +174,7 @@ pub(crate) fn convert_to_guarded_return(acc: &mut Assists, ctx: &AssistContext) | |||
174 | .take_while(|i| *i != end_of_then), | 174 | .take_while(|i| *i != end_of_then), |
175 | ); | 175 | ); |
176 | replace_children( | 176 | replace_children( |
177 | &parent_block.syntax(), | 177 | parent_block.syntax(), |
178 | RangeInclusive::new( | 178 | RangeInclusive::new( |
179 | if_expr.clone().syntax().clone().into(), | 179 | if_expr.clone().syntax().clone().into(), |
180 | if_expr.syntax().clone().into(), | 180 | if_expr.syntax().clone().into(), |
diff --git a/crates/ide_assists/src/handlers/extract_function.rs b/crates/ide_assists/src/handlers/extract_function.rs index a2dba915c..f2be091f4 100644 --- a/crates/ide_assists/src/handlers/extract_function.rs +++ b/crates/ide_assists/src/handlers/extract_function.rs | |||
@@ -76,7 +76,7 @@ pub(crate) fn extract_function(acc: &mut Assists, ctx: &AssistContext) -> Option | |||
76 | let module = ctx.sema.scope(&insert_after).module()?; | 76 | let module = ctx.sema.scope(&insert_after).module()?; |
77 | 77 | ||
78 | let vars_defined_in_body_and_outlive = | 78 | let vars_defined_in_body_and_outlive = |
79 | vars_defined_in_body_and_outlive(ctx, &body, &node.parent().as_ref().unwrap_or(&node)); | 79 | vars_defined_in_body_and_outlive(ctx, &body, node.parent().as_ref().unwrap_or(&node)); |
80 | let ret_ty = body_return_ty(ctx, &body)?; | 80 | let ret_ty = body_return_ty(ctx, &body)?; |
81 | 81 | ||
82 | // FIXME: we compute variables that outlive here just to check `never!` condition | 82 | // FIXME: we compute variables that outlive here just to check `never!` condition |
@@ -782,7 +782,7 @@ fn expr_require_exclusive_access(ctx: &AssistContext, expr: &ast::Expr) -> Optio | |||
782 | Some(false) | 782 | Some(false) |
783 | } | 783 | } |
784 | 784 | ||
785 | /// Container of local varaible usages | 785 | /// Container of local variable usages |
786 | /// | 786 | /// |
787 | /// Semanticall same as `UsageSearchResult`, but provides more convenient interface | 787 | /// Semanticall same as `UsageSearchResult`, but provides more convenient interface |
788 | struct LocalUsages(ide_db::search::UsageSearchResult); | 788 | struct LocalUsages(ide_db::search::UsageSearchResult); |
@@ -808,7 +808,7 @@ trait HasTokenAtOffset { | |||
808 | 808 | ||
809 | impl HasTokenAtOffset for SyntaxNode { | 809 | impl HasTokenAtOffset for SyntaxNode { |
810 | fn token_at_offset(&self, offset: TextSize) -> TokenAtOffset<SyntaxToken> { | 810 | fn token_at_offset(&self, offset: TextSize) -> TokenAtOffset<SyntaxToken> { |
811 | SyntaxNode::token_at_offset(&self, offset) | 811 | SyntaxNode::token_at_offset(self, offset) |
812 | } | 812 | } |
813 | } | 813 | } |
814 | 814 | ||
@@ -854,7 +854,7 @@ fn vars_defined_in_body_and_outlive( | |||
854 | body: &FunctionBody, | 854 | body: &FunctionBody, |
855 | parent: &SyntaxNode, | 855 | parent: &SyntaxNode, |
856 | ) -> Vec<OutlivedLocal> { | 856 | ) -> Vec<OutlivedLocal> { |
857 | let vars_defined_in_body = vars_defined_in_body(&body, ctx); | 857 | let vars_defined_in_body = vars_defined_in_body(body, ctx); |
858 | vars_defined_in_body | 858 | vars_defined_in_body |
859 | .into_iter() | 859 | .into_iter() |
860 | .filter_map(|var| var_outlives_body(ctx, body, var, parent)) | 860 | .filter_map(|var| var_outlives_body(ctx, body, var, parent)) |
@@ -868,7 +868,7 @@ fn is_defined_before( | |||
868 | src: &hir::InFile<Either<ast::IdentPat, ast::SelfParam>>, | 868 | src: &hir::InFile<Either<ast::IdentPat, ast::SelfParam>>, |
869 | ) -> bool { | 869 | ) -> bool { |
870 | src.file_id.original_file(ctx.db()) == ctx.frange.file_id | 870 | src.file_id.original_file(ctx.db()) == ctx.frange.file_id |
871 | && !body.contains_node(&either_syntax(&src.value)) | 871 | && !body.contains_node(either_syntax(&src.value)) |
872 | } | 872 | } |
873 | 873 | ||
874 | fn either_syntax(value: &Either<ast::IdentPat, ast::SelfParam>) -> &SyntaxNode { | 874 | fn either_syntax(value: &Either<ast::IdentPat, ast::SelfParam>) -> &SyntaxNode { |
diff --git a/crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs b/crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs index 007aba23d..d3ff7b65c 100644 --- a/crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs +++ b/crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs | |||
@@ -11,14 +11,19 @@ use ide_db::{ | |||
11 | search::FileReference, | 11 | search::FileReference, |
12 | RootDatabase, | 12 | RootDatabase, |
13 | }; | 13 | }; |
14 | use itertools::Itertools; | ||
14 | use rustc_hash::FxHashSet; | 15 | use rustc_hash::FxHashSet; |
15 | use syntax::{ | 16 | use syntax::{ |
16 | algo::find_node_at_offset, | 17 | ast::{ |
17 | ast::{self, make, AstNode, NameOwner, VisibilityOwner}, | 18 | self, make, AstNode, AttrsOwner, GenericParamsOwner, NameOwner, TypeBoundsOwner, |
18 | ted, SyntaxNode, T, | 19 | VisibilityOwner, |
20 | }, | ||
21 | match_ast, | ||
22 | ted::{self, Position}, | ||
23 | SyntaxNode, T, | ||
19 | }; | 24 | }; |
20 | 25 | ||
21 | use crate::{AssistContext, AssistId, AssistKind, Assists}; | 26 | use crate::{assist_context::AssistBuilder, AssistContext, AssistId, AssistKind, Assists}; |
22 | 27 | ||
23 | // Assist: extract_struct_from_enum_variant | 28 | // Assist: extract_struct_from_enum_variant |
24 | // | 29 | // |
@@ -70,11 +75,10 @@ pub(crate) fn extract_struct_from_enum_variant( | |||
70 | continue; | 75 | continue; |
71 | } | 76 | } |
72 | builder.edit_file(file_id); | 77 | builder.edit_file(file_id); |
73 | let source_file = builder.make_mut(ctx.sema.parse(file_id)); | ||
74 | let processed = process_references( | 78 | let processed = process_references( |
75 | ctx, | 79 | ctx, |
80 | builder, | ||
76 | &mut visited_modules_set, | 81 | &mut visited_modules_set, |
77 | source_file.syntax(), | ||
78 | &enum_module_def, | 82 | &enum_module_def, |
79 | &variant_hir_name, | 83 | &variant_hir_name, |
80 | references, | 84 | references, |
@@ -84,13 +88,12 @@ pub(crate) fn extract_struct_from_enum_variant( | |||
84 | }); | 88 | }); |
85 | } | 89 | } |
86 | builder.edit_file(ctx.frange.file_id); | 90 | builder.edit_file(ctx.frange.file_id); |
87 | let source_file = builder.make_mut(ctx.sema.parse(ctx.frange.file_id)); | ||
88 | let variant = builder.make_mut(variant.clone()); | 91 | let variant = builder.make_mut(variant.clone()); |
89 | if let Some(references) = def_file_references { | 92 | if let Some(references) = def_file_references { |
90 | let processed = process_references( | 93 | let processed = process_references( |
91 | ctx, | 94 | ctx, |
95 | builder, | ||
92 | &mut visited_modules_set, | 96 | &mut visited_modules_set, |
93 | source_file.syntax(), | ||
94 | &enum_module_def, | 97 | &enum_module_def, |
95 | &variant_hir_name, | 98 | &variant_hir_name, |
96 | references, | 99 | references, |
@@ -100,12 +103,12 @@ pub(crate) fn extract_struct_from_enum_variant( | |||
100 | }); | 103 | }); |
101 | } | 104 | } |
102 | 105 | ||
103 | let def = create_struct_def(variant_name.clone(), &field_list, enum_ast.visibility()); | 106 | let def = create_struct_def(variant_name.clone(), &field_list, &enum_ast); |
104 | let start_offset = &variant.parent_enum().syntax().clone(); | 107 | let start_offset = &variant.parent_enum().syntax().clone(); |
105 | ted::insert_raw(ted::Position::before(start_offset), def.syntax()); | 108 | ted::insert_raw(ted::Position::before(start_offset), def.syntax()); |
106 | ted::insert_raw(ted::Position::before(start_offset), &make::tokens::blank_line()); | 109 | ted::insert_raw(ted::Position::before(start_offset), &make::tokens::blank_line()); |
107 | 110 | ||
108 | update_variant(&variant); | 111 | update_variant(&variant, enum_ast.generic_param_list()); |
109 | }, | 112 | }, |
110 | ) | 113 | ) |
111 | } | 114 | } |
@@ -149,7 +152,7 @@ fn existing_definition(db: &RootDatabase, variant_name: &ast::Name, variant: &Va | |||
149 | fn create_struct_def( | 152 | fn create_struct_def( |
150 | variant_name: ast::Name, | 153 | variant_name: ast::Name, |
151 | field_list: &Either<ast::RecordFieldList, ast::TupleFieldList>, | 154 | field_list: &Either<ast::RecordFieldList, ast::TupleFieldList>, |
152 | visibility: Option<ast::Visibility>, | 155 | enum_: &ast::Enum, |
153 | ) -> ast::Struct { | 156 | ) -> ast::Struct { |
154 | let pub_vis = make::visibility_pub(); | 157 | let pub_vis = make::visibility_pub(); |
155 | 158 | ||
@@ -184,12 +187,38 @@ fn create_struct_def( | |||
184 | } | 187 | } |
185 | }; | 188 | }; |
186 | 189 | ||
187 | make::struct_(visibility, variant_name, None, field_list).clone_for_update() | 190 | // FIXME: This uses all the generic params of the enum, but the variant might not use all of them. |
191 | let strukt = | ||
192 | make::struct_(enum_.visibility(), variant_name, enum_.generic_param_list(), field_list) | ||
193 | .clone_for_update(); | ||
194 | |||
195 | // copy attributes | ||
196 | ted::insert_all( | ||
197 | Position::first_child_of(strukt.syntax()), | ||
198 | enum_.attrs().map(|it| it.syntax().clone_for_update().into()).collect(), | ||
199 | ); | ||
200 | strukt | ||
188 | } | 201 | } |
189 | 202 | ||
190 | fn update_variant(variant: &ast::Variant) -> Option<()> { | 203 | fn update_variant(variant: &ast::Variant, generic: Option<ast::GenericParamList>) -> Option<()> { |
191 | let name = variant.name()?; | 204 | let name = variant.name()?; |
192 | let tuple_field = make::tuple_field(None, make::ty(&name.text())); | 205 | let ty = match generic { |
206 | // FIXME: This uses all the generic params of the enum, but the variant might not use all of them. | ||
207 | Some(gpl) => { | ||
208 | let gpl = gpl.clone_for_update(); | ||
209 | gpl.generic_params().for_each(|gp| { | ||
210 | match gp { | ||
211 | ast::GenericParam::LifetimeParam(it) => it.type_bound_list(), | ||
212 | ast::GenericParam::TypeParam(it) => it.type_bound_list(), | ||
213 | ast::GenericParam::ConstParam(_) => return, | ||
214 | } | ||
215 | .map(|it| it.remove()); | ||
216 | }); | ||
217 | make::ty(&format!("{}<{}>", name.text(), gpl.generic_params().join(", "))) | ||
218 | } | ||
219 | None => make::ty(&name.text()), | ||
220 | }; | ||
221 | let tuple_field = make::tuple_field(None, ty); | ||
193 | let replacement = make::variant( | 222 | let replacement = make::variant( |
194 | name, | 223 | name, |
195 | Some(ast::FieldList::TupleFieldList(make::tuple_field_list(iter::once(tuple_field)))), | 224 | Some(ast::FieldList::TupleFieldList(make::tuple_field_list(iter::once(tuple_field)))), |
@@ -208,18 +237,17 @@ fn apply_references( | |||
208 | if let Some((scope, path)) = import { | 237 | if let Some((scope, path)) = import { |
209 | insert_use(&scope, mod_path_to_ast(&path), insert_use_cfg); | 238 | insert_use(&scope, mod_path_to_ast(&path), insert_use_cfg); |
210 | } | 239 | } |
211 | ted::insert_raw( | 240 | // deep clone to prevent cycle |
212 | ted::Position::before(segment.syntax()), | 241 | let path = make::path_from_segments(iter::once(segment.clone_subtree()), false); |
213 | make::path_from_text(&format!("{}", segment)).clone_for_update().syntax(), | 242 | ted::insert_raw(ted::Position::before(segment.syntax()), path.clone_for_update().syntax()); |
214 | ); | ||
215 | ted::insert_raw(ted::Position::before(segment.syntax()), make::token(T!['('])); | 243 | ted::insert_raw(ted::Position::before(segment.syntax()), make::token(T!['('])); |
216 | ted::insert_raw(ted::Position::after(&node), make::token(T![')'])); | 244 | ted::insert_raw(ted::Position::after(&node), make::token(T![')'])); |
217 | } | 245 | } |
218 | 246 | ||
219 | fn process_references( | 247 | fn process_references( |
220 | ctx: &AssistContext, | 248 | ctx: &AssistContext, |
249 | builder: &mut AssistBuilder, | ||
221 | visited_modules: &mut FxHashSet<Module>, | 250 | visited_modules: &mut FxHashSet<Module>, |
222 | source_file: &SyntaxNode, | ||
223 | enum_module_def: &ModuleDef, | 251 | enum_module_def: &ModuleDef, |
224 | variant_hir_name: &Name, | 252 | variant_hir_name: &Name, |
225 | refs: Vec<FileReference>, | 253 | refs: Vec<FileReference>, |
@@ -228,8 +256,9 @@ fn process_references( | |||
228 | // and corresponding nodes up front | 256 | // and corresponding nodes up front |
229 | refs.into_iter() | 257 | refs.into_iter() |
230 | .flat_map(|reference| { | 258 | .flat_map(|reference| { |
231 | let (segment, scope_node, module) = | 259 | let (segment, scope_node, module) = reference_to_node(&ctx.sema, reference)?; |
232 | reference_to_node(&ctx.sema, source_file, reference)?; | 260 | let segment = builder.make_mut(segment); |
261 | let scope_node = builder.make_syntax_mut(scope_node); | ||
233 | if !visited_modules.contains(&module) { | 262 | if !visited_modules.contains(&module) { |
234 | let mod_path = module.find_use_path_prefixed( | 263 | let mod_path = module.find_use_path_prefixed( |
235 | ctx.sema.db, | 264 | ctx.sema.db, |
@@ -251,23 +280,22 @@ fn process_references( | |||
251 | 280 | ||
252 | fn reference_to_node( | 281 | fn reference_to_node( |
253 | sema: &hir::Semantics<RootDatabase>, | 282 | sema: &hir::Semantics<RootDatabase>, |
254 | source_file: &SyntaxNode, | ||
255 | reference: FileReference, | 283 | reference: FileReference, |
256 | ) -> Option<(ast::PathSegment, SyntaxNode, hir::Module)> { | 284 | ) -> Option<(ast::PathSegment, SyntaxNode, hir::Module)> { |
257 | let offset = reference.range.start(); | 285 | let segment = |
258 | if let Some(path_expr) = find_node_at_offset::<ast::PathExpr>(source_file, offset) { | 286 | reference.name.as_name_ref()?.syntax().parent().and_then(ast::PathSegment::cast)?; |
259 | // tuple variant | 287 | let parent = segment.parent_path().syntax().parent()?; |
260 | Some((path_expr.path()?.segment()?, path_expr.syntax().parent()?)) | 288 | let expr_or_pat = match_ast! { |
261 | } else if let Some(record_expr) = find_node_at_offset::<ast::RecordExpr>(source_file, offset) { | 289 | match parent { |
262 | // record variant | 290 | ast::PathExpr(_it) => parent.parent()?, |
263 | Some((record_expr.path()?.segment()?, record_expr.syntax().clone())) | 291 | ast::RecordExpr(_it) => parent, |
264 | } else { | 292 | ast::TupleStructPat(_it) => parent, |
265 | None | 293 | ast::RecordPat(_it) => parent, |
266 | } | 294 | _ => return None, |
267 | .and_then(|(segment, expr)| { | 295 | } |
268 | let module = sema.scope(&expr).module()?; | 296 | }; |
269 | Some((segment, expr, module)) | 297 | let module = sema.scope(&expr_or_pat).module()?; |
270 | }) | 298 | Some((segment, expr_or_pat, module)) |
271 | } | 299 | } |
272 | 300 | ||
273 | #[cfg(test)] | 301 | #[cfg(test)] |
@@ -278,6 +306,12 @@ mod tests { | |||
278 | 306 | ||
279 | use super::*; | 307 | use super::*; |
280 | 308 | ||
309 | fn check_not_applicable(ra_fixture: &str) { | ||
310 | let fixture = | ||
311 | format!("//- /main.rs crate:main deps:core\n{}\n{}", ra_fixture, FamousDefs::FIXTURE); | ||
312 | check_assist_not_applicable(extract_struct_from_enum_variant, &fixture) | ||
313 | } | ||
314 | |||
281 | #[test] | 315 | #[test] |
282 | fn test_extract_struct_several_fields_tuple() { | 316 | fn test_extract_struct_several_fields_tuple() { |
283 | check_assist( | 317 | check_assist( |
@@ -312,6 +346,32 @@ enum A { One(One) }"#, | |||
312 | } | 346 | } |
313 | 347 | ||
314 | #[test] | 348 | #[test] |
349 | fn test_extract_struct_carries_over_generics() { | ||
350 | check_assist( | ||
351 | extract_struct_from_enum_variant, | ||
352 | r"enum En<T> { Var { a: T$0 } }", | ||
353 | r#"struct Var<T>{ pub a: T } | ||
354 | |||
355 | enum En<T> { Var(Var<T>) }"#, | ||
356 | ); | ||
357 | } | ||
358 | |||
359 | #[test] | ||
360 | fn test_extract_struct_carries_over_attributes() { | ||
361 | check_assist( | ||
362 | extract_struct_from_enum_variant, | ||
363 | r#"#[derive(Debug)] | ||
364 | #[derive(Clone)] | ||
365 | enum Enum { Variant{ field: u32$0 } }"#, | ||
366 | r#"#[derive(Debug)]#[derive(Clone)] struct Variant{ pub field: u32 } | ||
367 | |||
368 | #[derive(Debug)] | ||
369 | #[derive(Clone)] | ||
370 | enum Enum { Variant(Variant) }"#, | ||
371 | ); | ||
372 | } | ||
373 | |||
374 | #[test] | ||
315 | fn test_extract_struct_keep_comments_and_attrs_one_field_named() { | 375 | fn test_extract_struct_keep_comments_and_attrs_one_field_named() { |
316 | check_assist( | 376 | check_assist( |
317 | extract_struct_from_enum_variant, | 377 | extract_struct_from_enum_variant, |
@@ -496,7 +556,7 @@ enum E { | |||
496 | } | 556 | } |
497 | 557 | ||
498 | fn f() { | 558 | fn f() { |
499 | let e = E::V { i: 9, j: 2 }; | 559 | let E::V { i, j } = E::V { i: 9, j: 2 }; |
500 | } | 560 | } |
501 | "#, | 561 | "#, |
502 | r#" | 562 | r#" |
@@ -507,7 +567,34 @@ enum E { | |||
507 | } | 567 | } |
508 | 568 | ||
509 | fn f() { | 569 | fn f() { |
510 | let e = E::V(V { i: 9, j: 2 }); | 570 | let E::V(V { i, j }) = E::V(V { i: 9, j: 2 }); |
571 | } | ||
572 | "#, | ||
573 | ) | ||
574 | } | ||
575 | |||
576 | #[test] | ||
577 | fn extract_record_fix_references2() { | ||
578 | check_assist( | ||
579 | extract_struct_from_enum_variant, | ||
580 | r#" | ||
581 | enum E { | ||
582 | $0V(i32, i32) | ||
583 | } | ||
584 | |||
585 | fn f() { | ||
586 | let E::V(i, j) = E::V(9, 2); | ||
587 | } | ||
588 | "#, | ||
589 | r#" | ||
590 | struct V(pub i32, pub i32); | ||
591 | |||
592 | enum E { | ||
593 | V(V) | ||
594 | } | ||
595 | |||
596 | fn f() { | ||
597 | let E::V(V(i, j)) = E::V(V(9, 2)); | ||
511 | } | 598 | } |
512 | "#, | 599 | "#, |
513 | ) | 600 | ) |
@@ -610,12 +697,6 @@ fn foo() { | |||
610 | ); | 697 | ); |
611 | } | 698 | } |
612 | 699 | ||
613 | fn check_not_applicable(ra_fixture: &str) { | ||
614 | let fixture = | ||
615 | format!("//- /main.rs crate:main deps:core\n{}\n{}", ra_fixture, FamousDefs::FIXTURE); | ||
616 | check_assist_not_applicable(extract_struct_from_enum_variant, &fixture) | ||
617 | } | ||
618 | |||
619 | #[test] | 700 | #[test] |
620 | fn test_extract_enum_not_applicable_for_element_with_no_fields() { | 701 | fn test_extract_enum_not_applicable_for_element_with_no_fields() { |
621 | check_not_applicable("enum A { $0One }"); | 702 | check_not_applicable("enum A { $0One }"); |
diff --git a/crates/ide_assists/src/handlers/extract_type_alias.rs b/crates/ide_assists/src/handlers/extract_type_alias.rs index 998e0de7b..eac8857c6 100644 --- a/crates/ide_assists/src/handlers/extract_type_alias.rs +++ b/crates/ide_assists/src/handlers/extract_type_alias.rs | |||
@@ -1,4 +1,7 @@ | |||
1 | use syntax::ast::{self, AstNode}; | 1 | use syntax::{ |
2 | ast::{self, edit::IndentLevel, AstNode}, | ||
3 | match_ast, | ||
4 | }; | ||
2 | 5 | ||
3 | use crate::{AssistContext, AssistId, AssistKind, Assists}; | 6 | use crate::{AssistContext, AssistId, AssistKind, Assists}; |
4 | 7 | ||
@@ -25,12 +28,15 @@ pub(crate) fn extract_type_alias(acc: &mut Assists, ctx: &AssistContext) -> Opti | |||
25 | } | 28 | } |
26 | 29 | ||
27 | let node = ctx.find_node_at_range::<ast::Type>()?; | 30 | let node = ctx.find_node_at_range::<ast::Type>()?; |
28 | let insert = ctx | 31 | let item = ctx.find_node_at_offset::<ast::Item>()?; |
29 | .find_node_at_offset::<ast::Impl>() | 32 | let insert = match_ast! { |
30 | .map(|imp| imp.syntax().clone()) | 33 | match (item.syntax().parent()?) { |
31 | .or_else(|| ctx.find_node_at_offset::<ast::Item>().map(|item| item.syntax().clone()))? | 34 | ast::AssocItemList(it) => it.syntax().parent()?, |
32 | .text_range() | 35 | _ => item.syntax().clone(), |
33 | .start(); | 36 | } |
37 | }; | ||
38 | let indent = IndentLevel::from_node(&insert); | ||
39 | let insert = insert.text_range().start(); | ||
34 | let target = node.syntax().text_range(); | 40 | let target = node.syntax().text_range(); |
35 | 41 | ||
36 | acc.add( | 42 | acc.add( |
@@ -42,10 +48,14 @@ pub(crate) fn extract_type_alias(acc: &mut Assists, ctx: &AssistContext) -> Opti | |||
42 | builder.replace(target, "Type"); | 48 | builder.replace(target, "Type"); |
43 | match ctx.config.snippet_cap { | 49 | match ctx.config.snippet_cap { |
44 | Some(cap) => { | 50 | Some(cap) => { |
45 | builder.insert_snippet(cap, insert, format!("type $0Type = {};\n\n", node)); | 51 | builder.insert_snippet( |
52 | cap, | ||
53 | insert, | ||
54 | format!("type $0Type = {};\n\n{}", node, indent), | ||
55 | ); | ||
46 | } | 56 | } |
47 | None => { | 57 | None => { |
48 | builder.insert(insert, format!("type Type = {};\n\n", node)); | 58 | builder.insert(insert, format!("type Type = {};\n\n{}", node, indent)); |
49 | } | 59 | } |
50 | } | 60 | } |
51 | }, | 61 | }, |
@@ -153,9 +163,9 @@ struct S { | |||
153 | } | 163 | } |
154 | 164 | ||
155 | #[test] | 165 | #[test] |
156 | fn extract_from_impl() { | 166 | fn extract_from_impl_or_trait() { |
157 | // When invoked in an impl, extracted type alias should be placed next to the impl, not | 167 | // When invoked in an impl/trait, extracted type alias should be placed next to the |
158 | // inside. | 168 | // impl/trait, not inside. |
159 | check_assist( | 169 | check_assist( |
160 | extract_type_alias, | 170 | extract_type_alias, |
161 | r#" | 171 | r#" |
@@ -171,5 +181,39 @@ impl S { | |||
171 | } | 181 | } |
172 | "#, | 182 | "#, |
173 | ); | 183 | ); |
184 | check_assist( | ||
185 | extract_type_alias, | ||
186 | r#" | ||
187 | trait Tr { | ||
188 | fn f() -> $0(u8, u8)$0 {} | ||
189 | } | ||
190 | "#, | ||
191 | r#" | ||
192 | type $0Type = (u8, u8); | ||
193 | |||
194 | trait Tr { | ||
195 | fn f() -> Type {} | ||
196 | } | ||
197 | "#, | ||
198 | ); | ||
199 | } | ||
200 | |||
201 | #[test] | ||
202 | fn indentation() { | ||
203 | check_assist( | ||
204 | extract_type_alias, | ||
205 | r#" | ||
206 | mod m { | ||
207 | fn f() -> $0u8$0 {} | ||
208 | } | ||
209 | "#, | ||
210 | r#" | ||
211 | mod m { | ||
212 | type $0Type = u8; | ||
213 | |||
214 | fn f() -> Type {} | ||
215 | } | ||
216 | "#, | ||
217 | ); | ||
174 | } | 218 | } |
175 | } | 219 | } |
diff --git a/crates/ide_assists/src/handlers/extract_variable.rs b/crates/ide_assists/src/handlers/extract_variable.rs index ae084c86c..46b54a5f5 100644 --- a/crates/ide_assists/src/handlers/extract_variable.rs +++ b/crates/ide_assists/src/handlers/extract_variable.rs | |||
@@ -36,6 +36,11 @@ pub(crate) fn extract_variable(acc: &mut Assists, ctx: &AssistContext) -> Option | |||
36 | return None; | 36 | return None; |
37 | } | 37 | } |
38 | let to_extract = node.ancestors().find_map(valid_target_expr)?; | 38 | let to_extract = node.ancestors().find_map(valid_target_expr)?; |
39 | if let Some(ty) = ctx.sema.type_of_expr(&to_extract) { | ||
40 | if ty.is_unit() { | ||
41 | return None; | ||
42 | } | ||
43 | } | ||
39 | let anchor = Anchor::from(&to_extract)?; | 44 | let anchor = Anchor::from(&to_extract)?; |
40 | let indent = anchor.syntax().prev_sibling_or_token()?.as_token()?.clone(); | 45 | let indent = anchor.syntax().prev_sibling_or_token()?.as_token()?.clone(); |
41 | let target = to_extract.syntax().text_range(); | 46 | let target = to_extract.syntax().text_range(); |
@@ -275,15 +280,23 @@ fn foo() { | |||
275 | check_assist( | 280 | check_assist( |
276 | extract_variable, | 281 | extract_variable, |
277 | r#" | 282 | r#" |
278 | fn foo() { | 283 | fn foo() -> i32 { |
279 | $0bar(1 + 1)$0 | 284 | $0bar(1 + 1)$0 |
280 | } | 285 | } |
286 | |||
287 | fn bar(i: i32) -> i32 { | ||
288 | i | ||
289 | } | ||
281 | "#, | 290 | "#, |
282 | r#" | 291 | r#" |
283 | fn foo() { | 292 | fn foo() -> i32 { |
284 | let $0bar = bar(1 + 1); | 293 | let $0bar = bar(1 + 1); |
285 | bar | 294 | bar |
286 | } | 295 | } |
296 | |||
297 | fn bar(i: i32) -> i32 { | ||
298 | i | ||
299 | } | ||
287 | "#, | 300 | "#, |
288 | ) | 301 | ) |
289 | } | 302 | } |
@@ -796,6 +809,22 @@ fn foo() { | |||
796 | check_assist_not_applicable(extract_variable, "fn main() { loop { $0break$0; }; }"); | 809 | check_assist_not_applicable(extract_variable, "fn main() { loop { $0break$0; }; }"); |
797 | } | 810 | } |
798 | 811 | ||
812 | #[test] | ||
813 | fn test_extract_var_unit_expr_not_applicable() { | ||
814 | check_assist_not_applicable( | ||
815 | extract_variable, | ||
816 | r#" | ||
817 | fn foo() { | ||
818 | let mut i = 3; | ||
819 | $0if i >= 0 { | ||
820 | i += 1; | ||
821 | } else { | ||
822 | i -= 1; | ||
823 | }$0 | ||
824 | }"#, | ||
825 | ); | ||
826 | } | ||
827 | |||
799 | // FIXME: This is not quite correct, but good enough(tm) for the sorting heuristic | 828 | // FIXME: This is not quite correct, but good enough(tm) for the sorting heuristic |
800 | #[test] | 829 | #[test] |
801 | fn extract_var_target() { | 830 | fn extract_var_target() { |
diff --git a/crates/ide_assists/src/handlers/fill_match_arms.rs b/crates/ide_assists/src/handlers/fill_match_arms.rs index 3d2cd739a..5a43bdd6f 100644 --- a/crates/ide_assists/src/handlers/fill_match_arms.rs +++ b/crates/ide_assists/src/handlers/fill_match_arms.rs | |||
@@ -202,7 +202,7 @@ impl ExtendedEnum { | |||
202 | fn variants(self, db: &RootDatabase) -> Vec<ExtendedVariant> { | 202 | fn variants(self, db: &RootDatabase) -> Vec<ExtendedVariant> { |
203 | match self { | 203 | match self { |
204 | ExtendedEnum::Enum(e) => { | 204 | ExtendedEnum::Enum(e) => { |
205 | e.variants(db).into_iter().map(|x| ExtendedVariant::Variant(x)).collect::<Vec<_>>() | 205 | e.variants(db).into_iter().map(ExtendedVariant::Variant).collect::<Vec<_>>() |
206 | } | 206 | } |
207 | ExtendedEnum::Bool => { | 207 | ExtendedEnum::Bool => { |
208 | Vec::<ExtendedVariant>::from([ExtendedVariant::True, ExtendedVariant::False]) | 208 | Vec::<ExtendedVariant>::from([ExtendedVariant::True, ExtendedVariant::False]) |
@@ -212,7 +212,7 @@ impl ExtendedEnum { | |||
212 | } | 212 | } |
213 | 213 | ||
214 | fn resolve_enum_def(sema: &Semantics<RootDatabase>, expr: &ast::Expr) -> Option<ExtendedEnum> { | 214 | fn resolve_enum_def(sema: &Semantics<RootDatabase>, expr: &ast::Expr) -> Option<ExtendedEnum> { |
215 | sema.type_of_expr(&expr)?.autoderef(sema.db).find_map(|ty| match ty.as_adt() { | 215 | sema.type_of_expr(expr)?.autoderef(sema.db).find_map(|ty| match ty.as_adt() { |
216 | Some(Adt::Enum(e)) => Some(ExtendedEnum::Enum(e)), | 216 | Some(Adt::Enum(e)) => Some(ExtendedEnum::Enum(e)), |
217 | _ => { | 217 | _ => { |
218 | if ty.is_bool() { | 218 | if ty.is_bool() { |
@@ -228,7 +228,7 @@ fn resolve_tuple_of_enum_def( | |||
228 | sema: &Semantics<RootDatabase>, | 228 | sema: &Semantics<RootDatabase>, |
229 | expr: &ast::Expr, | 229 | expr: &ast::Expr, |
230 | ) -> Option<Vec<ExtendedEnum>> { | 230 | ) -> Option<Vec<ExtendedEnum>> { |
231 | sema.type_of_expr(&expr)? | 231 | sema.type_of_expr(expr)? |
232 | .tuple_fields(sema.db) | 232 | .tuple_fields(sema.db) |
233 | .iter() | 233 | .iter() |
234 | .map(|ty| { | 234 | .map(|ty| { |
diff --git a/crates/ide_assists/src/handlers/fix_visibility.rs b/crates/ide_assists/src/handlers/fix_visibility.rs index 89f7b2c2c..9b432e92f 100644 --- a/crates/ide_assists/src/handlers/fix_visibility.rs +++ b/crates/ide_assists/src/handlers/fix_visibility.rs | |||
@@ -43,7 +43,7 @@ fn add_vis_to_referenced_module_def(acc: &mut Assists, ctx: &AssistContext) -> O | |||
43 | _ => return None, | 43 | _ => return None, |
44 | }; | 44 | }; |
45 | 45 | ||
46 | let current_module = ctx.sema.scope(&path.syntax()).module()?; | 46 | let current_module = ctx.sema.scope(path.syntax()).module()?; |
47 | let target_module = def.module(ctx.db())?; | 47 | let target_module = def.module(ctx.db())?; |
48 | 48 | ||
49 | let vis = target_module.visibility_of(ctx.db(), &def)?; | 49 | let vis = target_module.visibility_of(ctx.db(), &def)?; |
diff --git a/crates/ide_assists/src/handlers/generate_enum_is_method.rs b/crates/ide_assists/src/handlers/generate_enum_is_method.rs index a9f71a703..24939f262 100644 --- a/crates/ide_assists/src/handlers/generate_enum_is_method.rs +++ b/crates/ide_assists/src/handlers/generate_enum_is_method.rs | |||
@@ -47,7 +47,7 @@ pub(crate) fn generate_enum_is_method(acc: &mut Assists, ctx: &AssistContext) -> | |||
47 | let fn_name = format!("is_{}", &to_lower_snake_case(&variant_name.text())); | 47 | let fn_name = format!("is_{}", &to_lower_snake_case(&variant_name.text())); |
48 | 48 | ||
49 | // Return early if we've found an existing new fn | 49 | // Return early if we've found an existing new fn |
50 | let impl_def = find_struct_impl(&ctx, &parent_enum, &fn_name)?; | 50 | let impl_def = find_struct_impl(ctx, &parent_enum, &fn_name)?; |
51 | 51 | ||
52 | let target = variant.syntax().text_range(); | 52 | let target = variant.syntax().text_range(); |
53 | acc.add( | 53 | acc.add( |
diff --git a/crates/ide_assists/src/handlers/generate_enum_projection_method.rs b/crates/ide_assists/src/handlers/generate_enum_projection_method.rs index e2f572ba3..986fb2315 100644 --- a/crates/ide_assists/src/handlers/generate_enum_projection_method.rs +++ b/crates/ide_assists/src/handlers/generate_enum_projection_method.rs | |||
@@ -136,7 +136,7 @@ fn generate_enum_projection_method( | |||
136 | format!("{}_{}", props.fn_name_prefix, &to_lower_snake_case(&variant_name.text())); | 136 | format!("{}_{}", props.fn_name_prefix, &to_lower_snake_case(&variant_name.text())); |
137 | 137 | ||
138 | // Return early if we've found an existing new fn | 138 | // Return early if we've found an existing new fn |
139 | let impl_def = find_struct_impl(&ctx, &parent_enum, &fn_name)?; | 139 | let impl_def = find_struct_impl(ctx, &parent_enum, &fn_name)?; |
140 | 140 | ||
141 | let target = variant.syntax().text_range(); | 141 | let target = variant.syntax().text_range(); |
142 | acc.add(AssistId(assist_id, AssistKind::Generate), assist_description, target, |builder| { | 142 | acc.add(AssistId(assist_id, AssistKind::Generate), assist_description, target, |builder| { |
diff --git a/crates/ide_assists/src/handlers/generate_function.rs b/crates/ide_assists/src/handlers/generate_function.rs index bc9fc524b..706c995ac 100644 --- a/crates/ide_assists/src/handlers/generate_function.rs +++ b/crates/ide_assists/src/handlers/generate_function.rs | |||
@@ -59,7 +59,7 @@ pub(crate) fn generate_function(acc: &mut Assists, ctx: &AssistContext) -> Optio | |||
59 | None => None, | 59 | None => None, |
60 | }; | 60 | }; |
61 | 61 | ||
62 | let function_builder = FunctionBuilder::from_call(&ctx, &call, &path, target_module)?; | 62 | let function_builder = FunctionBuilder::from_call(ctx, &call, &path, target_module)?; |
63 | 63 | ||
64 | let target = call.syntax().text_range(); | 64 | let target = call.syntax().text_range(); |
65 | acc.add( | 65 | acc.add( |
@@ -128,12 +128,12 @@ impl FunctionBuilder { | |||
128 | file = in_file; | 128 | file = in_file; |
129 | target | 129 | target |
130 | } | 130 | } |
131 | None => next_space_for_fn_after_call_site(&call)?, | 131 | None => next_space_for_fn_after_call_site(call)?, |
132 | }; | 132 | }; |
133 | let needs_pub = target_module.is_some(); | 133 | let needs_pub = target_module.is_some(); |
134 | let target_module = target_module.or_else(|| ctx.sema.scope(target.syntax()).module())?; | 134 | let target_module = target_module.or_else(|| ctx.sema.scope(target.syntax()).module())?; |
135 | let fn_name = fn_name(&path)?; | 135 | let fn_name = fn_name(path)?; |
136 | let (type_params, params) = fn_args(ctx, target_module, &call)?; | 136 | let (type_params, params) = fn_args(ctx, target_module, call)?; |
137 | 137 | ||
138 | // should_render_snippet intends to express a rough level of confidence about | 138 | // should_render_snippet intends to express a rough level of confidence about |
139 | // the correctness of the return type. | 139 | // the correctness of the return type. |
diff --git a/crates/ide_assists/src/handlers/generate_getter.rs b/crates/ide_assists/src/handlers/generate_getter.rs index 09971226e..cc020c92c 100644 --- a/crates/ide_assists/src/handlers/generate_getter.rs +++ b/crates/ide_assists/src/handlers/generate_getter.rs | |||
@@ -75,7 +75,7 @@ pub(crate) fn generate_getter_impl( | |||
75 | if mutable { | 75 | if mutable { |
76 | format_to!(fn_name, "_mut"); | 76 | format_to!(fn_name, "_mut"); |
77 | } | 77 | } |
78 | let impl_def = find_struct_impl(&ctx, &ast::Adt::Struct(strukt.clone()), fn_name.as_str())?; | 78 | let impl_def = find_struct_impl(ctx, &ast::Adt::Struct(strukt.clone()), fn_name.as_str())?; |
79 | 79 | ||
80 | let (id, label) = if mutable { | 80 | let (id, label) = if mutable { |
81 | ("generate_getter_mut", "Generate a mut getter method") | 81 | ("generate_getter_mut", "Generate a mut getter method") |
diff --git a/crates/ide_assists/src/handlers/generate_new.rs b/crates/ide_assists/src/handlers/generate_new.rs index 959a1f86c..b65e8387b 100644 --- a/crates/ide_assists/src/handlers/generate_new.rs +++ b/crates/ide_assists/src/handlers/generate_new.rs | |||
@@ -36,7 +36,7 @@ pub(crate) fn generate_new(acc: &mut Assists, ctx: &AssistContext) -> Option<()> | |||
36 | }; | 36 | }; |
37 | 37 | ||
38 | // Return early if we've found an existing new fn | 38 | // Return early if we've found an existing new fn |
39 | let impl_def = find_struct_impl(&ctx, &ast::Adt::Struct(strukt.clone()), "new")?; | 39 | let impl_def = find_struct_impl(ctx, &ast::Adt::Struct(strukt.clone()), "new")?; |
40 | 40 | ||
41 | let target = strukt.syntax().text_range(); | 41 | let target = strukt.syntax().text_range(); |
42 | acc.add(AssistId("generate_new", AssistKind::Generate), "Generate `new`", target, |builder| { | 42 | acc.add(AssistId("generate_new", AssistKind::Generate), "Generate `new`", target, |builder| { |
diff --git a/crates/ide_assists/src/handlers/generate_setter.rs b/crates/ide_assists/src/handlers/generate_setter.rs index 288cf745d..5bdf6b3f4 100644 --- a/crates/ide_assists/src/handlers/generate_setter.rs +++ b/crates/ide_assists/src/handlers/generate_setter.rs | |||
@@ -39,7 +39,7 @@ pub(crate) fn generate_setter(acc: &mut Assists, ctx: &AssistContext) -> Option< | |||
39 | // Return early if we've found an existing fn | 39 | // Return early if we've found an existing fn |
40 | let fn_name = to_lower_snake_case(&field_name.to_string()); | 40 | let fn_name = to_lower_snake_case(&field_name.to_string()); |
41 | let impl_def = find_struct_impl( | 41 | let impl_def = find_struct_impl( |
42 | &ctx, | 42 | ctx, |
43 | &ast::Adt::Struct(strukt.clone()), | 43 | &ast::Adt::Struct(strukt.clone()), |
44 | format!("set_{}", fn_name).as_str(), | 44 | format!("set_{}", fn_name).as_str(), |
45 | )?; | 45 | )?; |
diff --git a/crates/ide_assists/src/handlers/inline_local_variable.rs b/crates/ide_assists/src/handlers/inline_local_variable.rs index f5dafc8cb..2441dbb8b 100644 --- a/crates/ide_assists/src/handlers/inline_local_variable.rs +++ b/crates/ide_assists/src/handlers/inline_local_variable.rs | |||
@@ -182,6 +182,10 @@ fn inline_usage(ctx: &AssistContext) -> Option<InlineData> { | |||
182 | PathResolution::Local(local) => local, | 182 | PathResolution::Local(local) => local, |
183 | _ => return None, | 183 | _ => return None, |
184 | }; | 184 | }; |
185 | if local.is_mut(ctx.sema.db) { | ||
186 | cov_mark::hit!(test_not_inline_mut_variable_use); | ||
187 | return None; | ||
188 | } | ||
185 | 189 | ||
186 | let bind_pat = match local.source(ctx.db()).value { | 190 | let bind_pat = match local.source(ctx.db()).value { |
187 | Either::Left(ident) => ident, | 191 | Either::Left(ident) => ident, |
@@ -427,6 +431,19 @@ fn foo() { | |||
427 | } | 431 | } |
428 | 432 | ||
429 | #[test] | 433 | #[test] |
434 | fn test_not_inline_mut_variable_use() { | ||
435 | cov_mark::check!(test_not_inline_mut_variable_use); | ||
436 | check_assist_not_applicable( | ||
437 | inline_local_variable, | ||
438 | r" | ||
439 | fn foo() { | ||
440 | let mut a = 1 + 1; | ||
441 | a$0 + 1; | ||
442 | }", | ||
443 | ); | ||
444 | } | ||
445 | |||
446 | #[test] | ||
430 | fn test_call_expr() { | 447 | fn test_call_expr() { |
431 | check_assist( | 448 | check_assist( |
432 | inline_local_variable, | 449 | inline_local_variable, |
diff --git a/crates/ide_assists/src/handlers/remove_dbg.rs b/crates/ide_assists/src/handlers/remove_dbg.rs index c8226550f..b20fe992d 100644 --- a/crates/ide_assists/src/handlers/remove_dbg.rs +++ b/crates/ide_assists/src/handlers/remove_dbg.rs | |||
@@ -85,7 +85,7 @@ fn whitespace_start(it: SyntaxElement) -> Option<TextSize> { | |||
85 | } | 85 | } |
86 | 86 | ||
87 | fn adjusted_macro_contents(macro_call: &ast::MacroCall) -> Option<String> { | 87 | fn adjusted_macro_contents(macro_call: &ast::MacroCall) -> Option<String> { |
88 | let contents = get_valid_macrocall_contents(¯o_call, "dbg")?; | 88 | let contents = get_valid_macrocall_contents(macro_call, "dbg")?; |
89 | let macro_text_with_brackets = macro_call.token_tree()?.syntax().text(); | 89 | let macro_text_with_brackets = macro_call.token_tree()?.syntax().text(); |
90 | let macro_text_in_brackets = macro_text_with_brackets.slice(TextRange::new( | 90 | let macro_text_in_brackets = macro_text_with_brackets.slice(TextRange::new( |
91 | TextSize::of('('), | 91 | TextSize::of('('), |
diff --git a/crates/ide_assists/src/handlers/remove_unused_param.rs b/crates/ide_assists/src/handlers/remove_unused_param.rs index 2699d2861..fabfe7e93 100644 --- a/crates/ide_assists/src/handlers/remove_unused_param.rs +++ b/crates/ide_assists/src/handlers/remove_unused_param.rs | |||
@@ -37,8 +37,20 @@ pub(crate) fn remove_unused_param(acc: &mut Assists, ctx: &AssistContext) -> Opt | |||
37 | _ => return None, | 37 | _ => return None, |
38 | }; | 38 | }; |
39 | let func = param.syntax().ancestors().find_map(ast::Fn::cast)?; | 39 | let func = param.syntax().ancestors().find_map(ast::Fn::cast)?; |
40 | let param_position = func.param_list()?.params().position(|it| it == param)?; | ||
41 | 40 | ||
41 | // check if fn is in impl Trait for .. | ||
42 | if func | ||
43 | .syntax() | ||
44 | .parent() // AssocItemList | ||
45 | .and_then(|x| x.parent()) | ||
46 | .and_then(ast::Impl::cast) | ||
47 | .map_or(false, |imp| imp.trait_().is_some()) | ||
48 | { | ||
49 | cov_mark::hit!(trait_impl); | ||
50 | return None; | ||
51 | } | ||
52 | |||
53 | let param_position = func.param_list()?.params().position(|it| it == param)?; | ||
42 | let fn_def = { | 54 | let fn_def = { |
43 | let func = ctx.sema.to_def(&func)?; | 55 | let func = ctx.sema.to_def(&func)?; |
44 | Definition::ModuleDef(func.into()) | 56 | Definition::ModuleDef(func.into()) |
@@ -254,6 +266,22 @@ fn main() { foo(9, 2) } | |||
254 | } | 266 | } |
255 | 267 | ||
256 | #[test] | 268 | #[test] |
269 | fn trait_impl() { | ||
270 | cov_mark::check!(trait_impl); | ||
271 | check_assist_not_applicable( | ||
272 | remove_unused_param, | ||
273 | r#" | ||
274 | trait Trait { | ||
275 | fn foo(x: i32); | ||
276 | } | ||
277 | impl Trait for () { | ||
278 | fn foo($0x: i32) {} | ||
279 | } | ||
280 | "#, | ||
281 | ); | ||
282 | } | ||
283 | |||
284 | #[test] | ||
257 | fn remove_across_files() { | 285 | fn remove_across_files() { |
258 | check_assist( | 286 | check_assist( |
259 | remove_unused_param, | 287 | remove_unused_param, |
diff --git a/crates/ide_assists/src/handlers/reorder_fields.rs b/crates/ide_assists/src/handlers/reorder_fields.rs index 933acead1..f6a926042 100644 --- a/crates/ide_assists/src/handlers/reorder_fields.rs +++ b/crates/ide_assists/src/handlers/reorder_fields.rs | |||
@@ -28,7 +28,7 @@ pub(crate) fn reorder_fields(acc: &mut Assists, ctx: &AssistContext) -> Option<( | |||
28 | .or_else(|| ctx.find_node_at_offset::<ast::RecordPat>().map(Either::Right))?; | 28 | .or_else(|| ctx.find_node_at_offset::<ast::RecordPat>().map(Either::Right))?; |
29 | 29 | ||
30 | let path = record.as_ref().either(|it| it.path(), |it| it.path())?; | 30 | let path = record.as_ref().either(|it| it.path(), |it| it.path())?; |
31 | let ranks = compute_fields_ranks(&path, &ctx)?; | 31 | let ranks = compute_fields_ranks(&path, ctx)?; |
32 | let get_rank_of_field = | 32 | let get_rank_of_field = |
33 | |of: Option<_>| *ranks.get(&of.unwrap_or_default()).unwrap_or(&usize::MAX); | 33 | |of: Option<_>| *ranks.get(&of.unwrap_or_default()).unwrap_or(&usize::MAX); |
34 | 34 | ||
diff --git a/crates/ide_assists/src/handlers/replace_derive_with_manual_impl.rs b/crates/ide_assists/src/handlers/replace_derive_with_manual_impl.rs index 10d9cec31..f9474c9f5 100644 --- a/crates/ide_assists/src/handlers/replace_derive_with_manual_impl.rs +++ b/crates/ide_assists/src/handlers/replace_derive_with_manual_impl.rs | |||
@@ -112,7 +112,7 @@ fn add_assist( | |||
112 | let insert_pos = adt.syntax().text_range().end(); | 112 | let insert_pos = adt.syntax().text_range().end(); |
113 | let impl_def_with_items = | 113 | let impl_def_with_items = |
114 | impl_def_from_trait(&ctx.sema, &annotated_name, trait_, trait_path); | 114 | impl_def_from_trait(&ctx.sema, &annotated_name, trait_, trait_path); |
115 | update_attribute(builder, &input, &trait_name, &attr); | 115 | update_attribute(builder, input, &trait_name, attr); |
116 | let trait_path = format!("{}", trait_path); | 116 | let trait_path = format!("{}", trait_path); |
117 | match (ctx.config.snippet_cap, impl_def_with_items) { | 117 | match (ctx.config.snippet_cap, impl_def_with_items) { |
118 | (None, _) => { | 118 | (None, _) => { |
diff --git a/crates/ide_assists/src/handlers/replace_if_let_with_match.rs b/crates/ide_assists/src/handlers/replace_if_let_with_match.rs index aee880625..9404aa26d 100644 --- a/crates/ide_assists/src/handlers/replace_if_let_with_match.rs +++ b/crates/ide_assists/src/handlers/replace_if_let_with_match.rs | |||
@@ -169,7 +169,7 @@ pub(crate) fn replace_match_with_if_let(acc: &mut Assists, ctx: &AssistContext) | |||
169 | } | 169 | } |
170 | 170 | ||
171 | fn is_pat_wildcard_or_sad(sema: &hir::Semantics<RootDatabase>, pat: &ast::Pat) -> bool { | 171 | fn is_pat_wildcard_or_sad(sema: &hir::Semantics<RootDatabase>, pat: &ast::Pat) -> bool { |
172 | sema.type_of_pat(&pat) | 172 | sema.type_of_pat(pat) |
173 | .and_then(|ty| TryEnum::from_ty(sema, &ty)) | 173 | .and_then(|ty| TryEnum::from_ty(sema, &ty)) |
174 | .map(|it| it.sad_pattern().syntax().text() == pat.syntax().text()) | 174 | .map(|it| it.sad_pattern().syntax().text() == pat.syntax().text()) |
175 | .unwrap_or_else(|| matches!(pat, ast::Pat::WildcardPat(_))) | 175 | .unwrap_or_else(|| matches!(pat, ast::Pat::WildcardPat(_))) |
diff --git a/crates/ide_assists/src/handlers/wrap_return_type_in_result.rs b/crates/ide_assists/src/handlers/wrap_return_type_in_result.rs index 2f1da82c7..140e27356 100644 --- a/crates/ide_assists/src/handlers/wrap_return_type_in_result.rs +++ b/crates/ide_assists/src/handlers/wrap_return_type_in_result.rs | |||
@@ -123,7 +123,7 @@ impl TailReturnCollector { | |||
123 | fn handle_exprs(&mut self, expr: &Expr, collect_break: bool) { | 123 | fn handle_exprs(&mut self, expr: &Expr, collect_break: bool) { |
124 | match expr { | 124 | match expr { |
125 | Expr::BlockExpr(block_expr) => { | 125 | Expr::BlockExpr(block_expr) => { |
126 | self.collect_jump_exprs(&block_expr, collect_break); | 126 | self.collect_jump_exprs(block_expr, collect_break); |
127 | } | 127 | } |
128 | Expr::ReturnExpr(ret_expr) => { | 128 | Expr::ReturnExpr(ret_expr) => { |
129 | if let Some(ret_expr_arg) = &ret_expr.expr() { | 129 | if let Some(ret_expr_arg) = &ret_expr.expr() { |
diff --git a/crates/ide_assists/src/lib.rs b/crates/ide_assists/src/lib.rs index 16af72927..331a6df2b 100644 --- a/crates/ide_assists/src/lib.rs +++ b/crates/ide_assists/src/lib.rs | |||
@@ -47,14 +47,14 @@ impl AssistKind { | |||
47 | } | 47 | } |
48 | 48 | ||
49 | match self { | 49 | match self { |
50 | AssistKind::None | AssistKind::Generate => return true, | 50 | AssistKind::None | AssistKind::Generate => true, |
51 | AssistKind::Refactor => match other { | 51 | AssistKind::Refactor => match other { |
52 | AssistKind::RefactorExtract | 52 | AssistKind::RefactorExtract |
53 | | AssistKind::RefactorInline | 53 | | AssistKind::RefactorInline |
54 | | AssistKind::RefactorRewrite => return true, | 54 | | AssistKind::RefactorRewrite => true, |
55 | _ => return false, | 55 | _ => false, |
56 | }, | 56 | }, |
57 | _ => return false, | 57 | _ => false, |
58 | } | 58 | } |
59 | } | 59 | } |
60 | 60 | ||
diff --git a/crates/ide_assists/src/tests.rs b/crates/ide_assists/src/tests.rs index 2b7c2d581..bdf9cb71c 100644 --- a/crates/ide_assists/src/tests.rs +++ b/crates/ide_assists/src/tests.rs | |||
@@ -74,7 +74,7 @@ pub(crate) fn check_assist_unresolved(assist: Handler, ra_fixture: &str) { | |||
74 | #[track_caller] | 74 | #[track_caller] |
75 | fn check_doc_test(assist_id: &str, before: &str, after: &str) { | 75 | fn check_doc_test(assist_id: &str, before: &str, after: &str) { |
76 | let after = trim_indent(after); | 76 | let after = trim_indent(after); |
77 | let (db, file_id, selection) = RootDatabase::with_range_or_offset(&before); | 77 | let (db, file_id, selection) = RootDatabase::with_range_or_offset(before); |
78 | let before = db.file_text(file_id).to_string(); | 78 | let before = db.file_text(file_id).to_string(); |
79 | let frange = FileRange { file_id, range: selection.into() }; | 79 | let frange = FileRange { file_id, range: selection.into() }; |
80 | 80 | ||
diff --git a/crates/ide_assists/src/utils.rs b/crates/ide_assists/src/utils.rs index 30128a24a..068df005b 100644 --- a/crates/ide_assists/src/utils.rs +++ b/crates/ide_assists/src/utils.rs | |||
@@ -492,7 +492,7 @@ pub(crate) fn add_method_to_adt( | |||
492 | let start_offset = impl_def | 492 | let start_offset = impl_def |
493 | .and_then(|impl_def| find_impl_block_end(impl_def, &mut buf)) | 493 | .and_then(|impl_def| find_impl_block_end(impl_def, &mut buf)) |
494 | .unwrap_or_else(|| { | 494 | .unwrap_or_else(|| { |
495 | buf = generate_impl_text(&adt, &buf); | 495 | buf = generate_impl_text(adt, &buf); |
496 | adt.syntax().text_range().end() | 496 | adt.syntax().text_range().end() |
497 | }); | 497 | }); |
498 | 498 | ||
diff --git a/crates/ide_assists/src/utils/suggest_name.rs b/crates/ide_assists/src/utils/suggest_name.rs index b3aabeab3..cb8bc8b2f 100644 --- a/crates/ide_assists/src/utils/suggest_name.rs +++ b/crates/ide_assists/src/utils/suggest_name.rs | |||
@@ -187,7 +187,7 @@ fn from_method_call(expr: &ast::Expr) -> Option<String> { | |||
187 | } | 187 | } |
188 | } | 188 | } |
189 | 189 | ||
190 | normalize(&name) | 190 | normalize(name) |
191 | } | 191 | } |
192 | 192 | ||
193 | fn from_param(expr: &ast::Expr, sema: &Semantics<'_, RootDatabase>) -> Option<String> { | 193 | fn from_param(expr: &ast::Expr, sema: &Semantics<'_, RootDatabase>) -> Option<String> { |