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