Skip to content

Commit 3e40519

Browse files
committed
Handle mut & ref
1 parent 478b298 commit 3e40519

File tree

1 file changed

+111
-10
lines changed

1 file changed

+111
-10
lines changed

crates/ide_assists/src/handlers/destructure_tuple_binding.rs

Lines changed: 111 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ fn collect_data(ident_pat: IdentPat, ctx: &AssistContext) -> Option<TupleData> {
8080
.map(|i| generate_name(i, &name, &ident_pat, &usages, ctx))
8181
.collect_vec();
8282

83-
Some(TupleData { range, field_names, usages })
83+
Some(TupleData { ident_pat, range, field_names, usages })
8484
}
8585

8686
fn generate_name(
@@ -95,31 +95,39 @@ fn generate_name(
9595
}
9696

9797
struct TupleData {
98-
// ident_pat: IdentPat,
98+
ident_pat: IdentPat,
9999
// name: String,
100100
range: TextRange,
101101
field_names: Vec<String>,
102102
// field_types: Vec<Type>,
103103
usages: Option<UsageSearchResult>,
104104
}
105105
fn edit_tuple_assignment(data: &TupleData, builder: &mut AssistBuilder, ctx: &AssistContext) {
106-
let new_tuple = {
107-
let fields = data
106+
let tuple_pat = {
107+
let original = &data.ident_pat;
108+
let is_ref = original.ref_token().is_some();
109+
let is_mut = original.mut_token().is_some();
110+
let fields =
111+
data
108112
.field_names
109113
.iter()
110-
.map(|name| ast::Pat::from(ast::make::ident_pat(false, false, ast::make::name(name))));
114+
.map(|name| ast::Pat::from(ast::make::ident_pat(is_ref, is_mut, ast::make::name(name))));
111115
ast::make::tuple_pat(fields)
112116
};
113117

118+
let add_cursor = |text: &str| {
119+
// place cursor on first tuple item
120+
let first_tuple = &data.field_names[0];
121+
text.replacen(first_tuple, &format!("$0{}", first_tuple), 1)
122+
};
123+
124+
let text = tuple_pat.to_string();
114125
match ctx.config.snippet_cap {
115126
Some(cap) => {
116-
// No support for placeholders in Code Actions, except for special rust analyzer handling which supports only first `$0`
117-
// -> place cursor on first variable
118-
let mut snip = new_tuple.to_string();
119-
snip.insert_str(1, "$0");
127+
let snip = add_cursor(&text);
120128
builder.replace_snippet(cap, data.range, snip);
121129
}
122-
None => builder.replace(data.range, new_tuple.to_string()),
130+
None => builder.replace(data.range, text),
123131
};
124132
}
125133

@@ -462,6 +470,74 @@ fn foo(t: &(usize, usize)) -> usize {
462470
)
463471
}
464472

473+
#[test]
474+
fn with_ref() {
475+
//Note: `v` has different types:
476+
// * in 1st: `i32`
477+
// * in 2nd: `&i32`
478+
check_assist(
479+
destructure_tuple_binding,
480+
r#"
481+
fn main() {
482+
let ref $0t = (1,2);
483+
let v = t.0;
484+
}
485+
"#,
486+
r#"
487+
fn main() {
488+
let (ref $0_0, ref _1) = (1,2);
489+
let v = _0;
490+
}
491+
"#,
492+
)
493+
}
494+
495+
#[test]
496+
fn with_mut() {
497+
check_assist(
498+
destructure_tuple_binding,
499+
r#"
500+
fn main() {
501+
let mut $0t = (1,2);
502+
t.0 = 42;
503+
let v = t.0;
504+
}
505+
"#,
506+
r#"
507+
fn main() {
508+
let (mut $0_0, mut _1) = (1,2);
509+
_0 = 42;
510+
let v = _0;
511+
}
512+
"#,
513+
)
514+
}
515+
516+
#[test]
517+
fn with_ref_mut() {
518+
//Note: `v` has different types:
519+
// * in 1st: `i32`
520+
// * in 2nd: `&mut i32`
521+
// Note: 2nd `_0 = 42` isn't valid; requires dereferencing (`*_0`), but isn't handled here!
522+
check_assist(
523+
destructure_tuple_binding,
524+
r#"
525+
fn main() {
526+
let ref mut $0t = (1,2);
527+
t.0 = 42;
528+
let v = t.0;
529+
}
530+
"#,
531+
r#"
532+
fn main() {
533+
let (ref mut $0_0, ref mut _1) = (1,2);
534+
_0 = 42;
535+
let v = _0;
536+
}
537+
"#,
538+
)
539+
}
540+
465541
#[test]
466542
fn dont_trigger_for_non_tuple_reference() {
467543
check_assist_not_applicable(
@@ -733,6 +809,31 @@ fn main() {
733809
"#,
734810
)
735811
}
812+
#[test]
813+
fn in_match_reference_option() {
814+
check_assist(
815+
destructure_tuple_binding,
816+
r#"
817+
//- minicore: option
818+
fn main() {
819+
let t = (1,2);
820+
match Some(&t) {
821+
Some($0t) => t.1,
822+
_ => 0,
823+
};
824+
}
825+
"#,
826+
r#"
827+
fn main() {
828+
let t = (1,2);
829+
match Some(&t) {
830+
Some(($0_0, _1)) => _1,
831+
_ => 0,
832+
};
833+
}
834+
"#,
835+
)
836+
}
736837

737838
#[test]
738839
fn in_for() {

0 commit comments

Comments
 (0)