@@ -20,7 +20,7 @@ use crate::{utils::suggest_name, AssistContext, AssistId, AssistKind, Assists};
2020// ->
2121// ```
2222// fn main() {
23- // let $0var_name = ( 1 + 2) ;
23+ // let $0var_name = 1 + 2;
2424// var_name * 4;
2525// }
2626// ```
@@ -59,23 +59,29 @@ pub(crate) fn extract_variable(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op
5959
6060 let parent = to_extract. syntax ( ) . parent ( ) . and_then ( ast:: Expr :: cast) ;
6161 // 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 {
6363 ast:: Expr :: FieldExpr ( _)
6464 | ast:: Expr :: MethodCallExpr ( _)
6565 | ast:: Expr :: CallExpr ( _)
6666 | ast:: Expr :: AwaitExpr ( _) => true ,
6767 ast:: Expr :: IndexExpr ( index) if index. base ( ) . as_ref ( ) == Some ( & to_extract) => true ,
6868 _ => false ,
6969 } ) ;
70+ let mut to_extract_no_ref = peel_parens ( to_extract. clone ( ) ) ;
7071 let needs_ref = needs_adjust
71- && matches ! (
72- to_extract,
72+ && match & to_extract_no_ref {
7373 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+ } ;
7985
8086 let anchor = Anchor :: from ( & to_extract) ?;
8187 let target = to_extract. syntax ( ) . text_range ( ) ;
@@ -111,19 +117,19 @@ pub(crate) fn extract_variable(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op
111117 _ => make:: ident_pat ( false , false , make:: name ( & var_name) ) ,
112118 } ;
113119
114- let to_extract = match ty. as_ref ( ) . filter ( |_| needs_ref) {
120+ let to_extract_no_ref = match ty. as_ref ( ) . filter ( |_| needs_ref) {
115121 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 )
117123 }
118124 Some ( receiver_type) if receiver_type. is_reference ( ) => {
119- make:: expr_ref ( to_extract , false )
125+ make:: expr_ref ( to_extract_no_ref , false )
120126 }
121- _ => to_extract ,
127+ _ => to_extract_no_ref ,
122128 } ;
123129
124130 let expr_replace = edit. make_syntax_mut ( expr_replace) ;
125131 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 ( ) ;
127133 let name_expr = make:: expr_path ( make:: ext:: ident_path ( & var_name) ) . clone_for_update ( ) ;
128134
129135 match anchor {
@@ -223,6 +229,14 @@ pub(crate) fn extract_variable(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op
223229 )
224230}
225231
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+
226240/// Check whether the node is a valid expression which can be extracted to a variable.
227241/// In general that's true for any expression, but in some cases that would produce invalid code.
228242fn valid_target_expr ( node : SyntaxNode ) -> Option < ast:: Expr > {
@@ -1547,4 +1561,34 @@ fn foo() {
15471561}"# ,
15481562 ) ;
15491563 }
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+ }
15501594}
0 commit comments