Skip to content

Commit 5e533e5

Browse files
committed
Handle all rename special cases for all record pattern fields
1 parent 6a07bf6 commit 5e533e5

File tree

4 files changed

+112
-23
lines changed

4 files changed

+112
-23
lines changed

crates/ide/src/rename.rs

Lines changed: 65 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1332,9 +1332,71 @@ fn foo(foo: Foo) {
13321332
struct Foo { baz: i32 }
13331333
13341334
fn foo(foo: Foo) {
1335-
let Foo { ref baz @ qux } = foo;
1335+
let Foo { baz: ref baz @ qux } = foo;
13361336
let _ = qux;
13371337
}
1338+
"#,
1339+
);
1340+
check(
1341+
"baz",
1342+
r#"
1343+
struct Foo { i$0: i32 }
1344+
1345+
fn foo(foo: Foo) {
1346+
let Foo { i: ref baz } = foo;
1347+
let _ = qux;
1348+
}
1349+
"#,
1350+
r#"
1351+
struct Foo { baz: i32 }
1352+
1353+
fn foo(foo: Foo) {
1354+
let Foo { ref baz } = foo;
1355+
let _ = qux;
1356+
}
1357+
"#,
1358+
);
1359+
}
1360+
1361+
#[test]
1362+
fn test_struct_local_pat_into_shorthand() {
1363+
cov_mark::check!(test_rename_local_put_init_shorthand_pat);
1364+
check(
1365+
"field",
1366+
r#"
1367+
struct Foo { field: i32 }
1368+
1369+
fn foo(foo: Foo) {
1370+
let Foo { field: qux$0 } = foo;
1371+
let _ = qux;
1372+
}
1373+
"#,
1374+
r#"
1375+
struct Foo { field: i32 }
1376+
1377+
fn foo(foo: Foo) {
1378+
let Foo { field } = foo;
1379+
let _ = field;
1380+
}
1381+
"#,
1382+
);
1383+
check(
1384+
"field",
1385+
r#"
1386+
struct Foo { field: i32 }
1387+
1388+
fn foo(foo: Foo) {
1389+
let Foo { field: x @ qux$0 } = foo;
1390+
let _ = qux;
1391+
}
1392+
"#,
1393+
r#"
1394+
struct Foo { field: i32 }
1395+
1396+
fn foo(foo: Foo) {
1397+
let Foo { field: x @ field } = foo;
1398+
let _ = field;
1399+
}
13381400
"#,
13391401
);
13401402
}
@@ -1390,7 +1452,7 @@ struct Foo {
13901452
i: i32
13911453
}
13921454
1393-
fn foo(Foo { i }: foo) -> i32 {
1455+
fn foo(Foo { i }: Foo) -> i32 {
13941456
i$0
13951457
}
13961458
"#,
@@ -1399,7 +1461,7 @@ struct Foo {
13991461
i: i32
14001462
}
14011463
1402-
fn foo(Foo { i: bar }: foo) -> i32 {
1464+
fn foo(Foo { i: bar }: Foo) -> i32 {
14031465
bar
14041466
}
14051467
"#,

crates/ide_db/src/helpers/import_assets.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,11 +120,11 @@ impl ImportAssets {
120120
}
121121

122122
pub fn for_ident_pat(pat: &ast::IdentPat, sema: &Semantics<RootDatabase>) -> Option<Self> {
123-
let name = pat.name()?;
124-
let candidate_node = pat.syntax().clone();
125123
if !pat.is_simple_ident() {
126124
return None;
127125
}
126+
let name = pat.name()?;
127+
let candidate_node = pat.syntax().clone();
128128
Some(Self {
129129
import_candidate: ImportCandidate::for_name(sema, &name)?,
130130
module_with_candidate: sema.scope(&candidate_node).module()?,

crates/ide_db/src/rename.rs

Lines changed: 42 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,7 @@ pub fn source_edit_from_references(
320320
.unwrap_or_else(|| (reference.range, new_name.to_string()));
321321
edit.replace(range, replacement);
322322
}
323+
323324
edit.finish()
324325
}
325326

@@ -334,6 +335,7 @@ fn source_edit_from_name(name: &ast::Name, new_name: &str) -> Option<(TextRange,
334335
));
335336
}
336337
}
338+
337339
None
338340
}
339341

