Skip to content

Commit e39979a

Browse files
author
Jonas Schievink
committed
Implement "Extract type alias" assist
1 parent 4ecaad9 commit e39979a

File tree

3 files changed

+186
-0
lines changed

3 files changed

+186
-0
lines changed
Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
}

crates/ide_assists/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ mod handlers {
121121
mod expand_glob_import;
122122
mod extract_function;
123123
mod extract_struct_from_enum_variant;
124+
mod extract_type_alias;
124125
mod extract_variable;
125126
mod fill_match_arms;
126127
mod fix_visibility;
@@ -187,6 +188,7 @@ mod handlers {
187188
early_return::convert_to_guarded_return,
188189
expand_glob_import::expand_glob_import,
189190
extract_struct_from_enum_variant::extract_struct_from_enum_variant,
191+
extract_type_alias::extract_type_alias,
190192
fill_match_arms::fill_match_arms,
191193
fix_visibility::fix_visibility,
192194
flip_binexpr::flip_binexpr,

crates/ide_assists/src/tests/generated.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,25 @@ enum A { One(One) }
328328
)
329329
}
330330

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+
331350
#[test]
332351
fn doctest_extract_variable() {
333352
check_doc_test(

0 commit comments

Comments
 (0)