]> git.lizzy.rs Git - rust.git/blob - crates/ide/src/references/rename.rs
Fix renaming owned self to parameter emitting ref
[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     match (self_param.amp_token(), self_param.mut_token()) {
284         (None, None) => (),
285         (Some(_), None) => replacement_text.push('&'),
286         (_, Some(_)) => replacement_text.push_str("&mut "),
287     };
288     replacement_text.push_str(type_name.as_str());
289
290     Some(TextEdit::replace(self_param.syntax().text_range(), replacement_text))
291 }
292
293 fn rename_self_to_param(
294     sema: &Semantics<RootDatabase>,
295     position: FilePosition,
296     self_token: SyntaxToken,
297     new_name: &str,
298 ) -> Result<RangeInfo<SourceChange>, RenameError> {
299     let source_file = sema.parse(position.file_id);
300     let syn = source_file.syntax();
301
302     let text = sema.db.file_text(position.file_id);
303     let fn_def = find_node_at_offset::<ast::Fn>(syn, position.offset)
304         .ok_or_else(|| RenameError("No surrounding method declaration found".to_string()))?;
305     let search_range = fn_def.syntax().text_range();
306
307     let mut edits: Vec<SourceFileEdit> = vec![];
308
309     for (idx, _) in text.match_indices("self") {
310         let offset: TextSize = idx.try_into().unwrap();
311         if !search_range.contains_inclusive(offset) {
312             continue;
313         }
314         if let Some(ref usage) =
315             syn.token_at_offset(offset).find(|t| t.kind() == SyntaxKind::SELF_KW)
316         {
317             let edit = if let Some(ref self_param) = ast::SelfParam::cast(usage.parent()) {
318                 text_edit_from_self_param(syn, self_param, new_name)
319                     .ok_or_else(|| RenameError("No target type found".to_string()))?
320             } else {
321                 TextEdit::replace(usage.text_range(), String::from(new_name))
322             };
323             edits.push(SourceFileEdit { file_id: position.file_id, edit });
324         }
325     }
326
327     let range = ast::SelfParam::cast(self_token.parent())
328         .map_or(self_token.text_range(), |p| p.syntax().text_range());
329
330     Ok(RangeInfo::new(range, SourceChange::from(edits)))
331 }
332
333 fn rename_reference(
334     sema: &Semantics<RootDatabase>,
335     position: FilePosition,
336     new_name: &str,
337 ) -> Result<RangeInfo<SourceChange>, RenameError> {
338     let RangeInfo { range, info: refs } = match find_all_refs(sema, position, None) {
339         Some(range_info) => range_info,
340         None => return Err(RenameError("No references found at position".to_string())),
341     };
342
343     let edit = refs
344         .into_iter()
345         .map(|reference| source_edit_from_reference(sema, reference, new_name))
346         .collect::<Vec<_>>();
347
348     if edit.is_empty() {
349         return Err(RenameError("No references found at position".to_string()));
350     }
351
352     Ok(RangeInfo::new(range, SourceChange::from(edit)))
353 }
354
355 #[cfg(test)]
356 mod tests {
357     use expect_test::{expect, Expect};
358     use stdx::trim_indent;
359     use test_utils::{assert_eq_text, mark};
360     use text_edit::TextEdit;
361
362     use crate::{fixture, FileId};
363
364     fn check(new_name: &str, ra_fixture_before: &str, ra_fixture_after: &str) {
365         let ra_fixture_after = &trim_indent(ra_fixture_after);
366         let (analysis, position) = fixture::position(ra_fixture_before);
367         let rename_result = analysis
368             .rename(position, new_name)
369             .unwrap_or_else(|err| panic!("Rename to '{}' was cancelled: {}", new_name, err));
370         match rename_result {
371             Ok(source_change) => {
372                 let mut text_edit_builder = TextEdit::builder();
373                 let mut file_id: Option<FileId> = None;
374                 for edit in source_change.info.source_file_edits {
375                     file_id = Some(edit.file_id);
376                     for indel in edit.edit.into_iter() {
377                         text_edit_builder.replace(indel.delete, indel.insert);
378                     }
379                 }
380                 let mut result = analysis.file_text(file_id.unwrap()).unwrap().to_string();
381                 text_edit_builder.finish().apply(&mut result);
382                 assert_eq_text!(ra_fixture_after, &*result);
383             }
384             Err(err) => {
385                 if ra_fixture_after.starts_with("error:") {
386                     let error_message = ra_fixture_after
387                         .chars()
388                         .into_iter()
389                         .skip("error:".len())
390                         .collect::<String>();
391                     assert_eq!(error_message.trim(), err.to_string());
392                     return;
393                 } else {
394                     panic!("Rename to '{}' failed unexpectedly: {}", new_name, err)
395                 }
396             }
397         };
398     }
399
400     fn check_expect(new_name: &str, ra_fixture: &str, expect: Expect) {
401         let (analysis, position) = fixture::position(ra_fixture);
402         let source_change = analysis
403             .rename(position, new_name)
404             .unwrap()
405             .expect("Expect returned RangeInfo to be Some, but was None");
406         expect.assert_debug_eq(&source_change)
407     }
408
409     #[test]
410     fn test_rename_to_underscore() {
411         check("_", r#"fn main() { let i<|> = 1; }"#, r#"fn main() { let _ = 1; }"#);
412     }
413
414     #[test]
415     fn test_rename_to_raw_identifier() {
416         check("r#fn", r#"fn main() { let i<|> = 1; }"#, r#"fn main() { let r#fn = 1; }"#);
417     }
418
419     #[test]
420     fn test_rename_to_invalid_identifier1() {
421         check(
422             "invalid!",
423             r#"fn main() { let i<|> = 1; }"#,
424             "error: Invalid name `invalid!`: not an identifier",
425         );
426     }
427
428     #[test]
429     fn test_rename_to_invalid_identifier2() {
430         check(
431             "multiple tokens",
432             r#"fn main() { let i<|> = 1; }"#,
433             "error: Invalid name `multiple tokens`: not an identifier",
434         );
435     }
436
437     #[test]
438     fn test_rename_to_invalid_identifier3() {
439         check(
440             "let",
441             r#"fn main() { let i<|> = 1; }"#,
442             "error: Invalid name `let`: not an identifier",
443         );
444     }
445
446     #[test]
447     fn test_rename_for_local() {
448         check(
449             "k",
450             r#"
451 fn main() {
452     let mut i = 1;
453     let j = 1;
454     i = i<|> + j;
455
456     { i = 0; }
457
458     i = 5;
459 }
460 "#,
461             r#"
462 fn main() {
463     let mut k = 1;
464     let j = 1;
465     k = k + j;
466
467     { k = 0; }
468
469     k = 5;
470 }
471 "#,
472         );
473     }
474
475     #[test]
476     fn test_rename_unresolved_reference() {
477         check(
478             "new_name",
479             r#"fn main() { let _ = unresolved_ref<|>; }"#,
480             "error: No references found at position",
481         );
482     }
483
484     #[test]
485     fn test_rename_for_macro_args() {
486         check(
487             "b",
488             r#"
489 macro_rules! foo {($i:ident) => {$i} }
490 fn main() {
491     let a<|> = "test";
492     foo!(a);
493 }
494 "#,
495             r#"
496 macro_rules! foo {($i:ident) => {$i} }
497 fn main() {
498     let b = "test";
499     foo!(b);
500 }
501 "#,
502         );
503     }
504
505     #[test]
506     fn test_rename_for_macro_args_rev() {
507         check(
508             "b",
509             r#"
510 macro_rules! foo {($i:ident) => {$i} }
511 fn main() {
512     let a = "test";
513     foo!(a<|>);
514 }
515 "#,
516             r#"
517 macro_rules! foo {($i:ident) => {$i} }
518 fn main() {
519     let b = "test";
520     foo!(b);
521 }
522 "#,
523         );
524     }
525
526     #[test]
527     fn test_rename_for_macro_define_fn() {
528         check(
529             "bar",
530             r#"
531 macro_rules! define_fn {($id:ident) => { fn $id{} }}
532 define_fn!(foo);
533 fn main() {
534     fo<|>o();
535 }
536 "#,
537             r#"
538 macro_rules! define_fn {($id:ident) => { fn $id{} }}
539 define_fn!(bar);
540 fn main() {
541     bar();
542 }
543 "#,
544         );
545     }
546
547     #[test]
548     fn test_rename_for_macro_define_fn_rev() {
549         check(
550             "bar",
551             r#"
552 macro_rules! define_fn {($id:ident) => { fn $id{} }}
553 define_fn!(fo<|>o);
554 fn main() {
555     foo();
556 }
557 "#,
558             r#"
559 macro_rules! define_fn {($id:ident) => { fn $id{} }}
560 define_fn!(bar);
561 fn main() {
562     bar();
563 }
564 "#,
565         );
566     }
567
568     #[test]
569     fn test_rename_for_param_inside() {
570         check("j", r#"fn foo(i : u32) -> u32 { i<|> }"#, r#"fn foo(j : u32) -> u32 { j }"#);
571     }
572
573     #[test]
574     fn test_rename_refs_for_fn_param() {
575         check("j", r#"fn foo(i<|> : u32) -> u32 { i }"#, r#"fn foo(j : u32) -> u32 { j }"#);
576     }
577
578     #[test]
579     fn test_rename_for_mut_param() {
580         check("j", r#"fn foo(mut i<|> : u32) -> u32 { i }"#, r#"fn foo(mut j : u32) -> u32 { j }"#);
581     }
582
583     #[test]
584     fn test_rename_struct_field() {
585         check(
586             "j",
587             r#"
588 struct Foo { i<|>: i32 }
589
590 impl Foo {
591     fn new(i: i32) -> Self {
592         Self { i: i }
593     }
594 }
595 "#,
596             r#"
597 struct Foo { j: i32 }
598
599 impl Foo {
600     fn new(i: i32) -> Self {
601         Self { j: i }
602     }
603 }
604 "#,
605         );
606     }
607
608     #[test]
609     fn test_rename_struct_field_for_shorthand() {
610         mark::check!(test_rename_struct_field_for_shorthand);
611         check(
612             "j",
613             r#"
614 struct Foo { i<|>: i32 }
615
616 impl Foo {
617     fn new(i: i32) -> Self {
618         Self { i }
619     }
620 }
621 "#,
622             r#"
623 struct Foo { j: i32 }
624
625 impl Foo {
626     fn new(i: i32) -> Self {
627         Self { j: i }
628     }
629 }
630 "#,
631         );
632     }
633
634     #[test]
635     fn test_rename_local_for_field_shorthand() {
636         mark::check!(test_rename_local_for_field_shorthand);
637         check(
638             "j",
639             r#"
640 struct Foo { i: i32 }
641
642 impl Foo {
643     fn new(i<|>: i32) -> Self {
644         Self { i }
645     }
646 }
647 "#,
648             r#"
649 struct Foo { i: i32 }
650
651 impl Foo {
652     fn new(j: i32) -> Self {
653         Self { i: j }
654     }
655 }
656 "#,
657         );
658     }
659
660     #[test]
661     fn test_field_shorthand_correct_struct() {
662         check(
663             "j",
664             r#"
665 struct Foo { i<|>: i32 }
666 struct Bar { i: i32 }
667
668 impl Bar {
669     fn new(i: i32) -> Self {
670         Self { i }
671     }
672 }
673 "#,
674             r#"
675 struct Foo { j: i32 }
676 struct Bar { i: i32 }
677
678 impl Bar {
679     fn new(i: i32) -> Self {
680         Self { i }
681     }
682 }
683 "#,
684         );
685     }
686
687     #[test]
688     fn test_shadow_local_for_struct_shorthand() {
689         check(
690             "j",
691             r#"
692 struct Foo { i: i32 }
693
694 fn baz(i<|>: i32) -> Self {
695      let x = Foo { i };
696      {
697          let i = 0;
698          Foo { i }
699      }
700 }
701 "#,
702             r#"
703 struct Foo { i: i32 }
704
705 fn baz(j: i32) -> Self {
706      let x = Foo { i: j };
707      {
708          let i = 0;
709          Foo { i }
710      }
711 }
712 "#,
713         );
714     }
715
716     #[test]
717     fn test_rename_mod() {
718         check_expect(
719             "foo2",
720             r#"
721 //- /lib.rs
722 mod bar;
723
724 //- /bar.rs
725 mod foo<|>;
726
727 //- /bar/foo.rs
728 // empty
729 "#,
730             expect![[r#"
731                 RangeInfo {
732                     range: 4..7,
733                     info: SourceChange {
734                         source_file_edits: [
735                             SourceFileEdit {
736                                 file_id: FileId(
737                                     1,
738                                 ),
739                                 edit: TextEdit {
740                                     indels: [
741                                         Indel {
742                                             insert: "foo2",
743                                             delete: 4..7,
744                                         },
745                                     ],
746                                 },
747                             },
748                         ],
749                         file_system_edits: [
750                             MoveFile {
751                                 src: FileId(
752                                     2,
753                                 ),
754                                 anchor: FileId(
755                                     2,
756                                 ),
757                                 dst: "foo2.rs",
758                             },
759                         ],
760                         is_snippet: false,
761                     },
762                 }
763             "#]],
764         );
765     }
766
767     #[test]
768     fn test_rename_mod_in_use_tree() {
769         check_expect(
770             "quux",
771             r#"
772 //- /main.rs
773 pub mod foo;
774 pub mod bar;
775 fn main() {}
776
777 //- /foo.rs
778 pub struct FooContent;
779
780 //- /bar.rs
781 use crate::foo<|>::FooContent;
782 "#,
783             expect![[r#"
784                 RangeInfo {
785                     range: 11..14,
786                     info: SourceChange {
787                         source_file_edits: [
788                             SourceFileEdit {
789                                 file_id: FileId(
790                                     0,
791                                 ),
792                                 edit: TextEdit {
793                                     indels: [
794                                         Indel {
795                                             insert: "quux",
796                                             delete: 8..11,
797                                         },
798                                     ],
799                                 },
800                             },
801                             SourceFileEdit {
802                                 file_id: FileId(
803                                     2,
804                                 ),
805                                 edit: TextEdit {
806                                     indels: [
807                                         Indel {
808                                             insert: "quux",
809                                             delete: 11..14,
810                                         },
811                                     ],
812                                 },
813                             },
814                         ],
815                         file_system_edits: [
816                             MoveFile {
817                                 src: FileId(
818                                     1,
819                                 ),
820                                 anchor: FileId(
821                                     1,
822                                 ),
823                                 dst: "quux.rs",
824                             },
825                         ],
826                         is_snippet: false,
827                     },
828                 }
829             "#]],
830         );
831     }
832
833     #[test]
834     fn test_rename_mod_in_dir() {
835         check_expect(
836             "foo2",
837             r#"
838 //- /lib.rs
839 mod fo<|>o;
840 //- /foo/mod.rs
841 // emtpy
842 "#,
843             expect![[r#"
844                 RangeInfo {
845                     range: 4..7,
846                     info: SourceChange {
847                         source_file_edits: [
848                             SourceFileEdit {
849                                 file_id: FileId(
850                                     0,
851                                 ),
852                                 edit: TextEdit {
853                                     indels: [
854                                         Indel {
855                                             insert: "foo2",
856                                             delete: 4..7,
857                                         },
858                                     ],
859                                 },
860                             },
861                         ],
862                         file_system_edits: [
863                             MoveFile {
864                                 src: FileId(
865                                     1,
866                                 ),
867                                 anchor: FileId(
868                                     1,
869                                 ),
870                                 dst: "../foo2/mod.rs",
871                             },
872                         ],
873                         is_snippet: false,
874                     },
875                 }
876             "#]],
877         );
878     }
879
880     #[test]
881     fn test_rename_unusually_nested_mod() {
882         check_expect(
883             "bar",
884             r#"
885 //- /lib.rs
886 mod outer { mod fo<|>o; }
887
888 //- /outer/foo.rs
889 // emtpy
890 "#,
891             expect![[r#"
892                 RangeInfo {
893                     range: 16..19,
894                     info: SourceChange {
895                         source_file_edits: [
896                             SourceFileEdit {
897                                 file_id: FileId(
898                                     0,
899                                 ),
900                                 edit: TextEdit {
901                                     indels: [
902                                         Indel {
903                                             insert: "bar",
904                                             delete: 16..19,
905                                         },
906                                     ],
907                                 },
908                             },
909                         ],
910                         file_system_edits: [
911                             MoveFile {
912                                 src: FileId(
913                                     1,
914                                 ),
915                                 anchor: FileId(
916                                     1,
917                                 ),
918                                 dst: "bar.rs",
919                             },
920                         ],
921                         is_snippet: false,
922                     },
923                 }
924             "#]],
925         );
926     }
927
928     #[test]
929     fn test_module_rename_in_path() {
930         check(
931             "baz",
932             r#"
933 mod <|>foo { pub fn bar() {} }
934
935 fn main() { foo::bar(); }
936 "#,
937             r#"
938 mod baz { pub fn bar() {} }
939
940 fn main() { baz::bar(); }
941 "#,
942         );
943     }
944
945     #[test]
946     fn test_rename_mod_filename_and_path() {
947         check_expect(
948             "foo2",
949             r#"
950 //- /lib.rs
951 mod bar;
952 fn f() {
953     bar::foo::fun()
954 }
955
956 //- /bar.rs
957 pub mod foo<|>;
958
959 //- /bar/foo.rs
960 // pub fn fun() {}
961 "#,
962             expect![[r#"
963                 RangeInfo {
964                     range: 8..11,
965                     info: SourceChange {
966                         source_file_edits: [
967                             SourceFileEdit {
968                                 file_id: FileId(
969                                     1,
970                                 ),
971                                 edit: TextEdit {
972                                     indels: [
973                                         Indel {
974                                             insert: "foo2",
975                                             delete: 8..11,
976                                         },
977                                     ],
978                                 },
979                             },
980                             SourceFileEdit {
981                                 file_id: FileId(
982                                     0,
983                                 ),
984                                 edit: TextEdit {
985                                     indels: [
986                                         Indel {
987                                             insert: "foo2",
988                                             delete: 27..30,
989                                         },
990                                     ],
991                                 },
992                             },
993                         ],
994                         file_system_edits: [
995                             MoveFile {
996                                 src: FileId(
997                                     2,
998                                 ),
999                                 anchor: FileId(
1000                                     2,
1001                                 ),
1002                                 dst: "foo2.rs",
1003                             },
1004                         ],
1005                         is_snippet: false,
1006                     },
1007                 }
1008             "#]],
1009         );
1010     }
1011
1012     #[test]
1013     fn test_enum_variant_from_module_1() {
1014         check(
1015             "Baz",
1016             r#"
1017 mod foo {
1018     pub enum Foo { Bar<|> }
1019 }
1020
1021 fn func(f: foo::Foo) {
1022     match f {
1023         foo::Foo::Bar => {}
1024     }
1025 }
1026 "#,
1027             r#"
1028 mod foo {
1029     pub enum Foo { Baz }
1030 }
1031
1032 fn func(f: foo::Foo) {
1033     match f {
1034         foo::Foo::Baz => {}
1035     }
1036 }
1037 "#,
1038         );
1039     }
1040
1041     #[test]
1042     fn test_enum_variant_from_module_2() {
1043         check(
1044             "baz",
1045             r#"
1046 mod foo {
1047     pub struct Foo { pub bar<|>: uint }
1048 }
1049
1050 fn foo(f: foo::Foo) {
1051     let _ = f.bar;
1052 }
1053 "#,
1054             r#"
1055 mod foo {
1056     pub struct Foo { pub baz: uint }
1057 }
1058
1059 fn foo(f: foo::Foo) {
1060     let _ = f.baz;
1061 }
1062 "#,
1063         );
1064     }
1065
1066     #[test]
1067     fn test_parameter_to_self() {
1068         check(
1069             "self",
1070             r#"
1071 struct Foo { i: i32 }
1072
1073 impl Foo {
1074     fn f(foo<|>: &mut Foo) -> i32 {
1075         foo.i
1076     }
1077 }
1078 "#,
1079             r#"
1080 struct Foo { i: i32 }
1081
1082 impl Foo {
1083     fn f(&mut self) -> i32 {
1084         self.i
1085     }
1086 }
1087 "#,
1088         );
1089     }
1090
1091     #[test]
1092     fn test_self_to_parameter() {
1093         check(
1094             "foo",
1095             r#"
1096 struct Foo { i: i32 }
1097
1098 impl Foo {
1099     fn f(&mut <|>self) -> i32 {
1100         self.i
1101     }
1102 }
1103 "#,
1104             r#"
1105 struct Foo { i: i32 }
1106
1107 impl Foo {
1108     fn f(foo: &mut Foo) -> i32 {
1109         foo.i
1110     }
1111 }
1112 "#,
1113         );
1114     }
1115
1116     #[test]
1117     fn test_owned_self_to_parameter() {
1118         check(
1119             "foo",
1120             r#"
1121 struct Foo { i: i32 }
1122
1123 impl Foo {
1124     fn f(<|>self) -> i32 {
1125         self.i
1126     }
1127 }
1128 "#,
1129             r#"
1130 struct Foo { i: i32 }
1131
1132 impl Foo {
1133     fn f(foo: Foo) -> i32 {
1134         foo.i
1135     }
1136 }
1137 "#,
1138         );
1139     }
1140
1141     #[test]
1142     fn test_self_in_path_to_parameter() {
1143         check(
1144             "foo",
1145             r#"
1146 struct Foo { i: i32 }
1147
1148 impl Foo {
1149     fn f(&self) -> i32 {
1150         let self_var = 1;
1151         self<|>.i
1152     }
1153 }
1154 "#,
1155             r#"
1156 struct Foo { i: i32 }
1157
1158 impl Foo {
1159     fn f(foo: &Foo) -> i32 {
1160         let self_var = 1;
1161         foo.i
1162     }
1163 }
1164 "#,
1165         );
1166     }
1167
1168     #[test]
1169     fn test_initializer_use_field_init_shorthand() {
1170         mark::check!(test_rename_field_expr_pat);
1171         check(
1172             "bar",
1173             r#"
1174 struct Foo { i<|>: i32 }
1175
1176 fn foo(bar: i32) -> Foo {
1177     Foo { i: bar }
1178 }
1179 "#,
1180             r#"
1181 struct Foo { bar: i32 }
1182
1183 fn foo(bar: i32) -> Foo {
1184     Foo { bar }
1185 }
1186 "#,
1187         );
1188     }
1189
1190     #[test]
1191     fn test_struct_field_destructure_into_shorthand() {
1192         check(
1193             "baz",
1194             r#"
1195 struct Foo { i<|>: i32 }
1196
1197 fn foo(foo: Foo) {
1198     let Foo { i: baz } = foo;
1199     let _ = baz;
1200 }
1201 "#,
1202             r#"
1203 struct Foo { baz: i32 }
1204
1205 fn foo(foo: Foo) {
1206     let Foo { baz } = foo;
1207     let _ = baz;
1208 }
1209 "#,
1210         );
1211     }
1212
1213     #[test]
1214     fn test_rename_binding_in_destructure_pat() {
1215         let expected_fixture = r#"
1216 struct Foo {
1217     i: i32,
1218 }
1219
1220 fn foo(foo: Foo) {
1221     let Foo { i: bar } = foo;
1222     let _ = bar;
1223 }
1224 "#;
1225         check(
1226             "bar",
1227             r#"
1228 struct Foo {
1229     i: i32,
1230 }
1231
1232 fn foo(foo: Foo) {
1233     let Foo { i: b } = foo;
1234     let _ = b<|>;
1235 }
1236 "#,
1237             expected_fixture,
1238         );
1239         check(
1240             "bar",
1241             r#"
1242 struct Foo {
1243     i: i32,
1244 }
1245
1246 fn foo(foo: Foo) {
1247     let Foo { i } = foo;
1248     let _ = i<|>;
1249 }
1250 "#,
1251             expected_fixture,
1252         );
1253     }
1254
1255     #[test]
1256     fn test_rename_binding_in_destructure_param_pat() {
1257         check(
1258             "bar",
1259             r#"
1260 struct Foo {
1261     i: i32
1262 }
1263
1264 fn foo(Foo { i }: foo) -> i32 {
1265     i<|>
1266 }
1267 "#,
1268             r#"
1269 struct Foo {
1270     i: i32
1271 }
1272
1273 fn foo(Foo { i: bar }: foo) -> i32 {
1274     bar
1275 }
1276 "#,
1277         )
1278     }
1279 }