mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-10-01 06:11:35 +00:00
Don't rename field record patterns directly
This commit is contained in:
parent
9b04506924
commit
7b64622780
2 changed files with 73 additions and 39 deletions
|
@ -183,25 +183,41 @@ fn source_edit_from_references(
|
||||||
) -> (FileId, TextEdit) {
|
) -> (FileId, TextEdit) {
|
||||||
let mut edit = TextEdit::builder();
|
let mut edit = TextEdit::builder();
|
||||||
for reference in references {
|
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
|
// 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
|
// to make special rewrites like shorthand syntax and such, so just rename the node in
|
||||||
// the macro input
|
// the macro input
|
||||||
Some(name_ref) if name_ref.syntax().text_range() == reference.range => {
|
NameLike::NameRef(name_ref) if name_ref.syntax().text_range() == reference.range => {
|
||||||
let (range, replacement) = source_edit_from_name_ref(name_ref, new_name, def);
|
source_edit_from_name_ref(name_ref, new_name, def)
|
||||||
edit.replace(range, replacement);
|
|
||||||
}
|
}
|
||||||
_ => 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())
|
(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(
|
fn source_edit_from_name_ref(
|
||||||
name_ref: &ast::NameRef,
|
name_ref: &ast::NameRef,
|
||||||
new_name: &str,
|
new_name: &str,
|
||||||
def: Definition,
|
def: Definition,
|
||||||
) -> (TextRange, String) {
|
) -> Option<(TextRange, String)> {
|
||||||
if let Some(record_field) = ast::RecordExprField::for_name_ref(name_ref) {
|
if let Some(record_field) = ast::RecordExprField::for_name_ref(name_ref) {
|
||||||
let rcf_name_ref = record_field.name_ref();
|
let rcf_name_ref = record_field.name_ref();
|
||||||
let rcf_expr = record_field.expr();
|
let rcf_expr = record_field.expr();
|
||||||
|
@ -215,7 +231,7 @@ fn source_edit_from_name_ref(
|
||||||
// we do not want to erase attributes hence this range start
|
// we do not want to erase attributes hence this range start
|
||||||
let s = field_name.syntax().text_range().start();
|
let s = field_name.syntax().text_range().start();
|
||||||
let e = record_field.syntax().text_range().end();
|
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 {
|
} else if init == *name_ref {
|
||||||
if field_name.text() == new_name {
|
if field_name.text() == new_name {
|
||||||
|
@ -224,32 +240,27 @@ fn source_edit_from_name_ref(
|
||||||
// we do not want to erase attributes hence this range start
|
// we do not want to erase attributes hence this range start
|
||||||
let s = field_name.syntax().text_range().start();
|
let s = field_name.syntax().text_range().start();
|
||||||
let e = record_field.syntax().text_range().end();
|
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
|
// init shorthand
|
||||||
(None, Some(_)) => {
|
// FIXME: instead of splitting the shorthand, recursively trigger a rename of the
|
||||||
// FIXME: instead of splitting the shorthand, recursively trigger a rename of the
|
// other name https://github.com/rust-analyzer/rust-analyzer/issues/6547
|
||||||
// other name https://github.com/rust-analyzer/rust-analyzer/issues/6547
|
(None, Some(_)) if matches!(def, Definition::Field(_)) => {
|
||||||
match def {
|
mark::hit!(test_rename_field_in_field_shorthand);
|
||||||
Definition::Field(_) => {
|
let s = name_ref.syntax().text_range().start();
|
||||||
mark::hit!(test_rename_field_in_field_shorthand);
|
Some((TextRange::empty(s), format!("{}: ", new_name)))
|
||||||
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));
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
_ => {}
|
(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,
|
||||||
}
|
}
|
||||||
}
|
} else if let Some(record_field) = ast::RecordPatField::for_field_name_ref(name_ref) {
|
||||||
if let Some(record_field) = ast::RecordPatField::for_field_name_ref(name_ref) {
|
|
||||||
let rcf_name_ref = record_field.name_ref();
|
let rcf_name_ref = record_field.name_ref();
|
||||||
let rcf_pat = record_field.pat();
|
let rcf_pat = record_field.pat();
|
||||||
match (rcf_name_ref, rcf_pat) {
|
match (rcf_name_ref, rcf_pat) {
|
||||||
|
@ -262,13 +273,16 @@ fn source_edit_from_name_ref(
|
||||||
// we do not want to erase attributes hence this range start
|
// we do not want to erase attributes hence this range start
|
||||||
let s = field_name.syntax().text_range().start();
|
let s = field_name.syntax().text_range().start();
|
||||||
let e = record_field.syntax().text_range().end();
|
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(
|
fn rename_mod(
|
||||||
|
@ -1491,7 +1505,7 @@ fn foo(i: i32) -> Foo {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_struct_field_destructure_into_shorthand() {
|
fn test_struct_field_pat_into_shorthand() {
|
||||||
mark::check!(test_rename_field_put_init_shorthand_pat);
|
mark::check!(test_rename_field_put_init_shorthand_pat);
|
||||||
check(
|
check(
|
||||||
"baz",
|
"baz",
|
||||||
|
@ -1499,16 +1513,16 @@ fn foo(i: i32) -> Foo {
|
||||||
struct Foo { i$0: i32 }
|
struct Foo { i$0: i32 }
|
||||||
|
|
||||||
fn foo(foo: Foo) {
|
fn foo(foo: Foo) {
|
||||||
let Foo { i: baz } = foo;
|
let Foo { i: ref baz @ qux } = foo;
|
||||||
let _ = baz;
|
let _ = qux;
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
r#"
|
r#"
|
||||||
struct Foo { baz: i32 }
|
struct Foo { baz: i32 }
|
||||||
|
|
||||||
fn foo(foo: Foo) {
|
fn foo(foo: Foo) {
|
||||||
let Foo { baz } = foo;
|
let Foo { ref baz @ qux } = foo;
|
||||||
let _ = baz;
|
let _ = qux;
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
|
@ -1581,6 +1595,27 @@ fn foo(Foo { i: bar }: foo) -> i32 {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[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]
|
#[test]
|
||||||
fn test_rename_lifetimes() {
|
fn test_rename_lifetimes() {
|
||||||
mark::check!(rename_lifetime);
|
mark::check!(rename_lifetime);
|
||||||
|
|
|
@ -3,12 +3,11 @@
|
||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
use ast::AttrsOwner;
|
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use parser::SyntaxKind;
|
use parser::SyntaxKind;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
ast::{self, support, AstNode, AstToken, NameOwner, SyntaxNode},
|
ast::{self, support, AstNode, AstToken, AttrsOwner, NameOwner, SyntaxNode},
|
||||||
SmolStr, SyntaxElement, SyntaxToken, T,
|
SmolStr, SyntaxElement, SyntaxToken, T,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -324,7 +323,7 @@ impl ast::RecordPatField {
|
||||||
|
|
||||||
pub fn for_field_name(field_name: &ast::Name) -> Option<ast::RecordPatField> {
|
pub fn for_field_name(field_name: &ast::Name) -> Option<ast::RecordPatField> {
|
||||||
let candidate =
|
let candidate =
|
||||||
field_name.syntax().ancestors().nth(3).and_then(ast::RecordPatField::cast)?;
|
field_name.syntax().ancestors().nth(2).and_then(ast::RecordPatField::cast)?;
|
||||||
match candidate.field_name()? {
|
match candidate.field_name()? {
|
||||||
NameOrNameRef::Name(name) if name == *field_name => Some(candidate),
|
NameOrNameRef::Name(name) if name == *field_name => Some(candidate),
|
||||||
_ => None,
|
_ => None,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue