Unnamed repository; edit this file 'description' to name the repository.
| -rw-r--r-- | crates/hir/src/semantics.rs | 4 | ||||
| -rw-r--r-- | crates/ide-db/src/rename.rs | 178 | ||||
| -rw-r--r-- | crates/ide/src/rename.rs | 94 |
3 files changed, 161 insertions, 115 deletions
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs index 09377df615..a75c56aa8f 100644 --- a/crates/hir/src/semantics.rs +++ b/crates/hir/src/semantics.rs @@ -659,7 +659,7 @@ impl<'db> SemanticsImpl<'db> { /// Checks if renaming `renamed` to `new_name` may introduce conflicts with other locals, /// and returns the conflicting locals. - pub fn rename_conflicts(&self, to_be_renamed: &Local, new_name: &str) -> Vec<Local> { + pub fn rename_conflicts(&self, to_be_renamed: &Local, new_name: &Name) -> Vec<Local> { let body = self.db.body(to_be_renamed.parent); let resolver = to_be_renamed.parent.resolver(self.db); let starting_expr = @@ -668,7 +668,7 @@ impl<'db> SemanticsImpl<'db> { body: &body, conflicts: FxHashSet::default(), db: self.db, - new_name: Symbol::intern(new_name), + new_name: new_name.symbol().clone(), old_name: to_be_renamed.name(self.db).symbol().clone(), owner: to_be_renamed.parent, to_be_renamed: to_be_renamed.binding_id, diff --git a/crates/ide-db/src/rename.rs b/crates/ide-db/src/rename.rs index e4d42146ca..4e737e27f0 100644 --- a/crates/ide-db/src/rename.rs +++ b/crates/ide-db/src/rename.rs @@ -20,7 +20,7 @@ //! //! The correct behavior in such cases is probably to show a dialog to the user. //! Our current behavior is ¯\_(ツ)_/¯. -use std::fmt; +use std::fmt::{self, Display}; use crate::{ source_change::ChangeAnnotation, @@ -28,13 +28,12 @@ use crate::{ }; use base_db::AnchoredPathBuf; use either::Either; -use hir::{EditionedFileId, FieldSource, FileRange, InFile, ModuleSource, Semantics}; +use hir::{FieldSource, FileRange, InFile, ModuleSource, Name, Semantics, sym}; use span::{Edition, FileId, SyntaxContext}; use stdx::{TupleExt, never}; use syntax::{ AstNode, SyntaxKind, T, TextRange, ast::{self, HasName}, - utils::is_raw_identifier, }; use crate::{ @@ -87,13 +86,16 @@ impl Definition { // self is a built-in attr, built-in type or tool module. // it is not allowed for these defs to be renamed. // cases where self.krate() is None is handled below. - if let Some(krate) = self.krate(sema.db) { + let edition = if let Some(krate) = self.krate(sema.db) { // Can we not rename non-local items? // Then bail if non-local if !krate.origin(sema.db).is_local() { bail!("Cannot rename a non-local definition") } - } + krate.edition(sema.db) + } else { + Edition::LATEST + }; match *self { Definition::Module(module) => rename_mod(sema, module, new_name), @@ -108,9 +110,9 @@ impl Definition { } Definition::SelfType(_) => bail!("Cannot rename `Self`"), Definition::Macro(mac) => { - rename_reference(sema, Definition::Macro(mac), new_name, rename_definition) + rename_reference(sema, Definition::Macro(mac), new_name, rename_definition, edition) } - def => rename_reference(sema, def, new_name, rename_definition), + def => rename_reference(sema, def, new_name, rename_definition, edition), } } @@ -243,10 +245,6 @@ fn rename_mod( module: hir::Module, new_name: &str, ) -> Result<SourceChange> { - if IdentifierKind::classify(new_name)? != IdentifierKind::Ident { - bail!("Invalid name `{0}`: cannot rename module to {0}", new_name); - } - let mut source_change = SourceChange::default(); if module.is_crate_root() { @@ -254,6 +252,14 @@ fn rename_mod( } let InFile { file_id, value: def_source } = module.definition_source(sema.db); + let edition = file_id.edition(sema.db); + let (new_name, kind) = IdentifierKind::classify(edition, new_name)?; + if kind != IdentifierKind::Ident { + bail!( + "Invalid name `{0}`: cannot rename module to {0}", + new_name.display(sema.db, edition) + ); + } if let ModuleSource::SourceFile(..) = def_source { let anchor = file_id.original_file(sema.db).file_id(sema.db); @@ -262,7 +268,7 @@ fn rename_mod( // Module exists in a named file if !is_mod_rs { - let path = format!("{new_name}.rs"); + let path = format!("{}.rs", new_name.as_str()); let dst = AnchoredPathBuf { anchor, path }; source_change.push_file_system_edit(FileSystemEdit::MoveFile { src: anchor, dst }) } @@ -273,11 +279,11 @@ fn rename_mod( let dir_paths = match (is_mod_rs, has_detached_child, module.name(sema.db)) { // Go up one level since the anchor is inside the dir we're trying to rename (true, _, Some(mod_name)) => { - Some((format!("../{}", mod_name.as_str()), format!("../{new_name}"))) + Some((format!("../{}", mod_name.as_str()), format!("../{}", new_name.as_str()))) } // The anchor is on the same level as target dir (false, true, Some(mod_name)) => { - Some((mod_name.as_str().to_owned(), new_name.to_owned())) + Some((mod_name.as_str().to_owned(), new_name.as_str().to_owned())) } _ => None, }; @@ -302,11 +308,7 @@ fn rename_mod( .original_file_range_opt(sema.db) .map(TupleExt::head) { - let new_name = if is_raw_identifier(new_name, file_id.edition(sema.db)) { - format!("r#{new_name}") - } else { - new_name.to_owned() - }; + let new_name = new_name.display(sema.db, edition).to_string(); source_change.insert_source_edit( file_id.file_id(sema.db), TextEdit::replace(file_range.range, new_name), @@ -320,9 +322,10 @@ fn rename_mod( let def = Definition::Module(module); let usages = def.usages(sema).all(); let ref_edits = usages.iter().map(|(file_id, references)| { + let edition = file_id.edition(sema.db); ( file_id.file_id(sema.db), - source_edit_from_references(references, def, new_name, file_id.edition(sema.db)), + source_edit_from_references(sema.db, references, def, &new_name, edition), ) }); source_change.extend(ref_edits); @@ -335,8 +338,9 @@ fn rename_reference( def: Definition, new_name: &str, rename_definition: RenameDefinition, + edition: Edition, ) -> Result<SourceChange> { - let ident_kind = IdentifierKind::classify(new_name)?; + let (mut new_name, ident_kind) = IdentifierKind::classify(edition, new_name)?; if matches!( def, @@ -344,18 +348,34 @@ fn rename_reference( ) { match ident_kind { IdentifierKind::Underscore => { - bail!("Invalid name `{}`: not a lifetime identifier", new_name); + bail!( + "Invalid name `{}`: not a lifetime identifier", + new_name.display(sema.db, edition) + ); + } + IdentifierKind::Ident => { + new_name = Name::new_lifetime(&format!("'{}", new_name.as_str())) } - _ => cov_mark::hit!(rename_lifetime), + IdentifierKind::Lifetime => (), + IdentifierKind::LowercaseSelf => bail!( + "Invalid name `{}`: not a lifetime identifier", + new_name.display(sema.db, edition) + ), } } else { match ident_kind { IdentifierKind::Lifetime => { cov_mark::hit!(rename_not_an_ident_ref); - bail!("Invalid name `{}`: not an identifier", new_name); + bail!("Invalid name `{}`: not an identifier", new_name.display(sema.db, edition)); } IdentifierKind::Ident => cov_mark::hit!(rename_non_local), IdentifierKind::Underscore => (), + IdentifierKind::LowercaseSelf => { + bail!( + "Invalid name `{}`: cannot rename to `self`", + new_name.display(sema.db, edition) + ); + } } } @@ -368,31 +388,29 @@ fn rename_reference( } let mut source_change = SourceChange::default(); source_change.extend(usages.iter().map(|(file_id, references)| { + let edition = file_id.edition(sema.db); ( file_id.file_id(sema.db), - source_edit_from_references(references, def, new_name, file_id.edition(sema.db)), + source_edit_from_references(sema.db, references, def, &new_name, edition), ) })); if rename_definition == RenameDefinition::Yes { // This needs to come after the references edits, because we change the annotation of existing edits // if a conflict is detected. - let (file_id, edit) = source_edit_from_def(sema, def, new_name, &mut source_change)?; + let (file_id, edit) = source_edit_from_def(sema, def, &new_name, &mut source_change)?; source_change.insert_source_edit(file_id, edit); } Ok(source_change) } pub fn source_edit_from_references( + db: &RootDatabase, references: &[FileReference], def: Definition, - new_name: &str, + new_name: &Name, edition: Edition, ) -> TextEdit { - let new_name = if is_raw_identifier(new_name, edition) { - format!("r#{new_name}") - } else { - new_name.to_owned() - }; + let name_display = new_name.display(db, edition); let mut edit = TextEdit::builder(); // macros can cause multiple refs to occur for the same text range, so keep track of what we have edited so far let mut edited_ranges = Vec::new(); @@ -403,23 +421,15 @@ pub fn source_edit_from_references( // to make special rewrites like shorthand syntax and such, so just rename the node in // the macro input FileReferenceNode::NameRef(name_ref) if name_range == range => { - source_edit_from_name_ref(&mut edit, name_ref, &new_name, def) + source_edit_from_name_ref(&mut edit, name_ref, &name_display, def) } FileReferenceNode::Name(name) if name_range == range => { - source_edit_from_name(&mut edit, name, &new_name) + source_edit_from_name(&mut edit, name, &name_display) } _ => false, }; if !has_emitted_edit && !edited_ranges.contains(&range.start()) { - let (range, new_name) = match name { - FileReferenceNode::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); + edit.replace(range, name_display.to_string()); edited_ranges.push(range.start()); } } @@ -427,7 +437,11 @@ pub fn source_edit_from_references( edit.finish() } -fn source_edit_from_name(edit: &mut TextEditBuilder, name: &ast::Name, new_name: &str) -> bool { +fn source_edit_from_name( + edit: &mut TextEditBuilder, + name: &ast::Name, + new_name: &dyn Display, +) -> bool { if ast::RecordPatField::for_field_name(name).is_some() { if let Some(ident_pat) = name.syntax().parent().and_then(ast::IdentPat::cast) { cov_mark::hit!(rename_record_pat_field_name_split); @@ -447,7 +461,7 @@ fn source_edit_from_name(edit: &mut TextEditBuilder, name: &ast::Name, new_name: fn source_edit_from_name_ref( edit: &mut TextEditBuilder, name_ref: &ast::NameRef, - new_name: &str, + new_name: &dyn Display, def: Definition, ) -> bool { if name_ref.super_token().is_some() { @@ -460,6 +474,7 @@ fn source_edit_from_name_ref( match &(rcf_name_ref, rcf_expr.and_then(|it| expr_as_name_ref(&it))) { // field: init-expr, check if we can use a field init shorthand (Some(field_name), Some(init)) => { + let new_name = new_name.to_string(); if field_name == name_ref { if init.text() == new_name { cov_mark::hit!(test_rename_field_put_init_shorthand); @@ -515,6 +530,7 @@ fn source_edit_from_name_ref( { // field name is being renamed if let Some(name) = pat.name() { + let new_name = new_name.to_string(); if name.text() == new_name { cov_mark::hit!(test_rename_field_put_init_shorthand_pat); // Foo { field: ref mut local } -> Foo { ref mut field } @@ -526,7 +542,7 @@ fn source_edit_from_name_ref( let s = field_name.syntax().text_range().start(); let e = pat.syntax().text_range().start(); edit.delete(TextRange::new(s, e)); - edit.replace(name.syntax().text_range(), new_name.to_owned()); + edit.replace(name.syntax().text_range(), new_name); return true; } } @@ -540,16 +556,9 @@ fn source_edit_from_name_ref( fn source_edit_from_def( sema: &Semantics<'_, RootDatabase>, def: Definition, - new_name: &str, + new_name: &Name, source_change: &mut SourceChange, ) -> Result<(FileId, TextEdit)> { - let new_name_edition_aware = |new_name: &str, file_id: EditionedFileId| { - if is_raw_identifier(new_name, file_id.edition(sema.db)) { - format!("r#{new_name}") - } else { - new_name.to_owned() - } - }; let mut edit = TextEdit::builder(); if let Definition::Local(local) = def { let mut file_id = None; @@ -581,7 +590,10 @@ fn source_edit_from_def( { Some(FileRange { file_id: file_id2, range }) => { file_id = Some(file_id2); - edit.replace(range, new_name_edition_aware(new_name, file_id2)); + edit.replace( + range, + new_name.display(sema.db, file_id2.edition(sema.db)).to_string(), + ); continue; } None => { @@ -595,7 +607,7 @@ fn source_edit_from_def( // special cases required for renaming fields/locals in Record patterns if let Some(pat_field) = pat.syntax().parent().and_then(ast::RecordPatField::cast) { if let Some(name_ref) = pat_field.name_ref() { - if new_name == name_ref.text().as_str().trim_start_matches("r#") + if new_name.as_str() == name_ref.text().as_str().trim_start_matches("r#") && pat.at_token().is_none() { // Foo { field: ref mut local } -> Foo { ref mut field } @@ -615,7 +627,9 @@ fn source_edit_from_def( // ^^^^^ replace this with `new_name` edit.replace( name_range, - new_name_edition_aware(new_name, source.file_id), + new_name + .display(sema.db, source.file_id.edition(sema.db)) + .to_string(), ); } } else { @@ -626,10 +640,16 @@ fn source_edit_from_def( pat.syntax().text_range().start(), format!("{}: ", pat_field.field_name().unwrap()), ); - edit.replace(name_range, new_name_edition_aware(new_name, source.file_id)); + edit.replace( + name_range, + new_name.display(sema.db, source.file_id.edition(sema.db)).to_string(), + ); } } else { - edit.replace(name_range, new_name_edition_aware(new_name, source.file_id)); + edit.replace( + name_range, + new_name.display(sema.db, source.file_id.edition(sema.db)).to_string(), + ); } } } @@ -647,16 +667,13 @@ fn source_edit_from_def( .range_for_rename(sema) .ok_or_else(|| format_err!("No identifier available to rename"))?; 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(), + Definition::ExternCrateDecl(decl) if decl.alias(sema.db).is_none() => ( + TextRange::empty(range.end()), + format!(" as {}", new_name.display(sema.db, file_id.edition(sema.db)),), ), - Definition::ExternCrateDecl(decl) if decl.alias(sema.db).is_none() => { - (TextRange::empty(range.end()), format!(" as {new_name}")) - } - _ => (range, new_name.to_owned()), + _ => (range, new_name.display(sema.db, file_id.edition(sema.db)).to_string()), }; - edit.replace(range, new_name_edition_aware(&new_name, file_id)); + edit.replace(range, new_name); Ok((file_id.file_id(sema.db), edit.finish())) } @@ -665,26 +682,27 @@ pub enum IdentifierKind { Ident, Lifetime, Underscore, + LowercaseSelf, } impl IdentifierKind { - pub fn classify(new_name: &str) -> Result<IdentifierKind> { - let new_name = new_name.trim_start_matches("r#"); - match parser::LexedStr::single_token(Edition::LATEST, new_name) { + pub fn classify(edition: Edition, new_name: &str) -> Result<(Name, IdentifierKind)> { + match parser::LexedStr::single_token(edition, new_name) { Some(res) => match res { - (SyntaxKind::IDENT, _) => { - if let Some(inner) = new_name.strip_prefix("r#") { - if matches!(inner, "self" | "crate" | "super" | "Self") { - bail!("Invalid name: `{}` cannot be a raw identifier", inner); - } - } - Ok(IdentifierKind::Ident) + (SyntaxKind::IDENT, _) => Ok((Name::new_root(new_name), IdentifierKind::Ident)), + (T![_], _) => { + Ok((Name::new_symbol_root(sym::underscore), IdentifierKind::Underscore)) } - (T![_], _) => Ok(IdentifierKind::Underscore), (SyntaxKind::LIFETIME_IDENT, _) if new_name != "'static" && new_name != "'_" => { - Ok(IdentifierKind::Lifetime) + Ok((Name::new_lifetime(new_name), IdentifierKind::Lifetime)) } - _ if is_raw_identifier(new_name, Edition::LATEST) => Ok(IdentifierKind::Ident), + _ if SyntaxKind::from_keyword(new_name, edition).is_some() => match new_name { + "self" => Ok((Name::new_root(new_name), IdentifierKind::LowercaseSelf)), + "crate" | "super" | "Self" => { + bail!("Invalid name `{}`: cannot rename to a keyword", new_name) + } + _ => Ok((Name::new_root(new_name), IdentifierKind::Ident)), + }, (_, 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 e959a9bd76..fb84e8e6b4 100644 --- a/crates/ide/src/rename.rs +++ b/crates/ide/src/rename.rs @@ -4,7 +4,7 @@ //! tests. This module also implements a couple of magic tricks, like renaming //! `self` and to `self` (to switch between associated function and method). -use hir::{AsAssocItem, InFile, Name, Semantics}; +use hir::{AsAssocItem, InFile, Name, Semantics, sym}; use ide_db::{ FileId, FileRange, RootDatabase, defs::{Definition, NameClass, NameRefClass}, @@ -33,7 +33,7 @@ pub(crate) fn prepare_rename( let source_file = sema.parse_guess_edition(position.file_id); let syntax = source_file.syntax(); - let res = find_definitions(&sema, syntax, position, "?")? + let res = find_definitions(&sema, syntax, position, &Name::new_symbol_root(sym::underscore))? .map(|(frange, kind, def, _, _)| { // ensure all ranges are valid @@ -88,22 +88,28 @@ pub(crate) fn rename( let source_file = sema.parse(file_id); let syntax = source_file.syntax(); - let defs = find_definitions(&sema, syntax, position, new_name)?; - let alias_fallback = alias_fallback(syntax, position, new_name); + let edition = file_id.edition(db); + let (new_name, kind) = IdentifierKind::classify(edition, new_name)?; + + let defs = find_definitions(&sema, syntax, position, &new_name)?; + let alias_fallback = + alias_fallback(syntax, position, &new_name.display(db, edition).to_string()); let ops: RenameResult<Vec<SourceChange>> = match alias_fallback { Some(_) => defs // FIXME: This can use the `ide_db::rename_reference` (or def.rename) method once we can // properly find "direct" usages/references. .map(|(.., def, new_name, _)| { - match IdentifierKind::classify(&new_name)? { + match kind { IdentifierKind::Ident => (), IdentifierKind::Lifetime => { bail!("Cannot alias reference to a lifetime identifier") } IdentifierKind::Underscore => bail!("Cannot alias reference to `_`"), + IdentifierKind::LowercaseSelf => { + bail!("Cannot rename alias reference to `self`") + } }; - let mut usages = def.usages(&sema).all(); // FIXME: hack - removes the usage that triggered this rename operation. @@ -120,7 +126,7 @@ pub(crate) fn rename( source_change.extend(usages.references.get_mut(&file_id).iter().map(|refs| { ( position.file_id, - source_edit_from_references(refs, def, &new_name, file_id.edition(db)), + source_edit_from_references(db, refs, def, &new_name, edition), ) })); @@ -132,14 +138,14 @@ pub(crate) fn rename( if let Definition::Local(local) = def { if let Some(self_param) = local.as_self_param(sema.db) { cov_mark::hit!(rename_self_to_param); - return rename_self_to_param(&sema, local, self_param, &new_name); + return rename_self_to_param(&sema, local, self_param, &new_name, kind); } - if new_name == "self" { + if kind == IdentifierKind::LowercaseSelf { cov_mark::hit!(rename_to_self); return rename_to_self(&sema, local); } } - def.rename(&sema, &new_name, rename_def) + def.rename(&sema, new_name.as_str(), rename_def) }) .collect(), }; @@ -200,8 +206,8 @@ fn find_definitions( sema: &Semantics<'_, RootDatabase>, syntax: &SyntaxNode, FilePosition { file_id, offset }: FilePosition, - new_name: &str, -) -> RenameResult<impl Iterator<Item = (FileRange, SyntaxKind, Definition, String, RenameDefinition)>> + new_name: &Name, +) -> RenameResult<impl Iterator<Item = (FileRange, SyntaxKind, Definition, Name, RenameDefinition)>> { let maybe_format_args = syntax.token_at_offset(offset).find(|t| matches!(t.kind(), SyntaxKind::STRING)); @@ -213,7 +219,7 @@ fn find_definitions( FileRange { file_id, range }, SyntaxKind::STRING, Definition::from(resolution), - new_name.to_owned(), + new_name.clone(), RenameDefinition::Yes, )] .into_iter()); @@ -224,7 +230,13 @@ fn find_definitions( .max_by_key(|t| { t.kind().is_any_identifier() || matches!(t.kind(), SyntaxKind::LIFETIME_IDENT) }) - .map(|t| Name::new_root(t.text())) + .map(|t| { + if t.kind() == SyntaxKind::LIFETIME_IDENT { + Name::new_lifetime(t.text()) + } else { + Name::new_root(t.text()) + } + }) .ok_or_else(|| format_err!("No references found at position"))?; let symbols = sema.find_namelike_at_offset_with_descend(syntax, offset).map(|name_like| { @@ -299,13 +311,12 @@ fn find_definitions( res.map(|def| { let n = def.name(sema.db)?; if n == original_ident { - Some((range, kind, def, new_name.to_owned(), RenameDefinition::Yes)) + Some((range, kind, def, new_name.clone(), RenameDefinition::Yes)) } else if let Some(suffix) = n.as_str().strip_prefix(original_ident.as_str()) { - Some((range, kind, def, format!("{new_name}{suffix}"), RenameDefinition::No)) - } else if let Some(prefix) = n.as_str().strip_suffix(original_ident.as_str()) { - Some((range, kind, def, format!("{prefix}{new_name}"), RenameDefinition::No)) + Some((range, kind, def, Name::new_root(&format!("{}{suffix}", new_name.as_str())), RenameDefinition::No)) } else { - None + n.as_str().strip_suffix(original_ident.as_str().trim_start_matches('\'')) + .map(|prefix| (range, kind, def, Name::new_root(&format!("{prefix}{}", new_name.as_str())), RenameDefinition::No)) } }) }); @@ -388,7 +399,13 @@ fn rename_to_self( source_change.extend(usages.iter().map(|(file_id, references)| { ( file_id.file_id(sema.db), - source_edit_from_references(references, def, "self", file_id.edition(sema.db)), + source_edit_from_references( + sema.db, + references, + def, + &Name::new_symbol_root(sym::self_), + file_id.edition(sema.db), + ), ) })); source_change.insert_source_edit( @@ -402,23 +419,25 @@ fn rename_self_to_param( sema: &Semantics<'_, RootDatabase>, local: hir::Local, self_param: hir::SelfParam, - new_name: &str, + new_name: &Name, + identifier_kind: IdentifierKind, ) -> RenameResult<SourceChange> { - if new_name == "self" { + if identifier_kind == IdentifierKind::LowercaseSelf { // Let's do nothing rather than complain. cov_mark::hit!(rename_self_to_self); return Ok(SourceChange::default()); } - let identifier_kind = IdentifierKind::classify(new_name)?; - let InFile { file_id, value: self_param } = sema.source(self_param).ok_or_else(|| format_err!("cannot find function source"))?; let def = Definition::Local(local); let usages = def.usages(sema).all(); - let edit = text_edit_from_self_param(&self_param, new_name) - .ok_or_else(|| format_err!("No target type found"))?; + let edit = text_edit_from_self_param( + &self_param, + new_name.display(sema.db, file_id.edition(sema.db)).to_string(), + ) + .ok_or_else(|| format_err!("No target type found"))?; if usages.len() > 1 && identifier_kind == IdentifierKind::Underscore { bail!("Cannot rename reference to `_` as it is being referenced multiple times"); } @@ -427,13 +446,19 @@ fn rename_self_to_param( source_change.extend(usages.iter().map(|(file_id, references)| { ( file_id.file_id(sema.db), - source_edit_from_references(references, def, new_name, file_id.edition(sema.db)), + source_edit_from_references( + sema.db, + references, + def, + new_name, + file_id.edition(sema.db), + ), ) })); Ok(source_change) } -fn text_edit_from_self_param(self_param: &ast::SelfParam, new_name: &str) -> Option<TextEdit> { +fn text_edit_from_self_param(self_param: &ast::SelfParam, new_name: String) -> Option<TextEdit> { fn target_type_name(impl_def: &ast::Impl) -> Option<String> { if let Some(ast::Type::PathType(p)) = impl_def.self_ty() { return Some(p.path()?.segment()?.name_ref()?.text().to_string()); @@ -445,7 +470,7 @@ fn text_edit_from_self_param(self_param: &ast::SelfParam, new_name: &str) -> Opt Some(impl_def) => { let type_name = target_type_name(&impl_def)?; - let mut replacement_text = String::from(new_name); + let mut replacement_text = new_name; replacement_text.push_str(": "); match (self_param.amp_token(), self_param.mut_token()) { (Some(_), None) => replacement_text.push('&'), @@ -458,7 +483,7 @@ fn text_edit_from_self_param(self_param: &ast::SelfParam, new_name: &str) -> Opt } None => { cov_mark::hit!(rename_self_outside_of_methods); - let mut replacement_text = String::from(new_name); + let mut replacement_text = new_name; replacement_text.push_str(": _"); Some(TextEdit::replace(self_param.syntax().text_range(), replacement_text)) } @@ -728,7 +753,7 @@ impl Foo { check( "super", r#"fn main() { let i$0 = 1; }"#, - "error: Invalid name `super`: not an identifier", + "error: Invalid name `super`: cannot rename to a keyword", ); } @@ -777,7 +802,11 @@ impl Foo { #[test] fn test_rename_mod_invalid_raw_ident() { - check("r#self", r#"mod foo$0 {}"#, "error: Invalid name `self`: not an identifier"); + check( + "r#self", + r#"mod foo$0 {}"#, + "error: Invalid name `self`: cannot rename module to self", + ); } #[test] @@ -2377,7 +2406,6 @@ fn foo(foo: Foo) { #[test] fn test_rename_lifetimes() { - cov_mark::check!(rename_lifetime); check( "'yeeee", r#" |