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