Skip to content

Commit a9a66c4

Browse files
authored
Merge pull request rust-lang#22523 from Albab-Hasan/extract-function-index-mut-method
fix: \`extract_function\` misses \`&mut\` for \`container[i].mut_method()\`
2 parents b679057 + 256fe3e commit a9a66c4

1 file changed

Lines changed: 57 additions & 2 deletions

File tree

crates/ide-assists/src/handlers/extract_function.rs

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1197,7 +1197,7 @@ fn reference_is_exclusive(reference: &FileReference, ctx: &AssistContext<'_, '_>
11971197
expr_require_exclusive_access(ctx, &path).unwrap_or(false)
11981198
}
11991199

1200-
/// checks if this expr requires `&mut` access, recurses on field access
1200+
/// checks if this expr requires `&mut` access, recurses on field/index access
12011201
fn expr_require_exclusive_access(ctx: &AssistContext<'_, '_>, expr: &ast::Expr) -> Option<bool> {
12021202
let parent = expr.syntax().parent()?;
12031203

@@ -1220,10 +1220,17 @@ fn expr_require_exclusive_access(ctx: &AssistContext<'_, '_>, expr: &ast::Expr)
12201220
return Some(matches!(access, hir::Access::Exclusive));
12211221
}
12221222

1223-
if let Some(field) = ast::FieldExpr::cast(parent) {
1223+
if let Some(field) = ast::FieldExpr::cast(parent.clone()) {
12241224
return expr_require_exclusive_access(ctx, &field.into());
12251225
}
12261226

1227+
// `container[i].mut_method()` needs `&mut container` but WRITE is not set (no direct assignment).
1228+
if let Some(index_expr) = ast::IndexExpr::cast(parent)
1229+
&& index_expr.base().is_some_and(|base| base.syntax() == expr.syntax())
1230+
{
1231+
return expr_require_exclusive_access(ctx, &index_expr.into());
1232+
}
1233+
12271234
Some(false)
12281235
}
12291236

@@ -3250,6 +3257,54 @@ fn $0fun_name(arr: &mut [i32; 1]) {
32503257
);
32513258
}
32523259

3260+
#[test]
3261+
fn mut_index_element_method_call() {
3262+
check_assist(
3263+
extract_function,
3264+
r#"
3265+
//- minicore: index
3266+
use core::ops::{Index, IndexMut};
3267+
struct Container([S; 2]);
3268+
struct S;
3269+
impl S { fn mutate(&mut self) {} }
3270+
impl Index<usize> for Container {
3271+
type Output = S;
3272+
fn index(&self, i: usize) -> &S { &self.0[i] }
3273+
}
3274+
impl IndexMut<usize> for Container {
3275+
fn index_mut(&mut self, i: usize) -> &mut S { &mut self.0[i] }
3276+
}
3277+
fn foo() {
3278+
let mut c = Container([S, S]);
3279+
$0c[0].mutate();$0
3280+
let _ = c;
3281+
}
3282+
"#,
3283+
r#"
3284+
use core::ops::{Index, IndexMut};
3285+
struct Container([S; 2]);
3286+
struct S;
3287+
impl S { fn mutate(&mut self) {} }
3288+
impl Index<usize> for Container {
3289+
type Output = S;
3290+
fn index(&self, i: usize) -> &S { &self.0[i] }
3291+
}
3292+
impl IndexMut<usize> for Container {
3293+
fn index_mut(&mut self, i: usize) -> &mut S { &mut self.0[i] }
3294+
}
3295+
fn foo() {
3296+
let mut c = Container([S, S]);
3297+
fun_name(&mut c);
3298+
let _ = c;
3299+
}
3300+
3301+
fn $0fun_name(c: &mut Container) {
3302+
c[0].mutate();
3303+
}
3304+
"#,
3305+
);
3306+
}
3307+
32533308
#[test]
32543309
fn mut_field_from_outer_scope() {
32553310
check_assist(

0 commit comments

Comments
 (0)