@@ -387,7 +389,9 @@ fn source_edit_from_name_ref(
387389
let rcf_pat = record_field.pat();
388390
match (rcf_name_ref, rcf_pat) {
389391
// field: rename
390-
(Some(field_name), Some(ast::Pat::IdentPat(pat))) if field_name == *name_ref => {
392+
(Some(field_name), Some(ast::Pat::IdentPat(pat)))
393+
if field_name == *name_ref && pat.at_token().is_none() =>
394+
{
391395
// field name is being renamed
392396
if pat.name().map_or(false, |it| it.text() == new_name) {
393397
cov_mark::hit!(test_rename_field_put_init_shorthand_pat);
@@ -412,32 +416,52 @@ fn source_edit_from_def(
412416
def: Definition,
413417
new_name: &str,
414418
) -> Result<(FileId, TextEdit)> {
415-
let frange = def
419+
let FileRange { file_id, range } = def
416420
.range_for_rename(sema)
417421
.ok_or_else(|| format_err!("No identifier available to rename"))?;
418422

419-
let mut replacement_text = String::new();
420-
let mut repl_range = frange.range;
423+
let mut edit = TextEdit::builder();
421424
if let Definition::Local(local) = def {
422425
if let Either::Left(pat) = local.source(sema.db).value {
423-
if matches!(
424-
pat.syntax().parent().and_then(ast::RecordPatField::cast),
425-
Some(pat_field) if pat_field.name_ref().is_none()
426-
) {
427-
replacement_text.push_str(": ");
428-
replacement_text.push_str(new_name);
429-
repl_range = TextRange::new(
430-
pat.syntax().text_range().end(),
431-
pat.syntax().text_range().end(),
432-
);
426+
// special cases required for renaming fields/locals in Record patterns
427+
if let Some(pat_field) = pat.syntax().parent().and_then(ast::RecordPatField::cast) {
428+
let name_range = pat.name().unwrap().syntax().text_range();
429+
if let Some(name_ref) = pat_field.name_ref() {
430+
if new_name == name_ref.text() && pat.at_token().is_none() {
431+
// Foo { field: ref mut local } -> Foo { ref mut field }
432+
// ^^^^^^ delete this
433+
// ^^^^^ replace this with `field`
434+
cov_mark::hit!(test_rename_local_put_init_shorthand_pat);
435+
edit.delete(
436+
name_ref
437+
.syntax()
438+
.text_range()
439+
.cover_offset(pat.syntax().text_range().start()),
440+
);
441+
edit.replace(name_range, name_ref.text().to_string());
442+
} else {
443+
// Foo { field: ref mut local @ local 2} -> Foo { field: ref mut new_name @ local2 }
444+
// Foo { field: ref mut local } -> Foo { field: ref mut new_name }
445+
// ^^^^^ replace this with `new_name`
446+
edit.replace(name_range, new_name.to_string());
447+
}
448+
} else {
449+
// Foo { ref mut field } -> Foo { field: ref mut new_name }
450+
// ^ insert `field: `
451+
// ^^^^^ replace this with `new_name`
452+
edit.insert(
453+
pat.syntax().text_range().start(),
454+
format!("{}: ", pat_field.field_name().unwrap()),
455+
);
456+
edit.replace(name_range, new_name.to_string());
457+
}
433458
}
434459
}
435460
}
436-
if replacement_text.is_empty() {
437-
replacement_text.push_str(new_name);
461+
if edit.is_empty() {
462+
edit.replace(range, new_name.to_string());
438463
}
439-
let edit = TextEdit::replace(repl_range, replacement_text);
440-
Ok((frange.file_id, edit))
464+
Ok((file_id, edit.finish()))
441465
}
442466

443467
#[derive(Copy, Clone, Debug, PartialEq)]

crates/text_edit/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,9 @@ impl<'a> IntoIterator for &'a TextEdit {
159159
}
160160

161161
impl TextEditBuilder {
162+
pub fn is_empty(&self) -> bool {
163+
self.indels.is_empty()
164+
}
162165
pub fn replace(&mut self, range: TextRange, replace_with: String) {
163166
self.indel(Indel::replace(range, replace_with))
164167
}

0 commit comments

Comments
 (0)