From 8678b92218a691d28861defc429f120f7dfc177b Mon Sep 17 00:00:00 2001 From: Alex Vasilev Date: Tue, 24 Jan 2023 12:43:13 +0530 Subject: [PATCH 1/4] Allow renaming lifetiems and labels without leading apostrophe --- crates/ide-db/src/rename.rs | 27 +++++++++++++++++++-------- crates/ide/src/rename.rs | 37 +++++++++++++++++++++++++++++++++---- 2 files changed, 52 insertions(+), 12 deletions(-) diff --git a/crates/ide-db/src/rename.rs b/crates/ide-db/src/rename.rs index 0e5906097c..0aa4b89247 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,14 @@ pub fn source_edit_from_references( _ => false, }; if !has_emitted_edit && !edited_ranges.contains(&range.start()) { - edit.replace(range, new_name.to_string()); + let new_name = match name { + ast::NameLike::Lifetime(_) => { + format!("'{}", new_name.trim_start_matches("'")) + } + _ => new_name.into(), + }; + + edit.replace(range, new_name); edited_ranges.push(range.start()); } } @@ -501,7 +507,15 @@ fn source_edit_from_def( } } if edit.is_empty() { - edit.replace(range, new_name.to_string()); + let new_name = match def { + Definition::GenericParam(hir::GenericParam::LifetimeParam(_)) + | Definition::Label(_) => { + format!("'{}", new_name.trim_start_matches("'")) + } + _ => new_name.into(), + }; + + edit.replace(range, new_name); } Ok((file_id, edit.finish())) } @@ -522,9 +536,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..0528ce85b2 100644 --- a/crates/ide/src/rename.rs +++ b/crates/ide/src/rename.rs @@ -521,14 +521,18 @@ 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); @@ -1745,7 +1749,7 @@ fn foo(foo: Foo) { #[test] fn test_rename_lifetimes() { - cov_mark::check!(rename_lifetime); + // cov_mark::check!(rename_lifetime); check( "'yeeee", r#" @@ -1831,6 +1835,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); From 5f1796f837c19b55eb628a0c90c769365bdead00 Mon Sep 17 00:00:00 2001 From: Alex Vasilev Date: Tue, 24 Jan 2023 12:45:51 +0530 Subject: [PATCH 2/4] uncomment check --- crates/ide/src/rename.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/ide/src/rename.rs b/crates/ide/src/rename.rs index 0528ce85b2..8519698c39 100644 --- a/crates/ide/src/rename.rs +++ b/crates/ide/src/rename.rs @@ -1749,7 +1749,7 @@ fn foo(foo: Foo) { #[test] fn test_rename_lifetimes() { - // cov_mark::check!(rename_lifetime); + cov_mark::check!(rename_lifetime); check( "'yeeee", r#" From 5d013a79d6852c56213d6fd052c8814397f5f714 Mon Sep 17 00:00:00 2001 From: Alex Vasilev Date: Tue, 24 Jan 2023 13:19:20 +0530 Subject: [PATCH 3/4] exclude ' --- crates/ide/src/rename.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/crates/ide/src/rename.rs b/crates/ide/src/rename.rs index 8519698c39..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"#]]); } From 3c898dd9a10350a53bdfe94eb5ffb848addeb762 Mon Sep 17 00:00:00 2001 From: Alex Vasilev Date: Tue, 24 Jan 2023 23:22:30 +0530 Subject: [PATCH 4/4] fix --- crates/ide-db/src/rename.rs | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/crates/ide-db/src/rename.rs b/crates/ide-db/src/rename.rs index 0aa4b89247..6da650aeb6 100644 --- a/crates/ide-db/src/rename.rs +++ b/crates/ide-db/src/rename.rs @@ -334,11 +334,12 @@ pub fn source_edit_from_references( _ => false, }; if !has_emitted_edit && !edited_ranges.contains(&range.start()) { - let new_name = match name { - ast::NameLike::Lifetime(_) => { - format!("'{}", new_name.trim_start_matches("'")) - } - _ => new_name.into(), + 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); @@ -507,14 +508,14 @@ fn source_edit_from_def( } } if edit.is_empty() { - let new_name = match def { + let (range, new_name) = match def { Definition::GenericParam(hir::GenericParam::LifetimeParam(_)) - | Definition::Label(_) => { - format!("'{}", new_name.trim_start_matches("'")) - } - _ => new_name.into(), + | 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()))