@@ -20,7 +20,7 @@ use crate::{utils::suggest_name, AssistContext, AssistId, AssistKind, Assists};
20
20
// ->
21
21
// ```
22
22
// fn main() {
23
- // let $0var_name = ( 1 + 2) ;
23
+ // let $0var_name = 1 + 2;
24
24
// var_name * 4;
25
25
// }
26
26
// ```
@@ -59,23 +59,29 @@ pub(crate) fn extract_variable(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op
59
59
60
60
let parent = to_extract. syntax ( ) . parent ( ) . and_then ( ast:: Expr :: cast) ;
61
61
// Any expression that autoderefs may need adjustment.
62
- let needs_adjust = parent. as_ref ( ) . map_or ( false , |it| match it {
62
+ let mut needs_adjust = parent. as_ref ( ) . map_or ( false , |it| match it {
63
63
ast:: Expr :: FieldExpr ( _)
64
64
| ast:: Expr :: MethodCallExpr ( _)
65
65
| ast:: Expr :: CallExpr ( _)
66
66
| ast:: Expr :: AwaitExpr ( _) => true ,
67
67
ast:: Expr :: IndexExpr ( index) if index. base ( ) . as_ref ( ) == Some ( & to_extract) => true ,
68
68
_ => false ,
69
69
} ) ;
70
+ let mut to_extract_no_ref = peel_parens ( to_extract. clone ( ) ) ;
70
71
let needs_ref = needs_adjust
71
- && matches ! (
72
- to_extract,
72
+ && match & to_extract_no_ref {
73
73
ast:: Expr :: FieldExpr ( _)
74
- | ast:: Expr :: IndexExpr ( _)
75
- | ast:: Expr :: MacroExpr ( _)
76
- | ast:: Expr :: ParenExpr ( _)
77
- | ast:: Expr :: PathExpr ( _)
78
- ) ;
74
+ | ast:: Expr :: IndexExpr ( _)
75
+ | ast:: Expr :: MacroExpr ( _)
76
+ | ast:: Expr :: ParenExpr ( _)
77
+ | ast:: Expr :: PathExpr ( _) => true ,
78
+ ast:: Expr :: PrefixExpr ( prefix) if prefix. op_kind ( ) == Some ( ast:: UnaryOp :: Deref ) => {
79
+ to_extract_no_ref = prefix. expr ( ) ?;
80
+ needs_adjust = false ;
81
+ false
82
+ }
83
+ _ => false ,
84
+ } ;
79
85
80
86
let anchor = Anchor :: from ( & to_extract) ?;
81
87
let target = to_extract. syntax ( ) . text_range ( ) ;
@@ -111,19 +117,19 @@ pub(crate) fn extract_variable(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op
111
117
_ => make:: ident_pat ( false , false , make:: name ( & var_name) ) ,
112
118
} ;
113
119
114
- let to_extract = match ty. as_ref ( ) . filter ( |_| needs_ref) {
120
+ let to_extract_no_ref = match ty. as_ref ( ) . filter ( |_| needs_ref) {
115
121
Some ( receiver_type) if receiver_type. is_mutable_reference ( ) => {
116
- make:: expr_ref ( to_extract , true )
122
+ make:: expr_ref ( to_extract_no_ref , true )
117
123
}
118
124
Some ( receiver_type) if receiver_type. is_reference ( ) => {
119
- make:: expr_ref ( to_extract , false )
125
+ make:: expr_ref ( to_extract_no_ref , false )
120
126
}
121
- _ => to_extract ,
127
+ _ => to_extract_no_ref ,
122
128
} ;
123
129
124
130
let expr_replace = edit. make_syntax_mut ( expr_replace) ;
125
131
let let_stmt =
126
- make:: let_stmt ( ident_pat. into ( ) , None , Some ( to_extract ) ) . clone_for_update ( ) ;
132
+ make:: let_stmt ( ident_pat. into ( ) , None , Some ( to_extract_no_ref ) ) . clone_for_update ( ) ;
127
133
let name_expr = make:: expr_path ( make:: ext:: ident_path ( & var_name) ) . clone_for_update ( ) ;
128
134
129
135
match anchor {
@@ -223,6 +229,14 @@ pub(crate) fn extract_variable(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op
223
229
)
224
230
}
225
231
232
+ fn peel_parens ( mut expr : ast:: Expr ) -> ast:: Expr {
233
+ while let ast:: Expr :: ParenExpr ( parens) = & expr {
234
+ let Some ( expr_inside) = parens. expr ( ) else { break } ;
235
+ expr = expr_inside;
236
+ }
237
+ expr
238
+ }
239
+
226
240
/// Check whether the node is a valid expression which can be extracted to a variable.
227
241
/// In general that's true for any expression, but in some cases that would produce invalid code.
228
242
fn valid_target_expr ( node : SyntaxNode ) -> Option < ast:: Expr > {
@@ -1547,4 +1561,34 @@ fn foo() {
1547
1561
}"# ,
1548
1562
) ;
1549
1563
}
1564
+
1565
+ #[ test]
1566
+ fn generates_no_ref_for_deref ( ) {
1567
+ check_assist (
1568
+ extract_variable,
1569
+ r#"
1570
+ struct S;
1571
+ impl S {
1572
+ fn do_work(&mut self) {}
1573
+ }
1574
+ fn bar() -> S { S }
1575
+ fn foo() {
1576
+ let v = &mut &mut bar();
1577
+ $0(**v)$0.do_work();
1578
+ }
1579
+ "# ,
1580
+ r#"
1581
+ struct S;
1582
+ impl S {
1583
+ fn do_work(&mut self) {}
1584
+ }
1585
+ fn bar() -> S { S }
1586
+ fn foo() {
1587
+ let v = &mut &mut bar();
1588
+ let $0s = *v;
1589
+ s.do_work();
1590
+ }
1591
+ "# ,
1592
+ ) ;
1593
+ }
1550
1594
}
0 commit comments