diff --git a/crates/ide-db/src/rename.rs b/crates/ide-db/src/rename.rs index 6da650aeb6b..689d23efd71 100644 --- a/crates/ide-db/src/rename.rs +++ b/crates/ide-db/src/rename.rs @@ -190,6 +190,7 @@ fn rename_mod( let InFile { file_id, value: def_source } = module.definition_source(sema.db); if let ModuleSource::SourceFile(..) = def_source { + let new_name = new_name.trim_start_matches("r#"); let anchor = file_id.original_file(sema.db); let is_mod_rs = module.is_mod_rs(sema.db); @@ -207,9 +208,13 @@ fn rename_mod( // - Module has submodules defined in separate files 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}"), format!("../{new_name}"))), + (true, _, Some(mod_name)) => { + Some((format!("../{}", mod_name.unescaped()), format!("../{new_name}"))) + } // The anchor is on the same level as target dir - (false, true, Some(mod_name)) => Some((mod_name.to_string(), new_name.to_string())), + (false, true, Some(mod_name)) => { + Some((mod_name.unescaped().to_string(), new_name.to_string())) + } _ => None, }; diff --git a/crates/ide/src/rename.rs b/crates/ide/src/rename.rs index 25d165d1113..84a14ccd979 100644 --- a/crates/ide/src/rename.rs +++ b/crates/ide/src/rename.rs @@ -13,7 +13,7 @@ }; use itertools::Itertools; use stdx::{always, never}; -use syntax::{ast, AstNode, SyntaxNode, TextRange, TextSize}; +use syntax::{ast, utils::is_raw_identifier, AstNode, SmolStr, SyntaxNode, TextRange, TextSize}; use text_edit::TextEdit; @@ -122,7 +122,11 @@ pub(crate) fn will_rename_file( let sema = Semantics::new(db); let module = sema.to_module_def(file_id)?; let def = Definition::Module(module); - let mut change = def.rename(&sema, new_name_stem).ok()?; + let mut change = if is_raw_identifier(new_name_stem) { + def.rename(&sema, &SmolStr::from_iter(["r#", new_name_stem])).ok()? + } else { + def.rename(&sema, new_name_stem).ok()? + }; change.file_system_edits.clear(); Some(change) } @@ -1286,6 +1290,143 @@ fn foo() {} ) } + #[test] + fn test_rename_mod_to_raw_ident() { + check_expect( + "r#fn", + r#" +//- /lib.rs +mod foo$0; + +fn main() { foo::bar::baz(); } + +//- /foo.rs +pub mod bar; + +//- /foo/bar.rs +pub fn baz() {} +"#, + expect![[r#" + SourceChange { + source_file_edits: { + FileId( + 0, + ): TextEdit { + indels: [ + Indel { + insert: "r#fn", + delete: 4..7, + }, + Indel { + insert: "r#fn", + delete: 22..25, + }, + ], + }, + }, + file_system_edits: [ + MoveFile { + src: FileId( + 1, + ), + dst: AnchoredPathBuf { + anchor: FileId( + 1, + ), + path: "fn.rs", + }, + }, + MoveDir { + src: AnchoredPathBuf { + anchor: FileId( + 1, + ), + path: "foo", + }, + src_id: FileId( + 1, + ), + dst: AnchoredPathBuf { + anchor: FileId( + 1, + ), + path: "fn", + }, + }, + ], + is_snippet: false, + } + "#]], + ); + } + + #[test] + fn test_rename_mod_from_raw_ident() { + // FIXME: `r#fn` in path expression is not renamed. + check_expect( + "foo", + r#" +//- /lib.rs +mod r#fn$0; + +fn main() { r#fn::bar::baz(); } + +//- /fn.rs +pub mod bar; + +//- /fn/bar.rs +pub fn baz() {} +"#, + expect![[r#" + SourceChange { + source_file_edits: { + FileId( + 0, + ): TextEdit { + indels: [ + Indel { + insert: "foo", + delete: 4..8, + }, + ], + }, + }, + file_system_edits: [ + MoveFile { + src: FileId( + 1, + ), + dst: AnchoredPathBuf { + anchor: FileId( + 1, + ), + path: "foo.rs", + }, + }, + MoveDir { + src: AnchoredPathBuf { + anchor: FileId( + 1, + ), + path: "fn", + }, + src_id: FileId( + 1, + ), + dst: AnchoredPathBuf { + anchor: FileId( + 1, + ), + path: "foo", + }, + }, + ], + is_snippet: false, + } + "#]], + ); + } + #[test] fn test_enum_variant_from_module_1() { cov_mark::check!(rename_non_local);