]> git.lizzy.rs Git - rust.git/blob - crates/ide/src/references/rename.rs
Merge #6137
[rust.git] / crates / ide / src / references / rename.rs
1 //! FIXME: write short doc here
2
3 use base_db::SourceDatabaseExt;
4 use hir::{Module, ModuleDef, ModuleSource, Semantics};
5 use ide_db::{
6     defs::{classify_name, classify_name_ref, Definition, NameClass, NameRefClass},
7     RootDatabase,
8 };
9
10 use std::{
11     convert::TryInto,
12     error::Error,
13     fmt::{self, Display},
14 };
15 use syntax::{
16     algo::find_node_at_offset,
17     ast::{self, NameOwner},
18     lex_single_syntax_kind, match_ast, AstNode, SyntaxKind, SyntaxNode, SyntaxToken,
19 };
20 use test_utils::mark;
21 use text_edit::TextEdit;
22
23 use crate::{
24     references::find_all_refs, FilePosition, FileSystemEdit, RangeInfo, Reference, ReferenceKind,
25     SourceChange, SourceFileEdit, TextRange, TextSize,
26 };
27
28 #[derive(Debug)]
29 pub struct RenameError(pub(crate) String);
30
31 impl fmt::Display for RenameError {
32     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
33         Display::fmt(&self.0, f)
34     }
35 }
36
37 impl Error for RenameError {}
38
39 pub(crate) fn rename(
40     db: &RootDatabase,
41     position: FilePosition,
42     new_name: &str,
43 ) -> Result<RangeInfo<SourceChange>, RenameError> {
44     let sema = Semantics::new(db);
45
46     match lex_single_syntax_kind(new_name) {
47         Some(res) => match res {
48             (SyntaxKind::IDENT, _) => (),
49             (SyntaxKind::UNDERSCORE, _) => (),
50             (SyntaxKind::SELF_KW, _) => return rename_to_self(&sema, position),
51             (_, Some(syntax_error)) => {
52                 return Err(RenameError(format!("Invalid name `{}`: {}", new_name, syntax_error)))
53             }
54             (_, None) => {
55                 return Err(RenameError(format!("Invalid name `{}`: not an identifier", new_name)))
56             }
57         },
58         None => return Err(RenameError(format!("Invalid name `{}`: not an identifier", new_name))),
59     }
60
61     let source_file = sema.parse(position.file_id);
62     let syntax = source_file.syntax();
63     if let Some(module) = find_module_at_offset(&sema, position, syntax) {
64         rename_mod(&sema, position, module, new_name)
65     } else if let Some(self_token) =
66         syntax.token_at_offset(position.offset).find(|t| t.kind() == SyntaxKind::SELF_KW)
67     {
68         rename_self_to_param(&sema, position, self_token, new_name)
69     } else {
70         rename_reference(&sema, position, new_name)
71     }
72 }
73
74 fn find_module_at_offset(
75     sema: &Semantics<RootDatabase>,
76     position: FilePosition,
77     syntax: &SyntaxNode,
78 ) -> Option<Module> {
79     let ident = syntax.token_at_offset(position.offset).find(|t| t.kind() == SyntaxKind::IDENT)?;
80
81     let module = match_ast! {
82         match (ident.parent()) {
83             ast::NameRef(name_ref) => {
84                 match classify_name_ref(sema, &name_ref)? {
85                     NameRefClass::Definition(Definition::ModuleDef(ModuleDef::Module(module))) => module,
86                     _ => return None,
87                 }
88             },
89             ast::Name(name) => {
90                 match classify_name(&sema, &name)? {
91                     NameClass::Definition(Definition::ModuleDef(ModuleDef::Module(module))) => module,
92                     _ => return None,
93                 }
94             },
95             _ => return None,
96         }
97     };
98
99     Some(module)
100 }
101
102 fn source_edit_from_reference(reference: Reference, new_name: &str) -> SourceFileEdit {
103     let mut replacement_text = String::new();
104     let file_id = reference.file_range.file_id;
105     let range = match reference.kind {
106         ReferenceKind::FieldShorthandForField => {
107             mark::hit!(test_rename_struct_field_for_shorthand);
108             replacement_text.push_str(new_name);
109             replacement_text.push_str(": ");
110             TextRange::new(reference.file_range.range.start(), reference.file_range.range.start())
111         }
112         ReferenceKind::FieldShorthandForLocal => {
113             mark::hit!(test_rename_local_for_field_shorthand);
114             replacement_text.push_str(": ");
115             replacement_text.push_str(new_name);
116             TextRange::new(reference.file_range.range.end(), reference.file_range.range.end())
117         }
118         _ => {
119             replacement_text.push_str(new_name);
120             reference.file_range.range
121         }
122     };
123     SourceFileEdit { file_id, edit: TextEdit::replace(range, replacement_text) }
124 }
125
126 fn rename_mod(
127     sema: &Semantics<RootDatabase>,
128     position: FilePosition,
129     module: Module,
130     new_name: &str,
131 ) -> Result<RangeInfo<SourceChange>, RenameError> {
132     let mut source_file_edits = Vec::new();
133     let mut file_system_edits = Vec::new();
134
135     let src = module.definition_source(sema.db);
136     let file_id = src.file_id.original_file(sema.db);
137     match src.value {
138         ModuleSource::SourceFile(..) => {
139             // mod is defined in path/to/dir/mod.rs
140             let dst = if module.is_mod_rs(sema.db) {
141                 format!("../{}/mod.rs", new_name)
142             } else {
143                 format!("{}.rs", new_name)
144             };
145             let move_file = FileSystemEdit::MoveFile { src: file_id, anchor: file_id, dst };
146             file_system_edits.push(move_file);
147         }
148         ModuleSource::Module(..) => {}
149     }
150
151     if let Some(src) = module.declaration_source(sema.db) {
152         let file_id = src.file_id.original_file(sema.db);
153         let name = src.value.name().unwrap();
154         let edit = SourceFileEdit {
155             file_id,
156             edit: TextEdit::replace(name.syntax().text_range(), new_name.into()),
157         };
158         source_file_edits.push(edit);
159     }
160
161     let RangeInfo { range, info: refs } = find_all_refs(sema, position, None)
162         .ok_or_else(|| RenameError("No references found at position".to_string()))?;
163     let ref_edits = refs
164         .references
165         .into_iter()
166         .map(|reference| source_edit_from_reference(reference, new_name));
167     source_file_edits.extend(ref_edits);
168
169     Ok(RangeInfo::new(range, SourceChange::from_edits(source_file_edits, file_system_edits)))
170 }
171
172 fn rename_to_self(
173     sema: &Semantics<RootDatabase>,
174     position: FilePosition,
175 ) -> Result<RangeInfo<SourceChange>, RenameError> {
176     let source_file = sema.parse(position.file_id);
177     let syn = source_file.syntax();
178
179     let fn_def = find_node_at_offset::<ast::Fn>(syn, position.offset)
180         .ok_or_else(|| RenameError("No surrounding method declaration found".to_string()))?;
181     let params =
182         fn_def.param_list().ok_or_else(|| RenameError("Method has no parameters".to_string()))?;
183     if params.self_param().is_some() {
184         return Err(RenameError("Method already has a self parameter".to_string()));
185     }
186     let first_param =
187         params.params().next().ok_or_else(|| RenameError("Method has no parameters".into()))?;
188     let mutable = match first_param.ty() {
189         Some(ast::Type::RefType(rt)) => rt.mut_token().is_some(),
190         _ => return Err(RenameError("Not renaming other types".to_string())),
191     };
192
193     let RangeInfo { range, info: refs } = find_all_refs(sema, position, None)
194         .ok_or_else(|| RenameError("No reference found at position".to_string()))?;
195
196     let param_range = first_param.syntax().text_range();
197     let (param_ref, usages): (Vec<Reference>, Vec<Reference>) = refs
198         .into_iter()
199         .partition(|reference| param_range.intersect(reference.file_range.range).is_some());
200
201     if param_ref.is_empty() {
202         return Err(RenameError("Parameter to rename not found".to_string()));
203     }
204
205     let mut edits = usages
206         .into_iter()
207         .map(|reference| source_edit_from_reference(reference, "self"))
208         .collect::<Vec<_>>();
209
210     edits.push(SourceFileEdit {
211         file_id: position.file_id,
212         edit: TextEdit::replace(
213             param_range,
214             String::from(if mutable { "&mut self" } else { "&self" }),
215         ),
216     });
217
218     Ok(RangeInfo::new(range, SourceChange::from(edits)))
219 }
220
221 fn text_edit_from_self_param(
222     syn: &SyntaxNode,
223     self_param: &ast::SelfParam,
224     new_name: &str,
225 ) -> Option<TextEdit> {
226     fn target_type_name(impl_def: &ast::Impl) -> Option<String> {
227         if let Some(ast::Type::PathType(p)) = impl_def.self_ty() {
228             return Some(p.path()?.segment()?.name_ref()?.text().to_string());
229         }
230         None
231     }
232
233     let impl_def = find_node_at_offset::<ast::Impl>(syn, self_param.syntax().text_range().start())?;
234     let type_name = target_type_name(&impl_def)?;
235
236     let mut replacement_text = String::from(new_name);
237     replacement_text.push_str(": ");
238     replacement_text.push_str(self_param.mut_token().map_or("&", |_| "&mut "));
239     replacement_text.push_str(type_name.as_str());
240
241     Some(TextEdit::replace(self_param.syntax().text_range(), replacement_text))
242 }
243
244 fn rename_self_to_param(
245     sema: &Semantics<RootDatabase>,
246     position: FilePosition,
247     self_token: SyntaxToken,
248     new_name: &str,
249 ) -> Result<RangeInfo<SourceChange>, RenameError> {
250     let source_file = sema.parse(position.file_id);
251     let syn = source_file.syntax();
252
253     let text = sema.db.file_text(position.file_id);
254     let fn_def = find_node_at_offset::<ast::Fn>(syn, position.offset)
255         .ok_or_else(|| RenameError("No surrounding method declaration found".to_string()))?;
256     let search_range = fn_def.syntax().text_range();
257
258     let mut edits: Vec<SourceFileEdit> = vec![];
259
260     for (idx, _) in text.match_indices("self") {
261         let offset: TextSize = idx.try_into().unwrap();
262         if !search_range.contains_inclusive(offset) {
263             continue;
264         }
265         if let Some(ref usage) =
266             syn.token_at_offset(offset).find(|t| t.kind() == SyntaxKind::SELF_KW)
267         {
268             let edit = if let Some(ref self_param) = ast::SelfParam::cast(usage.parent()) {
269                 text_edit_from_self_param(syn, self_param, new_name)
270                     .ok_or_else(|| RenameError("No target type found".to_string()))?
271             } else {
272                 TextEdit::replace(usage.text_range(), String::from(new_name))
273             };
274             edits.push(SourceFileEdit { file_id: position.file_id, edit });
275         }
276     }
277
278     let range = ast::SelfParam::cast(self_token.parent())
279         .map_or(self_token.text_range(), |p| p.syntax().text_range());
280
281     Ok(RangeInfo::new(range, SourceChange::from(edits)))
282 }
283
284 fn rename_reference(
285     sema: &Semantics<RootDatabase>,
286     position: FilePosition,
287     new_name: &str,
288 ) -> Result<RangeInfo<SourceChange>, RenameError> {
289     let RangeInfo { range, info: refs } = match find_all_refs(sema, position, None) {
290         Some(range_info) => range_info,
291         None => return Err(RenameError("No references found at position".to_string())),
292     };
293
294     let edit = refs
295         .into_iter()
296         .map(|reference| source_edit_from_reference(reference, new_name))
297         .collect::<Vec<_>>();
298
299     if edit.is_empty() {
300         return Err(RenameError("No references found at position".to_string()));
301     }
302
303     Ok(RangeInfo::new(range, SourceChange::from(edit)))
304 }
305
306 #[cfg(test)]
307 mod tests {
308     use expect_test::{expect, Expect};
309     use stdx::trim_indent;
310     use test_utils::{assert_eq_text, mark};
311     use text_edit::TextEdit;
312
313     use crate::{fixture, FileId};
314
315     fn check(new_name: &str, ra_fixture_before: &str, ra_fixture_after: &str) {
316         let ra_fixture_after = &trim_indent(ra_fixture_after);
317         let (analysis, position) = fixture::position(ra_fixture_before);
318         let rename_result = analysis
319             .rename(position, new_name)
320             .unwrap_or_else(|err| panic!("Rename to '{}' was cancelled: {}", new_name, err));
321         match rename_result {
322             Ok(source_change) => {
323                 let mut text_edit_builder = TextEdit::builder();
324                 let mut file_id: Option<FileId> = None;
325                 for edit in source_change.info.source_file_edits {
326                     file_id = Some(edit.file_id);
327                     for indel in edit.edit.into_iter() {
328                         text_edit_builder.replace(indel.delete, indel.insert);
329                     }
330                 }
331                 let mut result = analysis.file_text(file_id.unwrap()).unwrap().to_string();
332                 text_edit_builder.finish().apply(&mut result);
333                 assert_eq_text!(ra_fixture_after, &*result);
334             }
335             Err(err) => {
336                 if ra_fixture_after.starts_with("error:") {
337                     let error_message = ra_fixture_after
338                         .chars()
339                         .into_iter()
340                         .skip("error:".len())
341                         .collect::<String>();
342                     assert_eq!(error_message.trim(), err.to_string());
343                     return;
344                 } else {
345                     panic!("Rename to '{}' failed unexpectedly: {}", new_name, err)
346                 }
347             }
348         };
349     }
350
351     fn check_expect(new_name: &str, ra_fixture: &str, expect: Expect) {
352         let (analysis, position) = fixture::position(ra_fixture);
353         let source_change = analysis
354             .rename(position, new_name)
355             .unwrap()
356             .expect("Expect returned RangeInfo to be Some, but was None");
357         expect.assert_debug_eq(&source_change)
358     }
359
360     #[test]
361     fn test_rename_to_underscore() {
362         check("_", r#"fn main() { let i<|> = 1; }"#, r#"fn main() { let _ = 1; }"#);
363     }
364
365     #[test]
366     fn test_rename_to_raw_identifier() {
367         check("r#fn", r#"fn main() { let i<|> = 1; }"#, r#"fn main() { let r#fn = 1; }"#);
368     }
369
370     #[test]
371     fn test_rename_to_invalid_identifier1() {
372         check(
373             "invalid!",
374             r#"fn main() { let i<|> = 1; }"#,
375             "error: Invalid name `invalid!`: not an identifier",
376         );
377     }
378
379     #[test]
380     fn test_rename_to_invalid_identifier2() {
381         check(
382             "multiple tokens",
383             r#"fn main() { let i<|> = 1; }"#,
384             "error: Invalid name `multiple tokens`: not an identifier",
385         );
386     }
387
388     #[test]
389     fn test_rename_to_invalid_identifier3() {
390         check(
391             "let",
392             r#"fn main() { let i<|> = 1; }"#,
393             "error: Invalid name `let`: not an identifier",
394         );
395     }
396
397     #[test]
398     fn test_rename_for_local() {
399         check(
400             "k",
401             r#"
402 fn main() {
403     let mut i = 1;
404     let j = 1;
405     i = i<|> + j;
406
407     { i = 0; }
408
409     i = 5;
410 }
411 "#,
412             r#"
413 fn main() {
414     let mut k = 1;
415     let j = 1;
416     k = k + j;
417
418     { k = 0; }
419
420     k = 5;
421 }
422 "#,
423         );
424     }
425
426     #[test]
427     fn test_rename_unresolved_reference() {
428         check(
429             "new_name",
430             r#"fn main() { let _ = unresolved_ref<|>; }"#,
431             "error: No references found at position",
432         );
433     }
434
435     #[test]
436     fn test_rename_for_macro_args() {
437         check(
438             "b",
439             r#"
440 macro_rules! foo {($i:ident) => {$i} }
441 fn main() {
442     let a<|> = "test";
443     foo!(a);
444 }
445 "#,
446             r#"
447 macro_rules! foo {($i:ident) => {$i} }
448 fn main() {
449     let b = "test";
450     foo!(b);
451 }
452 "#,
453         );
454     }
455
456     #[test]
457     fn test_rename_for_macro_args_rev() {
458         check(
459             "b",
460             r#"
461 macro_rules! foo {($i:ident) => {$i} }
462 fn main() {
463     let a = "test";
464     foo!(a<|>);
465 }
466 "#,
467             r#"
468 macro_rules! foo {($i:ident) => {$i} }
469 fn main() {
470     let b = "test";
471     foo!(b);
472 }
473 "#,
474         );
475     }
476
477     #[test]
478     fn test_rename_for_macro_define_fn() {
479         check(
480             "bar",
481             r#"
482 macro_rules! define_fn {($id:ident) => { fn $id{} }}
483 define_fn!(foo);
484 fn main() {
485     fo<|>o();
486 }
487 "#,
488             r#"
489 macro_rules! define_fn {($id:ident) => { fn $id{} }}
490 define_fn!(bar);
491 fn main() {
492     bar();
493 }
494 "#,
495         );
496     }
497
498     #[test]
499     fn test_rename_for_macro_define_fn_rev() {
500         check(
501             "bar",
502             r#"
503 macro_rules! define_fn {($id:ident) => { fn $id{} }}
504 define_fn!(fo<|>o);
505 fn main() {
506     foo();
507 }
508 "#,
509             r#"
510 macro_rules! define_fn {($id:ident) => { fn $id{} }}
511 define_fn!(bar);
512 fn main() {
513     bar();
514 }
515 "#,
516         );
517     }
518
519     #[test]
520     fn test_rename_for_param_inside() {
521         check("j", r#"fn foo(i : u32) -> u32 { i<|> }"#, r#"fn foo(j : u32) -> u32 { j }"#);
522     }
523
524     #[test]
525     fn test_rename_refs_for_fn_param() {
526         check("j", r#"fn foo(i<|> : u32) -> u32 { i }"#, r#"fn foo(j : u32) -> u32 { j }"#);
527     }
528
529     #[test]
530     fn test_rename_for_mut_param() {
531         check("j", r#"fn foo(mut i<|> : u32) -> u32 { i }"#, r#"fn foo(mut j : u32) -> u32 { j }"#);
532     }
533
534     #[test]
535     fn test_rename_struct_field() {
536         check(
537             "j",
538             r#"
539 struct Foo { i<|>: i32 }
540
541 impl Foo {
542     fn new(i: i32) -> Self {
543         Self { i: i }
544     }
545 }
546 "#,
547             r#"
548 struct Foo { j: i32 }
549
550 impl Foo {
551     fn new(i: i32) -> Self {
552         Self { j: i }
553     }
554 }
555 "#,
556         );
557     }
558
559     #[test]
560     fn test_rename_struct_field_for_shorthand() {
561         mark::check!(test_rename_struct_field_for_shorthand);
562         check(
563             "j",
564             r#"
565 struct Foo { i<|>: i32 }
566
567 impl Foo {
568     fn new(i: i32) -> Self {
569         Self { i }
570     }
571 }
572 "#,
573             r#"
574 struct Foo { j: i32 }
575
576 impl Foo {
577     fn new(i: i32) -> Self {
578         Self { j: i }
579     }
580 }
581 "#,
582         );
583     }
584
585     #[test]
586     fn test_rename_local_for_field_shorthand() {
587         mark::check!(test_rename_local_for_field_shorthand);
588         check(
589             "j",
590             r#"
591 struct Foo { i: i32 }
592
593 impl Foo {
594     fn new(i<|>: i32) -> Self {
595         Self { i }
596     }
597 }
598 "#,
599             r#"
600 struct Foo { i: i32 }
601
602 impl Foo {
603     fn new(j: i32) -> Self {
604         Self { i: j }
605     }
606 }
607 "#,
608         );
609     }
610
611     #[test]
612     fn test_field_shorthand_correct_struct() {
613         check(
614             "j",
615             r#"
616 struct Foo { i<|>: i32 }
617 struct Bar { i: i32 }
618
619 impl Bar {
620     fn new(i: i32) -> Self {
621         Self { i }
622     }
623 }
624 "#,
625             r#"
626 struct Foo { j: i32 }
627 struct Bar { i: i32 }
628
629 impl Bar {
630     fn new(i: i32) -> Self {
631         Self { i }
632     }
633 }
634 "#,
635         );
636     }
637
638     #[test]
639     fn test_shadow_local_for_struct_shorthand() {
640         check(
641             "j",
642             r#"
643 struct Foo { i: i32 }
644
645 fn baz(i<|>: i32) -> Self {
646      let x = Foo { i };
647      {
648          let i = 0;
649          Foo { i }
650      }
651 }
652 "#,
653             r#"
654 struct Foo { i: i32 }
655
656 fn baz(j: i32) -> Self {
657      let x = Foo { i: j };
658      {
659          let i = 0;
660          Foo { i }
661      }
662 }
663 "#,
664         );
665     }
666
667     #[test]
668     fn test_rename_mod() {
669         check_expect(
670             "foo2",
671             r#"
672 //- /lib.rs
673 mod bar;
674
675 //- /bar.rs
676 mod foo<|>;
677
678 //- /bar/foo.rs
679 // empty
680 "#,
681             expect![[r#"
682                 RangeInfo {
683                     range: 4..7,
684                     info: SourceChange {
685                         source_file_edits: [
686                             SourceFileEdit {
687                                 file_id: FileId(
688                                     1,
689                                 ),
690                                 edit: TextEdit {
691                                     indels: [
692                                         Indel {
693                                             insert: "foo2",
694                                             delete: 4..7,
695                                         },
696                                     ],
697                                 },
698                             },
699                         ],
700                         file_system_edits: [
701                             MoveFile {
702                                 src: FileId(
703                                     2,
704                                 ),
705                                 anchor: FileId(
706                                     2,
707                                 ),
708                                 dst: "foo2.rs",
709                             },
710                         ],
711                         is_snippet: false,
712                     },
713                 }
714             "#]],
715         );
716     }
717
718     #[test]
719     fn test_rename_mod_in_use_tree() {
720         check_expect(
721             "quux",
722             r#"
723 //- /main.rs
724 pub mod foo;
725 pub mod bar;
726 fn main() {}
727
728 //- /foo.rs
729 pub struct FooContent;
730
731 //- /bar.rs
732 use crate::foo<|>::FooContent;
733 "#,
734             expect![[r#"
735                 RangeInfo {
736                     range: 11..14,
737                     info: SourceChange {
738                         source_file_edits: [
739                             SourceFileEdit {
740                                 file_id: FileId(
741                                     0,
742                                 ),
743                                 edit: TextEdit {
744                                     indels: [
745                                         Indel {
746                                             insert: "quux",
747                                             delete: 8..11,
748                                         },
749                                     ],
750                                 },
751                             },
752                             SourceFileEdit {
753                                 file_id: FileId(
754                                     2,
755                                 ),
756                                 edit: TextEdit {
757                                     indels: [
758                                         Indel {
759                                             insert: "quux",
760                                             delete: 11..14,
761                                         },
762                                     ],
763                                 },
764                             },
765                         ],
766                         file_system_edits: [
767                             MoveFile {
768                                 src: FileId(
769                                     1,
770                                 ),
771                                 anchor: FileId(
772                                     1,
773                                 ),
774                                 dst: "quux.rs",
775                             },
776                         ],
777                         is_snippet: false,
778                     },
779                 }
780             "#]],
781         );
782     }
783
784     #[test]
785     fn test_rename_mod_in_dir() {
786         check_expect(
787             "foo2",
788             r#"
789 //- /lib.rs
790 mod fo<|>o;
791 //- /foo/mod.rs
792 // emtpy
793 "#,
794             expect![[r#"
795                 RangeInfo {
796                     range: 4..7,
797                     info: SourceChange {
798                         source_file_edits: [
799                             SourceFileEdit {
800                                 file_id: FileId(
801                                     0,
802                                 ),
803                                 edit: TextEdit {
804                                     indels: [
805                                         Indel {
806                                             insert: "foo2",
807                                             delete: 4..7,
808                                         },
809                                     ],
810                                 },
811                             },
812                         ],
813                         file_system_edits: [
814                             MoveFile {
815                                 src: FileId(
816                                     1,
817                                 ),
818                                 anchor: FileId(
819                                     1,
820                                 ),
821                                 dst: "../foo2/mod.rs",
822                             },
823                         ],
824                         is_snippet: false,
825                     },
826                 }
827             "#]],
828         );
829     }
830
831     #[test]
832     fn test_rename_unusually_nested_mod() {
833         check_expect(
834             "bar",
835             r#"
836 //- /lib.rs
837 mod outer { mod fo<|>o; }
838
839 //- /outer/foo.rs
840 // emtpy
841 "#,
842             expect![[r#"
843                 RangeInfo {
844                     range: 16..19,
845                     info: SourceChange {
846                         source_file_edits: [
847                             SourceFileEdit {
848                                 file_id: FileId(
849                                     0,
850                                 ),
851                                 edit: TextEdit {
852                                     indels: [
853                                         Indel {
854                                             insert: "bar",
855                                             delete: 16..19,
856                                         },
857                                     ],
858                                 },
859                             },
860                         ],
861                         file_system_edits: [
862                             MoveFile {
863                                 src: FileId(
864                                     1,
865                                 ),
866                                 anchor: FileId(
867                                     1,
868                                 ),
869                                 dst: "bar.rs",
870                             },
871                         ],
872                         is_snippet: false,
873                     },
874                 }
875             "#]],
876         );
877     }
878
879     #[test]
880     fn test_module_rename_in_path() {
881         check(
882             "baz",
883             r#"
884 mod <|>foo { pub fn bar() {} }
885
886 fn main() { foo::bar(); }
887 "#,
888             r#"
889 mod baz { pub fn bar() {} }
890
891 fn main() { baz::bar(); }
892 "#,
893         );
894     }
895
896     #[test]
897     fn test_rename_mod_filename_and_path() {
898         check_expect(
899             "foo2",
900             r#"
901 //- /lib.rs
902 mod bar;
903 fn f() {
904     bar::foo::fun()
905 }
906
907 //- /bar.rs
908 pub mod foo<|>;
909
910 //- /bar/foo.rs
911 // pub fn fun() {}
912 "#,
913             expect![[r#"
914                 RangeInfo {
915                     range: 8..11,
916                     info: SourceChange {
917                         source_file_edits: [
918                             SourceFileEdit {
919                                 file_id: FileId(
920                                     1,
921                                 ),
922                                 edit: TextEdit {
923                                     indels: [
924                                         Indel {
925                                             insert: "foo2",
926                                             delete: 8..11,
927                                         },
928                                     ],
929                                 },
930                             },
931                             SourceFileEdit {
932                                 file_id: FileId(
933                                     0,
934                                 ),
935                                 edit: TextEdit {
936                                     indels: [
937                                         Indel {
938                                             insert: "foo2",
939                                             delete: 27..30,
940                                         },
941                                     ],
942                                 },
943                             },
944                         ],
945                         file_system_edits: [
946                             MoveFile {
947                                 src: FileId(
948                                     2,
949                                 ),
950                                 anchor: FileId(
951                                     2,
952                                 ),
953                                 dst: "foo2.rs",
954                             },
955                         ],
956                         is_snippet: false,
957                     },
958                 }
959             "#]],
960         );
961     }
962
963     #[test]
964     fn test_enum_variant_from_module_1() {
965         check(
966             "Baz",
967             r#"
968 mod foo {
969     pub enum Foo { Bar<|> }
970 }
971
972 fn func(f: foo::Foo) {
973     match f {
974         foo::Foo::Bar => {}
975     }
976 }
977 "#,
978             r#"
979 mod foo {
980     pub enum Foo { Baz }
981 }
982
983 fn func(f: foo::Foo) {
984     match f {
985         foo::Foo::Baz => {}
986     }
987 }
988 "#,
989         );
990     }
991
992     #[test]
993     fn test_enum_variant_from_module_2() {
994         check(
995             "baz",
996             r#"
997 mod foo {
998     pub struct Foo { pub bar<|>: uint }
999 }
1000
1001 fn foo(f: foo::Foo) {
1002     let _ = f.bar;
1003 }
1004 "#,
1005             r#"
1006 mod foo {
1007     pub struct Foo { pub baz: uint }
1008 }
1009
1010 fn foo(f: foo::Foo) {
1011     let _ = f.baz;
1012 }
1013 "#,
1014         );
1015     }
1016
1017     #[test]
1018     fn test_parameter_to_self() {
1019         check(
1020             "self",
1021             r#"
1022 struct Foo { i: i32 }
1023
1024 impl Foo {
1025     fn f(foo<|>: &mut Foo) -> i32 {
1026         foo.i
1027     }
1028 }
1029 "#,
1030             r#"
1031 struct Foo { i: i32 }
1032
1033 impl Foo {
1034     fn f(&mut self) -> i32 {
1035         self.i
1036     }
1037 }
1038 "#,
1039         );
1040     }
1041
1042     #[test]
1043     fn test_self_to_parameter() {
1044         check(
1045             "foo",
1046             r#"
1047 struct Foo { i: i32 }
1048
1049 impl Foo {
1050     fn f(&mut <|>self) -> i32 {
1051         self.i
1052     }
1053 }
1054 "#,
1055             r#"
1056 struct Foo { i: i32 }
1057
1058 impl Foo {
1059     fn f(foo: &mut Foo) -> i32 {
1060         foo.i
1061     }
1062 }
1063 "#,
1064         );
1065     }
1066
1067     #[test]
1068     fn test_self_in_path_to_parameter() {
1069         check(
1070             "foo",
1071             r#"
1072 struct Foo { i: i32 }
1073
1074 impl Foo {
1075     fn f(&self) -> i32 {
1076         let self_var = 1;
1077         self<|>.i
1078     }
1079 }
1080 "#,
1081             r#"
1082 struct Foo { i: i32 }
1083
1084 impl Foo {
1085     fn f(foo: &Foo) -> i32 {
1086         let self_var = 1;
1087         foo.i
1088     }
1089 }
1090 "#,
1091         );
1092     }
1093 }