ide_assists/handlers/
destructure_tuple_binding.rs

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