aboutsummaryrefslogtreecommitdiff
path: root/crates/ide_assists/src/handlers
diff options
context:
space:
mode:
authorConrad Ludgate <[email protected]>2021-03-02 14:28:53 +0000
committerConrad Ludgate <[email protected]>2021-03-02 14:30:11 +0000
commitd4fad2be8de4906ac00c373e53bb9ac593d61429 (patch)
tree792754ed2233241d438c7fee642b060b734f413f /crates/ide_assists/src/handlers
parent4a36129c7a018828548e2eddebdd49cdb7d6879d (diff)
refactor: re-use add_turbo_fish function
Diffstat (limited to 'crates/ide_assists/src/handlers')
-rw-r--r--crates/ide_assists/src/handlers/add_turbo_fish.rs138
-rw-r--r--crates/ide_assists/src/handlers/add_type_ascription.rs198
2 files changed, 137 insertions, 199 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)]
67mod tests { 88mod 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#"
191fn make<T>() -> T {}
192fn main() {
193 let x = make$0();
194}
195"#,
196 r#"
197fn make<T>() -> T {}
198fn 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#"
212fn make<T>() -> T {}
213fn main() {
214 let x = make()$0;
215}
216"#,
217 r#"
218fn make<T>() -> T {}
219fn 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#"
232struct S;
233impl S {
234 fn make<T>(&self) -> T {}
235}
236fn main() {
237 let x = S.make$0();
238}
239"#,
240 r#"
241struct S;
242impl S {
243 fn make<T>(&self) -> T {}
244}
245fn 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#"
259fn make<T>() -> T {}
260fn 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#"
273fn make<T>() -> T {}
274fn main() {
275 let x: () = make$0();
276}
277"#,
278 r#"
279fn make<T>() -> T {}
280fn 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#"
293fn make() -> () {}
294fn 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 @@
1use ide_db::defs::{Definition, NameRefClass};
2use syntax::{ast, AstNode, SyntaxKind, T};
3use test_utils::mark;
4
5use 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// ```
27pub(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)]
74mod 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#"
85fn make<T>() -> T {}
86fn main() {
87 let x = make$0();
88}
89"#,
90 r#"
91fn make<T>() -> T {}
92fn 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#"
105fn make<T>() -> T {}
106fn main() {
107 let x = make()$0;
108}
109"#,
110 r#"
111fn make<T>() -> T {}
112fn 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#"
124struct S;
125impl S {
126 fn make<T>(&self) -> T {}
127}
128fn main() {
129 let x = S.make$0();
130}
131"#,
132 r#"
133struct S;
134impl S {
135 fn make<T>(&self) -> T {}
136}
137fn 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#"
150fn make<T>() -> T {}
151fn 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#"
164fn make<T>() -> T {}
165fn 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#"
178fn make() -> () {}
179fn 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#"
191fn make<T>() -> T {}
192fn main() {
193 make$0();
194}
195"#,
196 );
197 }
198}