) -> (FileId, TextEdit) {
let mut edit = TextEdit::builder();
for reference in references {
- match reference.name.as_name_ref() {
+ let (range, replacement) = match &reference.name {
// if the ranges differ then the node is inside a macro call, we can't really attempt
// to make special rewrites like shorthand syntax and such, so just rename the node in
// the macro input
- Some(name_ref) if name_ref.syntax().text_range() == reference.range => {
- let (range, replacement) = source_edit_from_name_ref(name_ref, new_name, def);
- edit.replace(range, replacement);
+ NameLike::NameRef(name_ref) if name_ref.syntax().text_range() == reference.range => {
+ source_edit_from_name_ref(name_ref, new_name, def)
}
- _ => edit.replace(reference.range, new_name.to_owned()),
- };
+ NameLike::Name(name) if name.syntax().text_range() == reference.range => {
+ source_edit_from_name(name, new_name)
+ }
+ _ => None,
+ }
+ .unwrap_or_else(|| (reference.range, new_name.to_string()));
+ edit.replace(range, replacement);
}
(file_id, edit.finish())
}
+fn source_edit_from_name(name: &ast::Name, new_name: &str) -> Option<(TextRange, String)> {
+ if let Some(_) = ast::RecordPatField::for_field_name(name) {
+ if let Some(ident_pat) = name.syntax().parent().and_then(ast::IdentPat::cast) {
+ return Some((
+ TextRange::empty(ident_pat.syntax().text_range().start()),
+ format!("{}: ", new_name),
+ ));
+ }
+ }
+ None
+}
+
fn source_edit_from_name_ref(
name_ref: &ast::NameRef,
new_name: &str,
def: Definition,
-) -> (TextRange, String) {
+) -> Option<(TextRange, String)> {
if let Some(record_field) = ast::RecordExprField::for_name_ref(name_ref) {
let rcf_name_ref = record_field.name_ref();
let rcf_expr = record_field.expr();
// we do not want to erase attributes hence this range start
let s = field_name.syntax().text_range().start();
let e = record_field.syntax().text_range().end();
- return (TextRange::new(s, e), new_name.to_owned());
+ return Some((TextRange::new(s, e), new_name.to_owned()));
}
} else if init == *name_ref {
if field_name.text() == new_name {
// we do not want to erase attributes hence this range start
let s = field_name.syntax().text_range().start();
let e = record_field.syntax().text_range().end();
- return (TextRange::new(s, e), new_name.to_owned());
+ return Some((TextRange::new(s, e), new_name.to_owned()));
}
}
+ None
}
// init shorthand
- (None, Some(_)) => {
- // FIXME: instead of splitting the shorthand, recursively trigger a rename of the
- // other name https://github.com/rust-analyzer/rust-analyzer/issues/6547
- match def {
- Definition::Field(_) => {
- mark::hit!(test_rename_field_in_field_shorthand);
- let s = name_ref.syntax().text_range().start();
- return (TextRange::empty(s), format!("{}: ", new_name));
- }
- Definition::Local(_) => {
- mark::hit!(test_rename_local_in_field_shorthand);
- let s = name_ref.syntax().text_range().end();
- return (TextRange::empty(s), format!(": {}", new_name));
- }
- _ => {}
- }
+ // FIXME: instead of splitting the shorthand, recursively trigger a rename of the
+ // other name https://github.com/rust-analyzer/rust-analyzer/issues/6547
+ (None, Some(_)) if matches!(def, Definition::Field(_)) => {
+ mark::hit!(test_rename_field_in_field_shorthand);
+ let s = name_ref.syntax().text_range().start();
+ Some((TextRange::empty(s), format!("{}: ", new_name)))
+ }
+ (None, Some(_)) if matches!(def, Definition::Local(_)) => {
+ mark::hit!(test_rename_local_in_field_shorthand);
+ let s = name_ref.syntax().text_range().end();
+ Some((TextRange::empty(s), format!(": {}", new_name)))
}
- _ => {}
+ _ => None,
}
- }
- if let Some(record_field) = ast::RecordPatField::for_field_name_ref(name_ref) {
+ } else if let Some(record_field) = ast::RecordPatField::for_field_name_ref(name_ref) {
let rcf_name_ref = record_field.name_ref();
let rcf_pat = record_field.pat();
match (rcf_name_ref, rcf_pat) {
// we do not want to erase attributes hence this range start
let s = field_name.syntax().text_range().start();
let e = record_field.syntax().text_range().end();
- return (TextRange::new(s, e), new_name.to_owned());
+ Some((TextRange::new(s, e), pat.to_string()))
+ } else {
+ None
}
}
- _ => {}
+ _ => None,
}
+ } else {
+ None
}
- (name_ref.syntax().text_range(), new_name.to_owned())
}
fn rename_mod(
}
#[test]
- fn test_struct_field_destructure_into_shorthand() {
+ fn test_struct_field_pat_into_shorthand() {
mark::check!(test_rename_field_put_init_shorthand_pat);
check(
"baz",
struct Foo { i$0: i32 }
fn foo(foo: Foo) {
- let Foo { i: baz } = foo;
- let _ = baz;
+ let Foo { i: ref baz @ qux } = foo;
+ let _ = qux;
}
"#,
r#"
struct Foo { baz: i32 }
fn foo(foo: Foo) {
- let Foo { baz } = foo;
- let _ = baz;
+ let Foo { ref baz @ qux } = foo;
+ let _ = qux;
}
"#,
);
)
}
+ #[test]
+ fn test_struct_field_complex_ident_pat() {
+ check(
+ "baz",
+ r#"
+struct Foo { i$0: i32 }
+
+fn foo(foo: Foo) {
+ let Foo { ref i } = foo;
+}
+"#,
+ r#"
+struct Foo { baz: i32 }
+
+fn foo(foo: Foo) {
+ let Foo { baz: ref i } = foo;
+}
+"#,
+ );
+ }
+
#[test]
fn test_rename_lifetimes() {
mark::check!(rename_lifetime);