2 assists::{AssistId, AssistKind},
4 search::{FileReference, SearchScope, UsageSearchResult},
6 use itertools::Itertools;
8 ast::{self, AstNode, FieldExpr, HasName, IdentPat, MethodCallExpr},
12 use crate::assist_context::{AssistBuilder, AssistContext, Assists};
14 // Assist: destructure_tuple_binding
16 // Destructures a tuple binding in place.
27 // let ($0_0, _1) = (1,2);
31 pub(crate) fn destructure_tuple_binding(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
32 destructure_tuple_binding_impl(acc, ctx, false)
35 // And when `with_sub_pattern` enabled (currently disabled):
36 // Assist: destructure_tuple_binding_in_sub_pattern
38 // Destructures tuple items in sub-pattern (after `@`).
49 // let t @ ($0_0, _1) = (1,2);
53 pub(crate) fn destructure_tuple_binding_impl(
56 with_sub_pattern: bool,
58 let ident_pat = ctx.find_node_at_offset::<ast::IdentPat>()?;
59 let data = collect_data(ident_pat, ctx)?;
63 AssistId("destructure_tuple_binding_in_sub_pattern", AssistKind::RefactorRewrite),
64 "Destructure tuple in sub-pattern",
67 edit_tuple_assignment(ctx, builder, &data, true);
68 edit_tuple_usages(&data, builder, ctx, true);
74 AssistId("destructure_tuple_binding", AssistKind::RefactorRewrite),
75 if with_sub_pattern { "Destructure tuple in place" } else { "Destructure tuple" },
78 edit_tuple_assignment(ctx, builder, &data, false);
79 edit_tuple_usages(&data, builder, ctx, false);
86 fn collect_data(ident_pat: IdentPat, ctx: &AssistContext) -> Option<TupleData> {
87 if ident_pat.at_token().is_some() {
88 // Cannot destructure pattern with sub-pattern:
89 // Only IdentPat can have sub-pattern,
90 // but not TuplePat (`(a,b)`).
91 cov_mark::hit!(destructure_tuple_subpattern);
95 let ty = ctx.sema.type_of_pat(&ident_pat.clone().into())?.adjusted();
96 let ref_type = if ty.is_mutable_reference() {
97 Some(RefType::Mutable)
98 } else if ty.is_reference() {
99 Some(RefType::ReadOnly)
103 // might be reference
104 let ty = ty.strip_references();
106 let field_types = ty.tuple_fields(ctx.db());
107 if field_types.is_empty() {
108 cov_mark::hit!(destructure_tuple_no_tuple);
112 let name = ident_pat.name()?.to_string();
113 let range = ident_pat.syntax().text_range();
115 let usages = ctx.sema.to_def(&ident_pat).map(|def| {
116 Definition::Local(def)
118 .in_scope(SearchScope::single_file(ctx.frange.file_id))
122 let field_names = (0..field_types.len())
123 .map(|i| generate_name(ctx, i, &name, &ident_pat, &usages))
126 Some(TupleData { ident_pat, range, ref_type, field_names, usages })
130 _ctx: &AssistContext,
133 _ident_pat: &IdentPat,
134 _usages: &Option<UsageSearchResult>,
136 // FIXME: detect if name already used
137 format!("_{}", index)
148 ref_type: Option<RefType>,
149 field_names: Vec<String>,
150 // field_types: Vec<Type>,
151 usages: Option<UsageSearchResult>,
153 fn edit_tuple_assignment(
155 builder: &mut AssistBuilder,
157 in_sub_pattern: bool,
160 let original = &data.ident_pat;
161 let is_ref = original.ref_token().is_some();
162 let is_mut = original.mut_token().is_some();
163 let fields = data.field_names.iter().map(|name| {
164 ast::Pat::from(ast::make::ident_pat(is_ref, is_mut, ast::make::name(name)))
166 ast::make::tuple_pat(fields)
169 let add_cursor = |text: &str| {
170 // place cursor on first tuple item
171 let first_tuple = &data.field_names[0];
172 text.replacen(first_tuple, &format!("$0{}", first_tuple), 1)
175 // with sub_pattern: keep original tuple and add subpattern: `tup @ (_0, _1)`
177 let text = format!(" @ {}", tuple_pat.to_string());
178 match ctx.config.snippet_cap {
180 let snip = add_cursor(&text);
181 builder.insert_snippet(cap, data.range.end(), snip);
183 None => builder.insert(data.range.end(), text),
186 let text = tuple_pat.to_string();
187 match ctx.config.snippet_cap {
189 let snip = add_cursor(&text);
190 builder.replace_snippet(cap, data.range, snip);
192 None => builder.replace(data.range, text),
197 fn edit_tuple_usages(
199 builder: &mut AssistBuilder,
201 in_sub_pattern: bool,
203 if let Some(usages) = data.usages.as_ref() {
204 for (file_id, refs) in usages.iter() {
205 builder.edit_file(*file_id);
208 edit_tuple_usage(ctx, builder, r, data, in_sub_pattern);
215 builder: &mut AssistBuilder,
216 usage: &FileReference,
218 in_sub_pattern: bool,
220 match detect_tuple_index(usage, data) {
221 Some(index) => edit_tuple_field_usage(ctx, builder, data, index),
224 cov_mark::hit!(destructure_tuple_call_with_subpattern);
228 // no index access -> make invalid -> requires handling by user
229 // -> put usage in block comment
231 // Note: For macro invocations this might result in still valid code:
232 // When a macro accepts the tuple as argument, as well as no arguments at all,
233 // uncommenting the tuple still leaves the macro call working (see `tests::in_macro_call::empty_macro`).
234 // But this is an unlikely case. Usually the resulting macro call will become erroneous.
235 builder.insert(usage.range.start(), "/*");
236 builder.insert(usage.range.end(), "*/");
241 fn edit_tuple_field_usage(
243 builder: &mut AssistBuilder,
247 let field_name = &data.field_names[index.index];
249 if data.ref_type.is_some() {
250 let ref_data = handle_ref_field_usage(ctx, &index.field_expr);
251 builder.replace(ref_data.range, ref_data.format(field_name));
253 builder.replace(index.range, field_name);
259 field_expr: FieldExpr,
261 fn detect_tuple_index(usage: &FileReference, data: &TupleData) -> Option<TupleIndex> {
275 .skip_while(|s| !ast::PathExpr::can_cast(s.kind()))
276 .skip(1) // PATH_EXPR
277 .find(|s| !ast::ParenExpr::can_cast(s.kind()))?; // skip parentheses
279 if let Some(field_expr) = ast::FieldExpr::cast(node) {
280 let idx = field_expr.name_ref()?.as_tuple_field()?;
281 if idx < data.field_names.len() {
282 // special case: in macro call -> range of `field_expr` in applied macro, NOT range in actual file!
283 if field_expr.syntax().ancestors().any(|a| ast::MacroStmts::can_cast(a.kind())) {
284 cov_mark::hit!(destructure_tuple_macro_call);
286 // issue: cannot differentiate between tuple index passed into macro or tuple index as result of macro:
289 // ($t1:expr, $t2:expr) => { $t1; $t2.0 }
294 // -> 2 tuple index usages detected!
296 // -> only handle `t`
300 Some(TupleIndex { index: idx, range: field_expr.syntax().text_range(), field_expr })
302 // tuple index out of range
313 needs_parentheses: bool,
316 fn format(&self, field_name: &str) -> String {
317 match (self.needs_deref, self.needs_parentheses) {
318 (true, true) => format!("(*{})", field_name),
319 (true, false) => format!("*{}", field_name),
320 (false, true) => format!("({})", field_name),
321 (false, false) => field_name.to_string(),
325 fn handle_ref_field_usage(ctx: &AssistContext, field_expr: &FieldExpr) -> RefData {
326 let s = field_expr.syntax();
328 RefData { range: s.text_range(), needs_deref: true, needs_parentheses: true };
330 let parent = match s.parent().map(ast::Expr::cast) {
331 Some(Some(parent)) => parent,
333 ref_data.needs_parentheses = false;
336 None => return ref_data,
340 ast::Expr::ParenExpr(it) => {
341 // already parens in place -> don't replace
342 ref_data.needs_parentheses = false;
343 // there might be a ref outside: `&(t.0)` -> can be removed
344 if let Some(it) = it.syntax().parent().and_then(ast::RefExpr::cast) {
345 ref_data.needs_deref = false;
346 ref_data.range = it.syntax().text_range();
349 ast::Expr::RefExpr(it) => {
350 // `&*` -> cancel each other out
351 ref_data.needs_deref = false;
352 ref_data.needs_parentheses = false;
353 // might be surrounded by parens -> can be removed too
354 match it.syntax().parent().and_then(ast::ParenExpr::cast) {
355 Some(parent) => ref_data.range = parent.syntax().text_range(),
356 None => ref_data.range = it.syntax().text_range(),
359 // higher precedence than deref `*`
360 // https://doc.rust-lang.org/reference/expressions.html#expression-precedence
361 // -> requires parentheses
362 ast::Expr::PathExpr(_it) => {}
363 ast::Expr::MethodCallExpr(it) => {
364 // `field_expr` is `self_param` (otherwise it would be in `ArgList`)
366 // test if there's already auto-ref in place (`value` -> `&value`)
367 // -> no method accepting `self`, but `&self` -> no need for deref
369 // other combinations (`&value` -> `value`, `&&value` -> `&value`, `&value` -> `&&value`) might or might not be able to auto-ref/deref,
370 // but there might be trait implementations an added `&` might resolve to
371 // -> ONLY handle auto-ref from `value` to `&value`
372 fn is_auto_ref(ctx: &AssistContext, call_expr: &MethodCallExpr) -> bool {
373 fn impl_(ctx: &AssistContext, call_expr: &MethodCallExpr) -> Option<bool> {
374 let rec = call_expr.receiver()?;
375 let rec_ty = ctx.sema.type_of_expr(&rec)?.adjusted();
376 // input must be actual value
377 if rec_ty.is_reference() {
381 // doesn't resolve trait impl
382 let f = ctx.sema.resolve_method_call(call_expr)?;
383 let self_param = f.self_param(ctx.db())?;
385 match self_param.access(ctx.db()) {
386 hir::Access::Shared | hir::Access::Exclusive => Some(true),
387 hir::Access::Owned => Some(false),
390 impl_(ctx, call_expr).unwrap_or(false)
393 if is_auto_ref(ctx, &it) {
394 ref_data.needs_deref = false;
395 ref_data.needs_parentheses = false;
398 ast::Expr::FieldExpr(_it) => {
400 ref_data.needs_deref = false;
401 ref_data.needs_parentheses = false;
403 ast::Expr::IndexExpr(_it) => {
405 ref_data.needs_deref = false;
406 ref_data.needs_parentheses = false;
408 ast::Expr::TryExpr(_it) => {
410 // requires deref and parens: `(*_0)`
412 // lower precedence than deref `*` -> no parens
414 ref_data.needs_parentheses = false;
425 use crate::tests::{check_assist, check_assist_not_applicable};
427 // Tests for direct tuple destructure:
428 // `let $0t = (1,2);` -> `let (_0, _1) = (1,2);`
430 fn assist(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
431 destructure_tuple_binding_impl(acc, ctx, false)
435 fn dont_trigger_on_unit() {
436 cov_mark::check!(destructure_tuple_no_tuple);
437 check_assist_not_applicable(
447 fn dont_trigger_on_number() {
448 cov_mark::check!(destructure_tuple_no_tuple);
449 check_assist_not_applicable(
460 fn destructure_3_tuple() {
470 let ($0_0, _1, _2) = (1,2,3);
476 fn destructure_2_tuple() {
486 let ($0_0, _1) = (1,2);
492 fn replace_indices() {
505 let ($0_0, _1, _2) = (1,2,3);
515 fn replace_usage_in_parentheses() {
527 let ($0_0, _1, _2) = (1,2,3);
536 fn handle_function_call() {
547 let ($0_0, _1) = (1,2);
548 let v = /*tup*/.into();
555 fn handle_invalid_index() {
566 let ($0_0, _1) = (1,2);
574 fn dont_replace_variable_with_same_name_as_tuple() {
591 let ($0_0, _1, _2) = (1,2,3);
601 fn keep_function_call_in_tuple_item() {
606 let $0t = ("3.14", 0);
607 let pi: f32 = t.0.parse().unwrap_or(0.0);
612 let ($0_0, _1) = ("3.14", 0);
613 let pi: f32 = _0.parse().unwrap_or(0.0);
625 let $0t: (usize, i32) = (1,2);
630 let ($0_0, _1): (usize, i32) = (1,2);
637 fn destructure_reference() {
658 fn destructure_multiple_reference() {
671 let ($0_0, _1) = &&t;
679 fn keep_reference() {
683 fn foo(t: &(usize, usize)) -> usize {
690 fn foo(t: &(usize, usize)) -> usize {
711 let (ref $0_0, ref _1) = (1,2);
731 let (mut $0_0, mut _1) = (1,2);
745 let ref mut $0t = (1,2);
752 let (ref mut $0_0, ref mut _1) = (1,2);
761 fn dont_trigger_for_non_tuple_reference() {
762 check_assist_not_applicable(
774 fn dont_trigger_on_static_tuple() {
775 check_assist_not_applicable(
778 static $0TUP: (usize, usize) = (1,2);
784 fn dont_trigger_on_wildcard() {
785 check_assist_not_applicable(
796 fn dont_trigger_in_struct() {
797 check_assist_not_applicable(
801 $0tup: (usize, usize),
808 fn dont_trigger_in_struct_creation() {
809 check_assist_not_applicable(
825 fn dont_trigger_on_tuple_struct() {
826 check_assist_not_applicable(
829 struct S(usize, usize);
838 fn dont_trigger_when_subpattern_exists() {
839 // sub-pattern is only allowed with IdentPat (name), not other patterns (like TuplePat)
840 cov_mark::check!(destructure_tuple_subpattern);
841 check_assist_not_applicable(
844 fn sum(t: (usize, usize)) -> usize {
846 $0t @ (1..=3,1..=3) => t.0 + t.1,
860 let t1 @ (_, $0t2) = (1, (2,3));
861 let v = t1.0 + t2.0 + t2.1;
866 let t1 @ (_, ($0_0, _1)) = (1, (2,3));
867 let v = t1.0 + _0 + _1;
874 fn in_nested_tuple() {
879 let ($0tup, v) = ((1,2),3);
884 let (($0_0, _1), v) = ((1,2),3);
897 let f = |v| v + tup.1;
902 let ($0_0, _1, _2) = (1,2,3);
910 fn in_closure_args() {
915 let f = |$0t| t.0 + t.1;
921 let f = |($0_0, _1)| _0 + _1;
929 fn in_function_args() {
933 fn f($0t: (usize, usize)) {
938 fn f(($0_0, _1): (usize, usize)) {
950 fn f(t: (usize, usize)) {
957 fn f(t: (usize, usize)) {
958 if let ($0_0, _1) = t {
966 fn in_if_let_option() {
971 fn f(o: Option<(usize, usize)>) {
972 if let Some($0t) = o {
978 fn f(o: Option<(usize, usize)>) {
979 if let Some(($0_0, _1)) = o {
1008 fn in_match_option() {
1012 //- minicore: option
1023 Some(($0_0, _1)) => _1,
1031 fn in_match_reference_option() {
1035 //- minicore: option
1048 Some(($0_0, _1)) => *_1,
1061 //- minicore: iterators
1063 for $0t in core::iter::repeat((1,2)) {
1070 for ($0_0, _1) in core::iter::repeat((1,2)) {
1078 fn in_for_nested() {
1082 //- minicore: iterators
1084 for (a, $0b) in core::iter::repeat((1,(2,3))) {
1091 for (a, ($0_0, _1)) in core::iter::repeat((1,(2,3))) {
1100 fn not_applicable_on_tuple_usage() {
1101 //Improvement: might be reasonable to allow & implement
1102 check_assist_not_applicable(
1121 let s = (t.0 + t.1) / 2;
1122 let f = |v| v + t.0;
1127 (_,2) if t.0 > 2 => 1,
1134 let ($0_0, _1) = (1,2);
1136 let s = (_0 + _1) / 2;
1139 let e = /*t*/ == (9,0);
1142 (_,2) if _0 > 2 => 1,
1151 fn non_trivial_tuple_assignment() {
1193 use crate::tests::check_assist_by_label;
1195 fn assist(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
1196 destructure_tuple_binding_impl(acc, ctx, true)
1198 fn in_place_assist(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
1199 destructure_tuple_binding_impl(acc, ctx, false)
1202 pub(crate) fn check_in_place_assist(ra_fixture_before: &str, ra_fixture_after: &str) {
1203 check_assist_by_label(
1207 // "Destructure tuple in place",
1208 "Destructure tuple",
1212 pub(crate) fn check_sub_pattern_assist(ra_fixture_before: &str, ra_fixture_after: &str) {
1213 check_assist_by_label(
1217 "Destructure tuple in sub-pattern",
1221 pub(crate) fn check_both_assists(
1222 ra_fixture_before: &str,
1223 ra_fixture_after_in_place: &str,
1224 ra_fixture_after_in_sub_pattern: &str,
1226 check_in_place_assist(ra_fixture_before, ra_fixture_after_in_place);
1227 check_sub_pattern_assist(ra_fixture_before, ra_fixture_after_in_sub_pattern);
1231 /// Tests for destructure of tuple in sub-pattern:
1232 /// `let $0t = (1,2);` -> `let t @ (_0, _1) = (1,2);`
1234 use super::assist::*;
1236 use crate::tests::check_assist_by_label;
1239 fn destructure_in_sub_pattern() {
1240 check_sub_pattern_assist(
1242 #![feature(bindings_after_at)]
1249 #![feature(bindings_after_at)]
1252 let t @ ($0_0, _1) = (1,2);
1259 fn trigger_both_destructure_tuple_assists() {
1260 fn assist(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
1261 destructure_tuple_binding_impl(acc, ctx, true)
1268 check_assist_by_label(
1273 let ($0_0, _1) = (1,2);
1276 "Destructure tuple in place",
1278 check_assist_by_label(
1283 let t @ ($0_0, _1) = (1,2);
1286 "Destructure tuple in sub-pattern",
1291 fn replace_indices() {
1292 check_sub_pattern_assist(
1302 let t @ ($0_0, _1) = (1,2);
1311 fn keep_function_call() {
1312 cov_mark::check!(destructure_tuple_call_with_subpattern);
1313 check_sub_pattern_assist(
1322 let t @ ($0_0, _1) = (1,2);
1331 check_sub_pattern_assist(
1334 let $0t: (usize, i32) = (1,2);
1341 let t @ ($0_0, _1): (usize, i32) = (1,2);
1350 fn in_function_args() {
1351 check_sub_pattern_assist(
1353 fn f($0t: (usize, usize)) {
1359 fn f(t @ ($0_0, _1): (usize, usize)) {
1369 check_sub_pattern_assist(
1372 let ref $0t = (1,2);
1379 let ref t @ (ref $0_0, ref _1) = (1,2);
1388 check_sub_pattern_assist(
1391 let mut $0t = (1,2);
1398 let mut t @ (mut $0_0, mut _1) = (1,2);
1407 check_sub_pattern_assist(
1410 let ref mut $0t = (1,2);
1417 let ref mut t @ (ref mut $0_0, ref mut _1) = (1,2);
1426 /// Tests for tuple usage in macro call:
1427 /// `println!("{}", t.0)`
1429 use super::assist::*;
1432 fn detect_macro_call() {
1433 cov_mark::check!(destructure_tuple_macro_call);
1434 check_in_place_assist(
1437 ($e:expr) => { "foo"; $e };
1447 ($e:expr) => { "foo"; $e };
1451 let ($0_0, _1) = (1,2);
1461 // leading `"foo"` to ensure `$e` doesn't start at position `0`
1464 ($e:expr) => { "foo"; $e };
1474 ($e:expr) => { "foo"; $e };
1478 let ($0_0, _1) = (1,2);
1484 ($e:expr) => { "foo"; $e };
1488 let t @ ($0_0, _1) = (1,2);
1496 fn tuple_function_usage() {
1500 ($e:expr) => { "foo"; $e };
1510 ($e:expr) => { "foo"; $e };
1514 let ($0_0, _1) = (1,2);
1520 ($e:expr) => { "foo"; $e };
1524 let t @ ($0_0, _1) = (1,2);
1532 fn tuple_index_usage() {
1536 ($e:expr) => { "foo"; $e };
1544 // FIXME: replace `t.0` with `_0` (cannot detect range of tuple index in macro call)
1547 ($e:expr) => { "foo"; $e };
1551 let ($0_0, _1) = (1,2);
1555 // FIXME: replace `t.0` with `_0`
1558 ($e:expr) => { "foo"; $e };
1562 let t @ ($0_0, _1) = (1,2);
1570 fn tuple_in_parentheses_index_usage() {
1574 ($e:expr) => { "foo"; $e };
1582 // FIXME: replace `(t).0` with `_0`
1585 ($e:expr) => { "foo"; $e };
1589 let ($0_0, _1) = (1,2);
1593 // FIXME: replace `(t).0` with `_0`
1596 ($e:expr) => { "foo"; $e };
1600 let t @ ($0_0, _1) = (1,2);
1609 check_in_place_assist(
1613 ($e:expr) => { $e; "foo" };
1621 // FIXME: macro allows no arg -> is valid. But assist should result in invalid code
1625 ($e:expr) => { $e; "foo" };
1629 let ($0_0, _1) = (1,2);
1637 fn tuple_index_in_macro() {
1641 ($t:expr, $i:expr) => { $t.0 + $i };
1649 // FIXME: replace `t.0` in macro call (not IN macro) with `_0`
1652 ($t:expr, $i:expr) => { $t.0 + $i };
1656 let ($0_0, _1) = (1,2);
1660 // FIXME: replace `t.0` in macro call with `_0`
1663 ($t:expr, $i:expr) => { $t.0 + $i };
1667 let t @ ($0_0, _1) = (1,2);
1676 use super::assist::*;
1680 check_in_place_assist(
1689 let ($0_0, _1) = &(1,2);
1696 fn no_ref_with_parens() {
1697 check_in_place_assist(
1706 let ($0_0, _1) = &(1,2);
1714 check_in_place_assist(
1723 let ($0_0, _1) = &(1,2);
1730 fn with_ref_in_parens_ref() {
1731 check_in_place_assist(
1735 let v: &i32 = &(t.0);
1740 let ($0_0, _1) = &(1,2);
1747 fn with_ref_in_ref_parens() {
1748 check_in_place_assist(
1752 let v: &i32 = (&t.0);
1757 let ($0_0, _1) = &(1,2);
1765 fn deref_and_parentheses() {
1766 // Operator/Expressions with higher precedence than deref (`*`):
1767 // https://doc.rust-lang.org/reference/expressions.html#expression-precedence
1770 // * Field expression
1771 // * Function calls, array indexing
1773 check_in_place_assist(
1775 //- minicore: option
1779 fn do_stuff(self) {}
1782 fn do_stuff(self) {}
1785 fn do_stuff(self) {}
1791 fn foo() -> Option<()> {
1792 let $0t = &(0, (1,"1"), Some(2), [3;3], S4 { value: 4 }, &5);
1793 let v: i32 = t.0; // deref, no parens
1794 let v: &i32 = &t.0; // no deref, no parens, remove `&`
1795 f1(t.0); // deref, no parens
1796 f2(&t.0); // `&*` -> cancel out -> no deref, no parens
1797 // https://github.com/rust-analyzer/rust-analyzer/issues/1109#issuecomment-658868639
1798 // let v: i32 = t.1.0; // no deref, no parens
1799 let v: i32 = t.4.value; // no deref, no parens
1800 t.0.do_stuff(); // deref, parens
1801 let v: i32 = t.2?; // deref, parens
1802 let v: i32 = t.3[0]; // no deref, no parens
1803 (t.0).do_stuff(); // deref, no additional parens
1804 let v: i32 = *t.5; // deref (-> 2), no parens
1813 fn do_stuff(self) {}
1816 fn do_stuff(self) {}
1819 fn do_stuff(self) {}
1825 fn foo() -> Option<()> {
1826 let ($0_0, _1, _2, _3, _4, _5) = &(0, (1,"1"), Some(2), [3;3], S4 { value: 4 }, &5);
1827 let v: i32 = *_0; // deref, no parens
1828 let v: &i32 = _0; // no deref, no parens, remove `&`
1829 f1(*_0); // deref, no parens
1830 f2(_0); // `&*` -> cancel out -> no deref, no parens
1831 // https://github.com/rust-analyzer/rust-analyzer/issues/1109#issuecomment-658868639
1832 // let v: i32 = t.1.0; // no deref, no parens
1833 let v: i32 = _4.value; // no deref, no parens
1834 (*_0).do_stuff(); // deref, parens
1835 let v: i32 = (*_2)?; // deref, parens
1836 let v: i32 = _3[0]; // no deref, no parens
1837 (*_0).do_stuff(); // deref, no additional parens
1838 let v: i32 = **_5; // deref (-> 2), no parens
1850 fn self_auto_ref_doesnt_need_deref() {
1851 check_in_place_assist(
1853 #[derive(Clone, Copy)]
1865 #[derive(Clone, Copy)]
1872 let ($0_0, _1) = &(S,2);
1880 fn self_owned_requires_deref() {
1881 check_in_place_assist(
1883 #[derive(Clone, Copy)]
1895 #[derive(Clone, Copy)]
1902 let ($0_0, _1) = &(S,2);
1910 fn self_auto_ref_in_trait_call_doesnt_require_deref() {
1911 check_in_place_assist(
1916 #[derive(Clone, Copy)]
1927 // FIXME: doesn't need deref * parens. But `ctx.sema.resolve_method_call` doesn't resolve trait implementations
1932 #[derive(Clone, Copy)]
1939 let ($0_0, _1) = &(S,2);
1946 fn no_auto_deref_because_of_owned_and_ref_trait_impl() {
1947 check_in_place_assist(
1952 #[derive(Clone, Copy)]
1970 #[derive(Clone, Copy)]
1980 let ($0_0, _1) = &(S,2);
1988 fn no_outer_parens_when_ref_deref() {
1989 check_in_place_assist(
1991 #[derive(Clone, Copy)]
1994 fn do_stuff(&self) -> i32 { 42 }
1998 let v = (&t.0).do_stuff();
2002 #[derive(Clone, Copy)]
2005 fn do_stuff(&self) -> i32 { 42 }
2008 let ($0_0, _1) = &(S,&S);
2009 let v = _0.do_stuff();
2016 fn auto_ref_deref() {
2017 check_in_place_assist(
2019 #[derive(Clone, Copy)]
2022 fn do_stuff(&self) -> i32 { 42 }
2026 let v = (&t.0).do_stuff(); // no deref, remove parens
2027 // `t.0` gets auto-refed -> no deref needed -> no parens
2028 let v = t.0.do_stuff(); // no deref, no parens
2029 let v = &t.0.do_stuff(); // `&` is for result -> no deref, no parens
2030 // deref: `_1` is `&&S`, but method called is on `&S` -> there might be a method accepting `&&S`
2031 let v = t.1.do_stuff(); // deref, parens
2035 #[derive(Clone, Copy)]
2038 fn do_stuff(&self) -> i32 { 42 }
2041 let ($0_0, _1) = &(S,&S);
2042 let v = _0.do_stuff(); // no deref, remove parens
2043 // `t.0` gets auto-refed -> no deref needed -> no parens
2044 let v = _0.do_stuff(); // no deref, no parens
2045 let v = &_0.do_stuff(); // `&` is for result -> no deref, no parens
2046 // deref: `_1` is `&&S`, but method called is on `&S` -> there might be a method accepting `&&S`
2047 let v = (*_1).do_stuff(); // deref, parens
2055 check_in_place_assist(
2057 fn f_owned(v: i32) {}
2059 fn f_mut(v: &mut i32) { *v = 42; }
2062 let $0t = &mut (1,2);
2071 fn f_owned(v: i32) {}
2073 fn f_mut(v: &mut i32) { *v = 42; }
2076 let ($0_0, _1) = &mut (1,2);
2088 fn with_ref_keyword() {
2089 check_in_place_assist(
2091 fn f_owned(v: i32) {}
2095 let ref $0t = (1,2);
2102 fn f_owned(v: i32) {}
2106 let (ref $0_0, ref _1) = (1,2);
2115 fn with_ref_mut_keywords() {
2116 check_in_place_assist(
2118 fn f_owned(v: i32) {}
2120 fn f_mut(v: &mut i32) { *v = 42; }
2123 let ref mut $0t = (1,2);
2132 fn f_owned(v: i32) {}
2134 fn f_mut(v: &mut i32) { *v = 42; }
2137 let (ref mut $0_0, ref mut _1) = (1,2);