Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/ide-assists/src/handlers/inline_call.rs')
-rw-r--r--crates/ide-assists/src/handlers/inline_call.rs147
1 files changed, 130 insertions, 17 deletions
diff --git a/crates/ide-assists/src/handlers/inline_call.rs b/crates/ide-assists/src/handlers/inline_call.rs
index 2eb7089b7c..4ba33ada48 100644
--- a/crates/ide-assists/src/handlers/inline_call.rs
+++ b/crates/ide-assists/src/handlers/inline_call.rs
@@ -15,7 +15,7 @@ use ide_db::{
};
use itertools::{izip, Itertools};
use syntax::{
- ast::{self, edit::IndentLevel, edit_in_place::Indent, HasArgList, PathExpr},
+ ast::{self, edit::IndentLevel, edit_in_place::Indent, HasArgList, Pat, PathExpr},
ted, AstNode, NodeOrToken, SyntaxKind,
};
@@ -278,7 +278,7 @@ fn get_fn_params(
let mut params = Vec::new();
if let Some(self_param) = param_list.self_param() {
- // FIXME this should depend on the receiver as well as the self_param
+ // Keep `ref` and `mut` and transform them into `&` and `mut` later
params.push((
make::ident_pat(
self_param.amp_token().is_some(),
@@ -409,16 +409,55 @@ fn inline(
let mut let_stmts = Vec::new();
// Inline parameter expressions or generate `let` statements depending on whether inlining works or not.
- for ((pat, param_ty, _), usages, expr) in izip!(params, param_use_nodes, arguments) {
+ for ((pat, param_ty, param), usages, expr) in izip!(params, param_use_nodes, arguments) {
// izip confuses RA due to our lack of hygiene info currently losing us type info causing incorrect errors
let usages: &[ast::PathExpr] = &usages;
let expr: &ast::Expr = expr;
let mut insert_let_stmt = || {
let ty = sema.type_of_expr(expr).filter(TypeInfo::has_adjustment).and(param_ty.clone());
- let_stmts.push(
- make::let_stmt(pat.clone(), ty, Some(expr.clone())).clone_for_update().into(),
- );
+
+ let is_self = param
+ .name(sema.db)
+ .and_then(|name| name.as_text())
+ .is_some_and(|name| name == "self");
+
+ if is_self {
+ let mut this_pat = make::ident_pat(false, false, make::name("this"));
+ let mut expr = expr.clone();
+ if let Pat::IdentPat(pat) = pat {
+ match (pat.ref_token(), pat.mut_token()) {
+ // self => let this = obj
+ (None, None) => {}
+ // mut self => let mut this = obj
+ (None, Some(_)) => {
+ this_pat = make::ident_pat(false, true, make::name("this"));
+ }
+ // &self => let this = &obj
+ (Some(_), None) => {
+ expr = make::expr_ref(expr, false);
+ }
+ // let foo = &mut X; &mut self => let this = &mut obj
+ // let mut foo = X; &mut self => let this = &mut *obj (reborrow)
+ (Some(_), Some(_)) => {
+ let should_reborrow = sema
+ .type_of_expr(&expr)
+ .map(|ty| ty.original.is_mutable_reference());
+ expr = if let Some(true) = should_reborrow {
+ make::expr_reborrow(expr)
+ } else {
+ make::expr_ref(expr, true)
+ };
+ }
+ }
+ };
+ let_stmts
+ .push(make::let_stmt(this_pat.into(), ty, Some(expr)).clone_for_update().into())
+ } else {
+ let_stmts.push(
+ make::let_stmt(pat.clone(), ty, Some(expr.clone())).clone_for_update().into(),
+ );
+ }
};
// check if there is a local var in the function that conflicts with parameter
@@ -484,12 +523,10 @@ fn inline(
body = make::block_expr(let_stmts, Some(body.into())).clone_for_update();
}
} else if let Some(stmt_list) = body.stmt_list() {
- ted::insert_all(
- ted::Position::after(
- stmt_list.l_curly_token().expect("L_CURLY for StatementList is missing."),
- ),
- let_stmts.into_iter().map(|stmt| stmt.syntax().clone().into()).collect(),
- );
+ let position = stmt_list.l_curly_token().expect("L_CURLY for StatementList is missing.");
+ let_stmts.into_iter().rev().for_each(|let_stmt| {
+ ted::insert(ted::Position::after(position.clone()), let_stmt.syntax().clone());
+ });
}
let original_indentation = match node {
@@ -721,7 +758,7 @@ impl Foo {
fn main() {
let x = {
- let ref this = Foo(3);
+ let this = &Foo(3);
Foo(this.0 + 2)
};
}
@@ -757,7 +794,7 @@ impl Foo {
fn main() {
let x = {
- let ref this = Foo(3);
+ let this = &Foo(3);
Foo(this.0 + 2)
};
}
@@ -795,7 +832,7 @@ impl Foo {
fn main() {
let mut foo = Foo(3);
{
- let ref mut this = foo;
+ let this = &mut foo;
this.0 = 0;
};
}
@@ -882,7 +919,7 @@ impl Foo {
}
fn bar(&self) {
{
- let ref this = self;
+ let this = &self;
this;
this;
};
@@ -1557,7 +1594,7 @@ impl Enum {
fn a() -> bool {
{
- let ref this = Enum::A;
+ let this = &Enum::A;
this == &Enum::A || this == &Enum::B
}
}
@@ -1622,4 +1659,80 @@ fn main() {
"#,
)
}
+
+ #[test]
+ fn method_by_reborrow() {
+ check_assist(
+ inline_call,
+ r#"
+pub struct Foo(usize);
+
+impl Foo {
+ fn add1(&mut self) {
+ self.0 += 1;
+ }
+}
+
+pub fn main() {
+ let f = &mut Foo(0);
+ f.add1$0();
+}
+"#,
+ r#"
+pub struct Foo(usize);
+
+impl Foo {
+ fn add1(&mut self) {
+ self.0 += 1;
+ }
+}
+
+pub fn main() {
+ let f = &mut Foo(0);
+ {
+ let this = &mut *f;
+ this.0 += 1;
+ };
+}
+"#,
+ )
+ }
+
+ #[test]
+ fn method_by_mut() {
+ check_assist(
+ inline_call,
+ r#"
+pub struct Foo(usize);
+
+impl Foo {
+ fn add1(mut self) {
+ self.0 += 1;
+ }
+}
+
+pub fn main() {
+ let mut f = Foo(0);
+ f.add1$0();
+}
+"#,
+ r#"
+pub struct Foo(usize);
+
+impl Foo {
+ fn add1(mut self) {
+ self.0 += 1;
+ }
+}
+
+pub fn main() {
+ let mut f = Foo(0);
+ {
+ let mut this = f;
+ this.0 += 1;
+ };
+}
+"#,
+ )
+ }
}