Don't add reference when it isn't needed for the "Extract variable" assist
I.e. don't generate `let var_name = &foo()`. Anything that creates a new value don't need a reference. That excludes mostly field accesses and indexing. I had a thought that we can also not generate a reference for fields and indexing as long as the type is `Copy`, but sometimes people impl `Copy` even when they don't want to copy the values (e.g. a large type), so I didn't do that.
This commit is contained in:
parent
2a7ec0b0ad
commit
fe5f91ed8e
@ -67,6 +67,15 @@ pub(crate) fn extract_variable(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op
|
|||||||
ast::Expr::IndexExpr(index) if index.base().as_ref() == Some(&to_extract) => true,
|
ast::Expr::IndexExpr(index) if index.base().as_ref() == Some(&to_extract) => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
});
|
});
|
||||||
|
let needs_ref = needs_adjust
|
||||||
|
&& matches!(
|
||||||
|
to_extract,
|
||||||
|
ast::Expr::FieldExpr(_)
|
||||||
|
| ast::Expr::IndexExpr(_)
|
||||||
|
| ast::Expr::MacroExpr(_)
|
||||||
|
| ast::Expr::ParenExpr(_)
|
||||||
|
| ast::Expr::PathExpr(_)
|
||||||
|
);
|
||||||
|
|
||||||
let anchor = Anchor::from(&to_extract)?;
|
let anchor = Anchor::from(&to_extract)?;
|
||||||
let target = to_extract.syntax().text_range();
|
let target = to_extract.syntax().text_range();
|
||||||
@ -93,10 +102,16 @@ pub(crate) fn extract_variable(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op
|
|||||||
Some(ast::Expr::RefExpr(expr)) if expr.mut_token().is_some() => {
|
Some(ast::Expr::RefExpr(expr)) if expr.mut_token().is_some() => {
|
||||||
make::ident_pat(false, true, make::name(&var_name))
|
make::ident_pat(false, true, make::name(&var_name))
|
||||||
}
|
}
|
||||||
|
_ if needs_adjust
|
||||||
|
&& !needs_ref
|
||||||
|
&& ty.as_ref().is_some_and(|ty| ty.is_mutable_reference()) =>
|
||||||
|
{
|
||||||
|
make::ident_pat(false, true, make::name(&var_name))
|
||||||
|
}
|
||||||
_ => make::ident_pat(false, false, make::name(&var_name)),
|
_ => make::ident_pat(false, false, make::name(&var_name)),
|
||||||
};
|
};
|
||||||
|
|
||||||
let to_extract = match ty.as_ref().filter(|_| needs_adjust) {
|
let to_extract = match ty.as_ref().filter(|_| needs_ref) {
|
||||||
Some(receiver_type) if receiver_type.is_mutable_reference() => {
|
Some(receiver_type) if receiver_type.is_mutable_reference() => {
|
||||||
make::expr_ref(to_extract, true)
|
make::expr_ref(to_extract, true)
|
||||||
}
|
}
|
||||||
@ -1503,6 +1518,32 @@ fn foo() {
|
|||||||
fn foo() {
|
fn foo() {
|
||||||
let mut $0var_name = 0;
|
let mut $0var_name = 0;
|
||||||
let v = &mut var_name;
|
let v = &mut var_name;
|
||||||
|
}"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn generates_no_ref_on_calls() {
|
||||||
|
check_assist(
|
||||||
|
extract_variable,
|
||||||
|
r#"
|
||||||
|
struct S;
|
||||||
|
impl S {
|
||||||
|
fn do_work(&mut self) {}
|
||||||
|
}
|
||||||
|
fn bar() -> S { S }
|
||||||
|
fn foo() {
|
||||||
|
$0bar()$0.do_work();
|
||||||
|
}"#,
|
||||||
|
r#"
|
||||||
|
struct S;
|
||||||
|
impl S {
|
||||||
|
fn do_work(&mut self) {}
|
||||||
|
}
|
||||||
|
fn bar() -> S { S }
|
||||||
|
fn foo() {
|
||||||
|
let mut $0bar = bar();
|
||||||
|
bar.do_work();
|
||||||
}"#,
|
}"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user