From d98c04aac17d62ccddf26af501ee9e4d300ab6c5 Mon Sep 17 00:00:00 2001 From: Nikita Podoliako Date: Wed, 25 May 2022 18:47:11 +0300 Subject: [PATCH] fix(ide-db): correct single-file module rename --- crates/hir/src/has_source.rs | 5 +++++ crates/ide-db/src/rename.rs | 30 ++++++++++++++++++++++++------ crates/ide/src/rename.rs | 15 +++++++++++++-- 3 files changed, 42 insertions(+), 8 deletions(-) diff --git a/crates/hir/src/has_source.rs b/crates/hir/src/has_source.rs index 037f51ec8e0..f8b01db3e32 100644 --- a/crates/hir/src/has_source.rs +++ b/crates/hir/src/has_source.rs @@ -39,6 +39,11 @@ pub fn is_mod_rs(self, db: &dyn HirDatabase) -> bool { } } + pub fn is_inline(self, db: &dyn HirDatabase) -> bool { + let def_map = self.id.def_map(db.upcast()); + def_map[self.id.local_id].origin.is_inline() + } + /// Returns a node which declares this module, either a `mod foo;` or a `mod foo {}`. /// `None` for the crate root. pub fn declaration_source(self, db: &dyn HirDatabase) -> Option> { diff --git a/crates/ide-db/src/rename.rs b/crates/ide-db/src/rename.rs index 589975406a4..8f83496e938 100644 --- a/crates/ide-db/src/rename.rs +++ b/crates/ide-db/src/rename.rs @@ -180,15 +180,33 @@ fn rename_mod( let InFile { file_id, value: def_source } = module.definition_source(sema.db); if let ModuleSource::SourceFile(..) = def_source { let anchor = file_id.original_file(sema.db); - // not mod.rs and doesn't has children, rename file only - if !module.is_mod_rs(sema.db) && module.children(sema.db).next().is_none() { + + let is_mod_rs = module.is_mod_rs(sema.db); + let has_detached_child = module.children(sema.db).any(|child| !child.is_inline(sema.db)); + + // Module exists in a named file + if !is_mod_rs { let path = format!("{}.rs", new_name); let dst = AnchoredPathBuf { anchor, path }; source_change.push_file_system_edit(FileSystemEdit::MoveFile { src: anchor, dst }) - } else if let Some(mod_name) = module.name(sema.db) { - // is mod.rs or has children, rename dir - let src = AnchoredPathBuf { anchor, path: mod_name.to_string() }; - let dst = AnchoredPathBuf { anchor, path: new_name.to_string() }; + } + + // Rename the dir if: + // - Module source is in mod.rs + // - 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))) + } + // The anchor is on the same level as target dir + (false, true, Some(mod_name)) => Some((mod_name.to_string(), new_name.to_string())), + _ => None, + }; + + if let Some((src, dst)) = dir_paths { + let src = AnchoredPathBuf { anchor, path: src }; + let dst = AnchoredPathBuf { anchor, path: dst }; source_change.push_file_system_edit(FileSystemEdit::MoveDir { src, src_id: anchor, diff --git a/crates/ide/src/rename.rs b/crates/ide/src/rename.rs index f5bff5fd918..0f8033611a1 100644 --- a/crates/ide/src/rename.rs +++ b/crates/ide/src/rename.rs @@ -973,7 +973,7 @@ fn test_rename_mod_in_dir() { anchor: FileId( 1, ), - path: "foo", + path: "../foo", }, src_id: FileId( 1, @@ -982,7 +982,7 @@ fn test_rename_mod_in_dir() { anchor: FileId( 1, ), - path: "foo2", + path: "../foo2", }, }, ], @@ -1158,6 +1158,17 @@ fn test_rename_mod_recursive() { }, }, file_system_edits: [ + MoveFile { + src: FileId( + 1, + ), + dst: AnchoredPathBuf { + anchor: FileId( + 1, + ), + path: "foo2.rs", + }, + }, MoveDir { src: AnchoredPathBuf { anchor: FileId(