Skip to main content

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