diff options
Diffstat (limited to 'crates/assists/src/handlers')
-rw-r--r-- | crates/assists/src/handlers/add_turbo_fish.rs | 2 | ||||
-rw-r--r-- | crates/assists/src/handlers/change_return_type_to_result.rs | 121 | ||||
-rw-r--r-- | crates/assists/src/handlers/convert_integer_literal.rs | 395 | ||||
-rw-r--r-- | crates/assists/src/handlers/expand_glob_import.rs | 2 | ||||
-rw-r--r-- | crates/assists/src/handlers/flip_comma.rs | 2 | ||||
-rw-r--r-- | crates/assists/src/handlers/flip_trait_bound.rs | 2 | ||||
-rw-r--r-- | crates/assists/src/handlers/infer_function_return_type.rs | 337 | ||||
-rw-r--r-- | crates/assists/src/handlers/introduce_named_lifetime.rs | 2 | ||||
-rw-r--r-- | crates/assists/src/handlers/invert_if.rs | 2 | ||||
-rw-r--r-- | crates/assists/src/handlers/raw_string.rs | 34 | ||||
-rw-r--r-- | crates/assists/src/handlers/remove_mut.rs | 2 | ||||
-rw-r--r-- | crates/assists/src/handlers/replace_let_with_if_let.rs | 2 | ||||
-rw-r--r-- | crates/assists/src/handlers/replace_string_with_char.rs | 8 | ||||
-rw-r--r-- | crates/assists/src/handlers/split_import.rs | 2 | ||||
-rw-r--r-- | crates/assists/src/handlers/unwrap_block.rs | 2 |
15 files changed, 490 insertions, 425 deletions
diff --git a/crates/assists/src/handlers/add_turbo_fish.rs b/crates/assists/src/handlers/add_turbo_fish.rs index e3d84d698..1f486c013 100644 --- a/crates/assists/src/handlers/add_turbo_fish.rs +++ b/crates/assists/src/handlers/add_turbo_fish.rs | |||
@@ -25,7 +25,7 @@ use crate::{ | |||
25 | // } | 25 | // } |
26 | // ``` | 26 | // ``` |
27 | pub(crate) fn add_turbo_fish(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | 27 | pub(crate) fn add_turbo_fish(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
28 | let ident = ctx.find_token_at_offset(SyntaxKind::IDENT).or_else(|| { | 28 | let ident = ctx.find_token_syntax_at_offset(SyntaxKind::IDENT).or_else(|| { |
29 | let arg_list = ctx.find_node_at_offset::<ast::ArgList>()?; | 29 | let arg_list = ctx.find_node_at_offset::<ast::ArgList>()?; |
30 | if arg_list.args().count() > 0 { | 30 | if arg_list.args().count() > 0 { |
31 | return None; | 31 | return None; |
diff --git a/crates/assists/src/handlers/change_return_type_to_result.rs b/crates/assists/src/handlers/change_return_type_to_result.rs index be480943c..76f33a5b6 100644 --- a/crates/assists/src/handlers/change_return_type_to_result.rs +++ b/crates/assists/src/handlers/change_return_type_to_result.rs | |||
@@ -2,7 +2,7 @@ use std::iter; | |||
2 | 2 | ||
3 | use syntax::{ | 3 | use syntax::{ |
4 | ast::{self, make, BlockExpr, Expr, LoopBodyOwner}, | 4 | ast::{self, make, BlockExpr, Expr, LoopBodyOwner}, |
5 | AstNode, SyntaxNode, | 5 | match_ast, AstNode, SyntaxNode, |
6 | }; | 6 | }; |
7 | use test_utils::mark; | 7 | use test_utils::mark; |
8 | 8 | ||
@@ -21,8 +21,18 @@ use crate::{AssistContext, AssistId, AssistKind, Assists}; | |||
21 | // ``` | 21 | // ``` |
22 | pub(crate) fn change_return_type_to_result(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | 22 | pub(crate) fn change_return_type_to_result(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
23 | let ret_type = ctx.find_node_at_offset::<ast::RetType>()?; | 23 | let ret_type = ctx.find_node_at_offset::<ast::RetType>()?; |
24 | // FIXME: extend to lambdas as well | 24 | let parent = ret_type.syntax().parent()?; |
25 | let fn_def = ret_type.syntax().parent().and_then(ast::Fn::cast)?; | 25 | let block_expr = match_ast! { |
26 | match parent { | ||
27 | ast::Fn(func) => func.body()?, | ||
28 | ast::ClosureExpr(closure) => match closure.body()? { | ||
29 | Expr::BlockExpr(block) => block, | ||
30 | // closures require a block when a return type is specified | ||
31 | _ => return None, | ||
32 | }, | ||
33 | _ => return None, | ||
34 | } | ||
35 | }; | ||
26 | 36 | ||
27 | let type_ref = &ret_type.ty()?; | 37 | let type_ref = &ret_type.ty()?; |
28 | let ret_type_str = type_ref.syntax().text().to_string(); | 38 | let ret_type_str = type_ref.syntax().text().to_string(); |
@@ -34,16 +44,14 @@ pub(crate) fn change_return_type_to_result(acc: &mut Assists, ctx: &AssistContex | |||
34 | } | 44 | } |
35 | } | 45 | } |
36 | 46 | ||
37 | let block_expr = &fn_def.body()?; | ||
38 | |||
39 | acc.add( | 47 | acc.add( |
40 | AssistId("change_return_type_to_result", AssistKind::RefactorRewrite), | 48 | AssistId("change_return_type_to_result", AssistKind::RefactorRewrite), |
41 | "Wrap return type in Result", | 49 | "Wrap return type in Result", |
42 | type_ref.syntax().text_range(), | 50 | type_ref.syntax().text_range(), |
43 | |builder| { | 51 | |builder| { |
44 | let mut tail_return_expr_collector = TailReturnCollector::new(); | 52 | let mut tail_return_expr_collector = TailReturnCollector::new(); |
45 | tail_return_expr_collector.collect_jump_exprs(block_expr, false); | 53 | tail_return_expr_collector.collect_jump_exprs(&block_expr, false); |
46 | tail_return_expr_collector.collect_tail_exprs(block_expr); | 54 | tail_return_expr_collector.collect_tail_exprs(&block_expr); |
47 | 55 | ||
48 | for ret_expr_arg in tail_return_expr_collector.exprs_to_wrap { | 56 | for ret_expr_arg in tail_return_expr_collector.exprs_to_wrap { |
49 | let ok_wrapped = make::expr_call( | 57 | let ok_wrapped = make::expr_call( |
@@ -285,16 +293,20 @@ mod tests { | |||
285 | } | 293 | } |
286 | 294 | ||
287 | #[test] | 295 | #[test] |
288 | fn change_return_type_to_result_simple_return_type() { | 296 | fn change_return_type_to_result_simple_closure() { |
289 | check_assist( | 297 | check_assist( |
290 | change_return_type_to_result, | 298 | change_return_type_to_result, |
291 | r#"fn foo() -> i32<|> { | 299 | r#"fn foo() { |
292 | let test = "test"; | 300 | || -> i32<|> { |
293 | return 42i32; | 301 | let test = "test"; |
302 | return 42i32; | ||
303 | }; | ||
294 | }"#, | 304 | }"#, |
295 | r#"fn foo() -> Result<i32, ${0:_}> { | 305 | r#"fn foo() { |
296 | let test = "test"; | 306 | || -> Result<i32, ${0:_}> { |
297 | return Ok(42i32); | 307 | let test = "test"; |
308 | return Ok(42i32); | ||
309 | }; | ||
298 | }"#, | 310 | }"#, |
299 | ); | 311 | ); |
300 | } | 312 | } |
@@ -311,6 +323,29 @@ mod tests { | |||
311 | } | 323 | } |
312 | 324 | ||
313 | #[test] | 325 | #[test] |
326 | fn change_return_type_to_result_simple_return_type_bad_cursor_closure() { | ||
327 | check_assist_not_applicable( | ||
328 | change_return_type_to_result, | ||
329 | r#"fn foo() { | ||
330 | || -> i32 { | ||
331 | let test = "test";<|> | ||
332 | return 42i32; | ||
333 | }; | ||
334 | }"#, | ||
335 | ); | ||
336 | } | ||
337 | |||
338 | #[test] | ||
339 | fn change_return_type_to_result_closure_non_block() { | ||
340 | check_assist_not_applicable( | ||
341 | change_return_type_to_result, | ||
342 | r#"fn foo() { | ||
343 | || -> i<|>32 3; | ||
344 | }"#, | ||
345 | ); | ||
346 | } | ||
347 | |||
348 | #[test] | ||
314 | fn change_return_type_to_result_simple_return_type_already_result_std() { | 349 | fn change_return_type_to_result_simple_return_type_already_result_std() { |
315 | check_assist_not_applicable( | 350 | check_assist_not_applicable( |
316 | change_return_type_to_result, | 351 | change_return_type_to_result, |
@@ -334,6 +369,19 @@ mod tests { | |||
334 | } | 369 | } |
335 | 370 | ||
336 | #[test] | 371 | #[test] |
372 | fn change_return_type_to_result_simple_return_type_already_result_closure() { | ||
373 | check_assist_not_applicable( | ||
374 | change_return_type_to_result, | ||
375 | r#"fn foo() { | ||
376 | || -> Result<i32<|>, String> { | ||
377 | let test = "test"; | ||
378 | return 42i32; | ||
379 | }; | ||
380 | }"#, | ||
381 | ); | ||
382 | } | ||
383 | |||
384 | #[test] | ||
337 | fn change_return_type_to_result_simple_with_cursor() { | 385 | fn change_return_type_to_result_simple_with_cursor() { |
338 | check_assist( | 386 | check_assist( |
339 | change_return_type_to_result, | 387 | change_return_type_to_result, |
@@ -364,6 +412,25 @@ mod tests { | |||
364 | } | 412 | } |
365 | 413 | ||
366 | #[test] | 414 | #[test] |
415 | fn change_return_type_to_result_simple_with_tail_closure() { | ||
416 | check_assist( | ||
417 | change_return_type_to_result, | ||
418 | r#"fn foo() { | ||
419 | || -><|> i32 { | ||
420 | let test = "test"; | ||
421 | 42i32 | ||
422 | }; | ||
423 | }"#, | ||
424 | r#"fn foo() { | ||
425 | || -> Result<i32, ${0:_}> { | ||
426 | let test = "test"; | ||
427 | Ok(42i32) | ||
428 | }; | ||
429 | }"#, | ||
430 | ); | ||
431 | } | ||
432 | |||
433 | #[test] | ||
367 | fn change_return_type_to_result_simple_with_tail_only() { | 434 | fn change_return_type_to_result_simple_with_tail_only() { |
368 | check_assist( | 435 | check_assist( |
369 | change_return_type_to_result, | 436 | change_return_type_to_result, |
@@ -375,6 +442,7 @@ mod tests { | |||
375 | }"#, | 442 | }"#, |
376 | ); | 443 | ); |
377 | } | 444 | } |
445 | |||
378 | #[test] | 446 | #[test] |
379 | fn change_return_type_to_result_simple_with_tail_block_like() { | 447 | fn change_return_type_to_result_simple_with_tail_block_like() { |
380 | check_assist( | 448 | check_assist( |
@@ -397,6 +465,31 @@ mod tests { | |||
397 | } | 465 | } |
398 | 466 | ||
399 | #[test] | 467 | #[test] |
468 | fn change_return_type_to_result_simple_without_block_closure() { | ||
469 | check_assist( | ||
470 | change_return_type_to_result, | ||
471 | r#"fn foo() { | ||
472 | || -> i32<|> { | ||
473 | if true { | ||
474 | 42i32 | ||
475 | } else { | ||
476 | 24i32 | ||
477 | } | ||
478 | }; | ||
479 | }"#, | ||
480 | r#"fn foo() { | ||
481 | || -> Result<i32, ${0:_}> { | ||
482 | if true { | ||
483 | Ok(42i32) | ||
484 | } else { | ||
485 | Ok(24i32) | ||
486 | } | ||
487 | }; | ||
488 | }"#, | ||
489 | ); | ||
490 | } | ||
491 | |||
492 | #[test] | ||
400 | fn change_return_type_to_result_simple_with_nested_if() { | 493 | fn change_return_type_to_result_simple_with_nested_if() { |
401 | check_assist( | 494 | check_assist( |
402 | change_return_type_to_result, | 495 | change_return_type_to_result, |
diff --git a/crates/assists/src/handlers/convert_integer_literal.rs b/crates/assists/src/handlers/convert_integer_literal.rs index c8af80701..667115382 100644 --- a/crates/assists/src/handlers/convert_integer_literal.rs +++ b/crates/assists/src/handlers/convert_integer_literal.rs | |||
@@ -1,4 +1,4 @@ | |||
1 | use syntax::{ast, ast::Radix, AstNode}; | 1 | use syntax::{ast, ast::Radix, AstToken}; |
2 | 2 | ||
3 | use crate::{AssistContext, AssistId, AssistKind, Assists, GroupLabel}; | 3 | use crate::{AssistContext, AssistId, AssistKind, Assists, GroupLabel}; |
4 | 4 | ||
@@ -15,14 +15,16 @@ use crate::{AssistContext, AssistId, AssistKind, Assists, GroupLabel}; | |||
15 | // ``` | 15 | // ``` |
16 | pub(crate) fn convert_integer_literal(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | 16 | pub(crate) fn convert_integer_literal(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
17 | let literal = ctx.find_node_at_offset::<ast::Literal>()?; | 17 | let literal = ctx.find_node_at_offset::<ast::Literal>()?; |
18 | let (radix, value) = literal.int_value()?; | 18 | let literal = match literal.kind() { |
19 | ast::LiteralKind::IntNumber(it) => it, | ||
20 | _ => return None, | ||
21 | }; | ||
22 | let radix = literal.radix(); | ||
23 | let value = literal.value()?; | ||
24 | let suffix = literal.suffix(); | ||
19 | 25 | ||
20 | let range = literal.syntax().text_range(); | 26 | let range = literal.syntax().text_range(); |
21 | let group_id = GroupLabel("Convert integer base".into()); | 27 | let group_id = GroupLabel("Convert integer base".into()); |
22 | let suffix = match literal.kind() { | ||
23 | ast::LiteralKind::IntNumber { suffix } => suffix, | ||
24 | _ => return None, | ||
25 | }; | ||
26 | 28 | ||
27 | for &target_radix in Radix::ALL { | 29 | for &target_radix in Radix::ALL { |
28 | if target_radix == radix { | 30 | if target_radix == radix { |
@@ -36,16 +38,11 @@ pub(crate) fn convert_integer_literal(acc: &mut Assists, ctx: &AssistContext) -> | |||
36 | Radix::Hexadecimal => format!("0x{:X}", value), | 38 | Radix::Hexadecimal => format!("0x{:X}", value), |
37 | }; | 39 | }; |
38 | 40 | ||
39 | let label = format!( | 41 | let label = format!("Convert {} to {}{}", literal, converted, suffix.unwrap_or_default()); |
40 | "Convert {} to {}{}", | ||
41 | literal, | ||
42 | converted, | ||
43 | suffix.as_deref().unwrap_or_default() | ||
44 | ); | ||
45 | 42 | ||
46 | // Appends the type suffix back into the new literal if it exists. | 43 | // Appends the type suffix back into the new literal if it exists. |
47 | if let Some(suffix) = &suffix { | 44 | if let Some(suffix) = suffix { |
48 | converted.push_str(&suffix); | 45 | converted.push_str(suffix); |
49 | } | 46 | } |
50 | 47 | ||
51 | acc.add_group( | 48 | acc.add_group( |
@@ -132,34 +129,6 @@ mod tests { | |||
132 | ); | 129 | ); |
133 | } | 130 | } |
134 | 131 | ||
135 | // Decimal numbers under 3 digits have a special case where they return early because we can't fit a | ||
136 | // other base's prefix, so we have a separate test for that. | ||
137 | #[test] | ||
138 | fn convert_small_decimal_integer() { | ||
139 | let before = "const _: i32 = 10<|>;"; | ||
140 | |||
141 | check_assist_by_label( | ||
142 | convert_integer_literal, | ||
143 | before, | ||
144 | "const _: i32 = 0b1010;", | ||
145 | "Convert 10 to 0b1010", | ||
146 | ); | ||
147 | |||
148 | check_assist_by_label( | ||
149 | convert_integer_literal, | ||
150 | before, | ||
151 | "const _: i32 = 0o12;", | ||
152 | "Convert 10 to 0o12", | ||
153 | ); | ||
154 | |||
155 | check_assist_by_label( | ||
156 | convert_integer_literal, | ||
157 | before, | ||
158 | "const _: i32 = 0xA;", | ||
159 | "Convert 10 to 0xA", | ||
160 | ); | ||
161 | } | ||
162 | |||
163 | #[test] | 132 | #[test] |
164 | fn convert_hexadecimal_integer() { | 133 | fn convert_hexadecimal_integer() { |
165 | let before = "const _: i32 = 0xFF<|>;"; | 134 | let before = "const _: i32 = 0xFF<|>;"; |
@@ -239,7 +208,7 @@ mod tests { | |||
239 | } | 208 | } |
240 | 209 | ||
241 | #[test] | 210 | #[test] |
242 | fn convert_decimal_integer_with_underscores() { | 211 | fn convert_integer_with_underscores() { |
243 | let before = "const _: i32 = 1_00_0<|>;"; | 212 | let before = "const _: i32 = 1_00_0<|>;"; |
244 | 213 | ||
245 | check_assist_by_label( | 214 | check_assist_by_label( |
@@ -265,111 +234,7 @@ mod tests { | |||
265 | } | 234 | } |
266 | 235 | ||
267 | #[test] | 236 | #[test] |
268 | fn convert_small_decimal_integer_with_underscores() { | 237 | fn convert_integer_with_suffix() { |
269 | let before = "const _: i32 = 1_0<|>;"; | ||
270 | |||
271 | check_assist_by_label( | ||
272 | convert_integer_literal, | ||
273 | before, | ||
274 | "const _: i32 = 0b1010;", | ||
275 | "Convert 1_0 to 0b1010", | ||
276 | ); | ||
277 | |||
278 | check_assist_by_label( | ||
279 | convert_integer_literal, | ||
280 | before, | ||
281 | "const _: i32 = 0o12;", | ||
282 | "Convert 1_0 to 0o12", | ||
283 | ); | ||
284 | |||
285 | check_assist_by_label( | ||
286 | convert_integer_literal, | ||
287 | before, | ||
288 | "const _: i32 = 0xA;", | ||
289 | "Convert 1_0 to 0xA", | ||
290 | ); | ||
291 | } | ||
292 | |||
293 | #[test] | ||
294 | fn convert_hexadecimal_integer_with_underscores() { | ||
295 | let before = "const _: i32 = 0x_F_F<|>;"; | ||
296 | |||
297 | check_assist_by_label( | ||
298 | convert_integer_literal, | ||
299 | before, | ||
300 | "const _: i32 = 0b11111111;", | ||
301 | "Convert 0x_F_F to 0b11111111", | ||
302 | ); | ||
303 | |||
304 | check_assist_by_label( | ||
305 | convert_integer_literal, | ||
306 | before, | ||
307 | "const _: i32 = 0o377;", | ||
308 | "Convert 0x_F_F to 0o377", | ||
309 | ); | ||
310 | |||
311 | check_assist_by_label( | ||
312 | convert_integer_literal, | ||
313 | before, | ||
314 | "const _: i32 = 255;", | ||
315 | "Convert 0x_F_F to 255", | ||
316 | ); | ||
317 | } | ||
318 | |||
319 | #[test] | ||
320 | fn convert_binary_integer_with_underscores() { | ||
321 | let before = "const _: i32 = 0b1111_1111<|>;"; | ||
322 | |||
323 | check_assist_by_label( | ||
324 | convert_integer_literal, | ||
325 | before, | ||
326 | "const _: i32 = 0o377;", | ||
327 | "Convert 0b1111_1111 to 0o377", | ||
328 | ); | ||
329 | |||
330 | check_assist_by_label( | ||
331 | convert_integer_literal, | ||
332 | before, | ||
333 | "const _: i32 = 255;", | ||
334 | "Convert 0b1111_1111 to 255", | ||
335 | ); | ||
336 | |||
337 | check_assist_by_label( | ||
338 | convert_integer_literal, | ||
339 | before, | ||
340 | "const _: i32 = 0xFF;", | ||
341 | "Convert 0b1111_1111 to 0xFF", | ||
342 | ); | ||
343 | } | ||
344 | |||
345 | #[test] | ||
346 | fn convert_octal_integer_with_underscores() { | ||
347 | let before = "const _: i32 = 0o3_77<|>;"; | ||
348 | |||
349 | check_assist_by_label( | ||
350 | convert_integer_literal, | ||
351 | before, | ||
352 | "const _: i32 = 0b11111111;", | ||
353 | "Convert 0o3_77 to 0b11111111", | ||
354 | ); | ||
355 | |||
356 | check_assist_by_label( | ||
357 | convert_integer_literal, | ||
358 | before, | ||
359 | "const _: i32 = 255;", | ||
360 | "Convert 0o3_77 to 255", | ||
361 | ); | ||
362 | |||
363 | check_assist_by_label( | ||
364 | convert_integer_literal, | ||
365 | before, | ||
366 | "const _: i32 = 0xFF;", | ||
367 | "Convert 0o3_77 to 0xFF", | ||
368 | ); | ||
369 | } | ||
370 | |||
371 | #[test] | ||
372 | fn convert_decimal_integer_with_suffix() { | ||
373 | let before = "const _: i32 = 1000i32<|>;"; | 238 | let before = "const _: i32 = 1000i32<|>;"; |
374 | 239 | ||
375 | check_assist_by_label( | 240 | check_assist_by_label( |
@@ -395,240 +260,6 @@ mod tests { | |||
395 | } | 260 | } |
396 | 261 | ||
397 | #[test] | 262 | #[test] |
398 | fn convert_small_decimal_integer_with_suffix() { | ||
399 | let before = "const _: i32 = 10i32<|>;"; | ||
400 | |||
401 | check_assist_by_label( | ||
402 | convert_integer_literal, | ||
403 | before, | ||
404 | "const _: i32 = 0b1010i32;", | ||
405 | "Convert 10i32 to 0b1010i32", | ||
406 | ); | ||
407 | |||
408 | check_assist_by_label( | ||
409 | convert_integer_literal, | ||
410 | before, | ||
411 | "const _: i32 = 0o12i32;", | ||
412 | "Convert 10i32 to 0o12i32", | ||
413 | ); | ||
414 | |||
415 | check_assist_by_label( | ||
416 | convert_integer_literal, | ||
417 | before, | ||
418 | "const _: i32 = 0xAi32;", | ||
419 | "Convert 10i32 to 0xAi32", | ||
420 | ); | ||
421 | } | ||
422 | |||
423 | #[test] | ||
424 | fn convert_hexadecimal_integer_with_suffix() { | ||
425 | let before = "const _: i32 = 0xFFi32<|>;"; | ||
426 | |||
427 | check_assist_by_label( | ||
428 | convert_integer_literal, | ||
429 | before, | ||
430 | "const _: i32 = 0b11111111i32;", | ||
431 | "Convert 0xFFi32 to 0b11111111i32", | ||
432 | ); | ||
433 | |||
434 | check_assist_by_label( | ||
435 | convert_integer_literal, | ||
436 | before, | ||
437 | "const _: i32 = 0o377i32;", | ||
438 | "Convert 0xFFi32 to 0o377i32", | ||
439 | ); | ||
440 | |||
441 | check_assist_by_label( | ||
442 | convert_integer_literal, | ||
443 | before, | ||
444 | "const _: i32 = 255i32;", | ||
445 | "Convert 0xFFi32 to 255i32", | ||
446 | ); | ||
447 | } | ||
448 | |||
449 | #[test] | ||
450 | fn convert_binary_integer_with_suffix() { | ||
451 | let before = "const _: i32 = 0b11111111i32<|>;"; | ||
452 | |||
453 | check_assist_by_label( | ||
454 | convert_integer_literal, | ||
455 | before, | ||
456 | "const _: i32 = 0o377i32;", | ||
457 | "Convert 0b11111111i32 to 0o377i32", | ||
458 | ); | ||
459 | |||
460 | check_assist_by_label( | ||
461 | convert_integer_literal, | ||
462 | before, | ||
463 | "const _: i32 = 255i32;", | ||
464 | "Convert 0b11111111i32 to 255i32", | ||
465 | ); | ||
466 | |||
467 | check_assist_by_label( | ||
468 | convert_integer_literal, | ||
469 | before, | ||
470 | "const _: i32 = 0xFFi32;", | ||
471 | "Convert 0b11111111i32 to 0xFFi32", | ||
472 | ); | ||
473 | } | ||
474 | |||
475 | #[test] | ||
476 | fn convert_octal_integer_with_suffix() { | ||
477 | let before = "const _: i32 = 0o377i32<|>;"; | ||
478 | |||
479 | check_assist_by_label( | ||
480 | convert_integer_literal, | ||
481 | before, | ||
482 | "const _: i32 = 0b11111111i32;", | ||
483 | "Convert 0o377i32 to 0b11111111i32", | ||
484 | ); | ||
485 | |||
486 | check_assist_by_label( | ||
487 | convert_integer_literal, | ||
488 | before, | ||
489 | "const _: i32 = 255i32;", | ||
490 | "Convert 0o377i32 to 255i32", | ||
491 | ); | ||
492 | |||
493 | check_assist_by_label( | ||
494 | convert_integer_literal, | ||
495 | before, | ||
496 | "const _: i32 = 0xFFi32;", | ||
497 | "Convert 0o377i32 to 0xFFi32", | ||
498 | ); | ||
499 | } | ||
500 | |||
501 | #[test] | ||
502 | fn convert_decimal_integer_with_underscores_and_suffix() { | ||
503 | let before = "const _: i32 = 1_00_0i32<|>;"; | ||
504 | |||
505 | check_assist_by_label( | ||
506 | convert_integer_literal, | ||
507 | before, | ||
508 | "const _: i32 = 0b1111101000i32;", | ||
509 | "Convert 1_00_0i32 to 0b1111101000i32", | ||
510 | ); | ||
511 | |||
512 | check_assist_by_label( | ||
513 | convert_integer_literal, | ||
514 | before, | ||
515 | "const _: i32 = 0o1750i32;", | ||
516 | "Convert 1_00_0i32 to 0o1750i32", | ||
517 | ); | ||
518 | |||
519 | check_assist_by_label( | ||
520 | convert_integer_literal, | ||
521 | before, | ||
522 | "const _: i32 = 0x3E8i32;", | ||
523 | "Convert 1_00_0i32 to 0x3E8i32", | ||
524 | ); | ||
525 | } | ||
526 | |||
527 | #[test] | ||
528 | fn convert_small_decimal_integer_with_underscores_and_suffix() { | ||
529 | let before = "const _: i32 = 1_0i32<|>;"; | ||
530 | |||
531 | check_assist_by_label( | ||
532 | convert_integer_literal, | ||
533 | before, | ||
534 | "const _: i32 = 0b1010i32;", | ||
535 | "Convert 1_0i32 to 0b1010i32", | ||
536 | ); | ||
537 | |||
538 | check_assist_by_label( | ||
539 | convert_integer_literal, | ||
540 | before, | ||
541 | "const _: i32 = 0o12i32;", | ||
542 | "Convert 1_0i32 to 0o12i32", | ||
543 | ); | ||
544 | |||
545 | check_assist_by_label( | ||
546 | convert_integer_literal, | ||
547 | before, | ||
548 | "const _: i32 = 0xAi32;", | ||
549 | "Convert 1_0i32 to 0xAi32", | ||
550 | ); | ||
551 | } | ||
552 | |||
553 | #[test] | ||
554 | fn convert_hexadecimal_integer_with_underscores_and_suffix() { | ||
555 | let before = "const _: i32 = 0x_F_Fi32<|>;"; | ||
556 | |||
557 | check_assist_by_label( | ||
558 | convert_integer_literal, | ||
559 | before, | ||
560 | "const _: i32 = 0b11111111i32;", | ||
561 | "Convert 0x_F_Fi32 to 0b11111111i32", | ||
562 | ); | ||
563 | |||
564 | check_assist_by_label( | ||
565 | convert_integer_literal, | ||
566 | before, | ||
567 | "const _: i32 = 0o377i32;", | ||
568 | "Convert 0x_F_Fi32 to 0o377i32", | ||
569 | ); | ||
570 | |||
571 | check_assist_by_label( | ||
572 | convert_integer_literal, | ||
573 | before, | ||
574 | "const _: i32 = 255i32;", | ||
575 | "Convert 0x_F_Fi32 to 255i32", | ||
576 | ); | ||
577 | } | ||
578 | |||
579 | #[test] | ||
580 | fn convert_binary_integer_with_underscores_and_suffix() { | ||
581 | let before = "const _: i32 = 0b1111_1111i32<|>;"; | ||
582 | |||
583 | check_assist_by_label( | ||
584 | convert_integer_literal, | ||
585 | before, | ||
586 | "const _: i32 = 0o377i32;", | ||
587 | "Convert 0b1111_1111i32 to 0o377i32", | ||
588 | ); | ||
589 | |||
590 | check_assist_by_label( | ||
591 | convert_integer_literal, | ||
592 | before, | ||
593 | "const _: i32 = 255i32;", | ||
594 | "Convert 0b1111_1111i32 to 255i32", | ||
595 | ); | ||
596 | |||
597 | check_assist_by_label( | ||
598 | convert_integer_literal, | ||
599 | before, | ||
600 | "const _: i32 = 0xFFi32;", | ||
601 | "Convert 0b1111_1111i32 to 0xFFi32", | ||
602 | ); | ||
603 | } | ||
604 | |||
605 | #[test] | ||
606 | fn convert_octal_integer_with_underscores_and_suffix() { | ||
607 | let before = "const _: i32 = 0o3_77i32<|>;"; | ||
608 | |||
609 | check_assist_by_label( | ||
610 | convert_integer_literal, | ||
611 | before, | ||
612 | "const _: i32 = 0b11111111i32;", | ||
613 | "Convert 0o3_77i32 to 0b11111111i32", | ||
614 | ); | ||
615 | |||
616 | check_assist_by_label( | ||
617 | convert_integer_literal, | ||
618 | before, | ||
619 | "const _: i32 = 255i32;", | ||
620 | "Convert 0o3_77i32 to 255i32", | ||
621 | ); | ||
622 | |||
623 | check_assist_by_label( | ||
624 | convert_integer_literal, | ||
625 | before, | ||
626 | "const _: i32 = 0xFFi32;", | ||
627 | "Convert 0o3_77i32 to 0xFFi32", | ||
628 | ); | ||
629 | } | ||
630 | |||
631 | #[test] | ||
632 | fn convert_overflowing_literal() { | 263 | fn convert_overflowing_literal() { |
633 | let before = "const _: i32 = | 264 | let before = "const _: i32 = |
634 | 111111111111111111111111111111111111111111111111111111111111111111111111<|>;"; | 265 | 111111111111111111111111111111111111111111111111111111111111111111111111<|>;"; |
diff --git a/crates/assists/src/handlers/expand_glob_import.rs b/crates/assists/src/handlers/expand_glob_import.rs index 316a58d88..853266395 100644 --- a/crates/assists/src/handlers/expand_glob_import.rs +++ b/crates/assists/src/handlers/expand_glob_import.rs | |||
@@ -41,7 +41,7 @@ use crate::{ | |||
41 | // fn qux(bar: Bar, baz: Baz) {} | 41 | // fn qux(bar: Bar, baz: Baz) {} |
42 | // ``` | 42 | // ``` |
43 | pub(crate) fn expand_glob_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | 43 | pub(crate) fn expand_glob_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
44 | let star = ctx.find_token_at_offset(T![*])?; | 44 | let star = ctx.find_token_syntax_at_offset(T![*])?; |
45 | let (parent, mod_path) = find_parent_and_path(&star)?; | 45 | let (parent, mod_path) = find_parent_and_path(&star)?; |
46 | let target_module = match ctx.sema.resolve_path(&mod_path)? { | 46 | let target_module = match ctx.sema.resolve_path(&mod_path)? { |
47 | PathResolution::Def(ModuleDef::Module(it)) => it, | 47 | PathResolution::Def(ModuleDef::Module(it)) => it, |
diff --git a/crates/assists/src/handlers/flip_comma.rs b/crates/assists/src/handlers/flip_comma.rs index 5c69db53e..64b4b1a76 100644 --- a/crates/assists/src/handlers/flip_comma.rs +++ b/crates/assists/src/handlers/flip_comma.rs | |||
@@ -18,7 +18,7 @@ use crate::{AssistContext, AssistId, AssistKind, Assists}; | |||
18 | // } | 18 | // } |
19 | // ``` | 19 | // ``` |
20 | pub(crate) fn flip_comma(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | 20 | pub(crate) fn flip_comma(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
21 | let comma = ctx.find_token_at_offset(T![,])?; | 21 | let comma = ctx.find_token_syntax_at_offset(T![,])?; |
22 | let prev = non_trivia_sibling(comma.clone().into(), Direction::Prev)?; | 22 | let prev = non_trivia_sibling(comma.clone().into(), Direction::Prev)?; |
23 | let next = non_trivia_sibling(comma.clone().into(), Direction::Next)?; | 23 | let next = non_trivia_sibling(comma.clone().into(), Direction::Next)?; |
24 | 24 | ||
diff --git a/crates/assists/src/handlers/flip_trait_bound.rs b/crates/assists/src/handlers/flip_trait_bound.rs index 347e79b1d..92ee42181 100644 --- a/crates/assists/src/handlers/flip_trait_bound.rs +++ b/crates/assists/src/handlers/flip_trait_bound.rs | |||
@@ -20,7 +20,7 @@ use crate::{AssistContext, AssistId, AssistKind, Assists}; | |||
20 | pub(crate) fn flip_trait_bound(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | 20 | pub(crate) fn flip_trait_bound(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
21 | // We want to replicate the behavior of `flip_binexpr` by only suggesting | 21 | // We want to replicate the behavior of `flip_binexpr` by only suggesting |
22 | // the assist when the cursor is on a `+` | 22 | // the assist when the cursor is on a `+` |
23 | let plus = ctx.find_token_at_offset(T![+])?; | 23 | let plus = ctx.find_token_syntax_at_offset(T![+])?; |
24 | 24 | ||
25 | // Make sure we're in a `TypeBoundList` | 25 | // Make sure we're in a `TypeBoundList` |
26 | if ast::TypeBoundList::cast(plus.parent()).is_none() { | 26 | if ast::TypeBoundList::cast(plus.parent()).is_none() { |
diff --git a/crates/assists/src/handlers/infer_function_return_type.rs b/crates/assists/src/handlers/infer_function_return_type.rs new file mode 100644 index 000000000..520d07ae0 --- /dev/null +++ b/crates/assists/src/handlers/infer_function_return_type.rs | |||
@@ -0,0 +1,337 @@ | |||
1 | use hir::HirDisplay; | ||
2 | use syntax::{ast, AstNode, TextRange, TextSize}; | ||
3 | use test_utils::mark; | ||
4 | |||
5 | use crate::{AssistContext, AssistId, AssistKind, Assists}; | ||
6 | |||
7 | // Assist: infer_function_return_type | ||
8 | // | ||
9 | // Adds the return type to a function or closure inferred from its tail expression if it doesn't have a return | ||
10 | // type specified. This assists is useable in a functions or closures tail expression or return type position. | ||
11 | // | ||
12 | // ``` | ||
13 | // fn foo() { 4<|>2i32 } | ||
14 | // ``` | ||
15 | // -> | ||
16 | // ``` | ||
17 | // fn foo() -> i32 { 42i32 } | ||
18 | // ``` | ||
19 | pub(crate) fn infer_function_return_type(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | ||
20 | let (tail_expr, builder_edit_pos, wrap_expr) = extract_tail(ctx)?; | ||
21 | let module = ctx.sema.scope(tail_expr.syntax()).module()?; | ||
22 | let ty = ctx.sema.type_of_expr(&tail_expr)?; | ||
23 | if ty.is_unit() { | ||
24 | return None; | ||
25 | } | ||
26 | let ty = ty.display_source_code(ctx.db(), module.into()).ok()?; | ||
27 | |||
28 | acc.add( | ||
29 | AssistId("infer_function_return_type", AssistKind::RefactorRewrite), | ||
30 | "Add this function's return type", | ||
31 | tail_expr.syntax().text_range(), | ||
32 | |builder| { | ||
33 | match builder_edit_pos { | ||
34 | InsertOrReplace::Insert(insert_pos) => { | ||
35 | builder.insert(insert_pos, &format!("-> {} ", ty)) | ||
36 | } | ||
37 | InsertOrReplace::Replace(text_range) => { | ||
38 | builder.replace(text_range, &format!("-> {}", ty)) | ||
39 | } | ||
40 | } | ||
41 | if wrap_expr { | ||
42 | mark::hit!(wrap_closure_non_block_expr); | ||
43 | // `|x| x` becomes `|x| -> T x` which is invalid, so wrap it in a block | ||
44 | builder.replace(tail_expr.syntax().text_range(), &format!("{{{}}}", tail_expr)); | ||
45 | } | ||
46 | }, | ||
47 | ) | ||
48 | } | ||
49 | |||
50 | enum InsertOrReplace { | ||
51 | Insert(TextSize), | ||
52 | Replace(TextRange), | ||
53 | } | ||
54 | |||
55 | /// Check the potentially already specified return type and reject it or turn it into a builder command | ||
56 | /// if allowed. | ||
57 | fn ret_ty_to_action(ret_ty: Option<ast::RetType>, insert_pos: TextSize) -> Option<InsertOrReplace> { | ||
58 | match ret_ty { | ||
59 | Some(ret_ty) => match ret_ty.ty() { | ||
60 | Some(ast::Type::InferType(_)) | None => { | ||
61 | mark::hit!(existing_infer_ret_type); | ||
62 | mark::hit!(existing_infer_ret_type_closure); | ||
63 | Some(InsertOrReplace::Replace(ret_ty.syntax().text_range())) | ||
64 | } | ||
65 | _ => { | ||
66 | mark::hit!(existing_ret_type); | ||
67 | mark::hit!(existing_ret_type_closure); | ||
68 | None | ||
69 | } | ||
70 | }, | ||
71 | None => Some(InsertOrReplace::Insert(insert_pos + TextSize::from(1))), | ||
72 | } | ||
73 | } | ||
74 | |||
75 | fn extract_tail(ctx: &AssistContext) -> Option<(ast::Expr, InsertOrReplace, bool)> { | ||
76 | let (tail_expr, return_type_range, action, wrap_expr) = | ||
77 | if let Some(closure) = ctx.find_node_at_offset::<ast::ClosureExpr>() { | ||
78 | let rpipe_pos = closure.param_list()?.syntax().last_token()?.text_range().end(); | ||
79 | let action = ret_ty_to_action(closure.ret_type(), rpipe_pos)?; | ||
80 | |||
81 | let body = closure.body()?; | ||
82 | let body_start = body.syntax().first_token()?.text_range().start(); | ||
83 | let (tail_expr, wrap_expr) = match body { | ||
84 | ast::Expr::BlockExpr(block) => (block.expr()?, false), | ||
85 | body => (body, true), | ||
86 | }; | ||
87 | |||
88 | let ret_range = TextRange::new(rpipe_pos, body_start); | ||
89 | (tail_expr, ret_range, action, wrap_expr) | ||
90 | } else { | ||
91 | let func = ctx.find_node_at_offset::<ast::Fn>()?; | ||
92 | let rparen_pos = func.param_list()?.r_paren_token()?.text_range().end(); | ||
93 | let action = ret_ty_to_action(func.ret_type(), rparen_pos)?; | ||
94 | |||
95 | let body = func.body()?; | ||
96 | let tail_expr = body.expr()?; | ||
97 | |||
98 | let ret_range_end = body.l_curly_token()?.text_range().start(); | ||
99 | let ret_range = TextRange::new(rparen_pos, ret_range_end); | ||
100 | (tail_expr, ret_range, action, false) | ||
101 | }; | ||
102 | let frange = ctx.frange.range; | ||
103 | if return_type_range.contains_range(frange) { | ||
104 | mark::hit!(cursor_in_ret_position); | ||
105 | mark::hit!(cursor_in_ret_position_closure); | ||
106 | } else if tail_expr.syntax().text_range().contains_range(frange) { | ||
107 | mark::hit!(cursor_on_tail); | ||
108 | mark::hit!(cursor_on_tail_closure); | ||
109 | } else { | ||
110 | return None; | ||
111 | } | ||
112 | Some((tail_expr, action, wrap_expr)) | ||
113 | } | ||
114 | |||
115 | #[cfg(test)] | ||
116 | mod tests { | ||
117 | use crate::tests::{check_assist, check_assist_not_applicable}; | ||
118 | |||
119 | use super::*; | ||
120 | |||
121 | #[test] | ||
122 | fn infer_return_type_specified_inferred() { | ||
123 | mark::check!(existing_infer_ret_type); | ||
124 | check_assist( | ||
125 | infer_function_return_type, | ||
126 | r#"fn foo() -> <|>_ { | ||
127 | 45 | ||
128 | }"#, | ||
129 | r#"fn foo() -> i32 { | ||
130 | 45 | ||
131 | }"#, | ||
132 | ); | ||
133 | } | ||
134 | |||
135 | #[test] | ||
136 | fn infer_return_type_specified_inferred_closure() { | ||
137 | mark::check!(existing_infer_ret_type_closure); | ||
138 | check_assist( | ||
139 | infer_function_return_type, | ||
140 | r#"fn foo() { | ||
141 | || -> _ {<|>45}; | ||
142 | }"#, | ||
143 | r#"fn foo() { | ||
144 | || -> i32 {45}; | ||
145 | }"#, | ||
146 | ); | ||
147 | } | ||
148 | |||
149 | #[test] | ||
150 | fn infer_return_type_cursor_at_return_type_pos() { | ||
151 | mark::check!(cursor_in_ret_position); | ||
152 | check_assist( | ||
153 | infer_function_return_type, | ||
154 | r#"fn foo() <|>{ | ||
155 | 45 | ||
156 | }"#, | ||
157 | r#"fn foo() -> i32 { | ||
158 | 45 | ||
159 | }"#, | ||
160 | ); | ||
161 | } | ||
162 | |||
163 | #[test] | ||
164 | fn infer_return_type_cursor_at_return_type_pos_closure() { | ||
165 | mark::check!(cursor_in_ret_position_closure); | ||
166 | check_assist( | ||
167 | infer_function_return_type, | ||
168 | r#"fn foo() { | ||
169 | || <|>45 | ||
170 | }"#, | ||
171 | r#"fn foo() { | ||
172 | || -> i32 {45} | ||
173 | }"#, | ||
174 | ); | ||
175 | } | ||
176 | |||
177 | #[test] | ||
178 | fn infer_return_type() { | ||
179 | mark::check!(cursor_on_tail); | ||
180 | check_assist( | ||
181 | infer_function_return_type, | ||
182 | r#"fn foo() { | ||
183 | 45<|> | ||
184 | }"#, | ||
185 | r#"fn foo() -> i32 { | ||
186 | 45 | ||
187 | }"#, | ||
188 | ); | ||
189 | } | ||
190 | |||
191 | #[test] | ||
192 | fn infer_return_type_nested() { | ||
193 | check_assist( | ||
194 | infer_function_return_type, | ||
195 | r#"fn foo() { | ||
196 | if true { | ||
197 | 3<|> | ||
198 | } else { | ||
199 | 5 | ||
200 | } | ||
201 | }"#, | ||
202 | r#"fn foo() -> i32 { | ||
203 | if true { | ||
204 | 3 | ||
205 | } else { | ||
206 | 5 | ||
207 | } | ||
208 | }"#, | ||
209 | ); | ||
210 | } | ||
211 | |||
212 | #[test] | ||
213 | fn not_applicable_ret_type_specified() { | ||
214 | mark::check!(existing_ret_type); | ||
215 | check_assist_not_applicable( | ||
216 | infer_function_return_type, | ||
217 | r#"fn foo() -> i32 { | ||
218 | ( 45<|> + 32 ) * 123 | ||
219 | }"#, | ||
220 | ); | ||
221 | } | ||
222 | |||
223 | #[test] | ||
224 | fn not_applicable_non_tail_expr() { | ||
225 | check_assist_not_applicable( | ||
226 | infer_function_return_type, | ||
227 | r#"fn foo() { | ||
228 | let x = <|>3; | ||
229 | ( 45 + 32 ) * 123 | ||
230 | }"#, | ||
231 | ); | ||
232 | } | ||
233 | |||
234 | #[test] | ||
235 | fn not_applicable_unit_return_type() { | ||
236 | check_assist_not_applicable( | ||
237 | infer_function_return_type, | ||
238 | r#"fn foo() { | ||
239 | (<|>) | ||
240 | }"#, | ||
241 | ); | ||
242 | } | ||
243 | |||
244 | #[test] | ||
245 | fn infer_return_type_closure_block() { | ||
246 | mark::check!(cursor_on_tail_closure); | ||
247 | check_assist( | ||
248 | infer_function_return_type, | ||
249 | r#"fn foo() { | ||
250 | |x: i32| { | ||
251 | x<|> | ||
252 | }; | ||
253 | }"#, | ||
254 | r#"fn foo() { | ||
255 | |x: i32| -> i32 { | ||
256 | x | ||
257 | }; | ||
258 | }"#, | ||
259 | ); | ||
260 | } | ||
261 | |||
262 | #[test] | ||
263 | fn infer_return_type_closure() { | ||
264 | check_assist( | ||
265 | infer_function_return_type, | ||
266 | r#"fn foo() { | ||
267 | |x: i32| { x<|> }; | ||
268 | }"#, | ||
269 | r#"fn foo() { | ||
270 | |x: i32| -> i32 { x }; | ||
271 | }"#, | ||
272 | ); | ||
273 | } | ||
274 | |||
275 | #[test] | ||
276 | fn infer_return_type_closure_wrap() { | ||
277 | mark::check!(wrap_closure_non_block_expr); | ||
278 | check_assist( | ||
279 | infer_function_return_type, | ||
280 | r#"fn foo() { | ||
281 | |x: i32| x<|>; | ||
282 | }"#, | ||
283 | r#"fn foo() { | ||
284 | |x: i32| -> i32 {x}; | ||
285 | }"#, | ||
286 | ); | ||
287 | } | ||
288 | |||
289 | #[test] | ||
290 | fn infer_return_type_nested_closure() { | ||
291 | check_assist( | ||
292 | infer_function_return_type, | ||
293 | r#"fn foo() { | ||
294 | || { | ||
295 | if true { | ||
296 | 3<|> | ||
297 | } else { | ||
298 | 5 | ||
299 | } | ||
300 | } | ||
301 | }"#, | ||
302 | r#"fn foo() { | ||
303 | || -> i32 { | ||
304 | if true { | ||
305 | 3 | ||
306 | } else { | ||
307 | 5 | ||
308 | } | ||
309 | } | ||
310 | }"#, | ||
311 | ); | ||
312 | } | ||
313 | |||
314 | #[test] | ||
315 | fn not_applicable_ret_type_specified_closure() { | ||
316 | mark::check!(existing_ret_type_closure); | ||
317 | check_assist_not_applicable( | ||
318 | infer_function_return_type, | ||
319 | r#"fn foo() { | ||
320 | || -> i32 { 3<|> } | ||
321 | }"#, | ||
322 | ); | ||
323 | } | ||
324 | |||
325 | #[test] | ||
326 | fn not_applicable_non_tail_expr_closure() { | ||
327 | check_assist_not_applicable( | ||
328 | infer_function_return_type, | ||
329 | r#"fn foo() { | ||
330 | || -> i32 { | ||
331 | let x = 3<|>; | ||
332 | 6 | ||
333 | } | ||
334 | }"#, | ||
335 | ); | ||
336 | } | ||
337 | } | ||
diff --git a/crates/assists/src/handlers/introduce_named_lifetime.rs b/crates/assists/src/handlers/introduce_named_lifetime.rs index 5f623e5f7..4cc8dae65 100644 --- a/crates/assists/src/handlers/introduce_named_lifetime.rs +++ b/crates/assists/src/handlers/introduce_named_lifetime.rs | |||
@@ -36,7 +36,7 @@ static ASSIST_LABEL: &str = "Introduce named lifetime"; | |||
36 | // FIXME: should also add support for the case fun(f: &Foo) -> &<|>Foo | 36 | // FIXME: should also add support for the case fun(f: &Foo) -> &<|>Foo |
37 | pub(crate) fn introduce_named_lifetime(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | 37 | pub(crate) fn introduce_named_lifetime(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
38 | let lifetime_token = ctx | 38 | let lifetime_token = ctx |
39 | .find_token_at_offset(SyntaxKind::LIFETIME) | 39 | .find_token_syntax_at_offset(SyntaxKind::LIFETIME) |
40 | .filter(|lifetime| lifetime.text() == "'_")?; | 40 | .filter(|lifetime| lifetime.text() == "'_")?; |
41 | if let Some(fn_def) = lifetime_token.ancestors().find_map(ast::Fn::cast) { | 41 | if let Some(fn_def) = lifetime_token.ancestors().find_map(ast::Fn::cast) { |
42 | generate_fn_def_assist(acc, &fn_def, lifetime_token.text_range()) | 42 | generate_fn_def_assist(acc, &fn_def, lifetime_token.text_range()) |
diff --git a/crates/assists/src/handlers/invert_if.rs b/crates/assists/src/handlers/invert_if.rs index 461fcf862..ea722b91b 100644 --- a/crates/assists/src/handlers/invert_if.rs +++ b/crates/assists/src/handlers/invert_if.rs | |||
@@ -29,7 +29,7 @@ use crate::{ | |||
29 | // ``` | 29 | // ``` |
30 | 30 | ||
31 | pub(crate) fn invert_if(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | 31 | pub(crate) fn invert_if(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
32 | let if_keyword = ctx.find_token_at_offset(T![if])?; | 32 | let if_keyword = ctx.find_token_syntax_at_offset(T![if])?; |
33 | let expr = ast::IfExpr::cast(if_keyword.parent())?; | 33 | let expr = ast::IfExpr::cast(if_keyword.parent())?; |
34 | let if_range = if_keyword.text_range(); | 34 | let if_range = if_keyword.text_range(); |
35 | let cursor_in_range = if_range.contains_range(ctx.frange.range); | 35 | let cursor_in_range = if_range.contains_range(ctx.frange.range); |
diff --git a/crates/assists/src/handlers/raw_string.rs b/crates/assists/src/handlers/raw_string.rs index 9ddd116e0..4c759cc25 100644 --- a/crates/assists/src/handlers/raw_string.rs +++ b/crates/assists/src/handlers/raw_string.rs | |||
@@ -1,11 +1,6 @@ | |||
1 | use std::borrow::Cow; | 1 | use std::borrow::Cow; |
2 | 2 | ||
3 | use syntax::{ | 3 | use syntax::{ast, AstToken, TextRange, TextSize}; |
4 | ast::{self, HasQuotes, HasStringValue}, | ||
5 | AstToken, | ||
6 | SyntaxKind::{RAW_STRING, STRING}, | ||
7 | TextRange, TextSize, | ||
8 | }; | ||
9 | use test_utils::mark; | 4 | use test_utils::mark; |
10 | 5 | ||
11 | use crate::{AssistContext, AssistId, AssistKind, Assists}; | 6 | use crate::{AssistContext, AssistId, AssistKind, Assists}; |
@@ -26,7 +21,10 @@ use crate::{AssistContext, AssistId, AssistKind, Assists}; | |||
26 | // } | 21 | // } |
27 | // ``` | 22 | // ``` |
28 | pub(crate) fn make_raw_string(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | 23 | pub(crate) fn make_raw_string(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
29 | let token = ctx.find_token_at_offset(STRING).and_then(ast::String::cast)?; | 24 | let token = ctx.find_token_at_offset::<ast::String>()?; |
25 | if token.is_raw() { | ||
26 | return None; | ||
27 | } | ||
30 | let value = token.value()?; | 28 | let value = token.value()?; |
31 | let target = token.syntax().text_range(); | 29 | let target = token.syntax().text_range(); |
32 | acc.add( | 30 | acc.add( |
@@ -65,7 +63,10 @@ pub(crate) fn make_raw_string(acc: &mut Assists, ctx: &AssistContext) -> Option< | |||
65 | // } | 63 | // } |
66 | // ``` | 64 | // ``` |
67 | pub(crate) fn make_usual_string(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | 65 | pub(crate) fn make_usual_string(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
68 | let token = ctx.find_token_at_offset(RAW_STRING).and_then(ast::RawString::cast)?; | 66 | let token = ctx.find_token_at_offset::<ast::String>()?; |
67 | if !token.is_raw() { | ||
68 | return None; | ||
69 | } | ||
69 | let value = token.value()?; | 70 | let value = token.value()?; |
70 | let target = token.syntax().text_range(); | 71 | let target = token.syntax().text_range(); |
71 | acc.add( | 72 | acc.add( |
@@ -104,11 +105,15 @@ pub(crate) fn make_usual_string(acc: &mut Assists, ctx: &AssistContext) -> Optio | |||
104 | // } | 105 | // } |
105 | // ``` | 106 | // ``` |
106 | pub(crate) fn add_hash(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | 107 | pub(crate) fn add_hash(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
107 | let token = ctx.find_token_at_offset(RAW_STRING)?; | 108 | let token = ctx.find_token_at_offset::<ast::String>()?; |
108 | let target = token.text_range(); | 109 | if !token.is_raw() { |
110 | return None; | ||
111 | } | ||
112 | let text_range = token.syntax().text_range(); | ||
113 | let target = text_range; | ||
109 | acc.add(AssistId("add_hash", AssistKind::Refactor), "Add #", target, |edit| { | 114 | acc.add(AssistId("add_hash", AssistKind::Refactor), "Add #", target, |edit| { |
110 | edit.insert(token.text_range().start() + TextSize::of('r'), "#"); | 115 | edit.insert(text_range.start() + TextSize::of('r'), "#"); |
111 | edit.insert(token.text_range().end(), "#"); | 116 | edit.insert(text_range.end(), "#"); |
112 | }) | 117 | }) |
113 | } | 118 | } |
114 | 119 | ||
@@ -128,7 +133,10 @@ pub(crate) fn add_hash(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | |||
128 | // } | 133 | // } |
129 | // ``` | 134 | // ``` |
130 | pub(crate) fn remove_hash(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | 135 | pub(crate) fn remove_hash(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
131 | let token = ctx.find_token_at_offset(RAW_STRING).and_then(ast::RawString::cast)?; | 136 | let token = ctx.find_token_at_offset::<ast::String>()?; |
137 | if !token.is_raw() { | ||
138 | return None; | ||
139 | } | ||
132 | 140 | ||
133 | let text = token.text().as_str(); | 141 | let text = token.text().as_str(); |
134 | if !text.starts_with("r#") && text.ends_with('#') { | 142 | if !text.starts_with("r#") && text.ends_with('#') { |
diff --git a/crates/assists/src/handlers/remove_mut.rs b/crates/assists/src/handlers/remove_mut.rs index 44f41daa9..575b271f7 100644 --- a/crates/assists/src/handlers/remove_mut.rs +++ b/crates/assists/src/handlers/remove_mut.rs | |||
@@ -18,7 +18,7 @@ use crate::{AssistContext, AssistId, AssistKind, Assists}; | |||
18 | // } | 18 | // } |
19 | // ``` | 19 | // ``` |
20 | pub(crate) fn remove_mut(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | 20 | pub(crate) fn remove_mut(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
21 | let mut_token = ctx.find_token_at_offset(T![mut])?; | 21 | let mut_token = ctx.find_token_syntax_at_offset(T![mut])?; |
22 | let delete_from = mut_token.text_range().start(); | 22 | let delete_from = mut_token.text_range().start(); |
23 | let delete_to = match mut_token.next_token() { | 23 | let delete_to = match mut_token.next_token() { |
24 | Some(it) if it.kind() == SyntaxKind::WHITESPACE => it.text_range().end(), | 24 | Some(it) if it.kind() == SyntaxKind::WHITESPACE => it.text_range().end(), |
diff --git a/crates/assists/src/handlers/replace_let_with_if_let.rs b/crates/assists/src/handlers/replace_let_with_if_let.rs index a5bcbda24..69d3b08d3 100644 --- a/crates/assists/src/handlers/replace_let_with_if_let.rs +++ b/crates/assists/src/handlers/replace_let_with_if_let.rs | |||
@@ -37,7 +37,7 @@ use ide_db::ty_filter::TryEnum; | |||
37 | // fn compute() -> Option<i32> { None } | 37 | // fn compute() -> Option<i32> { None } |
38 | // ``` | 38 | // ``` |
39 | pub(crate) fn replace_let_with_if_let(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | 39 | pub(crate) fn replace_let_with_if_let(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
40 | let let_kw = ctx.find_token_at_offset(T![let])?; | 40 | let let_kw = ctx.find_token_syntax_at_offset(T![let])?; |
41 | let let_stmt = let_kw.ancestors().find_map(ast::LetStmt::cast)?; | 41 | let let_stmt = let_kw.ancestors().find_map(ast::LetStmt::cast)?; |
42 | let init = let_stmt.initializer()?; | 42 | let init = let_stmt.initializer()?; |
43 | let original_pat = let_stmt.pat()?; | 43 | let original_pat = let_stmt.pat()?; |
diff --git a/crates/assists/src/handlers/replace_string_with_char.rs b/crates/assists/src/handlers/replace_string_with_char.rs index 4ca87a8ec..b4b898846 100644 --- a/crates/assists/src/handlers/replace_string_with_char.rs +++ b/crates/assists/src/handlers/replace_string_with_char.rs | |||
@@ -1,8 +1,4 @@ | |||
1 | use syntax::{ | 1 | use syntax::{ast, AstToken, SyntaxKind::STRING}; |
2 | ast::{self, HasStringValue}, | ||
3 | AstToken, | ||
4 | SyntaxKind::STRING, | ||
5 | }; | ||
6 | 2 | ||
7 | use crate::{AssistContext, AssistId, AssistKind, Assists}; | 3 | use crate::{AssistContext, AssistId, AssistKind, Assists}; |
8 | 4 | ||
@@ -22,7 +18,7 @@ use crate::{AssistContext, AssistId, AssistKind, Assists}; | |||
22 | // } | 18 | // } |
23 | // ``` | 19 | // ``` |
24 | pub(crate) fn replace_string_with_char(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | 20 | pub(crate) fn replace_string_with_char(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
25 | let token = ctx.find_token_at_offset(STRING).and_then(ast::String::cast)?; | 21 | let token = ctx.find_token_syntax_at_offset(STRING).and_then(ast::String::cast)?; |
26 | let value = token.value()?; | 22 | let value = token.value()?; |
27 | let target = token.syntax().text_range(); | 23 | let target = token.syntax().text_range(); |
28 | 24 | ||
diff --git a/crates/assists/src/handlers/split_import.rs b/crates/assists/src/handlers/split_import.rs index 15e67eaa1..ef1f6b8a1 100644 --- a/crates/assists/src/handlers/split_import.rs +++ b/crates/assists/src/handlers/split_import.rs | |||
@@ -16,7 +16,7 @@ use crate::{AssistContext, AssistId, AssistKind, Assists}; | |||
16 | // use std::{collections::HashMap}; | 16 | // use std::{collections::HashMap}; |
17 | // ``` | 17 | // ``` |
18 | pub(crate) fn split_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | 18 | pub(crate) fn split_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
19 | let colon_colon = ctx.find_token_at_offset(T![::])?; | 19 | let colon_colon = ctx.find_token_syntax_at_offset(T![::])?; |
20 | let path = ast::Path::cast(colon_colon.parent())?.qualifier()?; | 20 | let path = ast::Path::cast(colon_colon.parent())?.qualifier()?; |
21 | let top_path = successors(Some(path.clone()), |it| it.parent_path()).last()?; | 21 | let top_path = successors(Some(path.clone()), |it| it.parent_path()).last()?; |
22 | 22 | ||
diff --git a/crates/assists/src/handlers/unwrap_block.rs b/crates/assists/src/handlers/unwrap_block.rs index 3851aeb3e..36ef871b9 100644 --- a/crates/assists/src/handlers/unwrap_block.rs +++ b/crates/assists/src/handlers/unwrap_block.rs | |||
@@ -29,7 +29,7 @@ pub(crate) fn unwrap_block(acc: &mut Assists, ctx: &AssistContext) -> Option<()> | |||
29 | let assist_id = AssistId("unwrap_block", AssistKind::RefactorRewrite); | 29 | let assist_id = AssistId("unwrap_block", AssistKind::RefactorRewrite); |
30 | let assist_label = "Unwrap block"; | 30 | let assist_label = "Unwrap block"; |
31 | 31 | ||
32 | let l_curly_token = ctx.find_token_at_offset(T!['{'])?; | 32 | let l_curly_token = ctx.find_token_syntax_at_offset(T!['{'])?; |
33 | let mut block = ast::BlockExpr::cast(l_curly_token.parent())?; | 33 | let mut block = ast::BlockExpr::cast(l_curly_token.parent())?; |
34 | let mut parent = block.syntax().parent()?; | 34 | let mut parent = block.syntax().parent()?; |
35 | if ast::MatchArm::can_cast(parent.kind()) { | 35 | if ast::MatchArm::can_cast(parent.kind()) { |