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