]> git.lizzy.rs Git - rust.git/blob - crates/ide_assists/src/handlers/extract_type_alias.rs
a66f6abeaf3a7778a0d4510fa00f74814f2cf3fb
[rust.git] / crates / ide_assists / src / handlers / extract_type_alias.rs
1 use syntax::{
2     ast::{self, AstNode},
3     match_ast,
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 $0Type = (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 = ctx.find_node_at_range::<ast::Type>()?;
31     let item = ctx.find_node_at_offset::<ast::Item>()?;
32     let insert = match_ast! {
33         match (item.syntax().parent()?) {
34             ast::AssocItemList(it) => it.syntax().parent()?.text_range().start(),
35             _ => item.syntax().text_range().start(),
36         }
37     };
38     let target = node.syntax().text_range();
39
40     acc.add(
41         AssistId("extract_type_alias", AssistKind::RefactorExtract),
42         "Extract type as type alias",
43         target,
44         |builder| {
45             builder.edit_file(ctx.frange.file_id);
46             builder.replace(target, "Type");
47             match ctx.config.snippet_cap {
48                 Some(cap) => {
49                     builder.insert_snippet(cap, insert, format!("type $0Type = {};\n\n", node));
50                 }
51                 None => {
52                     builder.insert(insert, format!("type Type = {};\n\n", node));
53                 }
54             }
55         },
56     )
57 }
58
59 #[cfg(test)]
60 mod tests {
61     use crate::tests::{check_assist, check_assist_not_applicable};
62
63     use super::*;
64
65     #[test]
66     fn test_not_applicable_without_selection() {
67         check_assist_not_applicable(
68             extract_type_alias,
69             r"
70 struct S {
71     field: $0(u8, u8, u8),
72 }
73             ",
74         );
75     }
76
77     #[test]
78     fn test_simple_types() {
79         check_assist(
80             extract_type_alias,
81             r"
82 struct S {
83     field: $0u8$0,
84 }
85             ",
86             r#"
87 type $0Type = u8;
88
89 struct S {
90     field: Type,
91 }
92             "#,
93         );
94     }
95
96     #[test]
97     fn test_generic_type_arg() {
98         check_assist(
99             extract_type_alias,
100             r"
101 fn generic<T>() {}
102
103 fn f() {
104     generic::<$0()$0>();
105 }
106             ",
107             r#"
108 fn generic<T>() {}
109
110 type $0Type = ();
111
112 fn f() {
113     generic::<Type>();
114 }
115             "#,
116         );
117     }
118
119     #[test]
120     fn test_inner_type_arg() {
121         check_assist(
122             extract_type_alias,
123             r"
124 struct Vec<T> {}
125 struct S {
126     v: Vec<Vec<$0Vec<u8>$0>>,
127 }
128             ",
129             r#"
130 struct Vec<T> {}
131 type $0Type = Vec<u8>;
132
133 struct S {
134     v: Vec<Vec<Type>>,
135 }
136             "#,
137         );
138     }
139
140     #[test]
141     fn test_extract_inner_type() {
142         check_assist(
143             extract_type_alias,
144             r"
145 struct S {
146     field: ($0u8$0,),
147 }
148             ",
149             r#"
150 type $0Type = u8;
151
152 struct S {
153     field: (Type,),
154 }
155             "#,
156         );
157     }
158
159     #[test]
160     fn extract_from_impl_or_trait() {
161         // When invoked in an impl/trait, extracted type alias should be placed next to the
162         // impl/trait, not inside.
163         check_assist(
164             extract_type_alias,
165             r#"
166 impl S {
167     fn f() -> $0(u8, u8)$0 {}
168 }
169             "#,
170             r#"
171 type $0Type = (u8, u8);
172
173 impl S {
174     fn f() -> Type {}
175 }
176             "#,
177         );
178         check_assist(
179             extract_type_alias,
180             r#"
181 trait Tr {
182     fn f() -> $0(u8, u8)$0 {}
183 }
184             "#,
185             r#"
186 type $0Type = (u8, u8);
187
188 trait Tr {
189     fn f() -> Type {}
190 }
191             "#,
192         );
193     }
194 }