@@ -15,7 +15,7 @@ use ide_db::{
15
15
};
16
16
use itertools::{izip, Itertools};
17
17
use syntax::{
18
- ast::{self, edit::IndentLevel, edit_in_place::Indent, HasArgList, PathExpr},
18
+ ast::{self, edit::IndentLevel, edit_in_place::Indent, HasArgList, Pat, PathExpr},
19
19
ted, AstNode, NodeOrToken, SyntaxKind,
20
20
};
21
21
@@ -278,7 +278,7 @@ fn get_fn_params(
278
278
279
279
let mut params = Vec::new();
280
280
if let Some(self_param) = param_list.self_param() {
281
- // FIXME this should depend on the receiver as well as the self_param
281
+ // Keep `ref` and `mut` and transform them into `&` and `mut` later
282
282
params.push((
283
283
make::ident_pat(
284
284
self_param.amp_token().is_some(),
@@ -409,16 +409,56 @@ fn inline(
409
409
let mut let_stmts = Vec::new();
410
410
411
411
// Inline parameter expressions or generate `let` statements depending on whether inlining works or not.
412
- for ((pat, param_ty, _ ), usages, expr) in izip!(params, param_use_nodes, arguments) {
412
+ for ((pat, param_ty, param ), usages, expr) in izip!(params, param_use_nodes, arguments) {
413
413
// izip confuses RA due to our lack of hygiene info currently losing us type info causing incorrect errors
414
414
let usages: &[ast::PathExpr] = &usages;
415
415
let expr: &ast::Expr = expr;
416
416
417
417
let mut insert_let_stmt = || {
418
418
let ty = sema.type_of_expr(expr).filter(TypeInfo::has_adjustment).and(param_ty.clone());
419
- let_stmts.push(
420
- make::let_stmt(pat.clone(), ty, Some(expr.clone())).clone_for_update().into(),
421
- );
419
+
420
+ let is_self = param
421
+ .name(sema.db)
422
+ .and_then(|name| name.as_text())
423
+ .is_some_and(|name| name == "self");
424
+
425
+ if is_self {
426
+ let mut this_pat = make::ident_pat(false, false, make::name("this"));
427
+ let mut expr = expr.clone();
428
+ match pat {
429
+ Pat::IdentPat(pat) => match (pat.ref_token(), pat.mut_token()) {
430
+ // self => let this = obj
431
+ (None, None) => {}
432
+ // mut self => let mut this = obj
433
+ (None, Some(_)) => {
434
+ this_pat = make::ident_pat(false, true, make::name("this"));
435
+ }
436
+ // &self => let this = &obj
437
+ (Some(_), None) => {
438
+ expr = make::expr_ref(expr, false);
439
+ }
440
+ // let foo = &mut X; &mut self => let this = &mut obj
441
+ // let mut foo = X; &mut self => let this = &mut *obj (reborrow)
442
+ (Some(_), Some(_)) => {
443
+ let should_reborrow = sema
444
+ .type_of_expr(&expr)
445
+ .map(|ty| ty.original.is_mutable_reference());
446
+ expr = if let Some(true) = should_reborrow {
447
+ make::expr_reborrow(expr)
448
+ } else {
449
+ make::expr_ref(expr, true)
450
+ };
451
+ }
452
+ },
453
+ _ => {}
454
+ };
455
+ let_stmts
456
+ .push(make::let_stmt(this_pat.into(), ty, Some(expr)).clone_for_update().into())
457
+ } else {
458
+ let_stmts.push(
459
+ make::let_stmt(pat.clone(), ty, Some(expr.clone())).clone_for_update().into(),
460
+ );
461
+ }
422
462
};
423
463
424
464
// check if there is a local var in the function that conflicts with parameter
0 commit comments