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