Skip to content

Commit bd0c234

Browse files
committed
Auto merge of rust-lang#12387 - 00nktk:fix-mod-rename, r=Veykril
fix(ide-db): correct single-file module rename Fixes a bug where rust-analyzer would emit `WorkspaceEdit`s with paths to dirs instead of files for the following project layout. lib.rs ```rust mod foo; ``` foo.rs ```rust mod bar { struct Bar; } ``` Also fixes emitted paths for modules with mod.rs. The bug resulted in panic in helix editor when attempting to rename a module.
2 parents e4ead8a + d98c04a commit bd0c234

File tree

3 files changed

+42
-8
lines changed

3 files changed

+42
-8
lines changed

crates/hir/src/has_source.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,11 @@ impl Module {
3939
}
4040
}
4141

42+
pub fn is_inline(self, db: &dyn HirDatabase) -> bool {
43+
let def_map = self.id.def_map(db.upcast());
44+
def_map[self.id.local_id].origin.is_inline()
45+
}
46+
4247
/// Returns a node which declares this module, either a `mod foo;` or a `mod foo {}`.
4348
/// `None` for the crate root.
4449
pub fn declaration_source(self, db: &dyn HirDatabase) -> Option<InFile<ast::Module>> {

crates/ide-db/src/rename.rs

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -180,15 +180,33 @@ fn rename_mod(
180180
let InFile { file_id, value: def_source } = module.definition_source(sema.db);
181181
if let ModuleSource::SourceFile(..) = def_source {
182182
let anchor = file_id.original_file(sema.db);
183-
// not mod.rs and doesn't has children, rename file only
184-
if !module.is_mod_rs(sema.db) && module.children(sema.db).next().is_none() {
183+
184+
let is_mod_rs = module.is_mod_rs(sema.db);
185+
let has_detached_child = module.children(sema.db).any(|child| !child.is_inline(sema.db));
186+
187+
// Module exists in a named file
188+
if !is_mod_rs {
185189
let path = format!("{}.rs", new_name);
186190
let dst = AnchoredPathBuf { anchor, path };
187191
source_change.push_file_system_edit(FileSystemEdit::MoveFile { src: anchor, dst })
188-
} else if let Some(mod_name) = module.name(sema.db) {
189-
// is mod.rs or has children, rename dir
190-
let src = AnchoredPathBuf { anchor, path: mod_name.to_string() };
191-
let dst = AnchoredPathBuf { anchor, path: new_name.to_string() };
192+
}
193+
194+
// Rename the dir if:
195+
// - Module source is in mod.rs
196+
// - Module has submodules defined in separate files
197+
let dir_paths = match (is_mod_rs, has_detached_child, module.name(sema.db)) {
198+
// Go up one level since the anchor is inside the dir we're trying to rename
199+
(true, _, Some(mod_name)) => {
200+
Some((format!("../{}", mod_name), format!("../{}", new_name)))
201+
}
202+
// The anchor is on the same level as target dir
203+
(false, true, Some(mod_name)) => Some((mod_name.to_string(), new_name.to_string())),
204+
_ => None,
205+
};
206+
207+
if let Some((src, dst)) = dir_paths {
208+
let src = AnchoredPathBuf { anchor, path: src };
209+
let dst = AnchoredPathBuf { anchor, path: dst };
192210
source_change.push_file_system_edit(FileSystemEdit::MoveDir {
193211
src,
194212
src_id: anchor,

crates/ide/src/rename.rs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -973,7 +973,7 @@ mod fo$0o;
973973
anchor: FileId(
974974
1,
975975
),
976-
path: "foo",
976+
path: "../foo",
977977
},
978978
src_id: FileId(
979979
1,
@@ -982,7 +982,7 @@ mod fo$0o;
982982
anchor: FileId(
983983
1,
984984
),
985-
path: "foo2",
985+
path: "../foo2",
986986
},
987987
},
988988
],
@@ -1158,6 +1158,17 @@ mod quux;
11581158
},
11591159
},
11601160
file_system_edits: [
1161+
MoveFile {
1162+
src: FileId(
1163+
1,
1164+
),
1165+
dst: AnchoredPathBuf {
1166+
anchor: FileId(
1167+
1,
1168+
),
1169+
path: "foo2.rs",
1170+
},
1171+
},
11611172
MoveDir {
11621173
src: AnchoredPathBuf {
11631174
anchor: FileId(

0 commit comments

Comments
 (0)