Skip to content

Commit 3ff3d39

Browse files
Also handle deref expressions in "Extract variable"
And BTW, remove the parentheses of the extracted expression if there are.
1 parent fe5f91e commit 3ff3d39

File tree

2 files changed

+59
-15
lines changed

2 files changed

+59
-15
lines changed

Diff for: src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs

+58-14
Original file line numberDiff line numberDiff line change
@@ -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.
228242
fn 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
}

Diff for: src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -994,7 +994,7 @@ fn main() {
994994
"#####,
995995
r#####"
996996
fn main() {
997-
let $0var_name = (1 + 2);
997+
let $0var_name = 1 + 2;
998998
var_name * 4;
999999
}
10001000
"#####,

0 commit comments

Comments
 (0)