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