aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_assists/src/inline_local_variable.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_assists/src/inline_local_variable.rs')
-rw-r--r--crates/ra_assists/src/inline_local_variable.rs432
1 files changed, 386 insertions, 46 deletions
diff --git a/crates/ra_assists/src/inline_local_variable.rs b/crates/ra_assists/src/inline_local_variable.rs
index bd3cdb970..950c2910b 100644
--- a/crates/ra_assists/src/inline_local_variable.rs
+++ b/crates/ra_assists/src/inline_local_variable.rs
@@ -1,7 +1,11 @@
1use hir::db::HirDatabase; 1use hir::{
2use hir::source_binder::function_from_child_node; 2 db::HirDatabase,
3use ra_syntax::{ast::{self, AstNode}, TextRange}; 3 source_binder::function_from_child_node,
4use ra_syntax::ast::{PatKind, ExprKind}; 4};
5use ra_syntax::{
6 ast::{self, AstNode, AstToken, PatKind, ExprKind},
7 TextRange,
8};
5 9
6use crate::{Assist, AssistCtx, AssistId}; 10use crate::{Assist, AssistCtx, AssistId};
7use crate::assist_ctx::AssistBuilder; 11use crate::assist_ctx::AssistBuilder;
@@ -15,61 +19,77 @@ pub(crate) fn inline_local_varialbe(mut ctx: AssistCtx<impl HirDatabase>) -> Opt
15 if bind_pat.is_mutable() { 19 if bind_pat.is_mutable() {
16 return None; 20 return None;
17 } 21 }
18 let initializer = let_stmt.initializer()?; 22 let initializer_expr = let_stmt.initializer();
19 let wrap_in_parens = match initializer.kind() { 23 let delete_range = if let Some(whitespace) = let_stmt
20 ExprKind::LambdaExpr(_) 24 .syntax()
21 | ExprKind::IfExpr(_) 25 .next_sibling_or_token()
22 | ExprKind::LoopExpr(_) 26 .and_then(|it| ast::Whitespace::cast(it.as_token()?))
23 | ExprKind::ForExpr(_)
24 | ExprKind::WhileExpr(_)
25 | ExprKind::ContinueExpr(_)
26 | ExprKind::BreakExpr(_)
27 | ExprKind::Label(_)
28 | ExprKind::ReturnExpr(_)
29 | ExprKind::MatchExpr(_)
30 | ExprKind::StructLit(_)
31 | ExprKind::CastExpr(_)
32 | ExprKind::PrefixExpr(_)
33 | ExprKind::RangeExpr(_)
34 | ExprKind::BinExpr(_) => true,
35 ExprKind::CallExpr(_)
36 | ExprKind::IndexExpr(_)
37 | ExprKind::MethodCallExpr(_)
38 | ExprKind::FieldExpr(_)
39 | ExprKind::TryExpr(_)
40 | ExprKind::RefExpr(_)
41 | ExprKind::Literal(_)
42 | ExprKind::TupleExpr(_)
43 | ExprKind::ArrayExpr(_)
44 | ExprKind::ParenExpr(_)
45 | ExprKind::PathExpr(_)
46 | ExprKind::BlockExpr(_) => false,
47 };
48
49 let delete_range = if let Some(whitespace) =
50 let_stmt.syntax().next_sibling().and_then(ast::Whitespace::cast)
51 { 27 {
52 TextRange::from_to(let_stmt.syntax().range().start(), whitespace.syntax().range().end()) 28 TextRange::from_to(let_stmt.syntax().range().start(), whitespace.syntax().range().end())
53 } else { 29 } else {
54 let_stmt.syntax().range() 30 let_stmt.syntax().range()
55 }; 31 };
56 32
57 let init_str = if wrap_in_parens {
58 format!("({})", initializer.syntax().text().to_string())
59 } else {
60 initializer.syntax().text().to_string()
61 };
62 let function = function_from_child_node(ctx.db, ctx.frange.file_id, bind_pat.syntax())?; 33 let function = function_from_child_node(ctx.db, ctx.frange.file_id, bind_pat.syntax())?;
63 let scope = function.scopes(ctx.db); 34 let scope = function.scopes(ctx.db);
64 let refs = scope.find_all_refs(bind_pat); 35 let refs = scope.find_all_refs(bind_pat);
65 36
37 let mut wrap_in_parens = vec![true; refs.len()];
38
39 for (i, desc) in refs.iter().enumerate() {
40 let usage_node = ctx
41 .covering_node_for_range(desc.range)
42 .ancestors()
43 .find_map(|node| ast::PathExpr::cast(node))?;
44 let usage_parent_option = usage_node.syntax().parent().and_then(ast::Expr::cast);
45 let usage_parent = match usage_parent_option {
46 Some(u) => u,
47 None => {
48 wrap_in_parens[i] = false;
49 continue;
50 }
51 };
52
53 wrap_in_parens[i] = match (initializer_expr?.kind(), usage_parent.kind()) {
54 (ExprKind::CallExpr(_), _)
55 | (ExprKind::IndexExpr(_), _)
56 | (ExprKind::MethodCallExpr(_), _)
57 | (ExprKind::FieldExpr(_), _)
58 | (ExprKind::TryExpr(_), _)
59 | (ExprKind::RefExpr(_), _)
60 | (ExprKind::Literal(_), _)
61 | (ExprKind::TupleExpr(_), _)
62 | (ExprKind::ArrayExpr(_), _)
63 | (ExprKind::ParenExpr(_), _)
64 | (ExprKind::PathExpr(_), _)
65 | (ExprKind::BlockExpr(_), _)
66 | (_, ExprKind::CallExpr(_))
67 | (_, ExprKind::TupleExpr(_))
68 | (_, ExprKind::ArrayExpr(_))
69 | (_, ExprKind::ParenExpr(_))
70 | (_, ExprKind::ForExpr(_))
71 | (_, ExprKind::WhileExpr(_))
72 | (_, ExprKind::BreakExpr(_))
73 | (_, ExprKind::ReturnExpr(_))
74 | (_, ExprKind::MatchExpr(_)) => false,
75 _ => true,
76 };
77 }
78
79 let init_str = initializer_expr?.syntax().text().to_string();
80 let init_in_paren = format!("({})", &init_str);
81
66 ctx.add_action( 82 ctx.add_action(
67 AssistId("inline_local_variable"), 83 AssistId("inline_local_variable"),
68 "inline local variable", 84 "inline local variable",
69 move |edit: &mut AssistBuilder| { 85 move |edit: &mut AssistBuilder| {
70 edit.delete(delete_range); 86 edit.delete(delete_range);
71 for desc in refs { 87 for (desc, should_wrap) in refs.iter().zip(wrap_in_parens) {
72 edit.replace(desc.range, init_str.clone()) 88 if should_wrap {
89 edit.replace(desc.range, init_in_paren.clone())
90 } else {
91 edit.replace(desc.range, init_str.clone())
92 }
73 } 93 }
74 edit.set_cursor(delete_range.start()) 94 edit.set_cursor(delete_range.start())
75 }, 95 },
@@ -147,7 +167,7 @@ fn foo() {
147 167
148 } 168 }
149 let b = (1 + 1) * 10; 169 let b = (1 + 1) * 10;
150 bar((1 + 1)); 170 bar(1 + 1);
151}", 171}",
152 ); 172 );
153 } 173 }
@@ -215,7 +235,7 @@ fn foo() {
215 235
216 } 236 }
217 let b = (bar(1) as u64) * 10; 237 let b = (bar(1) as u64) * 10;
218 bar((bar(1) as u64)); 238 bar(bar(1) as u64);
219}", 239}",
220 ); 240 );
221 } 241 }
@@ -295,4 +315,324 @@ fn foo() {
295}", 315}",
296 ); 316 );
297 } 317 }
318
319 #[test]
320 fn test_call_expr() {
321 check_assist(
322 inline_local_varialbe,
323 "
324fn foo() {
325 let a<|> = bar(10 + 1);
326 let b = a * 10;
327 let c = a as usize;
328}",
329 "
330fn foo() {
331 <|>let b = bar(10 + 1) * 10;
332 let c = bar(10 + 1) as usize;
333}",
334 );
335 }
336
337 #[test]
338 fn test_index_expr() {
339 check_assist(
340 inline_local_varialbe,
341 "
342fn foo() {
343 let x = vec![1, 2, 3];
344 let a<|> = x[0];
345 let b = a * 10;
346 let c = a as usize;
347}",
348 "
349fn foo() {
350 let x = vec![1, 2, 3];
351 <|>let b = x[0] * 10;
352 let c = x[0] as usize;
353}",
354 );
355 }
356
357 #[test]
358 fn test_method_call_expr() {
359 check_assist(
360 inline_local_varialbe,
361 "
362fn foo() {
363 let bar = vec![1];
364 let a<|> = bar.len();
365 let b = a * 10;
366 let c = a as usize;
367}",
368 "
369fn foo() {
370 let bar = vec![1];
371 <|>let b = bar.len() * 10;
372 let c = bar.len() as usize;
373}",
374 );
375 }
376
377 #[test]
378 fn test_field_expr() {
379 check_assist(
380 inline_local_varialbe,
381 "
382struct Bar {
383 foo: usize
384}
385
386fn foo() {
387 let bar = Bar { foo: 1 };
388 let a<|> = bar.foo;
389 let b = a * 10;
390 let c = a as usize;
391}",
392 "
393struct Bar {
394 foo: usize
395}
396
397fn foo() {
398 let bar = Bar { foo: 1 };
399 <|>let b = bar.foo * 10;
400 let c = bar.foo as usize;
401}",
402 );
403 }
404
405 #[test]
406 fn test_try_expr() {
407 check_assist(
408 inline_local_varialbe,
409 "
410fn foo() -> Option<usize> {
411 let bar = Some(1);
412 let a<|> = bar?;
413 let b = a * 10;
414 let c = a as usize;
415 None
416}",
417 "
418fn foo() -> Option<usize> {
419 let bar = Some(1);
420 <|>let b = bar? * 10;
421 let c = bar? as usize;
422 None
423}",
424 );
425 }
426
427 #[test]
428 fn test_ref_expr() {
429 check_assist(
430 inline_local_varialbe,
431 "
432fn foo() {
433 let bar = 10;
434 let a<|> = &bar;
435 let b = a * 10;
436}",
437 "
438fn foo() {
439 let bar = 10;
440 <|>let b = &bar * 10;
441}",
442 );
443 }
444
445 #[test]
446 fn test_tuple_expr() {
447 check_assist(
448 inline_local_varialbe,
449 "
450fn foo() {
451 let a<|> = (10, 20);
452 let b = a[0];
453}",
454 "
455fn foo() {
456 <|>let b = (10, 20)[0];
457}",
458 );
459 }
460
461 #[test]
462 fn test_array_expr() {
463 check_assist(
464 inline_local_varialbe,
465 "
466fn foo() {
467 let a<|> = [1, 2, 3];
468 let b = a.len();
469}",
470 "
471fn foo() {
472 <|>let b = [1, 2, 3].len();
473}",
474 );
475 }
476
477 #[test]
478 fn test_paren() {
479 check_assist(
480 inline_local_varialbe,
481 "
482fn foo() {
483 let a<|> = (10 + 20);
484 let b = a * 10;
485 let c = a as usize;
486}",
487 "
488fn foo() {
489 <|>let b = (10 + 20) * 10;
490 let c = (10 + 20) as usize;
491}",
492 );
493 }
494
495 #[test]
496 fn test_path_expr() {
497 check_assist(
498 inline_local_varialbe,
499 "
500fn foo() {
501 let d = 10;
502 let a<|> = d;
503 let b = a * 10;
504 let c = a as usize;
505}",
506 "
507fn foo() {
508 let d = 10;
509 <|>let b = d * 10;
510 let c = d as usize;
511}",
512 );
513 }
514
515 #[test]
516 fn test_block_expr() {
517 check_assist(
518 inline_local_varialbe,
519 "
520fn foo() {
521 let a<|> = { 10 };
522 let b = a * 10;
523 let c = a as usize;
524}",
525 "
526fn foo() {
527 <|>let b = { 10 } * 10;
528 let c = { 10 } as usize;
529}",
530 );
531 }
532
533 #[test]
534 fn test_used_in_different_expr1() {
535 check_assist(
536 inline_local_varialbe,
537 "
538fn foo() {
539 let a<|> = 10 + 20;
540 let b = a * 10;
541 let c = (a, 20);
542 let d = [a, 10];
543 let e = (a);
544}",
545 "
546fn foo() {
547 <|>let b = (10 + 20) * 10;
548 let c = (10 + 20, 20);
549 let d = [10 + 20, 10];
550 let e = (10 + 20);
551}",
552 );
553 }
554
555 #[test]
556 fn test_used_in_for_expr() {
557 check_assist(
558 inline_local_varialbe,
559 "
560fn foo() {
561 let a<|> = vec![10, 20];
562 for i in a {}
563}",
564 "
565fn foo() {
566 <|>for i in vec![10, 20] {}
567}",
568 );
569 }
570
571 #[test]
572 fn test_used_in_while_expr() {
573 check_assist(
574 inline_local_varialbe,
575 "
576fn foo() {
577 let a<|> = 1 > 0;
578 while a {}
579}",
580 "
581fn foo() {
582 <|>while 1 > 0 {}
583}",
584 );
585 }
586
587 #[test]
588 fn test_used_in_break_expr() {
589 check_assist(
590 inline_local_varialbe,
591 "
592fn foo() {
593 let a<|> = 1 + 1;
594 loop {
595 break a;
596 }
597}",
598 "
599fn foo() {
600 <|>loop {
601 break 1 + 1;
602 }
603}",
604 );
605 }
606
607 #[test]
608 fn test_used_in_return_expr() {
609 check_assist(
610 inline_local_varialbe,
611 "
612fn foo() {
613 let a<|> = 1 > 0;
614 return a;
615}",
616 "
617fn foo() {
618 <|>return 1 > 0;
619}",
620 );
621 }
622
623 #[test]
624 fn test_used_in_match_expr() {
625 check_assist(
626 inline_local_varialbe,
627 "
628fn foo() {
629 let a<|> = 1 > 0;
630 match a {}
631}",
632 "
633fn foo() {
634 <|>match 1 > 0 {}
635}",
636 );
637 }
298} 638}