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