Skip to content

Commit e088a17

Browse files
committed
Don't rename field record patterns directly
1 parent 9b04506 commit e088a17

File tree

2 files changed

+73
-38
lines changed

2 files changed

+73
-38
lines changed

crates/ide/src/references/rename.rs

Lines changed: 71 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -183,25 +183,41 @@ fn source_edit_from_references(
183183
) -> (FileId, TextEdit) {
184184
let mut edit = TextEdit::builder();
185185
for reference in references {
186-
match reference.name.as_name_ref() {
186+
let (range, replacement) = match &reference.name {
187187
// if the ranges differ then the node is inside a macro call, we can't really attempt
188188
// to make special rewrites like shorthand syntax and such, so just rename the node in
189189
// the macro input
190-
Some(name_ref) if name_ref.syntax().text_range() == reference.range => {
191-
let (range, replacement) = source_edit_from_name_ref(name_ref, new_name, def);
192-
edit.replace(range, replacement);
190+
NameLike::NameRef(name_ref) if name_ref.syntax().text_range() == reference.range => {
191+
source_edit_from_name_ref(name_ref, new_name, def)
193192
}
194-
_ => edit.replace(reference.range, new_name.to_owned()),
195-
};
193+
NameLike::Name(name) if name.syntax().text_range() == reference.range => {
194+
source_edit_from_name(name, new_name)
195+
}
196+
_ => None,
197+
}
198+
.unwrap_or_else(|| (reference.range, new_name.to_string()));
199+
edit.replace(range, replacement);
196200
}
197201
(file_id, edit.finish())
198202
}
199203

204+
fn source_edit_from_name(name: &ast::Name, new_name: &str) -> Option<(TextRange, String)> {
205+
if let Some(_) = ast::RecordPatField::for_field_name(name) {
206+
if let Some(ident_pat) = name.syntax().parent().and_then(ast::IdentPat::cast) {
207+
return Some((
208+
TextRange::empty(ident_pat.syntax().text_range().start()),
209+
format!("{}: ", new_name),
210+
));
211+
}
212+
}
213+
None
214+
}
215+
200216
fn source_edit_from_name_ref(
201217
name_ref: &ast::NameRef,
202218
new_name: &str,
203219
def: Definition,
204-
) -> (TextRange, String) {
220+
) -> Option<(TextRange, String)> {
205221
if let Some(record_field) = ast::RecordExprField::for_name_ref(name_ref) {
206222
let rcf_name_ref = record_field.name_ref();
207223
let rcf_expr = record_field.expr();
@@ -215,7 +231,7 @@ fn source_edit_from_name_ref(
215231
// we do not want to erase attributes hence this range start
216232
let s = field_name.syntax().text_range().start();
217233
let e = record_field.syntax().text_range().end();
218-
return (TextRange::new(s, e), new_name.to_owned());
234+
return Some((TextRange::new(s, e), new_name.to_owned()));
219235
}
220236
} else if init == *name_ref {
221237
if field_name.text() == new_name {
@@ -224,32 +240,27 @@ fn source_edit_from_name_ref(
224240
// we do not want to erase attributes hence this range start
225241
let s = field_name.syntax().text_range().start();
226242
let e = record_field.syntax().text_range().end();
227-
return (TextRange::new(s, e), new_name.to_owned());
243+
return Some((TextRange::new(s, e), new_name.to_owned()));
228244
}
229245
}
246+
None
230247
}
231248
// init shorthand
232-
(None, Some(_)) => {
233-
// FIXME: instead of splitting the shorthand, recursively trigger a rename of the
234-
// other name https://github.com/rust-analyzer/rust-analyzer/issues/6547
235-
match def {
236-
Definition::Field(_) => {
237-
mark::hit!(test_rename_field_in_field_shorthand);
238-
let s = name_ref.syntax().text_range().start();
239-
return (TextRange::empty(s), format!("{}: ", new_name));
240-
}
241-
Definition::Local(_) => {
242-
mark::hit!(test_rename_local_in_field_shorthand);
243-
let s = name_ref.syntax().text_range().end();
244-
return (TextRange::empty(s), format!(": {}", new_name));
245-
}
246-
_ => {}
247-
}
249+
// FIXME: instead of splitting the shorthand, recursively trigger a rename of the
250+
// other name https://github.com/rust-analyzer/rust-analyzer/issues/6547
251+
(None, Some(_)) if matches!(def, Definition::Field(_)) => {
252+
mark::hit!(test_rename_field_in_field_shorthand);
253+
let s = name_ref.syntax().text_range().start();
254+
Some((TextRange::empty(s), format!("{}: ", new_name)))
255+
}
256+
(None, Some(_)) if matches!(def, Definition::Local(_)) => {
257+
mark::hit!(test_rename_local_in_field_shorthand);
258+
let s = name_ref.syntax().text_range().end();
259+
Some((TextRange::empty(s), format!(": {}", new_name)))
248260
}
249-
_ => {}
261+
_ => None,
250262
}
251-
}
252-
if let Some(record_field) = ast::RecordPatField::for_field_name_ref(name_ref) {
263+
} else if let Some(record_field) = ast::RecordPatField::for_field_name_ref(name_ref) {
253264
let rcf_name_ref = record_field.name_ref();
254265
let rcf_pat = record_field.pat();
255266
match (rcf_name_ref, rcf_pat) {
@@ -262,13 +273,16 @@ fn source_edit_from_name_ref(
262273
// we do not want to erase attributes hence this range start
263274
let s = field_name.syntax().text_range().start();
264275
let e = record_field.syntax().text_range().end();
265-
return (TextRange::new(s, e), new_name.to_owned());
276+
Some((TextRange::new(s, e), pat.to_string()))
277+
} else {
278+
None
266279
}
267280
}
268-
_ => {}
281+
_ => None,
269282
}
283+
} else {
284+
None
270285
}
271-
(name_ref.syntax().text_range(), new_name.to_owned())
272286
}
273287

