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