Unnamed repository; edit this file 'description' to name the repository.
Auto merge of #14015 - vasilev-alex:lifetime-rename, r=Veykril
Don't include lifetime or label apostrophe when renaming Closes #13907
bors 2023-01-25
parent 85736de · parent 3c898dd · commit 46084a1
-rw-r--r--crates/ide-db/src/rename.rs28
-rw-r--r--crates/ide/src/rename.rs47
2 files changed, 61 insertions, 14 deletions
diff --git a/crates/ide-db/src/rename.rs b/crates/ide-db/src/rename.rs
index 0e5906097c..6da650aeb6 100644
--- a/crates/ide-db/src/rename.rs
+++ b/crates/ide-db/src/rename.rs
@@ -263,11 +263,10 @@ fn rename_reference(
Definition::GenericParam(hir::GenericParam::LifetimeParam(_)) | Definition::Label(_)
) {
match ident_kind {
- IdentifierKind::Ident | IdentifierKind::Underscore => {
- cov_mark::hit!(rename_not_a_lifetime_ident_ref);
+ IdentifierKind::Underscore => {
bail!("Invalid name `{}`: not a lifetime identifier", new_name);
}
- IdentifierKind::Lifetime => cov_mark::hit!(rename_lifetime),
+ _ => cov_mark::hit!(rename_lifetime),
}
} else {
match ident_kind {
@@ -335,7 +334,15 @@ pub fn source_edit_from_references(
_ => false,
};
if !has_emitted_edit && !edited_ranges.contains(&range.start()) {
- edit.replace(range, new_name.to_string());
+ let (range, new_name) = match name {
+ ast::NameLike::Lifetime(_) => (
+ TextRange::new(range.start() + syntax::TextSize::from(1), range.end()),
+ new_name.strip_prefix('\'').unwrap_or(new_name).to_owned(),
+ ),
+ _ => (range, new_name.to_owned()),
+ };
+
+ edit.replace(range, new_name);
edited_ranges.push(range.start());
}
}
@@ -501,7 +508,15 @@ fn source_edit_from_def(
}
}
if edit.is_empty() {
- edit.replace(range, new_name.to_string());
+ let (range, new_name) = match def {
+ Definition::GenericParam(hir::GenericParam::LifetimeParam(_))
+ | Definition::Label(_) => (
+ TextRange::new(range.start() + syntax::TextSize::from(1), range.end()),
+ new_name.strip_prefix('\'').unwrap_or(new_name).to_owned(),
+ ),
+ _ => (range, new_name.to_owned()),
+ };
+ edit.replace(range, new_name);
}
Ok((file_id, edit.finish()))
}
@@ -522,9 +537,6 @@ impl IdentifierKind {
(SyntaxKind::LIFETIME_IDENT, _) if new_name != "'static" && new_name != "'_" => {
Ok(IdentifierKind::Lifetime)
}
- (SyntaxKind::LIFETIME_IDENT, _) => {
- bail!("Invalid name `{}`: not a lifetime identifier", new_name)
- }
(_, Some(syntax_error)) => bail!("Invalid name `{}`: {}", new_name, syntax_error),
(_, None) => bail!("Invalid name `{}`: not an identifier", new_name),
},
diff --git a/crates/ide/src/rename.rs b/crates/ide/src/rename.rs
index 15bdf14fb9..25d165d111 100644
--- a/crates/ide/src/rename.rs
+++ b/crates/ide/src/rename.rs
@@ -13,7 +13,7 @@ use ide_db::{
};
use itertools::Itertools;
use stdx::{always, never};
-use syntax::{ast, AstNode, SyntaxNode};
+use syntax::{ast, AstNode, SyntaxNode, TextRange, TextSize};
use text_edit::TextEdit;
@@ -48,7 +48,13 @@ pub(crate) fn prepare_rename(
frange.range.contains_inclusive(position.offset)
&& frange.file_id == position.file_id
);
- Ok(frange.range)
+
+ Ok(match name_like {
+ ast::NameLike::Lifetime(_) => {
+ TextRange::new(frange.range.start() + TextSize::from(1), frange.range.end())
+ }
+ _ => frange.range,
+ })
})
.reduce(|acc, cur| match (acc, cur) {
// ensure all ranges are the same
@@ -407,7 +413,7 @@ mod tests {
#[test]
fn test_prepare_rename_namelikes() {
check_prepare(r"fn name$0<'lifetime>() {}", expect![[r#"3..7: name"#]]);
- check_prepare(r"fn name<'lifetime$0>() {}", expect![[r#"8..17: 'lifetime"#]]);
+ check_prepare(r"fn name<'lifetime$0>() {}", expect![[r#"9..17: lifetime"#]]);
check_prepare(r"fn name<'lifetime>() { name$0(); }", expect![[r#"23..27: name"#]]);
}
@@ -521,15 +527,19 @@ impl Foo {
#[test]
fn test_rename_to_invalid_identifier_lifetime2() {
- cov_mark::check!(rename_not_a_lifetime_ident_ref);
check(
- "foo",
+ "_",
r#"fn main<'a>(_: &'a$0 ()) {}"#,
- "error: Invalid name `foo`: not a lifetime identifier",
+ r#"error: Invalid name `_`: not a lifetime identifier"#,
);
}
#[test]
+ fn test_rename_accepts_lifetime_without_apostrophe() {
+ check("foo", r#"fn main<'a>(_: &'a$0 ()) {}"#, r#"fn main<'foo>(_: &'foo ()) {}"#);
+ }
+
+ #[test]
fn test_rename_to_underscore_invalid() {
cov_mark::check!(rename_underscore_multiple);
check(
@@ -1832,6 +1842,31 @@ fn foo<'a>() -> &'a () {
}
#[test]
+ fn test_rename_label_new_name_without_apostrophe() {
+ check(
+ "foo",
+ r#"
+fn main() {
+ 'outer$0: loop {
+ 'inner: loop {
+ break 'outer;
+ }
+ }
+}
+ "#,
+ r#"
+fn main() {
+ 'foo: loop {
+ 'inner: loop {
+ break 'foo;
+ }
+ }
+}
+ "#,
+ );
+ }
+
+ #[test]
fn test_self_to_self() {
cov_mark::check!(rename_self_to_self);
check(