diff options
| author | A4-Tacks <wdsjxhno1001@163.com> | 2025-09-20 17:04:56 +0800 |
|---|---|---|
| committer | A4-Tacks <wdsjxhno1001@163.com> | 2025-09-20 17:52:01 +0800 |
| commit | 8eda71b98a8540f848cfd33b58f6d284edb64073 (patch) | |
| tree | 8527e294f89728bb9a1419a05591341fe1aeb4e9 | |
| parent | 300aee8239168bfd07114322654da9840d0a2331 (diff) | |
| download | rust-8eda71b98a8540f848cfd33b58f6d284edb64073.tar.gz rust-8eda71b98a8540f848cfd33b58f6d284edb64073.zip | |
Fix panic `!self.data().mutable` for destructure_struct_binding
When the reference type does not require adding a dereference or parentheses, it will panic
Example
---
```rust
struct Foo { bar: i32, baz: i32 }
fn main() {
let $0foo = &Foo { bar: 1, baz: 2 };
let _ = &foo.bar;
}
```
**Before this PR**:
Panic:
```
assertion failed: !self.data().mutable
```
**After this PR**:
```rust
struct Foo { bar: i32, baz: i32 }
fn main() {
let Foo { bar, baz } = &Foo { bar: 1, baz: 2 };
let _ = bar;
}
```
| -rw-r--r-- | src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs | 50 |
1 files changed, 48 insertions, 2 deletions
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs index 397327cb4ff..5ba2f96c01a 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs @@ -288,7 +288,7 @@ fn build_usage_edit( Some(field_expr) => Some({ let field_name: SmolStr = field_expr.name_ref()?.to_string().into(); let new_field_name = field_names.get(&field_name)?; - let new_expr = make.expr_path(ast::make::ext::ident_path(new_field_name)); + let new_expr = ast::make::expr_path(ast::make::ext::ident_path(new_field_name)); // If struct binding is a reference, we might need to deref field usages if data.is_ref { @@ -298,7 +298,7 @@ fn build_usage_edit( ref_data.wrap_expr(new_expr).syntax().clone_for_update(), ) } else { - (field_expr.syntax().clone(), new_expr.syntax().clone()) + (field_expr.syntax().clone(), new_expr.syntax().clone_for_update()) } }), None => Some(( @@ -611,6 +611,52 @@ mod tests { } #[test] + fn ref_not_add_parenthesis_and_deref_record() { + check_assist( + destructure_struct_binding, + r#" + struct Foo { bar: i32, baz: i32 } + + fn main() { + let $0foo = &Foo { bar: 1, baz: 2 }; + let _ = &foo.bar; + } + "#, + r#" + struct Foo { bar: i32, baz: i32 } + + fn main() { + let Foo { bar, baz } = &Foo { bar: 1, baz: 2 }; + let _ = bar; + } + "#, + ) + } + + #[test] + fn ref_not_add_parenthesis_and_deref_tuple() { + check_assist( + destructure_struct_binding, + r#" + struct Foo(i32, i32); + + fn main() { + let $0foo = &Foo(1, 2); + let _ = &foo.0; + } + "#, + r#" + struct Foo(i32, i32); + + fn main() { + let Foo(_0, _1) = &Foo(1, 2); + let _ = _0; + } + "#, + ) + } + + #[test] fn record_struct_name_collision() { check_assist( destructure_struct_binding, |
