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