]> git.proxmox.com Git - rustc.git/blob - src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_tuple_binding.rs
New upstream version 1.64.0+dfsg1
[rustc.git] / src / tools / rust-analyzer / crates / ide-assists / src / handlers / destructure_tuple_binding.rs
1 use ide_db::{
2 assists::{AssistId, AssistKind},
3 defs::Definition,
4 search::{FileReference, SearchScope, UsageSearchResult},
5 };
6 use syntax::{
7 ast::{self, AstNode, FieldExpr, HasName, IdentPat, MethodCallExpr},
8 TextRange,
9 };
10
11 use crate::assist_context::{AssistBuilder, AssistContext, Assists};
12
13 // Assist: destructure_tuple_binding
14 //
15 // Destructures a tuple binding in place.
16 //
17 // ```
18 // fn main() {
19 // let $0t = (1,2);
20 // let v = t.0;
21 // }
22 // ```
23 // ->
24 // ```
25 // fn main() {
26 // let ($0_0, _1) = (1,2);
27 // let v = _0;
28 // }
29 // ```
30 pub(crate) fn destructure_tuple_binding(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
31 destructure_tuple_binding_impl(acc, ctx, false)
32 }
33
34 // And when `with_sub_pattern` enabled (currently disabled):
35 // Assist: destructure_tuple_binding_in_sub_pattern
36 //
37 // Destructures tuple items in sub-pattern (after `@`).
38 //
39 // ```
40 // fn main() {
41 // let $0t = (1,2);
42 // let v = t.0;
43 // }
44 // ```
45 // ->
46 // ```
47 // fn main() {
48 // let t @ ($0_0, _1) = (1,2);
49 // let v = _0;
50 // }
51 // ```
52 pub(crate) fn destructure_tuple_binding_impl(
53 acc: &mut Assists,
54 ctx: &AssistContext<'_>,
55 with_sub_pattern: bool,
56 ) -> Option<()> {
57 let ident_pat = ctx.find_node_at_offset::<ast::IdentPat>()?;
58 let data = collect_data(ident_pat, ctx)?;
59
60 if with_sub_pattern {
61 acc.add(
62 AssistId("destructure_tuple_binding_in_sub_pattern", AssistKind::RefactorRewrite),
63 "Destructure tuple in sub-pattern",
64 data.range,
65 |builder| {
66 edit_tuple_assignment(ctx, builder, &data, true);
67 edit_tuple_usages(&data, builder, ctx, true);
68 },
69 );
70 }
71
72 acc.add(
73 AssistId("destructure_tuple_binding", AssistKind::RefactorRewrite),
74 if with_sub_pattern { "Destructure tuple in place" } else { "Destructure tuple" },
75 data.range,
76 |builder| {
77 edit_tuple_assignment(ctx, builder, &data, false);
78 edit_tuple_usages(&data, builder, ctx, false);
79 },
80 );
81
82 Some(())
83 }
84
85 fn collect_data(ident_pat: IdentPat, ctx: &AssistContext<'_>) -> Option<TupleData> {
86 if ident_pat.at_token().is_some() {
87 // Cannot destructure pattern with sub-pattern:
88 // Only IdentPat can have sub-pattern,
89 // but not TuplePat (`(a,b)`).
90 cov_mark::hit!(destructure_tuple_subpattern);
91 return None;
92 }
93
94 let ty = ctx.sema.type_of_pat(&ident_pat.clone().into())?.adjusted();
95 let ref_type = if ty.is_mutable_reference() {
96 Some(RefType::Mutable)
97 } else if ty.is_reference() {
98 Some(RefType::ReadOnly)
99 } else {
100 None
101 };
102 // might be reference
103 let ty = ty.strip_references();
104 // must be tuple
105 let field_types = ty.tuple_fields(ctx.db());
106 if field_types.is_empty() {
107 cov_mark::hit!(destructure_tuple_no_tuple);
108 return None;
109 }
110
111 let name = ident_pat.name()?.to_string();
112 let range = ident_pat.syntax().text_range();
113
114 let usages = ctx.sema.to_def(&ident_pat).map(|def| {
115 Definition::Local(def)
116 .usages(&ctx.sema)
117 .in_scope(SearchScope::single_file(ctx.file_id()))
118 .all()
119 });
120
121 let field_names = (0..field_types.len())
122 .map(|i| generate_name(ctx, i, &name, &ident_pat, &usages))
123 .collect::<Vec<_>>();
124
125 Some(TupleData { ident_pat, range, ref_type, field_names, usages })
126 }
127
128 fn generate_name(
129 _ctx: &AssistContext<'_>,
130 index: usize,
131 _tuple_name: &str,
132 _ident_pat: &IdentPat,
133 _usages: &Option<UsageSearchResult>,
134 ) -> String {
135 // FIXME: detect if name already used
136 format!("_{}", index)
137 }
138
139 enum RefType {
140 ReadOnly,
141 Mutable,
142 }
143 struct TupleData {
144 ident_pat: IdentPat,
145 // name: String,
146 range: TextRange,
147 ref_type: Option<RefType>,
148 field_names: Vec<String>,
149 // field_types: Vec<Type>,
150 usages: Option<UsageSearchResult>,
151 }
152 fn edit_tuple_assignment(
153 ctx: &AssistContext<'_>,
154 builder: &mut AssistBuilder,
155 data: &TupleData,
156 in_sub_pattern: bool,
157 ) {
158 let tuple_pat = {
159 let original = &data.ident_pat;
160 let is_ref = original.ref_token().is_some();
161 let is_mut = original.mut_token().is_some();
162 let fields = data.field_names.iter().map(|name| {
163 ast::Pat::from(ast::make::ident_pat(is_ref, is_mut, ast::make::name(name)))
164 });
165 ast::make::tuple_pat(fields)
166 };
167
168 let add_cursor = |text: &str| {
169 // place cursor on first tuple item
170 let first_tuple = &data.field_names[0];
171 text.replacen(first_tuple, &format!("$0{}", first_tuple), 1)
172 };
173
174 // with sub_pattern: keep original tuple and add subpattern: `tup @ (_0, _1)`
175 if in_sub_pattern {
176 let text = format!(" @ {}", tuple_pat);
177 match ctx.config.snippet_cap {
178 Some(cap) => {
179 let snip = add_cursor(&text);
180 builder.insert_snippet(cap, data.range.end(), snip);
181 }
182 None => builder.insert(data.range.end(), text),
183 };
184 } else {
185 let text = tuple_pat.to_string();
186 match ctx.config.snippet_cap {
187 Some(cap) => {
188 let snip = add_cursor(&text);
189 builder.replace_snippet(cap, data.range, snip);
190 }
191 None => builder.replace(data.range, text),
192 };
193 }
194 }
195
196 fn edit_tuple_usages(
197 data: &TupleData,
198 builder: &mut AssistBuilder,
199 ctx: &AssistContext<'_>,
200 in_sub_pattern: bool,
201 ) {
202 if let Some(usages) = data.usages.as_ref() {
203 for (file_id, refs) in usages.iter() {
204 builder.edit_file(*file_id);
205
206 for r in refs {
207 edit_tuple_usage(ctx, builder, r, data, in_sub_pattern);
208 }
209 }
210 }
211 }
212 fn edit_tuple_usage(
213 ctx: &AssistContext<'_>,
214 builder: &mut AssistBuilder,
215 usage: &FileReference,
216 data: &TupleData,
217 in_sub_pattern: bool,
218 ) {
219 match detect_tuple_index(usage, data) {
220 Some(index) => edit_tuple_field_usage(ctx, builder, data, index),
221 None => {
222 if in_sub_pattern {
223 cov_mark::hit!(destructure_tuple_call_with_subpattern);
224 return;
225 }
226
227 // no index access -> make invalid -> requires handling by user
228 // -> put usage in block comment
229 //
230 // Note: For macro invocations this might result in still valid code:
231 // When a macro accepts the tuple as argument, as well as no arguments at all,
232 // uncommenting the tuple still leaves the macro call working (see `tests::in_macro_call::empty_macro`).
233 // But this is an unlikely case. Usually the resulting macro call will become erroneous.
234 builder.insert(usage.range.start(), "/*");
235 builder.insert(usage.range.end(), "*/");
236 }
237 }
238 }
239
240 fn edit_tuple_field_usage(
241 ctx: &AssistContext<'_>,
242 builder: &mut AssistBuilder,
243 data: &TupleData,
244 index: TupleIndex,
245 ) {
246 let field_name = &data.field_names[index.index];
247
248 if data.ref_type.is_some() {
249 let ref_data = handle_ref_field_usage(ctx, &index.field_expr);
250 builder.replace(ref_data.range, ref_data.format(field_name));
251 } else {
252 builder.replace(index.range, field_name);
253 }
254 }
255 struct TupleIndex {
256 index: usize,
257 range: TextRange,
258 field_expr: FieldExpr,
259 }
260 fn detect_tuple_index(usage: &FileReference, data: &TupleData) -> Option<TupleIndex> {
261 // usage is IDENT
262 // IDENT
263 // NAME_REF
264 // PATH_SEGMENT
265 // PATH
266 // PATH_EXPR
267 // PAREN_EXRP*
268 // FIELD_EXPR
269
270 let node = usage
271 .name
272 .syntax()
273 .ancestors()
274 .skip_while(|s| !ast::PathExpr::can_cast(s.kind()))
275 .skip(1) // PATH_EXPR
276 .find(|s| !ast::ParenExpr::can_cast(s.kind()))?; // skip parentheses
277
278 if let Some(field_expr) = ast::FieldExpr::cast(node) {
279 let idx = field_expr.name_ref()?.as_tuple_field()?;
280 if idx < data.field_names.len() {
281 // special case: in macro call -> range of `field_expr` in applied macro, NOT range in actual file!
282 if field_expr.syntax().ancestors().any(|a| ast::MacroStmts::can_cast(a.kind())) {
283 cov_mark::hit!(destructure_tuple_macro_call);
284
285 // issue: cannot differentiate between tuple index passed into macro or tuple index as result of macro:
286 // ```rust
287 // macro_rules! m {
288 // ($t1:expr, $t2:expr) => { $t1; $t2.0 }
289 // }
290 // let t = (1,2);
291 // m!(t.0, t)
292 // ```
293 // -> 2 tuple index usages detected!
294 //
295 // -> only handle `t`
296 return None;
297 }
298
299 Some(TupleIndex { index: idx, range: field_expr.syntax().text_range(), field_expr })
300 } else {
301 // tuple index out of range
302 None
303 }
304 } else {
305 None
306 }
307 }
308
309 struct RefData {
310 range: TextRange,
311 needs_deref: bool,
312 needs_parentheses: bool,
313 }
314 impl RefData {
315 fn format(&self, field_name: &str) -> String {
316 match (self.needs_deref, self.needs_parentheses) {
317 (true, true) => format!("(*{})", field_name),
318 (true, false) => format!("*{}", field_name),
319 (false, true) => format!("({})", field_name),
320 (false, false) => field_name.to_string(),
321 }
322 }
323 }
324 fn handle_ref_field_usage(ctx: &AssistContext<'_>, field_expr: &FieldExpr) -> RefData {
325 let s = field_expr.syntax();
326 let mut ref_data =
327 RefData { range: s.text_range(), needs_deref: true, needs_parentheses: true };
328
329 let parent = match s.parent().map(ast::Expr::cast) {
330 Some(Some(parent)) => parent,
331 Some(None) => {
332 ref_data.needs_parentheses = false;
333 return ref_data;
334 }
335 None => return ref_data,
336 };
337
338 match parent {
339 ast::Expr::ParenExpr(it) => {
340 // already parens in place -> don't replace
341 ref_data.needs_parentheses = false;
342 // there might be a ref outside: `&(t.0)` -> can be removed
343 if let Some(it) = it.syntax().parent().and_then(ast::RefExpr::cast) {
344 ref_data.needs_deref = false;
345 ref_data.range = it.syntax().text_range();
346 }
347 }
348 ast::Expr::RefExpr(it) => {
349 // `&*` -> cancel each other out
350 ref_data.needs_deref = false;
351 ref_data.needs_parentheses = false;
352 // might be surrounded by parens -> can be removed too
353 match it.syntax().parent().and_then(ast::ParenExpr::cast) {
354 Some(parent) => ref_data.range = parent.syntax().text_range(),
355 None => ref_data.range = it.syntax().text_range(),
356 };
357 }
358 // higher precedence than deref `*`
359 // https://doc.rust-lang.org/reference/expressions.html#expression-precedence
360 // -> requires parentheses
361 ast::Expr::PathExpr(_it) => {}
362 ast::Expr::MethodCallExpr(it) => {
363 // `field_expr` is `self_param` (otherwise it would be in `ArgList`)
364
365 // test if there's already auto-ref in place (`value` -> `&value`)
366 // -> no method accepting `self`, but `&self` -> no need for deref
367 //
368 // other combinations (`&value` -> `value`, `&&value` -> `&value`, `&value` -> `&&value`) might or might not be able to auto-ref/deref,
369 // but there might be trait implementations an added `&` might resolve to
370 // -> ONLY handle auto-ref from `value` to `&value`
371 fn is_auto_ref(ctx: &AssistContext<'_>, call_expr: &MethodCallExpr) -> bool {
372 fn impl_(ctx: &AssistContext<'_>, call_expr: &MethodCallExpr) -> Option<bool> {
373 let rec = call_expr.receiver()?;
374 let rec_ty = ctx.sema.type_of_expr(&rec)?.original();
375 // input must be actual value
376 if rec_ty.is_reference() {
377 return Some(false);
378 }
379
380 // doesn't resolve trait impl
381 let f = ctx.sema.resolve_method_call(call_expr)?;
382 let self_param = f.self_param(ctx.db())?;
383 // self must be ref
384 match self_param.access(ctx.db()) {
385 hir::Access::Shared | hir::Access::Exclusive => Some(true),
386 hir::Access::Owned => Some(false),
387 }
388 }
389 impl_(ctx, call_expr).unwrap_or(false)
390 }
391
392 if is_auto_ref(ctx, &it) {
393 ref_data.needs_deref = false;
394 ref_data.needs_parentheses = false;
395 }
396 }
397 ast::Expr::FieldExpr(_it) => {
398 // `t.0.my_field`
399 ref_data.needs_deref = false;
400 ref_data.needs_parentheses = false;
401 }
402 ast::Expr::IndexExpr(_it) => {
403 // `t.0[1]`
404 ref_data.needs_deref = false;
405 ref_data.needs_parentheses = false;
406 }
407 ast::Expr::TryExpr(_it) => {
408 // `t.0?`
409 // requires deref and parens: `(*_0)`
410 }
411 // lower precedence than deref `*` -> no parens
412 _ => {
413 ref_data.needs_parentheses = false;
414 }
415 };
416
417 ref_data
418 }
419
420 #[cfg(test)]
421 mod tests {
422 use super::*;
423
424 use crate::tests::{check_assist, check_assist_not_applicable};
425
426 // Tests for direct tuple destructure:
427 // `let $0t = (1,2);` -> `let (_0, _1) = (1,2);`
428
429 fn assist(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
430 destructure_tuple_binding_impl(acc, ctx, false)
431 }
432
433 #[test]
434 fn dont_trigger_on_unit() {
435 cov_mark::check!(destructure_tuple_no_tuple);
436 check_assist_not_applicable(
437 assist,
438 r#"
439 fn main() {
440 let $0v = ();
441 }
442 "#,
443 )
444 }
445 #[test]
446 fn dont_trigger_on_number() {
447 cov_mark::check!(destructure_tuple_no_tuple);
448 check_assist_not_applicable(
449 assist,
450 r#"
451 fn main() {
452 let $0v = 32;
453 }
454 "#,
455 )
456 }
457
458 #[test]
459 fn destructure_3_tuple() {
460 check_assist(
461 assist,
462 r#"
463 fn main() {
464 let $0tup = (1,2,3);
465 }
466 "#,
467 r#"
468 fn main() {
469 let ($0_0, _1, _2) = (1,2,3);
470 }
471 "#,
472 )
473 }
474 #[test]
475 fn destructure_2_tuple() {
476 check_assist(
477 assist,
478 r#"
479 fn main() {
480 let $0tup = (1,2);
481 }
482 "#,
483 r#"
484 fn main() {
485 let ($0_0, _1) = (1,2);
486 }
487 "#,
488 )
489 }
490 #[test]
491 fn replace_indices() {
492 check_assist(
493 assist,
494 r#"
495 fn main() {
496 let $0tup = (1,2,3);
497 let v1 = tup.0;
498 let v2 = tup.1;
499 let v3 = tup.2;
500 }
501 "#,
502 r#"
503 fn main() {
504 let ($0_0, _1, _2) = (1,2,3);
505 let v1 = _0;
506 let v2 = _1;
507 let v3 = _2;
508 }
509 "#,
510 )
511 }
512
513 #[test]
514 fn replace_usage_in_parentheses() {
515 check_assist(
516 assist,
517 r#"
518 fn main() {
519 let $0tup = (1,2,3);
520 let a = (tup).1;
521 let b = ((tup)).1;
522 }
523 "#,
524 r#"
525 fn main() {
526 let ($0_0, _1, _2) = (1,2,3);
527 let a = _1;
528 let b = _1;
529 }
530 "#,
531 )
532 }
533
534 #[test]
535 fn handle_function_call() {
536 check_assist(
537 assist,
538 r#"
539 fn main() {
540 let $0tup = (1,2);
541 let v = tup.into();
542 }
543 "#,
544 r#"
545 fn main() {
546 let ($0_0, _1) = (1,2);
547 let v = /*tup*/.into();
548 }
549 "#,
550 )
551 }
552
553 #[test]
554 fn handle_invalid_index() {
555 check_assist(
556 assist,
557 r#"
558 fn main() {
559 let $0tup = (1,2);
560 let v = tup.3;
561 }
562 "#,
563 r#"
564 fn main() {
565 let ($0_0, _1) = (1,2);
566 let v = /*tup*/.3;
567 }
568 "#,
569 )
570 }
571
572 #[test]
573 fn dont_replace_variable_with_same_name_as_tuple() {
574 check_assist(
575 assist,
576 r#"
577 fn main() {
578 let tup = (1,2);
579 let v = tup.1;
580 let $0tup = (1,2,3);
581 let v = tup.1;
582 let tup = (1,2,3);
583 let v = tup.1;
584 }
585 "#,
586 r#"
587 fn main() {
588 let tup = (1,2);
589 let v = tup.1;
590 let ($0_0, _1, _2) = (1,2,3);
591 let v = _1;
592 let tup = (1,2,3);
593 let v = tup.1;
594 }
595 "#,
596 )
597 }
598
599 #[test]
600 fn keep_function_call_in_tuple_item() {
601 check_assist(
602 assist,
603 r#"
604 fn main() {
605 let $0t = ("3.14", 0);
606 let pi: f32 = t.0.parse().unwrap_or(0.0);
607 }
608 "#,
609 r#"
610 fn main() {
611 let ($0_0, _1) = ("3.14", 0);
612 let pi: f32 = _0.parse().unwrap_or(0.0);
613 }
614 "#,
615 )
616 }
617
618 #[test]
619 fn keep_type() {
620 check_assist(
621 assist,
622 r#"
623 fn main() {
624 let $0t: (usize, i32) = (1,2);
625 }
626 "#,
627 r#"
628 fn main() {
629 let ($0_0, _1): (usize, i32) = (1,2);
630 }
631 "#,
632 )
633 }
634
635 #[test]
636 fn destructure_reference() {
637 check_assist(
638 assist,
639 r#"
640 fn main() {
641 let t = (1,2);
642 let $0t = &t;
643 let v = t.0;
644 }
645 "#,
646 r#"
647 fn main() {
648 let t = (1,2);
649 let ($0_0, _1) = &t;
650 let v = *_0;
651 }
652 "#,
653 )
654 }
655
656 #[test]
657 fn destructure_multiple_reference() {
658 check_assist(
659 assist,
660 r#"
661 fn main() {
662 let t = (1,2);
663 let $0t = &&t;
664 let v = t.0;
665 }
666 "#,
667 r#"
668 fn main() {
669 let t = (1,2);
670 let ($0_0, _1) = &&t;
671 let v = *_0;
672 }
673 "#,
674 )
675 }
676
677 #[test]
678 fn keep_reference() {
679 check_assist(
680 assist,
681 r#"
682 fn foo(t: &(usize, usize)) -> usize {
683 match t {
684 &$0t => t.0
685 }
686 }
687 "#,
688 r#"
689 fn foo(t: &(usize, usize)) -> usize {
690 match t {
691 &($0_0, _1) => _0
692 }
693 }
694 "#,
695 )
696 }
697
698 #[test]
699 fn with_ref() {
700 check_assist(
701 assist,
702 r#"
703 fn main() {
704 let ref $0t = (1,2);
705 let v = t.0;
706 }
707 "#,
708 r#"
709 fn main() {
710 let (ref $0_0, ref _1) = (1,2);
711 let v = *_0;
712 }
713 "#,
714 )
715 }
716
717 #[test]
718 fn with_mut() {
719 check_assist(
720 assist,
721 r#"
722 fn main() {
723 let mut $0t = (1,2);
724 t.0 = 42;
725 let v = t.0;
726 }
727 "#,
728 r#"
729 fn main() {
730 let (mut $0_0, mut _1) = (1,2);
731 _0 = 42;
732 let v = _0;
733 }
734 "#,
735 )
736 }
737
738 #[test]
739 fn with_ref_mut() {
740 check_assist(
741 assist,
742 r#"
743 fn main() {
744 let ref mut $0t = (1,2);
745 t.0 = 42;
746 let v = t.0;
747 }
748 "#,
749 r#"
750 fn main() {
751 let (ref mut $0_0, ref mut _1) = (1,2);
752 *_0 = 42;
753 let v = *_0;
754 }
755 "#,
756 )
757 }
758
759 #[test]
760 fn dont_trigger_for_non_tuple_reference() {
761 check_assist_not_applicable(
762 assist,
763 r#"
764 fn main() {
765 let v = 42;
766 let $0v = &42;
767 }
768 "#,
769 )
770 }
771
772 #[test]
773 fn dont_trigger_on_static_tuple() {
774 check_assist_not_applicable(
775 assist,
776 r#"
777 static $0TUP: (usize, usize) = (1,2);
778 "#,
779 )
780 }
781
782 #[test]
783 fn dont_trigger_on_wildcard() {
784 check_assist_not_applicable(
785 assist,
786 r#"
787 fn main() {
788 let $0_ = (1,2);
789 }
790 "#,
791 )
792 }
793
794 #[test]
795 fn dont_trigger_in_struct() {
796 check_assist_not_applicable(
797 assist,
798 r#"
799 struct S {
800 $0tup: (usize, usize),
801 }
802 "#,
803 )
804 }
805
806 #[test]
807 fn dont_trigger_in_struct_creation() {
808 check_assist_not_applicable(
809 assist,
810 r#"
811 struct S {
812 tup: (usize, usize),
813 }
814 fn main() {
815 let s = S {
816 $0tup: (1,2),
817 };
818 }
819 "#,
820 )
821 }
822
823 #[test]
824 fn dont_trigger_on_tuple_struct() {
825 check_assist_not_applicable(
826 assist,
827 r#"
828 struct S(usize, usize);
829 fn main() {
830 let $0s = S(1,2);
831 }
832 "#,
833 )
834 }
835
836 #[test]
837 fn dont_trigger_when_subpattern_exists() {
838 // sub-pattern is only allowed with IdentPat (name), not other patterns (like TuplePat)
839 cov_mark::check!(destructure_tuple_subpattern);
840 check_assist_not_applicable(
841 assist,
842 r#"
843 fn sum(t: (usize, usize)) -> usize {
844 match t {
845 $0t @ (1..=3,1..=3) => t.0 + t.1,
846 _ => 0,
847 }
848 }
849 "#,
850 )
851 }
852
853 #[test]
854 fn in_subpattern() {
855 check_assist(
856 assist,
857 r#"
858 fn main() {
859 let t1 @ (_, $0t2) = (1, (2,3));
860 let v = t1.0 + t2.0 + t2.1;
861 }
862 "#,
863 r#"
864 fn main() {
865 let t1 @ (_, ($0_0, _1)) = (1, (2,3));
866 let v = t1.0 + _0 + _1;
867 }
868 "#,
869 )
870 }
871
872 #[test]
873 fn in_nested_tuple() {
874 check_assist(
875 assist,
876 r#"
877 fn main() {
878 let ($0tup, v) = ((1,2),3);
879 }
880 "#,
881 r#"
882 fn main() {
883 let (($0_0, _1), v) = ((1,2),3);
884 }
885 "#,
886 )
887 }
888
889 #[test]
890 fn in_closure() {
891 check_assist(
892 assist,
893 r#"
894 fn main() {
895 let $0tup = (1,2,3);
896 let f = |v| v + tup.1;
897 }
898 "#,
899 r#"
900 fn main() {
901 let ($0_0, _1, _2) = (1,2,3);
902 let f = |v| v + _1;
903 }
904 "#,
905 )
906 }
907
908 #[test]
909 fn in_closure_args() {
910 check_assist(
911 assist,
912 r#"
913 fn main() {
914 let f = |$0t| t.0 + t.1;
915 let v = f((1,2));
916 }
917 "#,
918 r#"
919 fn main() {
920 let f = |($0_0, _1)| _0 + _1;
921 let v = f((1,2));
922 }
923 "#,
924 )
925 }
926
927 #[test]
928 fn in_function_args() {
929 check_assist(
930 assist,
931 r#"
932 fn f($0t: (usize, usize)) {
933 let v = t.0;
934 }
935 "#,
936 r#"
937 fn f(($0_0, _1): (usize, usize)) {
938 let v = _0;
939 }
940 "#,
941 )
942 }
943
944 #[test]
945 fn in_if_let() {
946 check_assist(
947 assist,
948 r#"
949 fn f(t: (usize, usize)) {
950 if let $0t = t {
951 let v = t.0;
952 }
953 }
954 "#,
955 r#"
956 fn f(t: (usize, usize)) {
957 if let ($0_0, _1) = t {
958 let v = _0;
959 }
960 }
961 "#,
962 )
963 }
964 #[test]
965 fn in_if_let_option() {
966 check_assist(
967 assist,
968 r#"
969 //- minicore: option
970 fn f(o: Option<(usize, usize)>) {
971 if let Some($0t) = o {
972 let v = t.0;
973 }
974 }
975 "#,
976 r#"
977 fn f(o: Option<(usize, usize)>) {
978 if let Some(($0_0, _1)) = o {
979 let v = _0;
980 }
981 }
982 "#,
983 )
984 }
985
986 #[test]
987 fn in_match() {
988 check_assist(
989 assist,
990 r#"
991 fn main() {
992 match (1,2) {
993 $0t => t.1,
994 };
995 }
996 "#,
997 r#"
998 fn main() {
999 match (1,2) {
1000 ($0_0, _1) => _1,
1001 };
1002 }
1003 "#,
1004 )
1005 }
1006 #[test]
1007 fn in_match_option() {
1008 check_assist(
1009 assist,
1010 r#"
1011 //- minicore: option
1012 fn main() {
1013 match Some((1,2)) {
1014 Some($0t) => t.1,
1015 _ => 0,
1016 };
1017 }
1018 "#,
1019 r#"
1020 fn main() {
1021 match Some((1,2)) {
1022 Some(($0_0, _1)) => _1,
1023 _ => 0,
1024 };
1025 }
1026 "#,
1027 )
1028 }
1029 #[test]
1030 fn in_match_reference_option() {
1031 check_assist(
1032 assist,
1033 r#"
1034 //- minicore: option
1035 fn main() {
1036 let t = (1,2);
1037 match Some(&t) {
1038 Some($0t) => t.1,
1039 _ => 0,
1040 };
1041 }
1042 "#,
1043 r#"
1044 fn main() {
1045 let t = (1,2);
1046 match Some(&t) {
1047 Some(($0_0, _1)) => *_1,
1048 _ => 0,
1049 };
1050 }
1051 "#,
1052 )
1053 }
1054
1055 #[test]
1056 fn in_for() {
1057 check_assist(
1058 assist,
1059 r#"
1060 //- minicore: iterators
1061 fn main() {
1062 for $0t in core::iter::repeat((1,2)) {
1063 let v = t.1;
1064 }
1065 }
1066 "#,
1067 r#"
1068 fn main() {
1069 for ($0_0, _1) in core::iter::repeat((1,2)) {
1070 let v = _1;
1071 }
1072 }
1073 "#,
1074 )
1075 }
1076 #[test]
1077 fn in_for_nested() {
1078 check_assist(
1079 assist,
1080 r#"
1081 //- minicore: iterators
1082 fn main() {
1083 for (a, $0b) in core::iter::repeat((1,(2,3))) {
1084 let v = b.1;
1085 }
1086 }
1087 "#,
1088 r#"
1089 fn main() {
1090 for (a, ($0_0, _1)) in core::iter::repeat((1,(2,3))) {
1091 let v = _1;
1092 }
1093 }
1094 "#,
1095 )
1096 }
1097
1098 #[test]
1099 fn not_applicable_on_tuple_usage() {
1100 //Improvement: might be reasonable to allow & implement
1101 check_assist_not_applicable(
1102 assist,
1103 r#"
1104 fn main() {
1105 let t = (1,2);
1106 let v = $0t.0;
1107 }
1108 "#,
1109 )
1110 }
1111
1112 #[test]
1113 fn replace_all() {
1114 check_assist(
1115 assist,
1116 r#"
1117 fn main() {
1118 let $0t = (1,2);
1119 let v = t.1;
1120 let s = (t.0 + t.1) / 2;
1121 let f = |v| v + t.0;
1122 let r = f(t.1);
1123 let e = t == (9,0);
1124 let m =
1125 match t {
1126 (_,2) if t.0 > 2 => 1,
1127 _ => 0,
1128 };
1129 }
1130 "#,
1131 r#"
1132 fn main() {
1133 let ($0_0, _1) = (1,2);
1134 let v = _1;
1135 let s = (_0 + _1) / 2;
1136 let f = |v| v + _0;
1137 let r = f(_1);
1138 let e = /*t*/ == (9,0);
1139 let m =
1140 match /*t*/ {
1141 (_,2) if _0 > 2 => 1,
1142 _ => 0,
1143 };
1144 }
1145 "#,
1146 )
1147 }
1148
1149 #[test]
1150 fn non_trivial_tuple_assignment() {
1151 check_assist(
1152 assist,
1153 r#"
1154 fn main {
1155 let $0t =
1156 if 1 > 2 {
1157 (1,2)
1158 } else {
1159 (5,6)
1160 };
1161 let v1 = t.0;
1162 let v2 =
1163 if t.0 > t.1 {
1164 t.0 - t.1
1165 } else {
1166 t.1 - t.0
1167 };
1168 }
1169 "#,
1170 r#"
1171 fn main {
1172 let ($0_0, _1) =
1173 if 1 > 2 {
1174 (1,2)
1175 } else {
1176 (5,6)
1177 };
1178 let v1 = _0;
1179 let v2 =
1180 if _0 > _1 {
1181 _0 - _1
1182 } else {
1183 _1 - _0
1184 };
1185 }
1186 "#,
1187 )
1188 }
1189
1190 mod assist {
1191 use super::*;
1192 use crate::tests::check_assist_by_label;
1193
1194 fn assist(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
1195 destructure_tuple_binding_impl(acc, ctx, true)
1196 }
1197 fn in_place_assist(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
1198 destructure_tuple_binding_impl(acc, ctx, false)
1199 }
1200
1201 pub(crate) fn check_in_place_assist(ra_fixture_before: &str, ra_fixture_after: &str) {
1202 check_assist_by_label(
1203 in_place_assist,
1204 ra_fixture_before,
1205 ra_fixture_after,
1206 // "Destructure tuple in place",
1207 "Destructure tuple",
1208 );
1209 }
1210
1211 pub(crate) fn check_sub_pattern_assist(ra_fixture_before: &str, ra_fixture_after: &str) {
1212 check_assist_by_label(
1213 assist,
1214 ra_fixture_before,
1215 ra_fixture_after,
1216 "Destructure tuple in sub-pattern",
1217 );
1218 }
1219
1220 pub(crate) fn check_both_assists(
1221 ra_fixture_before: &str,
1222 ra_fixture_after_in_place: &str,
1223 ra_fixture_after_in_sub_pattern: &str,
1224 ) {
1225 check_in_place_assist(ra_fixture_before, ra_fixture_after_in_place);
1226 check_sub_pattern_assist(ra_fixture_before, ra_fixture_after_in_sub_pattern);
1227 }
1228 }
1229
1230 /// Tests for destructure of tuple in sub-pattern:
1231 /// `let $0t = (1,2);` -> `let t @ (_0, _1) = (1,2);`
1232 mod sub_pattern {
1233 use super::assist::*;
1234 use super::*;
1235 use crate::tests::check_assist_by_label;
1236
1237 #[test]
1238 fn destructure_in_sub_pattern() {
1239 check_sub_pattern_assist(
1240 r#"
1241 #![feature(bindings_after_at)]
1242
1243 fn main() {
1244 let $0t = (1,2);
1245 }
1246 "#,
1247 r#"
1248 #![feature(bindings_after_at)]
1249
1250 fn main() {
1251 let t @ ($0_0, _1) = (1,2);
1252 }
1253 "#,
1254 )
1255 }
1256
1257 #[test]
1258 fn trigger_both_destructure_tuple_assists() {
1259 fn assist(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
1260 destructure_tuple_binding_impl(acc, ctx, true)
1261 }
1262 let text = r#"
1263 fn main() {
1264 let $0t = (1,2);
1265 }
1266 "#;
1267 check_assist_by_label(
1268 assist,
1269 text,
1270 r#"
1271 fn main() {
1272 let ($0_0, _1) = (1,2);
1273 }
1274 "#,
1275 "Destructure tuple in place",
1276 );
1277 check_assist_by_label(
1278 assist,
1279 text,
1280 r#"
1281 fn main() {
1282 let t @ ($0_0, _1) = (1,2);
1283 }
1284 "#,
1285 "Destructure tuple in sub-pattern",
1286 );
1287 }
1288
1289 #[test]
1290 fn replace_indices() {
1291 check_sub_pattern_assist(
1292 r#"
1293 fn main() {
1294 let $0t = (1,2);
1295 let v1 = t.0;
1296 let v2 = t.1;
1297 }
1298 "#,
1299 r#"
1300 fn main() {
1301 let t @ ($0_0, _1) = (1,2);
1302 let v1 = _0;
1303 let v2 = _1;
1304 }
1305 "#,
1306 )
1307 }
1308
1309 #[test]
1310 fn keep_function_call() {
1311 cov_mark::check!(destructure_tuple_call_with_subpattern);
1312 check_sub_pattern_assist(
1313 r#"
1314 fn main() {
1315 let $0t = (1,2);
1316 let v = t.into();
1317 }
1318 "#,
1319 r#"
1320 fn main() {
1321 let t @ ($0_0, _1) = (1,2);
1322 let v = t.into();
1323 }
1324 "#,
1325 )
1326 }
1327
1328 #[test]
1329 fn keep_type() {
1330 check_sub_pattern_assist(
1331 r#"
1332 fn main() {
1333 let $0t: (usize, i32) = (1,2);
1334 let v = t.1;
1335 let f = t.into();
1336 }
1337 "#,
1338 r#"
1339 fn main() {
1340 let t @ ($0_0, _1): (usize, i32) = (1,2);
1341 let v = _1;
1342 let f = t.into();
1343 }
1344 "#,
1345 )
1346 }
1347
1348 #[test]
1349 fn in_function_args() {
1350 check_sub_pattern_assist(
1351 r#"
1352 fn f($0t: (usize, usize)) {
1353 let v = t.0;
1354 let f = t.into();
1355 }
1356 "#,
1357 r#"
1358 fn f(t @ ($0_0, _1): (usize, usize)) {
1359 let v = _0;
1360 let f = t.into();
1361 }
1362 "#,
1363 )
1364 }
1365
1366 #[test]
1367 fn with_ref() {
1368 check_sub_pattern_assist(
1369 r#"
1370 fn main() {
1371 let ref $0t = (1,2);
1372 let v = t.1;
1373 let f = t.into();
1374 }
1375 "#,
1376 r#"
1377 fn main() {
1378 let ref t @ (ref $0_0, ref _1) = (1,2);
1379 let v = *_1;
1380 let f = t.into();
1381 }
1382 "#,
1383 )
1384 }
1385 #[test]
1386 fn with_mut() {
1387 check_sub_pattern_assist(
1388 r#"
1389 fn main() {
1390 let mut $0t = (1,2);
1391 let v = t.1;
1392 let f = t.into();
1393 }
1394 "#,
1395 r#"
1396 fn main() {
1397 let mut t @ (mut $0_0, mut _1) = (1,2);
1398 let v = _1;
1399 let f = t.into();
1400 }
1401 "#,
1402 )
1403 }
1404 #[test]
1405 fn with_ref_mut() {
1406 check_sub_pattern_assist(
1407 r#"
1408 fn main() {
1409 let ref mut $0t = (1,2);
1410 let v = t.1;
1411 let f = t.into();
1412 }
1413 "#,
1414 r#"
1415 fn main() {
1416 let ref mut t @ (ref mut $0_0, ref mut _1) = (1,2);
1417 let v = *_1;
1418 let f = t.into();
1419 }
1420 "#,
1421 )
1422 }
1423 }
1424
1425 /// Tests for tuple usage in macro call:
1426 /// `println!("{}", t.0)`
1427 mod in_macro_call {
1428 use super::assist::*;
1429
1430 #[test]
1431 fn detect_macro_call() {
1432 cov_mark::check!(destructure_tuple_macro_call);
1433 check_in_place_assist(
1434 r#"
1435 macro_rules! m {
1436 ($e:expr) => { "foo"; $e };
1437 }
1438
1439 fn main() {
1440 let $0t = (1,2);
1441 m!(t.0);
1442 }
1443 "#,
1444 r#"
1445 macro_rules! m {
1446 ($e:expr) => { "foo"; $e };
1447 }
1448
1449 fn main() {
1450 let ($0_0, _1) = (1,2);
1451 m!(/*t*/.0);
1452 }
1453 "#,
1454 )
1455 }
1456
1457 #[test]
1458 fn tuple_usage() {
1459 check_both_assists(
1460 // leading `"foo"` to ensure `$e` doesn't start at position `0`
1461 r#"
1462 macro_rules! m {
1463 ($e:expr) => { "foo"; $e };
1464 }
1465
1466 fn main() {
1467 let $0t = (1,2);
1468 m!(t);
1469 }
1470 "#,
1471 r#"
1472 macro_rules! m {
1473 ($e:expr) => { "foo"; $e };
1474 }
1475
1476 fn main() {
1477 let ($0_0, _1) = (1,2);
1478 m!(/*t*/);
1479 }
1480 "#,
1481 r#"
1482 macro_rules! m {
1483 ($e:expr) => { "foo"; $e };
1484 }
1485
1486 fn main() {
1487 let t @ ($0_0, _1) = (1,2);
1488 m!(t);
1489 }
1490 "#,
1491 )
1492 }
1493
1494 #[test]
1495 fn tuple_function_usage() {
1496 check_both_assists(
1497 r#"
1498 macro_rules! m {
1499 ($e:expr) => { "foo"; $e };
1500 }
1501
1502 fn main() {
1503 let $0t = (1,2);
1504 m!(t.into());
1505 }
1506 "#,
1507 r#"
1508 macro_rules! m {
1509 ($e:expr) => { "foo"; $e };
1510 }
1511
1512 fn main() {
1513 let ($0_0, _1) = (1,2);
1514 m!(/*t*/.into());
1515 }
1516 "#,
1517 r#"
1518 macro_rules! m {
1519 ($e:expr) => { "foo"; $e };
1520 }
1521
1522 fn main() {
1523 let t @ ($0_0, _1) = (1,2);
1524 m!(t.into());
1525 }
1526 "#,
1527 )
1528 }
1529
1530 #[test]
1531 fn tuple_index_usage() {
1532 check_both_assists(
1533 r#"
1534 macro_rules! m {
1535 ($e:expr) => { "foo"; $e };
1536 }
1537
1538 fn main() {
1539 let $0t = (1,2);
1540 m!(t.0);
1541 }
1542 "#,
1543 // FIXME: replace `t.0` with `_0` (cannot detect range of tuple index in macro call)
1544 r#"
1545 macro_rules! m {
1546 ($e:expr) => { "foo"; $e };
1547 }
1548
1549 fn main() {
1550 let ($0_0, _1) = (1,2);
1551 m!(/*t*/.0);
1552 }
1553 "#,
1554 // FIXME: replace `t.0` with `_0`
1555 r#"
1556 macro_rules! m {
1557 ($e:expr) => { "foo"; $e };
1558 }
1559
1560 fn main() {
1561 let t @ ($0_0, _1) = (1,2);
1562 m!(t.0);
1563 }
1564 "#,
1565 )
1566 }
1567
1568 #[test]
1569 fn tuple_in_parentheses_index_usage() {
1570 check_both_assists(
1571 r#"
1572 macro_rules! m {
1573 ($e:expr) => { "foo"; $e };
1574 }
1575
1576 fn main() {
1577 let $0t = (1,2);
1578 m!((t).0);
1579 }
1580 "#,
1581 // FIXME: replace `(t).0` with `_0`
1582 r#"
1583 macro_rules! m {
1584 ($e:expr) => { "foo"; $e };
1585 }
1586
1587 fn main() {
1588 let ($0_0, _1) = (1,2);
1589 m!((/*t*/).0);
1590 }
1591 "#,
1592 // FIXME: replace `(t).0` with `_0`
1593 r#"
1594 macro_rules! m {
1595 ($e:expr) => { "foo"; $e };
1596 }
1597
1598 fn main() {
1599 let t @ ($0_0, _1) = (1,2);
1600 m!((t).0);
1601 }
1602 "#,
1603 )
1604 }
1605
1606 #[test]
1607 fn empty_macro() {
1608 check_in_place_assist(
1609 r#"
1610 macro_rules! m {
1611 () => { "foo" };
1612 ($e:expr) => { $e; "foo" };
1613 }
1614
1615 fn main() {
1616 let $0t = (1,2);
1617 m!(t);
1618 }
1619 "#,
1620 // FIXME: macro allows no arg -> is valid. But assist should result in invalid code
1621 r#"
1622 macro_rules! m {
1623 () => { "foo" };
1624 ($e:expr) => { $e; "foo" };
1625 }
1626
1627 fn main() {
1628 let ($0_0, _1) = (1,2);
1629 m!(/*t*/);
1630 }
1631 "#,
1632 )
1633 }
1634
1635 #[test]
1636 fn tuple_index_in_macro() {
1637 check_both_assists(
1638 r#"
1639 macro_rules! m {
1640 ($t:expr, $i:expr) => { $t.0 + $i };
1641 }
1642
1643 fn main() {
1644 let $0t = (1,2);
1645 m!(t, t.0);
1646 }
1647 "#,
1648 // FIXME: replace `t.0` in macro call (not IN macro) with `_0`
1649 r#"
1650 macro_rules! m {
1651 ($t:expr, $i:expr) => { $t.0 + $i };
1652 }
1653
1654 fn main() {
1655 let ($0_0, _1) = (1,2);
1656 m!(/*t*/, /*t*/.0);
1657 }
1658 "#,
1659 // FIXME: replace `t.0` in macro call with `_0`
1660 r#"
1661 macro_rules! m {
1662 ($t:expr, $i:expr) => { $t.0 + $i };
1663 }
1664
1665 fn main() {
1666 let t @ ($0_0, _1) = (1,2);
1667 m!(t, t.0);
1668 }
1669 "#,
1670 )
1671 }
1672 }
1673
1674 mod refs {
1675 use super::assist::*;
1676
1677 #[test]
1678 fn no_ref() {
1679 check_in_place_assist(
1680 r#"
1681 fn main() {
1682 let $0t = &(1,2);
1683 let v: i32 = t.0;
1684 }
1685 "#,
1686 r#"
1687 fn main() {
1688 let ($0_0, _1) = &(1,2);
1689 let v: i32 = *_0;
1690 }
1691 "#,
1692 )
1693 }
1694 #[test]
1695 fn no_ref_with_parens() {
1696 check_in_place_assist(
1697 r#"
1698 fn main() {
1699 let $0t = &(1,2);
1700 let v: i32 = (t.0);
1701 }
1702 "#,
1703 r#"
1704 fn main() {
1705 let ($0_0, _1) = &(1,2);
1706 let v: i32 = (*_0);
1707 }
1708 "#,
1709 )
1710 }
1711 #[test]
1712 fn with_ref() {
1713 check_in_place_assist(
1714 r#"
1715 fn main() {
1716 let $0t = &(1,2);
1717 let v: &i32 = &t.0;
1718 }
1719 "#,
1720 r#"
1721 fn main() {
1722 let ($0_0, _1) = &(1,2);
1723 let v: &i32 = _0;
1724 }
1725 "#,
1726 )
1727 }
1728 #[test]
1729 fn with_ref_in_parens_ref() {
1730 check_in_place_assist(
1731 r#"
1732 fn main() {
1733 let $0t = &(1,2);
1734 let v: &i32 = &(t.0);
1735 }
1736 "#,
1737 r#"
1738 fn main() {
1739 let ($0_0, _1) = &(1,2);
1740 let v: &i32 = _0;
1741 }
1742 "#,
1743 )
1744 }
1745 #[test]
1746 fn with_ref_in_ref_parens() {
1747 check_in_place_assist(
1748 r#"
1749 fn main() {
1750 let $0t = &(1,2);
1751 let v: &i32 = (&t.0);
1752 }
1753 "#,
1754 r#"
1755 fn main() {
1756 let ($0_0, _1) = &(1,2);
1757 let v: &i32 = _0;
1758 }
1759 "#,
1760 )
1761 }
1762
1763 #[test]
1764 fn deref_and_parentheses() {
1765 // Operator/Expressions with higher precedence than deref (`*`):
1766 // https://doc.rust-lang.org/reference/expressions.html#expression-precedence
1767 // * Path
1768 // * Method call
1769 // * Field expression
1770 // * Function calls, array indexing
1771 // * `?`
1772 check_in_place_assist(
1773 r#"
1774 //- minicore: option
1775 fn f1(v: i32) {}
1776 fn f2(v: &i32) {}
1777 trait T {
1778 fn do_stuff(self) {}
1779 }
1780 impl T for i32 {
1781 fn do_stuff(self) {}
1782 }
1783 impl T for &i32 {
1784 fn do_stuff(self) {}
1785 }
1786 struct S4 {
1787 value: i32,
1788 }
1789
1790 fn foo() -> Option<()> {
1791 let $0t = &(0, (1,"1"), Some(2), [3;3], S4 { value: 4 }, &5);
1792 let v: i32 = t.0; // deref, no parens
1793 let v: &i32 = &t.0; // no deref, no parens, remove `&`
1794 f1(t.0); // deref, no parens
1795 f2(&t.0); // `&*` -> cancel out -> no deref, no parens
1796 // https://github.com/rust-lang/rust-analyzer/issues/1109#issuecomment-658868639
1797 // let v: i32 = t.1.0; // no deref, no parens
1798 let v: i32 = t.4.value; // no deref, no parens
1799 t.0.do_stuff(); // deref, parens
1800 let v: i32 = t.2?; // deref, parens
1801 let v: i32 = t.3[0]; // no deref, no parens
1802 (t.0).do_stuff(); // deref, no additional parens
1803 let v: i32 = *t.5; // deref (-> 2), no parens
1804
1805 None
1806 }
1807 "#,
1808 r#"
1809 fn f1(v: i32) {}
1810 fn f2(v: &i32) {}
1811 trait T {
1812 fn do_stuff(self) {}
1813 }
1814 impl T for i32 {
1815 fn do_stuff(self) {}
1816 }
1817 impl T for &i32 {
1818 fn do_stuff(self) {}
1819 }
1820 struct S4 {
1821 value: i32,
1822 }
1823
1824 fn foo() -> Option<()> {
1825 let ($0_0, _1, _2, _3, _4, _5) = &(0, (1,"1"), Some(2), [3;3], S4 { value: 4 }, &5);
1826 let v: i32 = *_0; // deref, no parens
1827 let v: &i32 = _0; // no deref, no parens, remove `&`
1828 f1(*_0); // deref, no parens
1829 f2(_0); // `&*` -> cancel out -> no deref, no parens
1830 // https://github.com/rust-lang/rust-analyzer/issues/1109#issuecomment-658868639
1831 // let v: i32 = t.1.0; // no deref, no parens
1832 let v: i32 = _4.value; // no deref, no parens
1833 (*_0).do_stuff(); // deref, parens
1834 let v: i32 = (*_2)?; // deref, parens
1835 let v: i32 = _3[0]; // no deref, no parens
1836 (*_0).do_stuff(); // deref, no additional parens
1837 let v: i32 = **_5; // deref (-> 2), no parens
1838
1839 None
1840 }
1841 "#,
1842 )
1843 }
1844
1845 // ---------
1846 // auto-ref/deref
1847
1848 #[test]
1849 fn self_auto_ref_doesnt_need_deref() {
1850 check_in_place_assist(
1851 r#"
1852 #[derive(Clone, Copy)]
1853 struct S;
1854 impl S {
1855 fn f(&self) {}
1856 }
1857
1858 fn main() {
1859 let $0t = &(S,2);
1860 let s = t.0.f();
1861 }
1862 "#,
1863 r#"
1864 #[derive(Clone, Copy)]
1865 struct S;
1866 impl S {
1867 fn f(&self) {}
1868 }
1869
1870 fn main() {
1871 let ($0_0, _1) = &(S,2);
1872 let s = _0.f();
1873 }
1874 "#,
1875 )
1876 }
1877
1878 #[test]
1879 fn self_owned_requires_deref() {
1880 check_in_place_assist(
1881 r#"
1882 #[derive(Clone, Copy)]
1883 struct S;
1884 impl S {
1885 fn f(self) {}
1886 }
1887
1888 fn main() {
1889 let $0t = &(S,2);
1890 let s = t.0.f();
1891 }
1892 "#,
1893 r#"
1894 #[derive(Clone, Copy)]
1895 struct S;
1896 impl S {
1897 fn f(self) {}
1898 }
1899
1900 fn main() {
1901 let ($0_0, _1) = &(S,2);
1902 let s = (*_0).f();
1903 }
1904 "#,
1905 )
1906 }
1907
1908 #[test]
1909 fn self_auto_ref_in_trait_call_doesnt_require_deref() {
1910 check_in_place_assist(
1911 r#"
1912 trait T {
1913 fn f(self);
1914 }
1915 #[derive(Clone, Copy)]
1916 struct S;
1917 impl T for &S {
1918 fn f(self) {}
1919 }
1920
1921 fn main() {
1922 let $0t = &(S,2);
1923 let s = t.0.f();
1924 }
1925 "#,
1926 // FIXME: doesn't need deref * parens. But `ctx.sema.resolve_method_call` doesn't resolve trait implementations
1927 r#"
1928 trait T {
1929 fn f(self);
1930 }
1931 #[derive(Clone, Copy)]
1932 struct S;
1933 impl T for &S {
1934 fn f(self) {}
1935 }
1936
1937 fn main() {
1938 let ($0_0, _1) = &(S,2);
1939 let s = (*_0).f();
1940 }
1941 "#,
1942 )
1943 }
1944 #[test]
1945 fn no_auto_deref_because_of_owned_and_ref_trait_impl() {
1946 check_in_place_assist(
1947 r#"
1948 trait T {
1949 fn f(self);
1950 }
1951 #[derive(Clone, Copy)]
1952 struct S;
1953 impl T for S {
1954 fn f(self) {}
1955 }
1956 impl T for &S {
1957 fn f(self) {}
1958 }
1959
1960 fn main() {
1961 let $0t = &(S,2);
1962 let s = t.0.f();
1963 }
1964 "#,
1965 r#"
1966 trait T {
1967 fn f(self);
1968 }
1969 #[derive(Clone, Copy)]
1970 struct S;
1971 impl T for S {
1972 fn f(self) {}
1973 }
1974 impl T for &S {
1975 fn f(self) {}
1976 }
1977
1978 fn main() {
1979 let ($0_0, _1) = &(S,2);
1980 let s = (*_0).f();
1981 }
1982 "#,
1983 )
1984 }
1985
1986 #[test]
1987 fn no_outer_parens_when_ref_deref() {
1988 check_in_place_assist(
1989 r#"
1990 #[derive(Clone, Copy)]
1991 struct S;
1992 impl S {
1993 fn do_stuff(&self) -> i32 { 42 }
1994 }
1995 fn main() {
1996 let $0t = &(S,&S);
1997 let v = (&t.0).do_stuff();
1998 }
1999 "#,
2000 r#"
2001 #[derive(Clone, Copy)]
2002 struct S;
2003 impl S {
2004 fn do_stuff(&self) -> i32 { 42 }
2005 }
2006 fn main() {
2007 let ($0_0, _1) = &(S,&S);
2008 let v = _0.do_stuff();
2009 }
2010 "#,
2011 )
2012 }
2013
2014 #[test]
2015 fn auto_ref_deref() {
2016 check_in_place_assist(
2017 r#"
2018 #[derive(Clone, Copy)]
2019 struct S;
2020 impl S {
2021 fn do_stuff(&self) -> i32 { 42 }
2022 }
2023 fn main() {
2024 let $0t = &(S,&S);
2025 let v = (&t.0).do_stuff(); // no deref, remove parens
2026 // `t.0` gets auto-refed -> no deref needed -> no parens
2027 let v = t.0.do_stuff(); // no deref, no parens
2028 let v = &t.0.do_stuff(); // `&` is for result -> no deref, no parens
2029 // deref: `_1` is `&&S`, but method called is on `&S` -> there might be a method accepting `&&S`
2030 let v = t.1.do_stuff(); // deref, parens
2031 }
2032 "#,
2033 r#"
2034 #[derive(Clone, Copy)]
2035 struct S;
2036 impl S {
2037 fn do_stuff(&self) -> i32 { 42 }
2038 }
2039 fn main() {
2040 let ($0_0, _1) = &(S,&S);
2041 let v = _0.do_stuff(); // no deref, remove parens
2042 // `t.0` gets auto-refed -> no deref needed -> no parens
2043 let v = _0.do_stuff(); // no deref, no parens
2044 let v = &_0.do_stuff(); // `&` is for result -> no deref, no parens
2045 // deref: `_1` is `&&S`, but method called is on `&S` -> there might be a method accepting `&&S`
2046 let v = (*_1).do_stuff(); // deref, parens
2047 }
2048 "#,
2049 )
2050 }
2051
2052 #[test]
2053 fn mutable() {
2054 check_in_place_assist(
2055 r#"
2056 fn f_owned(v: i32) {}
2057 fn f(v: &i32) {}
2058 fn f_mut(v: &mut i32) { *v = 42; }
2059
2060 fn main() {
2061 let $0t = &mut (1,2);
2062 let v = t.0;
2063 t.0 = 42;
2064 f_owned(t.0);
2065 f(&t.0);
2066 f_mut(&mut t.0);
2067 }
2068 "#,
2069 r#"
2070 fn f_owned(v: i32) {}
2071 fn f(v: &i32) {}
2072 fn f_mut(v: &mut i32) { *v = 42; }
2073
2074 fn main() {
2075 let ($0_0, _1) = &mut (1,2);
2076 let v = *_0;
2077 *_0 = 42;
2078 f_owned(*_0);
2079 f(_0);
2080 f_mut(_0);
2081 }
2082 "#,
2083 )
2084 }
2085
2086 #[test]
2087 fn with_ref_keyword() {
2088 check_in_place_assist(
2089 r#"
2090 fn f_owned(v: i32) {}
2091 fn f(v: &i32) {}
2092
2093 fn main() {
2094 let ref $0t = (1,2);
2095 let v = t.0;
2096 f_owned(t.0);
2097 f(&t.0);
2098 }
2099 "#,
2100 r#"
2101 fn f_owned(v: i32) {}
2102 fn f(v: &i32) {}
2103
2104 fn main() {
2105 let (ref $0_0, ref _1) = (1,2);
2106 let v = *_0;
2107 f_owned(*_0);
2108 f(_0);
2109 }
2110 "#,
2111 )
2112 }
2113 #[test]
2114 fn with_ref_mut_keywords() {
2115 check_in_place_assist(
2116 r#"
2117 fn f_owned(v: i32) {}
2118 fn f(v: &i32) {}
2119 fn f_mut(v: &mut i32) { *v = 42; }
2120
2121 fn main() {
2122 let ref mut $0t = (1,2);
2123 let v = t.0;
2124 t.0 = 42;
2125 f_owned(t.0);
2126 f(&t.0);
2127 f_mut(&mut t.0);
2128 }
2129 "#,
2130 r#"
2131 fn f_owned(v: i32) {}
2132 fn f(v: &i32) {}
2133 fn f_mut(v: &mut i32) { *v = 42; }
2134
2135 fn main() {
2136 let (ref mut $0_0, ref mut _1) = (1,2);
2137 let v = *_0;
2138 *_0 = 42;
2139 f_owned(*_0);
2140 f(_0);
2141 f_mut(_0);
2142 }
2143 "#,
2144 )
2145 }
2146 }
2147 }