diff options
-rw-r--r-- | crates/ide_assists/src/handlers/extract_type_alias.rs | 165 | ||||
-rw-r--r-- | crates/ide_assists/src/lib.rs | 2 | ||||
-rw-r--r-- | crates/ide_assists/src/tests/generated.rs | 19 |
3 files changed, 186 insertions, 0 deletions
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..771868234 --- /dev/null +++ b/crates/ide_assists/src/handlers/extract_type_alias.rs | |||
@@ -0,0 +1,165 @@ | |||
1 | use syntax::{ | ||
2 | ast::{self, AstNode}, | ||
3 | SyntaxKind, | ||
4 | }; | ||
5 | |||
6 | use crate::{AssistContext, AssistId, AssistKind, Assists}; | ||
7 | |||
8 | // Assist: extract_type_alias | ||
9 | // | ||
10 | // Extracts the selected type as a type alias. | ||
11 | // | ||
12 | // ``` | ||
13 | // struct S { | ||
14 | // field: $0(u8, u8, u8)$0, | ||
15 | // } | ||
16 | // ``` | ||
17 | // -> | ||
18 | // ``` | ||
19 | // type Type = (u8, u8, u8); | ||
20 | // | ||
21 | // struct S { | ||
22 | // field: Type, | ||
23 | // } | ||
24 | // ``` | ||
25 | pub(crate) fn extract_type_alias(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | ||
26 | if ctx.frange.range.is_empty() { | ||
27 | return None; | ||
28 | } | ||
29 | |||
30 | let node = match ctx.covering_element() { | ||
31 | syntax::NodeOrToken::Node(node) => node, | ||
32 | syntax::NodeOrToken::Token(tok) => tok.parent()?, | ||
33 | }; | ||
34 | let range = node.text_range(); | ||
35 | let mut type_like_node = None; | ||
36 | for node in node.ancestors() { | ||
37 | if node.text_range() != range { | ||
38 | break; | ||
39 | } | ||
40 | |||
41 | let kind = node.kind(); | ||
42 | if ast::Type::can_cast(kind) || kind == SyntaxKind::TYPE_ARG { | ||
43 | type_like_node = Some(node); | ||
44 | break; | ||
45 | } | ||
46 | } | ||
47 | |||
48 | let node = type_like_node?; | ||
49 | |||
50 | let insert = ctx.find_node_at_offset::<ast::Item>()?.syntax().text_range().start(); | ||
51 | let target = node.text_range(); | ||
52 | |||
53 | acc.add( | ||
54 | AssistId("extract_type_alias", AssistKind::RefactorExtract), | ||
55 | "Extract type as type alias", | ||
56 | target, | ||
57 | |builder| { | ||
58 | builder.edit_file(ctx.frange.file_id); | ||
59 | // FIXME: add snippet support | ||
60 | builder.replace(target, "Type"); | ||
61 | builder.insert(insert, format!("type Type = {};\n\n", node)); | ||
62 | }, | ||
63 | ) | ||
64 | } | ||
65 | |||
66 | #[cfg(test)] | ||
67 | mod tests { | ||
68 | use crate::tests::{check_assist, check_assist_not_applicable}; | ||
69 | |||
70 | use super::*; | ||
71 | |||
72 | #[test] | ||
73 | fn test_not_applicable_without_selection() { | ||
74 | check_assist_not_applicable( | ||
75 | extract_type_alias, | ||
76 | r" | ||
77 | struct S { | ||
78 | field: $0(u8, u8, u8), | ||
79 | } | ||
80 | ", | ||
81 | ); | ||
82 | } | ||
83 | |||
84 | #[test] | ||
85 | fn test_simple_types() { | ||
86 | check_assist( | ||
87 | extract_type_alias, | ||
88 | r" | ||
89 | struct S { | ||
90 | field: $0u8$0, | ||
91 | } | ||
92 | ", | ||
93 | r#" | ||
94 | type Type = u8; | ||
95 | |||
96 | struct S { | ||
97 | field: Type, | ||
98 | } | ||
99 | "#, | ||
100 | ); | ||
101 | } | ||
102 | |||
103 | #[test] | ||
104 | fn test_generic_type_arg() { | ||
105 | check_assist( | ||
106 | extract_type_alias, | ||
107 | r" | ||
108 | fn generic<T>() {} | ||
109 | |||
110 | fn f() { | ||
111 | generic::<$0()$0>(); | ||
112 | } | ||
113 | ", | ||
114 | r#" | ||
115 | fn generic<T>() {} | ||
116 | |||
117 | type Type = (); | ||
118 | |||
119 | fn f() { | ||
120 | generic::<Type>(); | ||
121 | } | ||
122 | "#, | ||
123 | ); | ||
124 | } | ||
125 | |||
126 | #[test] | ||
127 | fn test_inner_type_arg() { | ||
128 | check_assist( | ||
129 | extract_type_alias, | ||
130 | r" | ||
131 | struct Vec<T> {} | ||
132 | struct S { | ||
133 | v: Vec<Vec<$0Vec<u8>$0>>, | ||
134 | } | ||
135 | ", | ||
136 | r#" | ||
137 | struct Vec<T> {} | ||
138 | type Type = Vec<u8>; | ||
139 | |||
140 | struct S { | ||
141 | v: Vec<Vec<Type>>, | ||
142 | } | ||
143 | "#, | ||
144 | ); | ||
145 | } | ||
146 | |||
147 | #[test] | ||
148 | fn test_extract_inner_type() { | ||
149 | check_assist( | ||
150 | extract_type_alias, | ||
151 | r" | ||
152 | struct S { | ||
153 | field: ($0u8$0,), | ||
154 | } | ||
155 | ", | ||
156 | r#" | ||
157 | type Type = u8; | ||
158 | |||
159 | struct S { | ||
160 | field: (Type,), | ||
161 | } | ||
162 | "#, | ||
163 | ); | ||
164 | } | ||
165 | } | ||
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..6bb65e6bc 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 Type = (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", |