diff options
-rw-r--r-- | crates/ide_assists/src/handlers/add_turbo_fish.rs | 138 | ||||
-rw-r--r-- | crates/ide_assists/src/handlers/add_type_ascription.rs | 198 | ||||
-rw-r--r-- | crates/ide_assists/src/lib.rs | 2 |
3 files changed, 137 insertions, 201 deletions
diff --git a/crates/ide_assists/src/handlers/add_turbo_fish.rs b/crates/ide_assists/src/handlers/add_turbo_fish.rs index 8e9ea4fad..f18e3edf9 100644 --- a/crates/ide_assists/src/handlers/add_turbo_fish.rs +++ b/crates/ide_assists/src/handlers/add_turbo_fish.rs | |||
@@ -31,11 +31,13 @@ pub(crate) fn add_turbo_fish(acc: &mut Assists, ctx: &AssistContext) -> Option<( | |||
31 | return None; | 31 | return None; |
32 | } | 32 | } |
33 | mark::hit!(add_turbo_fish_after_call); | 33 | mark::hit!(add_turbo_fish_after_call); |
34 | mark::hit!(add_type_ascription_after_call); | ||
34 | arg_list.l_paren_token()?.prev_token().filter(|it| it.kind() == SyntaxKind::IDENT) | 35 | arg_list.l_paren_token()?.prev_token().filter(|it| it.kind() == SyntaxKind::IDENT) |
35 | })?; | 36 | })?; |
36 | let next_token = ident.next_token()?; | 37 | let next_token = ident.next_token()?; |
37 | if next_token.kind() == T![::] { | 38 | if next_token.kind() == T![::] { |
38 | mark::hit!(add_turbo_fish_one_fish_is_enough); | 39 | mark::hit!(add_turbo_fish_one_fish_is_enough); |
40 | mark::hit!(add_type_ascription_turbofished); | ||
39 | return None; | 41 | return None; |
40 | } | 42 | } |
41 | let name_ref = ast::NameRef::cast(ident.parent())?; | 43 | let name_ref = ast::NameRef::cast(ident.parent())?; |
@@ -50,8 +52,27 @@ pub(crate) fn add_turbo_fish(acc: &mut Assists, ctx: &AssistContext) -> Option<( | |||
50 | let generics = hir::GenericDef::Function(fun).params(ctx.sema.db); | 52 | let generics = hir::GenericDef::Function(fun).params(ctx.sema.db); |
51 | if generics.is_empty() { | 53 | if generics.is_empty() { |
52 | mark::hit!(add_turbo_fish_non_generic); | 54 | mark::hit!(add_turbo_fish_non_generic); |
55 | mark::hit!(add_type_ascription_non_generic); | ||
53 | return None; | 56 | return None; |
54 | } | 57 | } |
58 | |||
59 | if let Some(let_stmt) = ctx.find_node_at_offset::<ast::LetStmt>() { | ||
60 | if let_stmt.colon_token().is_none() { | ||
61 | let type_pos = let_stmt.pat()?.syntax().last_token()?.text_range().end(); | ||
62 | acc.add( | ||
63 | AssistId("add_type_ascription", AssistKind::RefactorRewrite), | ||
64 | "Add `: _` before assignment operator", | ||
65 | ident.text_range(), | ||
66 | |builder| match ctx.config.snippet_cap { | ||
67 | Some(cap) => builder.insert_snippet(cap, type_pos, ": ${0:_}"), | ||
68 | None => builder.insert(type_pos, ": _"), | ||
69 | }, | ||
70 | )? | ||
71 | } else { | ||
72 | mark::hit!(add_type_ascription_already_typed); | ||
73 | } | ||
74 | } | ||
75 | |||
55 | acc.add( | 76 | acc.add( |
56 | AssistId("add_turbo_fish", AssistKind::RefactorRewrite), | 77 | AssistId("add_turbo_fish", AssistKind::RefactorRewrite), |
57 | "Add `::<>`", | 78 | "Add `::<>`", |
@@ -65,7 +86,7 @@ pub(crate) fn add_turbo_fish(acc: &mut Assists, ctx: &AssistContext) -> Option<( | |||
65 | 86 | ||
66 | #[cfg(test)] | 87 | #[cfg(test)] |
67 | mod tests { | 88 | mod tests { |
68 | use crate::tests::{check_assist, check_assist_not_applicable}; | 89 | use crate::tests::{check_assist, check_assist_by_label, check_assist_not_applicable}; |
69 | 90 | ||
70 | use super::*; | 91 | use super::*; |
71 | use test_utils::mark; | 92 | use test_utils::mark; |
@@ -161,4 +182,119 @@ fn main() { | |||
161 | "#, | 182 | "#, |
162 | ); | 183 | ); |
163 | } | 184 | } |
185 | |||
186 | #[test] | ||
187 | fn add_type_ascription_function() { | ||
188 | check_assist_by_label( | ||
189 | add_turbo_fish, | ||
190 | r#" | ||
191 | fn make<T>() -> T {} | ||
192 | fn main() { | ||
193 | let x = make$0(); | ||
194 | } | ||
195 | "#, | ||
196 | r#" | ||
197 | fn make<T>() -> T {} | ||
198 | fn main() { | ||
199 | let x: ${0:_} = make(); | ||
200 | } | ||
201 | "#, | ||
202 | "Add `: _` before assignment operator", | ||
203 | ); | ||
204 | } | ||
205 | |||
206 | #[test] | ||
207 | fn add_type_ascription_after_call() { | ||
208 | mark::check!(add_type_ascription_after_call); | ||
209 | check_assist_by_label( | ||
210 | add_turbo_fish, | ||
211 | r#" | ||
212 | fn make<T>() -> T {} | ||
213 | fn main() { | ||
214 | let x = make()$0; | ||
215 | } | ||
216 | "#, | ||
217 | r#" | ||
218 | fn make<T>() -> T {} | ||
219 | fn main() { | ||
220 | let x: ${0:_} = make(); | ||
221 | } | ||
222 | "#, | ||
223 | "Add `: _` before assignment operator", | ||
224 | ); | ||
225 | } | ||
226 | |||
227 | #[test] | ||
228 | fn add_type_ascription_method() { | ||
229 | check_assist_by_label( | ||
230 | add_turbo_fish, | ||
231 | r#" | ||
232 | struct S; | ||
233 | impl S { | ||
234 | fn make<T>(&self) -> T {} | ||
235 | } | ||
236 | fn main() { | ||
237 | let x = S.make$0(); | ||
238 | } | ||
239 | "#, | ||
240 | r#" | ||
241 | struct S; | ||
242 | impl S { | ||
243 | fn make<T>(&self) -> T {} | ||
244 | } | ||
245 | fn main() { | ||
246 | let x: ${0:_} = S.make(); | ||
247 | } | ||
248 | "#, | ||
249 | "Add `: _` before assignment operator", | ||
250 | ); | ||
251 | } | ||
252 | |||
253 | #[test] | ||
254 | fn add_type_ascription_turbofished() { | ||
255 | mark::check!(add_type_ascription_turbofished); | ||
256 | check_assist_not_applicable( | ||
257 | add_turbo_fish, | ||
258 | r#" | ||
259 | fn make<T>() -> T {} | ||
260 | fn main() { | ||
261 | let x = make$0::<()>(); | ||
262 | } | ||
263 | "#, | ||
264 | ); | ||
265 | } | ||
266 | |||
267 | #[test] | ||
268 | fn add_type_ascription_already_typed() { | ||
269 | mark::check!(add_type_ascription_already_typed); | ||
270 | check_assist( | ||
271 | add_turbo_fish, | ||
272 | r#" | ||
273 | fn make<T>() -> T {} | ||
274 | fn main() { | ||
275 | let x: () = make$0(); | ||
276 | } | ||
277 | "#, | ||
278 | r#" | ||
279 | fn make<T>() -> T {} | ||
280 | fn main() { | ||
281 | let x: () = make::<${0:_}>(); | ||
282 | } | ||
283 | "#, | ||
284 | ); | ||
285 | } | ||
286 | |||
287 | #[test] | ||
288 | fn add_type_ascription_non_generic() { | ||
289 | mark::check!(add_type_ascription_non_generic); | ||
290 | check_assist_not_applicable( | ||
291 | add_turbo_fish, | ||
292 | r#" | ||
293 | fn make() -> () {} | ||
294 | fn main() { | ||
295 | let x = make$0(); | ||
296 | } | ||
297 | "#, | ||
298 | ); | ||
299 | } | ||
164 | } | 300 | } |
diff --git a/crates/ide_assists/src/handlers/add_type_ascription.rs b/crates/ide_assists/src/handlers/add_type_ascription.rs deleted file mode 100644 index 060c326bf..000000000 --- a/crates/ide_assists/src/handlers/add_type_ascription.rs +++ /dev/null | |||
@@ -1,198 +0,0 @@ | |||
1 | use ide_db::defs::{Definition, NameRefClass}; | ||
2 | use syntax::{ast, AstNode, SyntaxKind, T}; | ||
3 | use test_utils::mark; | ||
4 | |||
5 | use crate::{ | ||
6 | assist_context::{AssistContext, Assists}, | ||
7 | AssistId, AssistKind, | ||
8 | }; | ||
9 | |||
10 | // Assist: add_type_ascription | ||
11 | // | ||
12 | // Adds `: _` before the assignment operator to prompt the user for a type. | ||
13 | // | ||
14 | // ``` | ||
15 | // fn make<T>() -> T { todo!() } | ||
16 | // fn main() { | ||
17 | // let x = make$0(); | ||
18 | // } | ||
19 | // ``` | ||
20 | // -> | ||
21 | // ``` | ||
22 | // fn make<T>() -> T { todo!() } | ||
23 | // fn main() { | ||
24 | // let x: ${0:_} = make(); | ||
25 | // } | ||
26 | // ``` | ||
27 | pub(crate) fn add_type_ascription(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | ||
28 | let let_stmt = ctx.find_node_at_offset::<ast::LetStmt>()?; | ||
29 | if let_stmt.colon_token().is_some() { | ||
30 | mark::hit!(add_type_ascription_already_typed); | ||
31 | return None; | ||
32 | } | ||
33 | let type_pos = let_stmt.pat()?.syntax().last_token()?.text_range().end(); | ||
34 | |||
35 | let ident = ctx.find_token_syntax_at_offset(SyntaxKind::IDENT).or_else(|| { | ||
36 | let arg_list = ctx.find_node_at_offset::<ast::ArgList>()?; | ||
37 | if arg_list.args().count() > 0 { | ||
38 | return None; | ||
39 | } | ||
40 | mark::hit!(add_type_ascription_after_call); | ||
41 | arg_list.l_paren_token()?.prev_token().filter(|it| it.kind() == SyntaxKind::IDENT) | ||
42 | })?; | ||
43 | let next_token = ident.next_token()?; | ||
44 | if next_token.kind() == T![::] { | ||
45 | mark::hit!(add_type_ascription_turbofished); | ||
46 | return None; | ||
47 | } | ||
48 | let name_ref = ast::NameRef::cast(ident.parent())?; | ||
49 | let def = match NameRefClass::classify(&ctx.sema, &name_ref)? { | ||
50 | NameRefClass::Definition(def) => def, | ||
51 | NameRefClass::ExternCrate(_) | NameRefClass::FieldShorthand { .. } => return None, | ||
52 | }; | ||
53 | let fun = match def { | ||
54 | Definition::ModuleDef(hir::ModuleDef::Function(it)) => it, | ||
55 | _ => return None, | ||
56 | }; | ||
57 | let generics = hir::GenericDef::Function(fun).params(ctx.sema.db); | ||
58 | if generics.is_empty() { | ||
59 | mark::hit!(add_type_ascription_non_generic); | ||
60 | return None; | ||
61 | } | ||
62 | acc.add( | ||
63 | AssistId("add_type_ascription", AssistKind::RefactorRewrite), | ||
64 | "Add `: _` before assignment operator", | ||
65 | ident.text_range(), | ||
66 | |builder| match ctx.config.snippet_cap { | ||
67 | Some(cap) => builder.insert_snippet(cap, type_pos, ": ${0:_}"), | ||
68 | None => builder.insert(type_pos, ": _"), | ||
69 | }, | ||
70 | ) | ||
71 | } | ||
72 | |||
73 | #[cfg(test)] | ||
74 | mod tests { | ||
75 | use crate::tests::{check_assist, check_assist_not_applicable}; | ||
76 | |||
77 | use super::*; | ||
78 | use test_utils::mark; | ||
79 | |||
80 | #[test] | ||
81 | fn add_type_ascription_function() { | ||
82 | check_assist( | ||
83 | add_type_ascription, | ||
84 | r#" | ||
85 | fn make<T>() -> T {} | ||
86 | fn main() { | ||
87 | let x = make$0(); | ||
88 | } | ||
89 | "#, | ||
90 | r#" | ||
91 | fn make<T>() -> T {} | ||
92 | fn main() { | ||
93 | let x: ${0:_} = make(); | ||
94 | } | ||
95 | "#, | ||
96 | ); | ||
97 | } | ||
98 | |||
99 | #[test] | ||
100 | fn add_type_ascription_after_call() { | ||
101 | mark::check!(add_type_ascription_after_call); | ||
102 | check_assist( | ||
103 | add_type_ascription, | ||
104 | r#" | ||
105 | fn make<T>() -> T {} | ||
106 | fn main() { | ||
107 | let x = make()$0; | ||
108 | } | ||
109 | "#, | ||
110 | r#" | ||
111 | fn make<T>() -> T {} | ||
112 | fn main() { | ||
113 | let x: ${0:_} = make(); | ||
114 | } | ||
115 | "#, | ||
116 | ); | ||
117 | } | ||
118 | |||
119 | #[test] | ||
120 | fn add_type_ascription_method() { | ||
121 | check_assist( | ||
122 | add_type_ascription, | ||
123 | r#" | ||
124 | struct S; | ||
125 | impl S { | ||
126 | fn make<T>(&self) -> T {} | ||
127 | } | ||
128 | fn main() { | ||
129 | let x = S.make$0(); | ||
130 | } | ||
131 | "#, | ||
132 | r#" | ||
133 | struct S; | ||
134 | impl S { | ||
135 | fn make<T>(&self) -> T {} | ||
136 | } | ||
137 | fn main() { | ||
138 | let x: ${0:_} = S.make(); | ||
139 | } | ||
140 | "#, | ||
141 | ); | ||
142 | } | ||
143 | |||
144 | #[test] | ||
145 | fn add_type_ascription_turbofished() { | ||
146 | mark::check!(add_type_ascription_turbofished); | ||
147 | check_assist_not_applicable( | ||
148 | add_type_ascription, | ||
149 | r#" | ||
150 | fn make<T>() -> T {} | ||
151 | fn main() { | ||
152 | let x = make$0::<()>(); | ||
153 | } | ||
154 | "#, | ||
155 | ); | ||
156 | } | ||
157 | |||
158 | #[test] | ||
159 | fn add_type_ascription_already_typed() { | ||
160 | mark::check!(add_type_ascription_already_typed); | ||
161 | check_assist_not_applicable( | ||
162 | add_type_ascription, | ||
163 | r#" | ||
164 | fn make<T>() -> T {} | ||
165 | fn main() { | ||
166 | let x: () = make$0(); | ||
167 | } | ||
168 | "#, | ||
169 | ); | ||
170 | } | ||
171 | |||
172 | #[test] | ||
173 | fn add_type_ascription_non_generic() { | ||
174 | mark::check!(add_type_ascription_non_generic); | ||
175 | check_assist_not_applicable( | ||
176 | add_type_ascription, | ||
177 | r#" | ||
178 | fn make() -> () {} | ||
179 | fn main() { | ||
180 | let x = make$0(); | ||
181 | } | ||
182 | "#, | ||
183 | ); | ||
184 | } | ||
185 | |||
186 | #[test] | ||
187 | fn add_type_ascription_no_let() { | ||
188 | check_assist_not_applicable( | ||
189 | add_type_ascription, | ||
190 | r#" | ||
191 | fn make<T>() -> T {} | ||
192 | fn main() { | ||
193 | make$0(); | ||
194 | } | ||
195 | "#, | ||
196 | ); | ||
197 | } | ||
198 | } | ||
diff --git a/crates/ide_assists/src/lib.rs b/crates/ide_assists/src/lib.rs index 0248cb9c0..9c8148462 100644 --- a/crates/ide_assists/src/lib.rs +++ b/crates/ide_assists/src/lib.rs | |||
@@ -111,7 +111,6 @@ mod handlers { | |||
111 | mod add_lifetime_to_type; | 111 | mod add_lifetime_to_type; |
112 | mod add_missing_impl_members; | 112 | mod add_missing_impl_members; |
113 | mod add_turbo_fish; | 113 | mod add_turbo_fish; |
114 | mod add_type_ascription; | ||
115 | mod apply_demorgan; | 114 | mod apply_demorgan; |
116 | mod auto_import; | 115 | mod auto_import; |
117 | mod change_visibility; | 116 | mod change_visibility; |
@@ -176,7 +175,6 @@ mod handlers { | |||
176 | add_explicit_type::add_explicit_type, | 175 | add_explicit_type::add_explicit_type, |
177 | add_lifetime_to_type::add_lifetime_to_type, | 176 | add_lifetime_to_type::add_lifetime_to_type, |
178 | add_turbo_fish::add_turbo_fish, | 177 | add_turbo_fish::add_turbo_fish, |
179 | add_type_ascription::add_type_ascription, | ||
180 | apply_demorgan::apply_demorgan, | 178 | apply_demorgan::apply_demorgan, |
181 | auto_import::auto_import, | 179 | auto_import::auto_import, |
182 | change_visibility::change_visibility, | 180 | change_visibility::change_visibility, |