diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2021-03-31 13:26:57 +0100 |
---|---|---|
committer | GitHub <[email protected]> | 2021-03-31 13:26:57 +0100 |
commit | 75011bbccbf2e00092222a1071ba9111f834a4ae (patch) | |
tree | 4e39b7bd20df44f57ab57c27ce1a3a71362b077f /crates | |
parent | aca9004c7e4bafe1fc60d0e0298f5687b2e7615a (diff) | |
parent | 3c6c1c99b41e2a3c9a31b0d4c73d660399255cba (diff) |
Merge #8210
8210: Implement "Extract type alias" assist r=jonas-schievink a=jonas-schievink
Co-authored-by: Jonas Schievink <[email protected]>
Co-authored-by: Jonas Schievink <[email protected]>
Diffstat (limited to 'crates')
-rw-r--r-- | crates/ide_assists/src/assist_context.rs | 5 | ||||
-rw-r--r-- | crates/ide_assists/src/handlers/extract_type_alias.rs | 149 | ||||
-rw-r--r-- | crates/ide_assists/src/lib.rs | 2 | ||||
-rw-r--r-- | crates/ide_assists/src/tests/generated.rs | 19 |
4 files changed, 174 insertions, 1 deletions
diff --git a/crates/ide_assists/src/assist_context.rs b/crates/ide_assists/src/assist_context.rs index 1482d37f8..8714e4978 100644 --- a/crates/ide_assists/src/assist_context.rs +++ b/crates/ide_assists/src/assist_context.rs | |||
@@ -13,7 +13,7 @@ use ide_db::{ | |||
13 | RootDatabase, | 13 | RootDatabase, |
14 | }; | 14 | }; |
15 | use syntax::{ | 15 | use syntax::{ |
16 | algo::{self, find_node_at_offset, SyntaxRewriter}, | 16 | algo::{self, find_node_at_offset, find_node_at_range, SyntaxRewriter}, |
17 | AstNode, AstToken, SourceFile, SyntaxElement, SyntaxKind, SyntaxNode, SyntaxNodePtr, | 17 | AstNode, AstToken, SourceFile, SyntaxElement, SyntaxKind, SyntaxNode, SyntaxNodePtr, |
18 | SyntaxToken, TextRange, TextSize, TokenAtOffset, | 18 | SyntaxToken, TextRange, TextSize, TokenAtOffset, |
19 | }; | 19 | }; |
@@ -89,6 +89,9 @@ impl<'a> AssistContext<'a> { | |||
89 | pub(crate) fn find_node_at_offset<N: AstNode>(&self) -> Option<N> { | 89 | pub(crate) fn find_node_at_offset<N: AstNode>(&self) -> Option<N> { |
90 | find_node_at_offset(self.source_file.syntax(), self.offset()) | 90 | find_node_at_offset(self.source_file.syntax(), self.offset()) |
91 | } | 91 | } |
92 | pub(crate) fn find_node_at_range<N: AstNode>(&self) -> Option<N> { | ||
93 | find_node_at_range(self.source_file.syntax(), self.frange.range) | ||
94 | } | ||
92 | pub(crate) fn find_node_at_offset_with_descend<N: AstNode>(&self) -> Option<N> { | 95 | pub(crate) fn find_node_at_offset_with_descend<N: AstNode>(&self) -> Option<N> { |
93 | self.sema.find_node_at_offset_with_descend(self.source_file.syntax(), self.offset()) | 96 | self.sema.find_node_at_offset_with_descend(self.source_file.syntax(), self.offset()) |
94 | } | 97 | } |
diff --git a/crates/ide_assists/src/handlers/extract_type_alias.rs b/crates/ide_assists/src/handlers/extract_type_alias.rs new file mode 100644 index 000000000..442a209b9 --- /dev/null +++ b/crates/ide_assists/src/handlers/extract_type_alias.rs | |||
@@ -0,0 +1,149 @@ | |||
1 | use syntax::ast::{self, AstNode}; | ||
2 | |||
3 | use crate::{AssistContext, AssistId, AssistKind, Assists}; | ||
4 | |||
5 | // Assist: extract_type_alias | ||
6 | // | ||
7 | // Extracts the selected type as a type alias. | ||
8 | // | ||
9 | // ``` | ||
10 | // struct S { | ||
11 | // field: $0(u8, u8, u8)$0, | ||
12 | // } | ||
13 | // ``` | ||
14 | // -> | ||
15 | // ``` | ||
16 | // type $0Type = (u8, u8, u8); | ||
17 | // | ||
18 | // struct S { | ||
19 | // field: Type, | ||
20 | // } | ||
21 | // ``` | ||
22 | pub(crate) fn extract_type_alias(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | ||
23 | if ctx.frange.range.is_empty() { | ||
24 | return None; | ||
25 | } | ||
26 | |||
27 | let node = ctx.find_node_at_range::<ast::Type>()?; | ||
28 | let insert = ctx.find_node_at_offset::<ast::Item>()?.syntax().text_range().start(); | ||
29 | let target = node.syntax().text_range(); | ||
30 | |||
31 | acc.add( | ||
32 | AssistId("extract_type_alias", AssistKind::RefactorExtract), | ||
33 | "Extract type as type alias", | ||
34 | target, | ||
35 | |builder| { | ||
36 | builder.edit_file(ctx.frange.file_id); | ||
37 | builder.replace(target, "Type"); | ||
38 | match ctx.config.snippet_cap { | ||
39 | Some(cap) => { | ||
40 | builder.insert_snippet(cap, insert, format!("type $0Type = {};\n\n", node)); | ||
41 | } | ||
42 | None => { | ||
43 | builder.insert(insert, format!("type Type = {};\n\n", node)); | ||
44 | } | ||
45 | } | ||
46 | }, | ||
47 | ) | ||
48 | } | ||
49 | |||
50 | #[cfg(test)] | ||
51 | mod tests { | ||
52 | use crate::tests::{check_assist, check_assist_not_applicable}; | ||
53 | |||
54 | use super::*; | ||
55 | |||
56 | #[test] | ||
57 | fn test_not_applicable_without_selection() { | ||
58 | check_assist_not_applicable( | ||
59 | extract_type_alias, | ||
60 | r" | ||
61 | struct S { | ||
62 | field: $0(u8, u8, u8), | ||
63 | } | ||
64 | ", | ||
65 | ); | ||
66 | } | ||
67 | |||
68 | #[test] | ||
69 | fn test_simple_types() { | ||
70 | check_assist( | ||
71 | extract_type_alias, | ||
72 | r" | ||
73 | struct S { | ||
74 | field: $0u8$0, | ||
75 | } | ||
76 | ", | ||
77 | r#" | ||
78 | type $0Type = u8; | ||
79 | |||
80 | struct S { | ||
81 | field: Type, | ||
82 | } | ||
83 | "#, | ||
84 | ); | ||
85 | } | ||
86 | |||
87 | #[test] | ||
88 | fn test_generic_type_arg() { | ||
89 | check_assist( | ||
90 | extract_type_alias, | ||
91 | r" | ||
92 | fn generic<T>() {} | ||
93 | |||
94 | fn f() { | ||
95 | generic::<$0()$0>(); | ||
96 | } | ||
97 | ", | ||
98 | r#" | ||
99 | fn generic<T>() {} | ||
100 | |||
101 | type $0Type = (); | ||
102 | |||
103 | fn f() { | ||
104 | generic::<Type>(); | ||
105 | } | ||
106 | "#, | ||
107 | ); | ||
108 | } | ||
109 | |||
110 | #[test] | ||
111 | fn test_inner_type_arg() { | ||
112 | check_assist( | ||
113 | extract_type_alias, | ||
114 | r" | ||
115 | struct Vec<T> {} | ||
116 | struct S { | ||
117 | v: Vec<Vec<$0Vec<u8>$0>>, | ||
118 | } | ||
119 | ", | ||
120 | r#" | ||
121 | struct Vec<T> {} | ||
122 | type $0Type = Vec<u8>; | ||
123 | |||
124 | struct S { | ||
125 | v: Vec<Vec<Type>>, | ||
126 | } | ||
127 | "#, | ||
128 | ); | ||
129 | } | ||
130 | |||
131 | #[test] | ||
132 | fn test_extract_inner_type() { | ||
133 | check_assist( | ||
134 | extract_type_alias, | ||
135 | r" | ||
136 | struct S { | ||
137 | field: ($0u8$0,), | ||
138 | } | ||
139 | ", | ||
140 | r#" | ||
141 | type $0Type = u8; | ||
142 | |||
143 | struct S { | ||
144 | field: (Type,), | ||
145 | } | ||
146 | "#, | ||
147 | ); | ||
148 | } | ||
149 | } | ||
diff --git a/crates/ide_assists/src/lib.rs b/crates/ide_assists/src/lib.rs index 8c068a6c0..3d1dcef4c 100644 --- a/crates/ide_assists/src/lib.rs +++ b/crates/ide_assists/src/lib.rs | |||
@@ -121,6 +121,7 @@ mod handlers { | |||
121 | mod expand_glob_import; | 121 | mod expand_glob_import; |
122 | mod extract_function; | 122 | mod extract_function; |
123 | mod extract_struct_from_enum_variant; | 123 | mod extract_struct_from_enum_variant; |
124 | mod extract_type_alias; | ||
124 | mod extract_variable; | 125 | mod extract_variable; |
125 | mod fill_match_arms; | 126 | mod fill_match_arms; |
126 | mod fix_visibility; | 127 | mod fix_visibility; |
@@ -187,6 +188,7 @@ mod handlers { | |||
187 | early_return::convert_to_guarded_return, | 188 | early_return::convert_to_guarded_return, |
188 | expand_glob_import::expand_glob_import, | 189 | expand_glob_import::expand_glob_import, |
189 | extract_struct_from_enum_variant::extract_struct_from_enum_variant, | 190 | extract_struct_from_enum_variant::extract_struct_from_enum_variant, |
191 | extract_type_alias::extract_type_alias, | ||
190 | fill_match_arms::fill_match_arms, | 192 | fill_match_arms::fill_match_arms, |
191 | fix_visibility::fix_visibility, | 193 | fix_visibility::fix_visibility, |
192 | flip_binexpr::flip_binexpr, | 194 | flip_binexpr::flip_binexpr, |
diff --git a/crates/ide_assists/src/tests/generated.rs b/crates/ide_assists/src/tests/generated.rs index 736027ff0..03b7fb366 100644 --- a/crates/ide_assists/src/tests/generated.rs +++ b/crates/ide_assists/src/tests/generated.rs | |||
@@ -329,6 +329,25 @@ enum A { One(One) } | |||
329 | } | 329 | } |
330 | 330 | ||
331 | #[test] | 331 | #[test] |
332 | fn doctest_extract_type_alias() { | ||
333 | check_doc_test( | ||
334 | "extract_type_alias", | ||
335 | r#####" | ||
336 | struct S { | ||
337 | field: $0(u8, u8, u8)$0, | ||
338 | } | ||
339 | "#####, | ||
340 | r#####" | ||
341 | type $0Type = (u8, u8, u8); | ||
342 | |||
343 | struct S { | ||
344 | field: Type, | ||
345 | } | ||
346 | "#####, | ||
347 | ) | ||
348 | } | ||
349 | |||
350 | #[test] | ||
332 | fn doctest_extract_variable() { | 351 | fn doctest_extract_variable() { |
333 | check_doc_test( | 352 | check_doc_test( |
334 | "extract_variable", | 353 | "extract_variable", |