274288
fn rename_mod(
@@ -1491,24 +1505,24 @@ fn foo(i: i32) -> Foo {
14911505
}
14921506

14931507
#[test]
1494-
fn test_struct_field_destructure_into_shorthand() {
1508+
fn test_struct_field_pat_into_shorthand() {
14951509
mark::check!(test_rename_field_put_init_shorthand_pat);
14961510
check(
14971511
"baz",
14981512
r#"
14991513
struct Foo { i$0: i32 }
15001514
15011515
fn foo(foo: Foo) {
1502-
let Foo { i: baz } = foo;
1503-
let _ = baz;
1516+
let Foo { i: ref baz @ qux } = foo;
1517+
let _ = qux;
15041518
}
15051519
"#,
15061520
r#"
15071521
struct Foo { baz: i32 }
15081522
15091523
fn foo(foo: Foo) {
1510-
let Foo { baz } = foo;
1511-
let _ = baz;
1524+
let Foo { ref baz @ qux } = foo;
1525+
let _ = qux;
15121526
}
15131527
"#,
15141528
);
@@ -1581,6 +1595,27 @@ fn foo(Foo { i: bar }: foo) -> i32 {
15811595
)
15821596
}
15831597

1598+
#[test]
1599+
fn test_struct_field_complex_ident_pat() {
1600+
check(
1601+
"baz",
1602+
r#"
1603+
struct Foo { i$0: i32 }
1604+
1605+
fn foo(foo: Foo) {
1606+
let Foo { ref i } = foo;
1607+
}
1608+
"#,
1609+
r#"
1610+
struct Foo { baz: i32 }
1611+
1612+
fn foo(foo: Foo) {
1613+
let Foo { baz: ref i } = foo;
1614+
}
1615+
"#,
1616+
);
1617+
}
1618+
15841619
#[test]
15851620
fn test_rename_lifetimes() {
15861621
mark::check!(rename_lifetime);

crates/syntax/src/ast/node_ext.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
44
use std::fmt;
55

6-
use ast::AttrsOwner;
6+
use ast::{AttrsOwner, IdentPat};
77
use itertools::Itertools;
88
use parser::SyntaxKind;
99

@@ -324,7 +324,7 @@ impl ast::RecordPatField {
324324

325325
pub fn for_field_name(field_name: &ast::Name) -> Option<ast::RecordPatField> {
326326
let candidate =
327-
field_name.syntax().ancestors().nth(3).and_then(ast::RecordPatField::cast)?;
327+
field_name.syntax().ancestors().nth(2).and_then(ast::RecordPatField::cast)?;
328328
match candidate.field_name()? {
329329
NameOrNameRef::Name(name) if name == *field_name => Some(candidate),
330330
_ => None,

0 commit comments

Comments
 (0)