Skip to content

Commit 6175353

Browse files
bors[bot]dzhu
andauthored
Merge #8658
8658: Check more carefully for cases where a rename can't be done r=Veykril a=dzhu Attempting to rename an element of a tuple field would previously replace the type with the new name, which doesn't make sense; now it fails instead. The check is done in both `prepare_rename` and `rename` so that the case is caught before the user is prompted for a new name. Some other existing failure cases are also now additionally checked in `prepare_rename`. Closes: #8592 (I threw in some doc edits for a relevant type; of course, I can remove those if the policy here is to be strict about scope of changes within a PR.) Co-authored-by: Danny Zhu <[email protected]>
2 parents d8578bf + 09fc5e1 commit 6175353

File tree

2 files changed

+105
-6
lines changed

2 files changed

+105
-6
lines changed

crates/ide/src/display/navigation_target.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use syntax::{
2020

2121
use crate::FileSymbol;
2222

23-
/// `NavigationTarget` represents and element in the editor's UI which you can
23+
/// `NavigationTarget` represents an element in the editor's UI which you can
2424
/// click on to navigate to a particular piece of code.
2525
///
2626
/// Typically, a `NavigationTarget` corresponds to some element in the source
@@ -35,12 +35,10 @@ pub struct NavigationTarget {
3535
/// Clients should use this range to answer "is the cursor inside the
3636
/// element?" question.
3737
pub full_range: TextRange,
38-
/// A "most interesting" range withing the `full_range`.
38+
/// A "most interesting" range within the `full_range`.
3939
///
4040
/// Typically, `full_range` is the whole syntax node, including doc
41-
/// comments, and `focus_range` is the range of the identifier. "Most
42-
/// interesting" range within the full range, typically the range of
43-
/// identifier.
41+
/// comments, and `focus_range` is the range of the identifier.
4442
///
4543
/// Clients should place the cursor on this range when navigating to this target.
4644
pub focus_range: Option<TextRange>,

crates/ide/src/references/rename.rs

Lines changed: 102 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,17 @@ pub(crate) fn prepare_rename(
5050
let sema = Semantics::new(db);
5151
let source_file = sema.parse(position.file_id);
5252
let syntax = source_file.syntax();
53+
54+
let def = find_definition(&sema, syntax, position)?;
55+
match def {
56+
Definition::SelfType(_) => bail!("Cannot rename `Self`"),
57+
Definition::ModuleDef(ModuleDef::BuiltinType(_)) => bail!("Cannot rename builtin type"),
58+
_ => {}
59+
};
60+
let nav =
61+
def.try_to_nav(sema.db).ok_or_else(|| format_err!("No references found at position"))?;
62+
nav.focus_range.ok_or_else(|| format_err!("No identifier available to rename"))?;
63+
5364
let name_like = sema
5465
.find_node_at_offset_with_descend(&syntax, position.offset)
5566
.ok_or_else(|| format_err!("No references found at position"))?;
@@ -507,7 +518,8 @@ fn source_edit_from_def(
507518
def.try_to_nav(sema.db).ok_or_else(|| format_err!("No references found at position"))?;
508519

509520
let mut replacement_text = String::new();
510-
let mut repl_range = nav.focus_or_full_range();
521+
let mut repl_range =
522+
nav.focus_range.ok_or_else(|| format_err!("No identifier available to rename"))?;
511523
if let Definition::Local(local) = def {
512524
if let Either::Left(pat) = local.source(sema.db).value {
513525
if matches!(
@@ -625,6 +637,49 @@ foo!(Foo$0);",
625637
check_prepare(r"struct$0 Foo;", expect![[r#"No references found at position"#]]);
626638
}
627639

640+
#[test]
641+
fn test_prepare_rename_tuple_field() {
642+
check_prepare(
643+
r#"
644+
struct Foo(i32);
645+
646+
fn baz() {
647+
let mut x = Foo(4);
648+
x.0$0 = 5;
649+
}
650+
"#,
651+
expect![[r#"No identifier available to rename"#]],
652+
);
653+
}
654+
655+
#[test]
656+
fn test_prepare_rename_builtin() {
657+
check_prepare(
658+
r#"
659+
fn foo() {
660+
let x: i32$0 = 0;
661+
}
662+
"#,
663+
expect![[r#"Cannot rename builtin type"#]],
664+
);
665+
}
666+
667+
#[test]
668+
fn test_prepare_rename_self() {
669+
check_prepare(
670+
r#"
671+
struct Foo {}
672+
673+
impl Foo {
674+
fn foo(self) -> Self$0 {
675+
self
676+
}
677+
}
678+
"#,
679+
expect![[r#"Cannot rename `Self`"#]],
680+
);
681+
}
682+
628683
#[test]
629684
fn test_rename_to_underscore() {
630685
check("_", r#"fn main() { let i$0 = 1; }"#, r#"fn main() { let _ = 1; }"#);
@@ -1787,4 +1842,50 @@ fn foo() {
17871842
"#,
17881843
)
17891844
}
1845+
1846+
#[test]
1847+
fn test_rename_tuple_field() {
1848+
check(
1849+
"foo",
1850+
r#"
1851+
struct Foo(i32);
1852+
1853+
fn baz() {
1854+
let mut x = Foo(4);
1855+
x.0$0 = 5;
1856+
}
1857+
"#,
1858+
"error: No identifier available to rename",
1859+
);
1860+
}
1861+
1862+
#[test]
1863+
fn test_rename_builtin() {
1864+
check(
1865+
"foo",
1866+
r#"
1867+
fn foo() {
1868+
let x: i32$0 = 0;
1869+
}
1870+
"#,
1871+
"error: Cannot rename builtin type",
1872+
);
1873+
}
1874+
1875+
#[test]
1876+
fn test_rename_self() {
1877+
check(
1878+
"foo",
1879+
r#"
1880+
struct Foo {}
1881+
1882+
impl Foo {
1883+
fn foo(self) -> Self$0 {
1884+
self
1885+
}
1886+
}
1887+
"#,
1888+
"error: Cannot rename `Self`",
1889+
);
1890+
}
17901891
}

0 commit comments

Comments
 (0)