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