Skip to content

Commit 19701b3

Browse files
bors[bot]unexge
andauthored
Merge #4928
4928: Fix renaming mod in use tree r=matklad a=unexge Fixes #4825 Co-authored-by: unexge <[email protected]>
2 parents 3370c81 + 320c775 commit 19701b3

File tree

1 file changed

+139
-48
lines changed

1 file changed

+139
-48
lines changed

crates/ra_ide/src/references/rename.rs

Lines changed: 139 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
//! FIXME: write short doc here
22
3-
use hir::{ModuleSource, Semantics};
3+
use hir::{Module, ModuleDef, ModuleSource, Semantics};
44
use ra_db::{RelativePathBuf, SourceDatabaseExt};
5-
use ra_ide_db::RootDatabase;
5+
use ra_ide_db::{
6+
defs::{classify_name, classify_name_ref, Definition, NameClass, NameRefClass},
7+
RootDatabase,
8+
};
69
use ra_syntax::{
7-
algo::find_node_at_offset, ast, ast::TypeAscriptionOwner, lex_single_valid_syntax_kind,
8-
AstNode, SyntaxKind, SyntaxNode, SyntaxToken,
10+
algo::find_node_at_offset, ast, ast::NameOwner, ast::TypeAscriptionOwner,
11+
lex_single_valid_syntax_kind, match_ast, AstNode, SyntaxKind, SyntaxNode, SyntaxToken,
912
};
1013
use ra_text_edit::TextEdit;
1114
use std::convert::TryInto;
@@ -30,10 +33,8 @@ pub(crate) fn rename(
3033
let sema = Semantics::new(db);
3134
let source_file = sema.parse(position.file_id);
3235
let syntax = source_file.syntax();
33-
if let Some((ast_name, ast_module)) = find_name_and_module_at_offset(syntax, position) {
34-
let range = ast_name.syntax().text_range();
35-
rename_mod(&sema, &ast_name, &ast_module, position, new_name)
36-
.map(|info| RangeInfo::new(range, info))
36+
if let Some(module) = find_module_at_offset(&sema, position, syntax) {
37+
rename_mod(db, position, module, new_name)
3738
} else if let Some(self_token) =
3839
syntax.token_at_offset(position.offset).find(|t| t.kind() == SyntaxKind::SELF_KW)
3940
{
@@ -43,13 +44,32 @@ pub(crate) fn rename(
4344
}
4445
}
4546

46-
fn find_name_and_module_at_offset(
47-
syntax: &SyntaxNode,
47+
fn find_module_at_offset(
48+
sema: &Semantics<RootDatabase>,
4849
position: FilePosition,
49-
) -> Option<(ast::Name, ast::Module)> {
50-
let ast_name = find_node_at_offset::<ast::Name>(syntax, position.offset)?;
51-
let ast_module = ast::Module::cast(ast_name.syntax().parent()?)?;
52-
Some((ast_name, ast_module))
50+
syntax: &SyntaxNode,
51+
) -> Option<Module> {
52+
let ident = syntax.token_at_offset(position.offset).find(|t| t.kind() == SyntaxKind::IDENT)?;
53+
54+
let module = match_ast! {
55+
match (ident.parent()) {
56+
ast::NameRef(name_ref) => {
57+
match classify_name_ref(sema, &name_ref)? {
58+
NameRefClass::Definition(Definition::ModuleDef(ModuleDef::Module(module))) => module,
59+
_ => return None,
60+
}
61+
},
62+
ast::Name(name) => {
63+
match classify_name(&sema, &name)? {
64+
NameClass::Definition(Definition::ModuleDef(ModuleDef::Module(module))) => module,
65+
_ => return None,
66+
}
67+
},
68+
_ => return None,
69+
}
70+
};
71+
72+
Some(module)
5373
}
5474

5575
fn source_edit_from_reference(reference: Reference, new_name: &str) -> SourceFileEdit {
@@ -77,49 +97,50 @@ fn source_edit_from_reference(reference: Reference, new_name: &str) -> SourceFil
7797
}
7898

7999
fn rename_mod(
80-
sema: &Semantics<RootDatabase>,
81-
ast_name: &ast::Name,
82-
ast_module: &ast::Module,
100+
db: &RootDatabase,
83101
position: FilePosition,
102+
module: Module,
84103
new_name: &str,
85-
) -> Option<SourceChange> {
104+
) -> Option<RangeInfo<SourceChange>> {
86105
let mut source_file_edits = Vec::new();
87106
let mut file_system_edits = Vec::new();
88-
if let Some(module) = sema.to_def(ast_module) {
89-
let src = module.definition_source(sema.db);
90-
let file_id = src.file_id.original_file(sema.db);
91-
match src.value {
92-
ModuleSource::SourceFile(..) => {
93-
let mod_path: RelativePathBuf = sema.db.file_relative_path(file_id);
94-
// mod is defined in path/to/dir/mod.rs
95-
let dst = if mod_path.file_stem() == Some("mod") {
96-
format!("../{}/mod.rs", new_name)
97-
} else {
98-
format!("{}.rs", new_name)
99-
};
100-
let move_file =
101-
FileSystemEdit::MoveFile { src: file_id, anchor: position.file_id, dst };
102-
file_system_edits.push(move_file);
103-
}
104-
ModuleSource::Module(..) => {}
107+
108+
let src = module.definition_source(db);
109+
let file_id = src.file_id.original_file(db);
110+
match src.value {
111+
ModuleSource::SourceFile(..) => {
112+
let mod_path: RelativePathBuf = db.file_relative_path(file_id);
113+
// mod is defined in path/to/dir/mod.rs
114+
let dst = if mod_path.file_stem() == Some("mod") {
115+
format!("../{}/mod.rs", new_name)
116+
} else {
117+
format!("{}.rs", new_name)
118+
};
119+
let move_file =
120+
FileSystemEdit::MoveFile { src: file_id, anchor: position.file_id, dst };
121+
file_system_edits.push(move_file);
105122
}
123+
ModuleSource::Module(..) => {}
106124
}
107125

108-
let edit = SourceFileEdit {
109-
file_id: position.file_id,
110-
edit: TextEdit::replace(ast_name.syntax().text_range(), new_name.into()),
111-
};
112-
source_file_edits.push(edit);
113-
114-
if let Some(RangeInfo { range: _, info: refs }) = find_all_refs(sema.db, position, None) {
115-
let ref_edits = refs
116-
.references
117-
.into_iter()
118-
.map(|reference| source_edit_from_reference(reference, new_name));
119-
source_file_edits.extend(ref_edits);
126+
if let Some(src) = module.declaration_source(db) {
127+
let file_id = src.file_id.original_file(db);
128+
let name = src.value.name()?;
129+
let edit = SourceFileEdit {
130+
file_id: file_id,
131+
edit: TextEdit::replace(name.syntax().text_range(), new_name.into()),
132+
};
133+
source_file_edits.push(edit);
120134
}
121135

122-
Some(SourceChange::from_edits(source_file_edits, file_system_edits))
136+
let RangeInfo { range, info: refs } = find_all_refs(db, position, None)?;
137+
let ref_edits = refs
138+
.references
139+
.into_iter()
140+
.map(|reference| source_edit_from_reference(reference, new_name));
141+
source_file_edits.extend(ref_edits);
142+
143+
Some(RangeInfo::new(range, SourceChange::from_edits(source_file_edits, file_system_edits)))
123144
}
124145

125146
fn rename_to_self(db: &RootDatabase, position: FilePosition) -> Option<RangeInfo<SourceChange>> {
@@ -666,6 +687,76 @@ mod foo<|>;
666687
"###);
667688
}
668689

690+
#[test]
691+
fn test_rename_mod_in_use_tree() {
692+
let (analysis, position) = analysis_and_position(
693+
r#"
694+
//- /main.rs
695+
pub mod foo;
696+
pub mod bar;
697+
fn main() {}
698+
699+
//- /foo.rs
700+
pub struct FooContent;
701+
702+
//- /bar.rs
703+
use crate::foo<|>::FooContent;
704+
"#,
705+
);
706+
let new_name = "qux";
707+
let source_change = analysis.rename(position, new_name).unwrap();
708+
assert_debug_snapshot!(&source_change,
709+
@r###"
710+
Some(
711+
RangeInfo {
712+
range: 11..14,
713+
info: SourceChange {
714+
source_file_edits: [
715+
SourceFileEdit {
716+
file_id: FileId(
717+
1,
718+
),
719+
edit: TextEdit {
720+
indels: [
721+
Indel {
722+
insert: "qux",
723+
delete: 8..11,
724+
},
725+
],
726+
},
727+
},
728+
SourceFileEdit {
729+
file_id: FileId(
730+
3,
731+
),
732+
edit: TextEdit {
733+
indels: [
734+
Indel {
735+
insert: "qux",
736+
delete: 11..14,
737+
},
738+
],
739+
},
740+
},
741+
],
742+
file_system_edits: [
743+
MoveFile {
744+
src: FileId(
745+
2,
746+
),
747+
anchor: FileId(
748+
3,
749+
),
750+
dst: "qux.rs",
751+
},
752+
],
753+
is_snippet: false,
754+
},
755+
},
756+
)
757+
"###);
758+
}
759+
669760
#[test]
670761
fn test_rename_mod_in_dir() {
671762
let (analysis, position) = analysis_and_position(

0 commit comments

Comments
 (0)