Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/ide_assists/src/handlers/extract_variable.rs')
-rw-r--r--crates/ide_assists/src/handlers/extract_variable.rs90
1 files changed, 88 insertions, 2 deletions
diff --git a/crates/ide_assists/src/handlers/extract_variable.rs b/crates/ide_assists/src/handlers/extract_variable.rs
index 7a57ab3b9b..d7a8e1dd4c 100644
--- a/crates/ide_assists/src/handlers/extract_variable.rs
+++ b/crates/ide_assists/src/handlers/extract_variable.rs
@@ -52,6 +52,12 @@ pub(crate) fn extract_variable(acc: &mut Assists, ctx: &AssistContext) -> Option
}
}
+ let is_mutable_reference = if let Some(receiver_type) = get_receiver_type(&ctx, &to_extract) {
+ receiver_type.is_mutable_reference()
+ } else {
+ false
+ };
+
let anchor = Anchor::from(&to_extract)?;
let indent = anchor.syntax().prev_sibling_or_token()?.as_token()?.clone();
let target = to_extract.syntax().text_range();
@@ -77,11 +83,15 @@ pub(crate) fn extract_variable(acc: &mut Assists, ctx: &AssistContext) -> Option
None => to_extract.syntax().text_range(),
};
+ let reference_modifier = if is_mutable_reference { "&mut " } else { "" };
+
match anchor {
Anchor::Before(_) | Anchor::Replace(_) => {
- format_to!(buf, "let {} = ", var_name)
+ format_to!(buf, "let {} = {}", var_name, reference_modifier)
+ }
+ Anchor::WrapInBlock(_) => {
+ format_to!(buf, "{{ let {} = {}", var_name, reference_modifier)
}
- Anchor::WrapInBlock(_) => format_to!(buf, "{{ let {} = ", var_name),
};
format_to!(buf, "{}", to_extract.syntax());
@@ -146,6 +156,22 @@ fn valid_target_expr(node: SyntaxNode) -> Option<ast::Expr> {
}
}
+fn get_receiver_type(ctx: &AssistContext, expression: &ast::Expr) -> Option<hir::Type> {
+ let receiver = get_receiver(expression.to_owned())?;
+ Some(ctx.sema.type_of_expr(&receiver)?.original())
+}
+
+fn get_receiver(expression: ast::Expr) -> Option<ast::Expr> {
+ match expression {
+ ast::Expr::FieldExpr(field) if field.expr().is_some() => {
+ let nested_expression = &field.expr()?;
+ get_receiver(nested_expression.to_owned())
+ }
+ ast::Expr::PathExpr(_) => Some(expression),
+ _ => None,
+ }
+}
+
#[derive(Debug)]
enum Anchor {
Before(SyntaxNode),
@@ -900,4 +926,64 @@ const X: usize = $0100$0;
",
);
}
+
+ #[test]
+ fn test_extract_var_mutable_reference_parameter() {
+ check_assist(
+ extract_variable,
+ r#"
+struct S {
+ vec: Vec<u8>
+}
+
+fn foo(s: &mut S) {
+ $0s.vec$0.push(0);
+}"#,
+ r#"
+struct S {
+ vec: Vec<u8>
+}
+
+fn foo(s: &mut S) {
+ let $0var_name = &mut s.vec;
+ var_name.push(0);
+}"#,
+ );
+ }
+
+ #[test]
+ fn test_extract_var_mutable_reference_parameter_deep_nesting() {
+ check_assist(
+ extract_variable,
+ r#"
+struct Y {
+ field: X
+}
+struct X {
+ field: S
+}
+struct S {
+ vec: Vec<u8>
+}
+
+fn foo(f: &mut Y) {
+ $0f.field.field.vec$0.push(0);
+}"#,
+ r#"
+struct Y {
+ field: X
+}
+struct X {
+ field: S
+}
+struct S {
+ vec: Vec<u8>
+}
+
+fn foo(f: &mut Y) {
+ let $0var_name = &mut f.field.field.vec;
+ var_name.push(0);
+}"#,
+ );
+ }
}