aboutsummaryrefslogtreecommitdiff
path: root/crates/assists/src/handlers/inline_local_variable.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/assists/src/handlers/inline_local_variable.rs')
-rw-r--r--crates/assists/src/handlers/inline_local_variable.rs724
1 files changed, 0 insertions, 724 deletions
diff --git a/crates/assists/src/handlers/inline_local_variable.rs b/crates/assists/src/handlers/inline_local_variable.rs
deleted file mode 100644
index 0e63a60e8..000000000
--- a/crates/assists/src/handlers/inline_local_variable.rs
+++ /dev/null
@@ -1,724 +0,0 @@
1use ide_db::{
2 defs::Definition,
3 search::{FileReference, ReferenceKind},
4};
5use syntax::{
6 ast::{self, AstNode, AstToken},
7 TextRange,
8};
9use test_utils::mark;
10
11use crate::{
12 assist_context::{AssistContext, Assists},
13 AssistId, AssistKind,
14};
15
16// Assist: inline_local_variable
17//
18// Inlines local variable.
19//
20// ```
21// fn main() {
22// let x$0 = 1 + 2;
23// x * 4;
24// }
25// ```
26// ->
27// ```
28// fn main() {
29// (1 + 2) * 4;
30// }
31// ```
32pub(crate) fn inline_local_variable(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
33 let let_stmt = ctx.find_node_at_offset::<ast::LetStmt>()?;
34 let bind_pat = match let_stmt.pat()? {
35 ast::Pat::IdentPat(pat) => pat,
36 _ => return None,
37 };
38 if bind_pat.mut_token().is_some() {
39 mark::hit!(test_not_inline_mut_variable);
40 return None;
41 }
42 if !bind_pat.syntax().text_range().contains_inclusive(ctx.offset()) {
43 mark::hit!(not_applicable_outside_of_bind_pat);
44 return None;
45 }
46 let initializer_expr = let_stmt.initializer()?;
47
48 let def = ctx.sema.to_def(&bind_pat)?;
49 let def = Definition::Local(def);
50 let usages = def.usages(&ctx.sema).all();
51 if usages.is_empty() {
52 mark::hit!(test_not_applicable_if_variable_unused);
53 return None;
54 };
55
56 let delete_range = if let Some(whitespace) = let_stmt
57 .syntax()
58 .next_sibling_or_token()
59 .and_then(|it| ast::Whitespace::cast(it.as_token()?.clone()))
60 {
61 TextRange::new(
62 let_stmt.syntax().text_range().start(),
63 whitespace.syntax().text_range().end(),
64 )
65 } else {
66 let_stmt.syntax().text_range()
67 };
68
69 let wrap_in_parens = usages
70 .references
71 .values()
72 .flatten()
73 .map(|&FileReference { range, .. }| {
74 let usage_node =
75 ctx.covering_node_for_range(range).ancestors().find_map(ast::PathExpr::cast)?;
76 let usage_parent_option = usage_node.syntax().parent().and_then(ast::Expr::cast);
77 let usage_parent = match usage_parent_option {
78 Some(u) => u,
79 None => return Ok(false),
80 };
81
82 Ok(!matches!(
83 (&initializer_expr, usage_parent),
84 (ast::Expr::CallExpr(_), _)
85 | (ast::Expr::IndexExpr(_), _)
86 | (ast::Expr::MethodCallExpr(_), _)
87 | (ast::Expr::FieldExpr(_), _)
88 | (ast::Expr::TryExpr(_), _)
89 | (ast::Expr::RefExpr(_), _)
90 | (ast::Expr::Literal(_), _)
91 | (ast::Expr::TupleExpr(_), _)
92 | (ast::Expr::ArrayExpr(_), _)
93 | (ast::Expr::ParenExpr(_), _)
94 | (ast::Expr::PathExpr(_), _)
95 | (ast::Expr::BlockExpr(_), _)
96 | (ast::Expr::EffectExpr(_), _)
97 | (_, ast::Expr::CallExpr(_))
98 | (_, ast::Expr::TupleExpr(_))
99 | (_, ast::Expr::ArrayExpr(_))
100 | (_, ast::Expr::ParenExpr(_))
101 | (_, ast::Expr::ForExpr(_))
102 | (_, ast::Expr::WhileExpr(_))
103 | (_, ast::Expr::BreakExpr(_))
104 | (_, ast::Expr::ReturnExpr(_))
105 | (_, ast::Expr::MatchExpr(_))
106 ))
107 })
108 .collect::<Result<Vec<_>, _>>()?;
109
110 let init_str = initializer_expr.syntax().text().to_string();
111 let init_in_paren = format!("({})", &init_str);
112
113 let target = bind_pat.syntax().text_range();
114 acc.add(
115 AssistId("inline_local_variable", AssistKind::RefactorInline),
116 "Inline variable",
117 target,
118 move |builder| {
119 builder.delete(delete_range);
120 for (reference, should_wrap) in usages.references.values().flatten().zip(wrap_in_parens)
121 {
122 let replacement =
123 if should_wrap { init_in_paren.clone() } else { init_str.clone() };
124 match reference.kind {
125 ReferenceKind::FieldShorthandForLocal => {
126 mark::hit!(inline_field_shorthand);
127 builder.insert(reference.range.end(), format!(": {}", replacement))
128 }
129 _ => builder.replace(reference.range, replacement),
130 }
131 }
132 },
133 )
134}
135
136#[cfg(test)]
137mod tests {
138 use test_utils::mark;
139
140 use crate::tests::{check_assist, check_assist_not_applicable};
141
142 use super::*;
143
144 #[test]
145 fn test_inline_let_bind_literal_expr() {
146 check_assist(
147 inline_local_variable,
148 r"
149fn bar(a: usize) {}
150fn foo() {
151 let a$0 = 1;
152 a + 1;
153 if a > 10 {
154 }
155
156 while a > 10 {
157
158 }
159 let b = a * 10;
160 bar(a);
161}",
162 r"
163fn bar(a: usize) {}
164fn foo() {
165 1 + 1;
166 if 1 > 10 {
167 }
168
169 while 1 > 10 {
170
171 }
172 let b = 1 * 10;
173 bar(1);
174}",
175 );
176 }
177
178 #[test]
179 fn test_inline_let_bind_bin_expr() {
180 check_assist(
181 inline_local_variable,
182 r"
183fn bar(a: usize) {}
184fn foo() {
185 let a$0 = 1 + 1;
186 a + 1;
187 if a > 10 {
188 }
189
190 while a > 10 {
191
192 }
193 let b = a * 10;
194 bar(a);
195}",
196 r"
197fn bar(a: usize) {}
198fn foo() {
199 (1 + 1) + 1;
200 if (1 + 1) > 10 {
201 }
202
203 while (1 + 1) > 10 {
204
205 }
206 let b = (1 + 1) * 10;
207 bar(1 + 1);
208}",
209 );
210 }
211
212 #[test]
213 fn test_inline_let_bind_function_call_expr() {
214 check_assist(
215 inline_local_variable,
216 r"
217fn bar(a: usize) {}
218fn foo() {
219 let a$0 = bar(1);
220 a + 1;
221 if a > 10 {
222 }
223
224 while a > 10 {
225
226 }
227 let b = a * 10;
228 bar(a);
229}",
230 r"
231fn bar(a: usize) {}
232fn foo() {
233 bar(1) + 1;
234 if bar(1) > 10 {
235 }
236
237 while bar(1) > 10 {
238
239 }
240 let b = bar(1) * 10;
241 bar(bar(1));
242}",
243 );
244 }
245
246 #[test]
247 fn test_inline_let_bind_cast_expr() {
248 check_assist(
249 inline_local_variable,
250 r"
251fn bar(a: usize): usize { a }
252fn foo() {
253 let a$0 = bar(1) as u64;
254 a + 1;
255 if a > 10 {
256 }
257
258 while a > 10 {
259
260 }
261 let b = a * 10;
262 bar(a);
263}",
264 r"
265fn bar(a: usize): usize { a }
266fn foo() {
267 (bar(1) as u64) + 1;
268 if (bar(1) as u64) > 10 {
269 }
270
271 while (bar(1) as u64) > 10 {
272
273 }
274 let b = (bar(1) as u64) * 10;
275 bar(bar(1) as u64);
276}",
277 );
278 }
279
280 #[test]
281 fn test_inline_let_bind_block_expr() {
282 check_assist(
283 inline_local_variable,
284 r"
285fn foo() {
286 let a$0 = { 10 + 1 };
287 a + 1;
288 if a > 10 {
289 }
290
291 while a > 10 {
292
293 }
294 let b = a * 10;
295 bar(a);
296}",
297 r"
298fn foo() {
299 { 10 + 1 } + 1;
300 if { 10 + 1 } > 10 {
301 }
302
303 while { 10 + 1 } > 10 {
304
305 }
306 let b = { 10 + 1 } * 10;
307 bar({ 10 + 1 });
308}",
309 );
310 }
311
312 #[test]
313 fn test_inline_let_bind_paren_expr() {
314 check_assist(
315 inline_local_variable,
316 r"
317fn foo() {
318 let a$0 = ( 10 + 1 );
319 a + 1;
320 if a > 10 {
321 }
322
323 while a > 10 {
324
325 }
326 let b = a * 10;
327 bar(a);
328}",
329 r"
330fn foo() {
331 ( 10 + 1 ) + 1;
332 if ( 10 + 1 ) > 10 {
333 }
334
335 while ( 10 + 1 ) > 10 {
336
337 }
338 let b = ( 10 + 1 ) * 10;
339 bar(( 10 + 1 ));
340}",
341 );
342 }
343
344 #[test]
345 fn test_not_inline_mut_variable() {
346 mark::check!(test_not_inline_mut_variable);
347 check_assist_not_applicable(
348 inline_local_variable,
349 r"
350fn foo() {
351 let mut a$0 = 1 + 1;
352 a + 1;
353}",
354 );
355 }
356
357 #[test]
358 fn test_call_expr() {
359 check_assist(
360 inline_local_variable,
361 r"
362fn foo() {
363 let a$0 = bar(10 + 1);
364 let b = a * 10;
365 let c = a as usize;
366}",
367 r"
368fn foo() {
369 let b = bar(10 + 1) * 10;
370 let c = bar(10 + 1) as usize;
371}",
372 );
373 }
374
375 #[test]
376 fn test_index_expr() {
377 check_assist(
378 inline_local_variable,
379 r"
380fn foo() {
381 let x = vec![1, 2, 3];
382 let a$0 = x[0];
383 let b = a * 10;
384 let c = a as usize;
385}",
386 r"
387fn foo() {
388 let x = vec![1, 2, 3];
389 let b = x[0] * 10;
390 let c = x[0] as usize;
391}",
392 );
393 }
394
395 #[test]
396 fn test_method_call_expr() {
397 check_assist(
398 inline_local_variable,
399 r"
400fn foo() {
401 let bar = vec![1];
402 let a$0 = bar.len();
403 let b = a * 10;
404 let c = a as usize;
405}",
406 r"
407fn foo() {
408 let bar = vec![1];
409 let b = bar.len() * 10;
410 let c = bar.len() as usize;
411}",
412 );
413 }
414
415 #[test]
416 fn test_field_expr() {
417 check_assist(
418 inline_local_variable,
419 r"
420struct Bar {
421 foo: usize
422}
423
424fn foo() {
425 let bar = Bar { foo: 1 };
426 let a$0 = bar.foo;
427 let b = a * 10;
428 let c = a as usize;
429}",
430 r"
431struct Bar {
432 foo: usize
433}
434
435fn foo() {
436 let bar = Bar { foo: 1 };
437 let b = bar.foo * 10;
438 let c = bar.foo as usize;
439}",
440 );
441 }
442
443 #[test]
444 fn test_try_expr() {
445 check_assist(
446 inline_local_variable,
447 r"
448fn foo() -> Option<usize> {
449 let bar = Some(1);
450 let a$0 = bar?;
451 let b = a * 10;
452 let c = a as usize;
453 None
454}",
455 r"
456fn foo() -> Option<usize> {
457 let bar = Some(1);
458 let b = bar? * 10;
459 let c = bar? as usize;
460 None
461}",
462 );
463 }
464
465 #[test]
466 fn test_ref_expr() {
467 check_assist(
468 inline_local_variable,
469 r"
470fn foo() {
471 let bar = 10;
472 let a$0 = &bar;
473 let b = a * 10;
474}",
475 r"
476fn foo() {
477 let bar = 10;
478 let b = &bar * 10;
479}",
480 );
481 }
482
483 #[test]
484 fn test_tuple_expr() {
485 check_assist(
486 inline_local_variable,
487 r"
488fn foo() {
489 let a$0 = (10, 20);
490 let b = a[0];
491}",
492 r"
493fn foo() {
494 let b = (10, 20)[0];
495}",
496 );
497 }
498
499 #[test]
500 fn test_array_expr() {
501 check_assist(
502 inline_local_variable,
503 r"
504fn foo() {
505 let a$0 = [1, 2, 3];
506 let b = a.len();
507}",
508 r"
509fn foo() {
510 let b = [1, 2, 3].len();
511}",
512 );
513 }
514
515 #[test]
516 fn test_paren() {
517 check_assist(
518 inline_local_variable,
519 r"
520fn foo() {
521 let a$0 = (10 + 20);
522 let b = a * 10;
523 let c = a as usize;
524}",
525 r"
526fn foo() {
527 let b = (10 + 20) * 10;
528 let c = (10 + 20) as usize;
529}",
530 );
531 }
532
533 #[test]
534 fn test_path_expr() {
535 check_assist(
536 inline_local_variable,
537 r"
538fn foo() {
539 let d = 10;
540 let a$0 = d;
541 let b = a * 10;
542 let c = a as usize;
543}",
544 r"
545fn foo() {
546 let d = 10;
547 let b = d * 10;
548 let c = d as usize;
549}",
550 );
551 }
552
553 #[test]
554 fn test_block_expr() {
555 check_assist(
556 inline_local_variable,
557 r"
558fn foo() {
559 let a$0 = { 10 };
560 let b = a * 10;
561 let c = a as usize;
562}",
563 r"
564fn foo() {
565 let b = { 10 } * 10;
566 let c = { 10 } as usize;
567}",
568 );
569 }
570
571 #[test]
572 fn test_used_in_different_expr1() {
573 check_assist(
574 inline_local_variable,
575 r"
576fn foo() {
577 let a$0 = 10 + 20;
578 let b = a * 10;
579 let c = (a, 20);
580 let d = [a, 10];
581 let e = (a);
582}",
583 r"
584fn foo() {
585 let b = (10 + 20) * 10;
586 let c = (10 + 20, 20);
587 let d = [10 + 20, 10];
588 let e = (10 + 20);
589}",
590 );
591 }
592
593 #[test]
594 fn test_used_in_for_expr() {
595 check_assist(
596 inline_local_variable,
597 r"
598fn foo() {
599 let a$0 = vec![10, 20];
600 for i in a {}
601}",
602 r"
603fn foo() {
604 for i in vec![10, 20] {}
605}",
606 );
607 }
608
609 #[test]
610 fn test_used_in_while_expr() {
611 check_assist(
612 inline_local_variable,
613 r"
614fn foo() {
615 let a$0 = 1 > 0;
616 while a {}
617}",
618 r"
619fn foo() {
620 while 1 > 0 {}
621}",
622 );
623 }
624
625 #[test]
626 fn test_used_in_break_expr() {
627 check_assist(
628 inline_local_variable,
629 r"
630fn foo() {
631 let a$0 = 1 + 1;
632 loop {
633 break a;
634 }
635}",
636 r"
637fn foo() {
638 loop {
639 break 1 + 1;
640 }
641}",
642 );
643 }
644
645 #[test]
646 fn test_used_in_return_expr() {
647 check_assist(
648 inline_local_variable,
649 r"
650fn foo() {
651 let a$0 = 1 > 0;
652 return a;
653}",
654 r"
655fn foo() {
656 return 1 > 0;
657}",
658 );
659 }
660
661 #[test]
662 fn test_used_in_match_expr() {
663 check_assist(
664 inline_local_variable,
665 r"
666fn foo() {
667 let a$0 = 1 > 0;
668 match a {}
669}",
670 r"
671fn foo() {
672 match 1 > 0 {}
673}",
674 );
675 }
676
677 #[test]
678 fn inline_field_shorthand() {
679 mark::check!(inline_field_shorthand);
680 check_assist(
681 inline_local_variable,
682 r"
683struct S { foo: i32}
684fn main() {
685 let $0foo = 92;
686 S { foo }
687}
688",
689 r"
690struct S { foo: i32}
691fn main() {
692 S { foo: 92 }
693}
694",
695 );
696 }
697
698 #[test]
699 fn test_not_applicable_if_variable_unused() {
700 mark::check!(test_not_applicable_if_variable_unused);
701 check_assist_not_applicable(
702 inline_local_variable,
703 r"
704fn foo() {
705 let $0a = 0;
706}
707 ",
708 )
709 }
710
711 #[test]
712 fn not_applicable_outside_of_bind_pat() {
713 mark::check!(not_applicable_outside_of_bind_pat);
714 check_assist_not_applicable(
715 inline_local_variable,
716 r"
717fn main() {
718 let x = $01 + 2;
719 x * 4;
720}
721",
722 )
723 }
724}