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