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