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