]> git.lizzy.rs Git - rust.git/blob - crates/ide/src/rename.rs
Merge #10556
[rust.git] / crates / ide / src / rename.rs
1 //! Renaming functionality.
2 //!
3 //! This is mostly front-end for [`ide_db::rename`], but it also includes the
4 //! tests. This module also implements a couple of magic tricks, like renaming
5 //! `self` and to `self` (to switch between associated function and method).
6 use hir::{AsAssocItem, InFile, Semantics};
7 use ide_db::{
8     base_db::FileId,
9     defs::{Definition, NameClass, NameRefClass},
10     rename::{bail, format_err, source_edit_from_references, IdentifierKind},
11     RootDatabase,
12 };
13 use stdx::{always, never};
14 use syntax::{ast, AstNode, SyntaxNode};
15
16 use text_edit::TextEdit;
17
18 use crate::{FilePosition, RangeInfo, SourceChange};
19
20 pub use ide_db::rename::RenameError;
21
22 type RenameResult<T> = Result<T, RenameError>;
23
24 /// Prepares a rename. The sole job of this function is to return the TextRange of the thing that is
25 /// being targeted for a rename.
26 pub(crate) fn prepare_rename(
27     db: &RootDatabase,
28     position: FilePosition,
29 ) -> RenameResult<RangeInfo<()>> {
30     let sema = Semantics::new(db);
31     let source_file = sema.parse(position.file_id);
32     let syntax = source_file.syntax();
33
34     let (name_like, def) = find_definition(&sema, syntax, position)?;
35     if def.range_for_rename(&sema).is_none() {
36         bail!("No references found at position")
37     }
38
39     let frange = sema.original_range(name_like.syntax());
40     always!(frange.range.contains_inclusive(position.offset) && frange.file_id == position.file_id);
41     Ok(RangeInfo::new(frange.range, ()))
42 }
43
44 // Feature: Rename
45 //
46 // Renames the item below the cursor and all of its references
47 //
48 // |===
49 // | Editor  | Shortcut
50 //
51 // | VS Code | kbd:[F2]
52 // |===
53 //
54 // image::https://user-images.githubusercontent.com/48062697/113065582-055aae80-91b1-11eb-8ade-2b58e6d81883.gif[]
55 pub(crate) fn rename(
56     db: &RootDatabase,
57     position: FilePosition,
58     new_name: &str,
59 ) -> RenameResult<SourceChange> {
60     let sema = Semantics::new(db);
61     let source_file = sema.parse(position.file_id);
62     let syntax = source_file.syntax();
63
64     let (_name_like, def) = find_definition(&sema, syntax, position)?;
65
66     if let Definition::Local(local) = def {
67         if let Some(self_param) = local.as_self_param(sema.db) {
68             cov_mark::hit!(rename_self_to_param);
69             return rename_self_to_param(&sema, local, self_param, new_name);
70         }
71         if new_name == "self" {
72             cov_mark::hit!(rename_to_self);
73             return rename_to_self(&sema, local);
74         }
75     }
76
77     def.rename(&sema, new_name)
78 }
79
80 /// Called by the client when it is about to rename a file.
81 pub(crate) fn will_rename_file(
82     db: &RootDatabase,
83     file_id: FileId,
84     new_name_stem: &str,
85 ) -> Option<SourceChange> {
86     let sema = Semantics::new(db);
87     let module = sema.to_module_def(file_id)?;
88     let def = Definition::ModuleDef(module.into());
89     let mut change = def.rename(&sema, new_name_stem).ok()?;
90     change.file_system_edits.clear();
91     Some(change)
92 }
93
94 fn find_definition(
95     sema: &Semantics<RootDatabase>,
96     syntax: &SyntaxNode,
97     position: FilePosition,
98 ) -> RenameResult<(ast::NameLike, Definition)> {
99     let name_like = sema
100         .find_node_at_offset_with_descend::<ast::NameLike>(syntax, position.offset)
101         .ok_or_else(|| format_err!("No references found at position"))?;
102
103     let def = match &name_like {
104         // renaming aliases would rename the item being aliased as the HIR doesn't track aliases yet
105         ast::NameLike::Name(name)
106             if name.syntax().parent().map_or(false, |it| ast::Rename::can_cast(it.kind())) =>
107         {
108             bail!("Renaming aliases is currently unsupported")
109         }
110         ast::NameLike::Name(name) => NameClass::classify(sema, name).map(|class| match class {
111             NameClass::Definition(it) | NameClass::ConstReference(it) => it,
112             NameClass::PatFieldShorthand { local_def, field_ref: _ } => {
113                 Definition::Local(local_def)
114             }
115         }),
116         ast::NameLike::NameRef(name_ref) => {
117             if let Some(def) = NameRefClass::classify(sema, name_ref).map(|class| match class {
118                 NameRefClass::Definition(def) => def,
119                 NameRefClass::FieldShorthand { local_ref, field_ref: _ } => {
120                     Definition::Local(local_ref)
121                 }
122             }) {
123                 // if the name differs from the definitions name it has to be an alias
124                 if def.name(sema.db).map_or(false, |it| it.to_string() != name_ref.text()) {
125                     bail!("Renaming aliases is currently unsupported");
126                 }
127                 Some(def)
128             } else {
129                 None
130             }
131         }
132         ast::NameLike::Lifetime(lifetime) => NameRefClass::classify_lifetime(sema, lifetime)
133             .and_then(|class| match class {
134                 NameRefClass::Definition(def) => Some(def),
135                 _ => None,
136             })
137             .or_else(|| {
138                 NameClass::classify_lifetime(sema, lifetime).and_then(|it| match it {
139                     NameClass::Definition(it) => Some(it),
140                     _ => None,
141                 })
142             }),
143     }
144     .ok_or_else(|| format_err!("No references found at position"))?;
145
146     Ok((name_like, def))
147 }
148
149 fn rename_to_self(sema: &Semantics<RootDatabase>, local: hir::Local) -> RenameResult<SourceChange> {
150     if never!(local.is_self(sema.db)) {
151         bail!("rename_to_self invoked on self");
152     }
153
154     let fn_def = match local.parent(sema.db) {
155         hir::DefWithBody::Function(func) => func,
156         _ => bail!("Cannot rename local to self outside of function"),
157     };
158
159     if fn_def.self_param(sema.db).is_some() {
160         bail!("Method already has a self parameter");
161     }
162
163     let params = fn_def.assoc_fn_params(sema.db);
164     let first_param = params
165         .first()
166         .ok_or_else(|| format_err!("Cannot rename local to self unless it is a parameter"))?;
167     if first_param.as_local(sema.db) != local {
168         bail!("Only the first parameter may be renamed to self");
169     }
170
171     let assoc_item = fn_def
172         .as_assoc_item(sema.db)
173         .ok_or_else(|| format_err!("Cannot rename parameter to self for free function"))?;
174     let impl_ = match assoc_item.container(sema.db) {
175         hir::AssocItemContainer::Trait(_) => {
176             bail!("Cannot rename parameter to self for trait functions");
177         }
178         hir::AssocItemContainer::Impl(impl_) => impl_,
179     };
180     let first_param_ty = first_param.ty();
181     let impl_ty = impl_.self_ty(sema.db);
182     let (ty, self_param) = if impl_ty.remove_ref().is_some() {
183         // if the impl is a ref to the type we can just match the `&T` with self directly
184         (first_param_ty.clone(), "self")
185     } else {
186         first_param_ty.remove_ref().map_or((first_param_ty.clone(), "self"), |ty| {
187             (ty, if first_param_ty.is_mutable_reference() { "&mut self" } else { "&self" })
188         })
189     };
190
191     if ty != impl_ty {
192         bail!("Parameter type differs from impl block type");
193     }
194
195     let InFile { file_id, value: param_source } =
196         first_param.source(sema.db).ok_or_else(|| format_err!("No source for parameter found"))?;
197
198     let def = Definition::Local(local);
199     let usages = def.usages(sema).all();
200     let mut source_change = SourceChange::default();
201     source_change.extend(usages.iter().map(|(&file_id, references)| {
202         (file_id, source_edit_from_references(references, def, "self"))
203     }));
204     source_change.insert_source_edit(
205         file_id.original_file(sema.db),
206         TextEdit::replace(param_source.syntax().text_range(), String::from(self_param)),
207     );
208     Ok(source_change)
209 }
210
211 fn rename_self_to_param(
212     sema: &Semantics<RootDatabase>,
213     local: hir::Local,
214     self_param: hir::SelfParam,
215     new_name: &str,
216 ) -> RenameResult<SourceChange> {
217     if new_name == "self" {
218         // Let's do nothing rather than complain.
219         cov_mark::hit!(rename_self_to_self);
220         return Ok(SourceChange::default());
221     }
222
223     let identifier_kind = IdentifierKind::classify(new_name)?;
224
225     let InFile { file_id, value: self_param } =
226         self_param.source(sema.db).ok_or_else(|| format_err!("cannot find function source"))?;
227
228     let def = Definition::Local(local);
229     let usages = def.usages(sema).all();
230     let edit = text_edit_from_self_param(&self_param, new_name)
231         .ok_or_else(|| format_err!("No target type found"))?;
232     if usages.len() > 1 && identifier_kind == IdentifierKind::Underscore {
233         bail!("Cannot rename reference to `_` as it is being referenced multiple times");
234     }
235     let mut source_change = SourceChange::default();
236     source_change.insert_source_edit(file_id.original_file(sema.db), edit);
237     source_change.extend(usages.iter().map(|(&file_id, references)| {
238         (file_id, source_edit_from_references(references, def, new_name))
239     }));
240     Ok(source_change)
241 }
242
243 fn text_edit_from_self_param(self_param: &ast::SelfParam, new_name: &str) -> Option<TextEdit> {
244     fn target_type_name(impl_def: &ast::Impl) -> Option<String> {
245         if let Some(ast::Type::PathType(p)) = impl_def.self_ty() {
246             return Some(p.path()?.segment()?.name_ref()?.text().to_string());
247         }
248         None
249     }
250
251     let impl_def = self_param.syntax().ancestors().find_map(ast::Impl::cast)?;
252     let type_name = target_type_name(&impl_def)?;
253
254     let mut replacement_text = String::from(new_name);
255     replacement_text.push_str(": ");
256     match (self_param.amp_token(), self_param.mut_token()) {
257         (Some(_), None) => replacement_text.push('&'),
258         (Some(_), Some(_)) => replacement_text.push_str("&mut "),
259         (_, _) => (),
260     };
261     replacement_text.push_str(type_name.as_str());
262
263     Some(TextEdit::replace(self_param.syntax().text_range(), replacement_text))
264 }
265
266 #[cfg(test)]
267 mod tests {
268     use expect_test::{expect, Expect};
269     use stdx::trim_indent;
270     use test_utils::assert_eq_text;
271     use text_edit::TextEdit;
272
273     use crate::{fixture, FileId};
274
275     use super::{RangeInfo, RenameError};
276
277     #[track_caller]
278     fn check(new_name: &str, ra_fixture_before: &str, ra_fixture_after: &str) {
279         let ra_fixture_after = &trim_indent(ra_fixture_after);
280         let (analysis, position) = fixture::position(ra_fixture_before);
281         let rename_result = analysis
282             .rename(position, new_name)
283             .unwrap_or_else(|err| panic!("Rename to '{}' was cancelled: {}", new_name, err));
284         match rename_result {
285             Ok(source_change) => {
286                 let mut text_edit_builder = TextEdit::builder();
287                 let mut file_id: Option<FileId> = None;
288                 for edit in source_change.source_file_edits {
289                     file_id = Some(edit.0);
290                     for indel in edit.1.into_iter() {
291                         text_edit_builder.replace(indel.delete, indel.insert);
292                     }
293                 }
294                 if let Some(file_id) = file_id {
295                     let mut result = analysis.file_text(file_id).unwrap().to_string();
296                     text_edit_builder.finish().apply(&mut result);
297                     assert_eq_text!(ra_fixture_after, &*result);
298                 }
299             }
300             Err(err) => {
301                 if ra_fixture_after.starts_with("error:") {
302                     let error_message = ra_fixture_after
303                         .chars()
304                         .into_iter()
305                         .skip("error:".len())
306                         .collect::<String>();
307                     assert_eq!(error_message.trim(), err.to_string());
308                 } else {
309                     panic!("Rename to '{}' failed unexpectedly: {}", new_name, err)
310                 }
311             }
312         };
313     }
314
315     fn check_expect(new_name: &str, ra_fixture: &str, expect: Expect) {
316         let (analysis, position) = fixture::position(ra_fixture);
317         let source_change =
318             analysis.rename(position, new_name).unwrap().expect("Expect returned a RenameError");
319         expect.assert_debug_eq(&source_change)
320     }
321
322     fn check_prepare(ra_fixture: &str, expect: Expect) {
323         let (analysis, position) = fixture::position(ra_fixture);
324         let result = analysis
325             .prepare_rename(position)
326             .unwrap_or_else(|err| panic!("PrepareRename was cancelled: {}", err));
327         match result {
328             Ok(RangeInfo { range, info: () }) => {
329                 let source = analysis.file_text(position.file_id).unwrap();
330                 expect.assert_eq(&format!("{:?}: {}", range, &source[range]))
331             }
332             Err(RenameError(err)) => expect.assert_eq(&err),
333         };
334     }
335
336     #[test]
337     fn test_prepare_rename_namelikes() {
338         check_prepare(r"fn name$0<'lifetime>() {}", expect![[r#"3..7: name"#]]);
339         check_prepare(r"fn name<'lifetime$0>() {}", expect![[r#"8..17: 'lifetime"#]]);
340         check_prepare(r"fn name<'lifetime>() { name$0(); }", expect![[r#"23..27: name"#]]);
341     }
342
343     #[test]
344     fn test_prepare_rename_in_macro() {
345         check_prepare(
346             r"macro_rules! foo {
347     ($ident:ident) => {
348         pub struct $ident;
349     }
350 }
351 foo!(Foo$0);",
352             expect![[r#"83..86: Foo"#]],
353         );
354     }
355
356     #[test]
357     fn test_prepare_rename_keyword() {
358         check_prepare(r"struct$0 Foo;", expect![[r#"No references found at position"#]]);
359     }
360
361     #[test]
362     fn test_prepare_rename_tuple_field() {
363         check_prepare(
364             r#"
365 struct Foo(i32);
366
367 fn baz() {
368     let mut x = Foo(4);
369     x.0$0 = 5;
370 }
371 "#,
372             expect![[r#"No references found at position"#]],
373         );
374     }
375
376     #[test]
377     fn test_prepare_rename_builtin() {
378         check_prepare(
379             r#"
380 fn foo() {
381     let x: i32$0 = 0;
382 }
383 "#,
384             expect![[r#"No references found at position"#]],
385         );
386     }
387
388     #[test]
389     fn test_prepare_rename_self() {
390         check_prepare(
391             r#"
392 struct Foo {}
393
394 impl Foo {
395     fn foo(self) -> Self$0 {
396         self
397     }
398 }
399 "#,
400             expect![[r#"No references found at position"#]],
401         );
402     }
403
404     #[test]
405     fn test_rename_to_underscore() {
406         check("_", r#"fn main() { let i$0 = 1; }"#, r#"fn main() { let _ = 1; }"#);
407     }
408
409     #[test]
410     fn test_rename_to_raw_identifier() {
411         check("r#fn", r#"fn main() { let i$0 = 1; }"#, r#"fn main() { let r#fn = 1; }"#);
412     }
413
414     #[test]
415     fn test_rename_to_invalid_identifier1() {
416         check(
417             "invalid!",
418             r#"fn main() { let i$0 = 1; }"#,
419             "error: Invalid name `invalid!`: not an identifier",
420         );
421     }
422
423     #[test]
424     fn test_rename_to_invalid_identifier2() {
425         check(
426             "multiple tokens",
427             r#"fn main() { let i$0 = 1; }"#,
428             "error: Invalid name `multiple tokens`: not an identifier",
429         );
430     }
431
432     #[test]
433     fn test_rename_to_invalid_identifier3() {
434         check(
435             "let",
436             r#"fn main() { let i$0 = 1; }"#,
437             "error: Invalid name `let`: not an identifier",
438         );
439     }
440
441     #[test]
442     fn test_rename_to_invalid_identifier_lifetime() {
443         cov_mark::check!(rename_not_an_ident_ref);
444         check(
445             "'foo",
446             r#"fn main() { let i$0 = 1; }"#,
447             "error: Invalid name `'foo`: not an identifier",
448         );
449     }
450
451     #[test]
452     fn test_rename_to_invalid_identifier_lifetime2() {
453         cov_mark::check!(rename_not_a_lifetime_ident_ref);
454         check(
455             "foo",
456             r#"fn main<'a>(_: &'a$0 ()) {}"#,
457             "error: Invalid name `foo`: not a lifetime identifier",
458         );
459     }
460
461     #[test]
462     fn test_rename_to_underscore_invalid() {
463         cov_mark::check!(rename_underscore_multiple);
464         check(
465             "_",
466             r#"fn main(foo$0: ()) {foo;}"#,
467             "error: Cannot rename reference to `_` as it is being referenced multiple times",
468         );
469     }
470
471     #[test]
472     fn test_rename_mod_invalid() {
473         check(
474             "'foo",
475             r#"mod foo$0 {}"#,
476             "error: Invalid name `'foo`: cannot rename module to 'foo",
477         );
478     }
479
480     #[test]
481     fn test_rename_for_local() {
482         check(
483             "k",
484             r#"
485 fn main() {
486     let mut i = 1;
487     let j = 1;
488     i = i$0 + j;
489
490     { i = 0; }
491
492     i = 5;
493 }
494 "#,
495             r#"
496 fn main() {
497     let mut k = 1;
498     let j = 1;
499     k = k + j;
500
501     { k = 0; }
502
503     k = 5;
504 }
505 "#,
506         );
507     }
508
509     #[test]
510     fn test_rename_unresolved_reference() {
511         check(
512             "new_name",
513             r#"fn main() { let _ = unresolved_ref$0; }"#,
514             "error: No references found at position",
515         );
516     }
517
518     #[test]
519     fn test_rename_for_macro_args() {
520         check(
521             "b",
522             r#"
523 macro_rules! foo {($i:ident) => {$i} }
524 fn main() {
525     let a$0 = "test";
526     foo!(a);
527 }
528 "#,
529             r#"
530 macro_rules! foo {($i:ident) => {$i} }
531 fn main() {
532     let b = "test";
533     foo!(b);
534 }
535 "#,
536         );
537     }
538
539     #[test]
540     fn test_rename_for_macro_args_rev() {
541         check(
542             "b",
543             r#"
544 macro_rules! foo {($i:ident) => {$i} }
545 fn main() {
546     let a = "test";
547     foo!(a$0);
548 }
549 "#,
550             r#"
551 macro_rules! foo {($i:ident) => {$i} }
552 fn main() {
553     let b = "test";
554     foo!(b);
555 }
556 "#,
557         );
558     }
559
560     #[test]
561     fn test_rename_for_macro_define_fn() {
562         check(
563             "bar",
564             r#"
565 macro_rules! define_fn {($id:ident) => { fn $id{} }}
566 define_fn!(foo);
567 fn main() {
568     fo$0o();
569 }
570 "#,
571             r#"
572 macro_rules! define_fn {($id:ident) => { fn $id{} }}
573 define_fn!(bar);
574 fn main() {
575     bar();
576 }
577 "#,
578         );
579     }
580
581     #[test]
582     fn test_rename_for_macro_define_fn_rev() {
583         check(
584             "bar",
585             r#"
586 macro_rules! define_fn {($id:ident) => { fn $id{} }}
587 define_fn!(fo$0o);
588 fn main() {
589     foo();
590 }
591 "#,
592             r#"
593 macro_rules! define_fn {($id:ident) => { fn $id{} }}
594 define_fn!(bar);
595 fn main() {
596     bar();
597 }
598 "#,
599         );
600     }
601
602     #[test]
603     fn test_rename_for_param_inside() {
604         check("j", r#"fn foo(i : u32) -> u32 { i$0 }"#, r#"fn foo(j : u32) -> u32 { j }"#);
605     }
606
607     #[test]
608     fn test_rename_refs_for_fn_param() {
609         check("j", r#"fn foo(i$0 : u32) -> u32 { i }"#, r#"fn foo(j : u32) -> u32 { j }"#);
610     }
611
612     #[test]
613     fn test_rename_for_mut_param() {
614         check("j", r#"fn foo(mut i$0 : u32) -> u32 { i }"#, r#"fn foo(mut j : u32) -> u32 { j }"#);
615     }
616
617     #[test]
618     fn test_rename_struct_field() {
619         check(
620             "foo",
621             r#"
622 struct Foo { field$0: i32 }
623
624 impl Foo {
625     fn new(i: i32) -> Self {
626         Self { field: i }
627     }
628 }
629 "#,
630             r#"
631 struct Foo { foo: i32 }
632
633 impl Foo {
634     fn new(i: i32) -> Self {
635         Self { foo: i }
636     }
637 }
638 "#,
639         );
640     }
641
642     #[test]
643     fn test_rename_field_in_field_shorthand() {
644         cov_mark::check!(test_rename_field_in_field_shorthand);
645         check(
646             "field",
647             r#"
648 struct Foo { foo$0: i32 }
649
650 impl Foo {
651     fn new(foo: i32) -> Self {
652         Self { foo }
653     }
654 }
655 "#,
656             r#"
657 struct Foo { field: i32 }
658
659 impl Foo {
660     fn new(foo: i32) -> Self {
661         Self { field: foo }
662     }
663 }
664 "#,
665         );
666     }
667
668     #[test]
669     fn test_rename_local_in_field_shorthand() {
670         cov_mark::check!(test_rename_local_in_field_shorthand);
671         check(
672             "j",
673             r#"
674 struct Foo { i: i32 }
675
676 impl Foo {
677     fn new(i$0: i32) -> Self {
678         Self { i }
679     }
680 }
681 "#,
682             r#"
683 struct Foo { i: i32 }
684
685 impl Foo {
686     fn new(j: i32) -> Self {
687         Self { i: j }
688     }
689 }
690 "#,
691         );
692     }
693
694     #[test]
695     fn test_field_shorthand_correct_struct() {
696         check(
697             "j",
698             r#"
699 struct Foo { i$0: i32 }
700 struct Bar { i: i32 }
701
702 impl Bar {
703     fn new(i: i32) -> Self {
704         Self { i }
705     }
706 }
707 "#,
708             r#"
709 struct Foo { j: i32 }
710 struct Bar { i: i32 }
711
712 impl Bar {
713     fn new(i: i32) -> Self {
714         Self { i }
715     }
716 }
717 "#,
718         );
719     }
720
721     #[test]
722     fn test_shadow_local_for_struct_shorthand() {
723         check(
724             "j",
725             r#"
726 struct Foo { i: i32 }
727
728 fn baz(i$0: i32) -> Self {
729      let x = Foo { i };
730      {
731          let i = 0;
732          Foo { i }
733      }
734 }
735 "#,
736             r#"
737 struct Foo { i: i32 }
738
739 fn baz(j: i32) -> Self {
740      let x = Foo { i: j };
741      {
742          let i = 0;
743          Foo { i }
744      }
745 }
746 "#,
747         );
748     }
749
750     #[test]
751     fn test_rename_mod() {
752         check_expect(
753             "foo2",
754             r#"
755 //- /lib.rs
756 mod bar;
757
758 //- /bar.rs
759 mod foo$0;
760
761 //- /bar/foo.rs
762 // empty
763 "#,
764             expect![[r#"
765                 SourceChange {
766                     source_file_edits: {
767                         FileId(
768                             1,
769                         ): TextEdit {
770                             indels: [
771                                 Indel {
772                                     insert: "foo2",
773                                     delete: 4..7,
774                                 },
775                             ],
776                         },
777                     },
778                     file_system_edits: [
779                         MoveFile {
780                             src: FileId(
781                                 2,
782                             ),
783                             dst: AnchoredPathBuf {
784                                 anchor: FileId(
785                                     2,
786                                 ),
787                                 path: "foo2.rs",
788                             },
789                         },
790                     ],
791                     is_snippet: false,
792                 }
793             "#]],
794         );
795     }
796
797     #[test]
798     fn test_rename_mod_in_use_tree() {
799         check_expect(
800             "quux",
801             r#"
802 //- /main.rs
803 pub mod foo;
804 pub mod bar;
805 fn main() {}
806
807 //- /foo.rs
808 pub struct FooContent;
809
810 //- /bar.rs
811 use crate::foo$0::FooContent;
812 "#,
813             expect![[r#"
814                 SourceChange {
815                     source_file_edits: {
816                         FileId(
817                             0,
818                         ): TextEdit {
819                             indels: [
820                                 Indel {
821                                     insert: "quux",
822                                     delete: 8..11,
823                                 },
824                             ],
825                         },
826                         FileId(
827                             2,
828                         ): TextEdit {
829                             indels: [
830                                 Indel {
831                                     insert: "quux",
832                                     delete: 11..14,
833                                 },
834                             ],
835                         },
836                     },
837                     file_system_edits: [
838                         MoveFile {
839                             src: FileId(
840                                 1,
841                             ),
842                             dst: AnchoredPathBuf {
843                                 anchor: FileId(
844                                     1,
845                                 ),
846                                 path: "quux.rs",
847                             },
848                         },
849                     ],
850                     is_snippet: false,
851                 }
852             "#]],
853         );
854     }
855
856     #[test]
857     fn test_rename_mod_in_dir() {
858         check_expect(
859             "foo2",
860             r#"
861 //- /lib.rs
862 mod fo$0o;
863 //- /foo/mod.rs
864 // empty
865 "#,
866             expect![[r#"
867                 SourceChange {
868                     source_file_edits: {
869                         FileId(
870                             0,
871                         ): TextEdit {
872                             indels: [
873                                 Indel {
874                                     insert: "foo2",
875                                     delete: 4..7,
876                                 },
877                             ],
878                         },
879                     },
880                     file_system_edits: [
881                         MoveFile {
882                             src: FileId(
883                                 1,
884                             ),
885                             dst: AnchoredPathBuf {
886                                 anchor: FileId(
887                                     1,
888                                 ),
889                                 path: "../foo2/mod.rs",
890                             },
891                         },
892                     ],
893                     is_snippet: false,
894                 }
895             "#]],
896         );
897     }
898
899     #[test]
900     fn test_rename_unusually_nested_mod() {
901         check_expect(
902             "bar",
903             r#"
904 //- /lib.rs
905 mod outer { mod fo$0o; }
906
907 //- /outer/foo.rs
908 // empty
909 "#,
910             expect![[r#"
911                 SourceChange {
912                     source_file_edits: {
913                         FileId(
914                             0,
915                         ): TextEdit {
916                             indels: [
917                                 Indel {
918                                     insert: "bar",
919                                     delete: 16..19,
920                                 },
921                             ],
922                         },
923                     },
924                     file_system_edits: [
925                         MoveFile {
926                             src: FileId(
927                                 1,
928                             ),
929                             dst: AnchoredPathBuf {
930                                 anchor: FileId(
931                                     1,
932                                 ),
933                                 path: "bar.rs",
934                             },
935                         },
936                     ],
937                     is_snippet: false,
938                 }
939             "#]],
940         );
941     }
942
943     #[test]
944     fn test_module_rename_in_path() {
945         check(
946             "baz",
947             r#"
948 mod $0foo {
949     pub use self::bar as qux;
950     pub fn bar() {}
951 }
952
953 fn main() { foo::bar(); }
954 "#,
955             r#"
956 mod baz {
957     pub use self::bar as qux;
958     pub fn bar() {}
959 }
960
961 fn main() { baz::bar(); }
962 "#,
963         );
964     }
965
966     #[test]
967     fn test_rename_mod_filename_and_path() {
968         check_expect(
969             "foo2",
970             r#"
971 //- /lib.rs
972 mod bar;
973 fn f() {
974     bar::foo::fun()
975 }
976
977 //- /bar.rs
978 pub mod foo$0;
979
980 //- /bar/foo.rs
981 // pub fn fun() {}
982 "#,
983             expect![[r#"
984                 SourceChange {
985                     source_file_edits: {
986                         FileId(
987                             0,
988                         ): TextEdit {
989                             indels: [
990                                 Indel {
991                                     insert: "foo2",
992                                     delete: 27..30,
993                                 },
994                             ],
995                         },
996                         FileId(
997                             1,
998                         ): TextEdit {
999                             indels: [
1000                                 Indel {
1001                                     insert: "foo2",
1002                                     delete: 8..11,
1003                                 },
1004                             ],
1005                         },
1006                     },
1007                     file_system_edits: [
1008                         MoveFile {
1009                             src: FileId(
1010                                 2,
1011                             ),
1012                             dst: AnchoredPathBuf {
1013                                 anchor: FileId(
1014                                     2,
1015                                 ),
1016                                 path: "foo2.rs",
1017                             },
1018                         },
1019                     ],
1020                     is_snippet: false,
1021                 }
1022             "#]],
1023         );
1024     }
1025
1026     #[test]
1027     fn test_enum_variant_from_module_1() {
1028         cov_mark::check!(rename_non_local);
1029         check(
1030             "Baz",
1031             r#"
1032 mod foo {
1033     pub enum Foo { Bar$0 }
1034 }
1035
1036 fn func(f: foo::Foo) {
1037     match f {
1038         foo::Foo::Bar => {}
1039     }
1040 }
1041 "#,
1042             r#"
1043 mod foo {
1044     pub enum Foo { Baz }
1045 }
1046
1047 fn func(f: foo::Foo) {
1048     match f {
1049         foo::Foo::Baz => {}
1050     }
1051 }
1052 "#,
1053         );
1054     }
1055
1056     #[test]
1057     fn test_enum_variant_from_module_2() {
1058         check(
1059             "baz",
1060             r#"
1061 mod foo {
1062     pub struct Foo { pub bar$0: uint }
1063 }
1064
1065 fn foo(f: foo::Foo) {
1066     let _ = f.bar;
1067 }
1068 "#,
1069             r#"
1070 mod foo {
1071     pub struct Foo { pub baz: uint }
1072 }
1073
1074 fn foo(f: foo::Foo) {
1075     let _ = f.baz;
1076 }
1077 "#,
1078         );
1079     }
1080
1081     #[test]
1082     fn test_parameter_to_self() {
1083         cov_mark::check!(rename_to_self);
1084         check(
1085             "self",
1086             r#"
1087 struct Foo { i: i32 }
1088
1089 impl Foo {
1090     fn f(foo$0: &mut Foo) -> i32 {
1091         foo.i
1092     }
1093 }
1094 "#,
1095             r#"
1096 struct Foo { i: i32 }
1097
1098 impl Foo {
1099     fn f(&mut self) -> i32 {
1100         self.i
1101     }
1102 }
1103 "#,
1104         );
1105         check(
1106             "self",
1107             r#"
1108 struct Foo { i: i32 }
1109
1110 impl Foo {
1111     fn f(foo$0: Foo) -> i32 {
1112         foo.i
1113     }
1114 }
1115 "#,
1116             r#"
1117 struct Foo { i: i32 }
1118
1119 impl Foo {
1120     fn f(self) -> i32 {
1121         self.i
1122     }
1123 }
1124 "#,
1125         );
1126     }
1127
1128     #[test]
1129     fn test_parameter_to_self_error_no_impl() {
1130         check(
1131             "self",
1132             r#"
1133 struct Foo { i: i32 }
1134
1135 fn f(foo$0: &mut Foo) -> i32 {
1136     foo.i
1137 }
1138 "#,
1139             "error: Cannot rename parameter to self for free function",
1140         );
1141         check(
1142             "self",
1143             r#"
1144 struct Foo { i: i32 }
1145 struct Bar;
1146
1147 impl Bar {
1148     fn f(foo$0: &mut Foo) -> i32 {
1149         foo.i
1150     }
1151 }
1152 "#,
1153             "error: Parameter type differs from impl block type",
1154         );
1155     }
1156
1157     #[test]
1158     fn test_parameter_to_self_error_not_first() {
1159         check(
1160             "self",
1161             r#"
1162 struct Foo { i: i32 }
1163 impl Foo {
1164     fn f(x: (), foo$0: &mut Foo) -> i32 {
1165         foo.i
1166     }
1167 }
1168 "#,
1169             "error: Only the first parameter may be renamed to self",
1170         );
1171     }
1172
1173     #[test]
1174     fn test_parameter_to_self_impl_ref() {
1175         check(
1176             "self",
1177             r#"
1178 struct Foo { i: i32 }
1179 impl &Foo {
1180     fn f(foo$0: &Foo) -> i32 {
1181         foo.i
1182     }
1183 }
1184 "#,
1185             r#"
1186 struct Foo { i: i32 }
1187 impl &Foo {
1188     fn f(self) -> i32 {
1189         self.i
1190     }
1191 }
1192 "#,
1193         );
1194     }
1195
1196     #[test]
1197     fn test_self_to_parameter() {
1198         check(
1199             "foo",
1200             r#"
1201 struct Foo { i: i32 }
1202
1203 impl Foo {
1204     fn f(&mut $0self) -> i32 {
1205         self.i
1206     }
1207 }
1208 "#,
1209             r#"
1210 struct Foo { i: i32 }
1211
1212 impl Foo {
1213     fn f(foo: &mut Foo) -> i32 {
1214         foo.i
1215     }
1216 }
1217 "#,
1218         );
1219     }
1220
1221     #[test]
1222     fn test_owned_self_to_parameter() {
1223         cov_mark::check!(rename_self_to_param);
1224         check(
1225             "foo",
1226             r#"
1227 struct Foo { i: i32 }
1228
1229 impl Foo {
1230     fn f($0self) -> i32 {
1231         self.i
1232     }
1233 }
1234 "#,
1235             r#"
1236 struct Foo { i: i32 }
1237
1238 impl Foo {
1239     fn f(foo: Foo) -> i32 {
1240         foo.i
1241     }
1242 }
1243 "#,
1244         );
1245     }
1246
1247     #[test]
1248     fn test_self_in_path_to_parameter() {
1249         check(
1250             "foo",
1251             r#"
1252 struct Foo { i: i32 }
1253
1254 impl Foo {
1255     fn f(&self) -> i32 {
1256         let self_var = 1;
1257         self$0.i
1258     }
1259 }
1260 "#,
1261             r#"
1262 struct Foo { i: i32 }
1263
1264 impl Foo {
1265     fn f(foo: &Foo) -> i32 {
1266         let self_var = 1;
1267         foo.i
1268     }
1269 }
1270 "#,
1271         );
1272     }
1273
1274     #[test]
1275     fn test_rename_field_put_init_shorthand() {
1276         cov_mark::check!(test_rename_field_put_init_shorthand);
1277         check(
1278             "bar",
1279             r#"
1280 struct Foo { i$0: i32 }
1281
1282 fn foo(bar: i32) -> Foo {
1283     Foo { i: bar }
1284 }
1285 "#,
1286             r#"
1287 struct Foo { bar: i32 }
1288
1289 fn foo(bar: i32) -> Foo {
1290     Foo { bar }
1291 }
1292 "#,
1293         );
1294     }
1295
1296     #[test]
1297     fn test_rename_local_put_init_shorthand() {
1298         cov_mark::check!(test_rename_local_put_init_shorthand);
1299         check(
1300             "i",
1301             r#"
1302 struct Foo { i: i32 }
1303
1304 fn foo(bar$0: i32) -> Foo {
1305     Foo { i: bar }
1306 }
1307 "#,
1308             r#"
1309 struct Foo { i: i32 }
1310
1311 fn foo(i: i32) -> Foo {
1312     Foo { i }
1313 }
1314 "#,
1315         );
1316     }
1317
1318     #[test]
1319     fn test_struct_field_pat_into_shorthand() {
1320         cov_mark::check!(test_rename_field_put_init_shorthand_pat);
1321         check(
1322             "baz",
1323             r#"
1324 struct Foo { i$0: i32 }
1325
1326 fn foo(foo: Foo) {
1327     let Foo { i: ref baz @ qux } = foo;
1328     let _ = qux;
1329 }
1330 "#,
1331             r#"
1332 struct Foo { baz: i32 }
1333
1334 fn foo(foo: Foo) {
1335     let Foo { baz: ref baz @ qux } = foo;
1336     let _ = qux;
1337 }
1338 "#,
1339         );
1340         check(
1341             "baz",
1342             r#"
1343 struct Foo { i$0: i32 }
1344
1345 fn foo(foo: Foo) {
1346     let Foo { i: ref baz } = foo;
1347     let _ = qux;
1348 }
1349 "#,
1350             r#"
1351 struct Foo { baz: i32 }
1352
1353 fn foo(foo: Foo) {
1354     let Foo { ref baz } = foo;
1355     let _ = qux;
1356 }
1357 "#,
1358         );
1359     }
1360
1361     #[test]
1362     fn test_struct_local_pat_into_shorthand() {
1363         cov_mark::check!(test_rename_local_put_init_shorthand_pat);
1364         check(
1365             "field",
1366             r#"
1367 struct Foo { field: i32 }
1368
1369 fn foo(foo: Foo) {
1370     let Foo { field: qux$0 } = foo;
1371     let _ = qux;
1372 }
1373 "#,
1374             r#"
1375 struct Foo { field: i32 }
1376
1377 fn foo(foo: Foo) {
1378     let Foo { field } = foo;
1379     let _ = field;
1380 }
1381 "#,
1382         );
1383         check(
1384             "field",
1385             r#"
1386 struct Foo { field: i32 }
1387
1388 fn foo(foo: Foo) {
1389     let Foo { field: x @ qux$0 } = foo;
1390     let _ = qux;
1391 }
1392 "#,
1393             r#"
1394 struct Foo { field: i32 }
1395
1396 fn foo(foo: Foo) {
1397     let Foo { field: x @ field } = foo;
1398     let _ = field;
1399 }
1400 "#,
1401         );
1402     }
1403
1404     #[test]
1405     fn test_rename_binding_in_destructure_pat() {
1406         let expected_fixture = r#"
1407 struct Foo {
1408     i: i32,
1409 }
1410
1411 fn foo(foo: Foo) {
1412     let Foo { i: bar } = foo;
1413     let _ = bar;
1414 }
1415 "#;
1416         check(
1417             "bar",
1418             r#"
1419 struct Foo {
1420     i: i32,
1421 }
1422
1423 fn foo(foo: Foo) {
1424     let Foo { i: b } = foo;
1425     let _ = b$0;
1426 }
1427 "#,
1428             expected_fixture,
1429         );
1430         check(
1431             "bar",
1432             r#"
1433 struct Foo {
1434     i: i32,
1435 }
1436
1437 fn foo(foo: Foo) {
1438     let Foo { i } = foo;
1439     let _ = i$0;
1440 }
1441 "#,
1442             expected_fixture,
1443         );
1444     }
1445
1446     #[test]
1447     fn test_rename_binding_in_destructure_param_pat() {
1448         check(
1449             "bar",
1450             r#"
1451 struct Foo {
1452     i: i32
1453 }
1454
1455 fn foo(Foo { i }: Foo) -> i32 {
1456     i$0
1457 }
1458 "#,
1459             r#"
1460 struct Foo {
1461     i: i32
1462 }
1463
1464 fn foo(Foo { i: bar }: Foo) -> i32 {
1465     bar
1466 }
1467 "#,
1468         )
1469     }
1470
1471     #[test]
1472     fn test_struct_field_complex_ident_pat() {
1473         cov_mark::check!(rename_record_pat_field_name_split);
1474         check(
1475             "baz",
1476             r#"
1477 struct Foo { i$0: i32 }
1478
1479 fn foo(foo: Foo) {
1480     let Foo { ref i } = foo;
1481 }
1482 "#,
1483             r#"
1484 struct Foo { baz: i32 }
1485
1486 fn foo(foo: Foo) {
1487     let Foo { baz: ref i } = foo;
1488 }
1489 "#,
1490         );
1491     }
1492
1493     #[test]
1494     fn test_rename_lifetimes() {
1495         cov_mark::check!(rename_lifetime);
1496         check(
1497             "'yeeee",
1498             r#"
1499 trait Foo<'a> {
1500     fn foo() -> &'a ();
1501 }
1502 impl<'a> Foo<'a> for &'a () {
1503     fn foo() -> &'a$0 () {
1504         unimplemented!()
1505     }
1506 }
1507 "#,
1508             r#"
1509 trait Foo<'a> {
1510     fn foo() -> &'a ();
1511 }
1512 impl<'yeeee> Foo<'yeeee> for &'yeeee () {
1513     fn foo() -> &'yeeee () {
1514         unimplemented!()
1515     }
1516 }
1517 "#,
1518         )
1519     }
1520
1521     #[test]
1522     fn test_rename_bind_pat() {
1523         check(
1524             "new_name",
1525             r#"
1526 fn main() {
1527     enum CustomOption<T> {
1528         None,
1529         Some(T),
1530     }
1531
1532     let test_variable = CustomOption::Some(22);
1533
1534     match test_variable {
1535         CustomOption::Some(foo$0) if foo == 11 => {}
1536         _ => (),
1537     }
1538 }"#,
1539             r#"
1540 fn main() {
1541     enum CustomOption<T> {
1542         None,
1543         Some(T),
1544     }
1545
1546     let test_variable = CustomOption::Some(22);
1547
1548     match test_variable {
1549         CustomOption::Some(new_name) if new_name == 11 => {}
1550         _ => (),
1551     }
1552 }"#,
1553         );
1554     }
1555
1556     #[test]
1557     fn test_rename_label() {
1558         check(
1559             "'foo",
1560             r#"
1561 fn foo<'a>() -> &'a () {
1562     'a: {
1563         'b: loop {
1564             break 'a$0;
1565         }
1566     }
1567 }
1568 "#,
1569             r#"
1570 fn foo<'a>() -> &'a () {
1571     'foo: {
1572         'b: loop {
1573             break 'foo;
1574         }
1575     }
1576 }
1577 "#,
1578         )
1579     }
1580
1581     #[test]
1582     fn test_self_to_self() {
1583         cov_mark::check!(rename_self_to_self);
1584         check(
1585             "self",
1586             r#"
1587 struct Foo;
1588 impl Foo {
1589     fn foo(self$0) {}
1590 }
1591 "#,
1592             r#"
1593 struct Foo;
1594 impl Foo {
1595     fn foo(self) {}
1596 }
1597 "#,
1598         )
1599     }
1600
1601     #[test]
1602     fn test_rename_field_in_pat_in_macro_doesnt_shorthand() {
1603         // ideally we would be able to make this emit a short hand, but I doubt this is easily possible
1604         check(
1605             "baz",
1606             r#"
1607 macro_rules! foo {
1608     ($pattern:pat) => {
1609         let $pattern = loop {};
1610     };
1611 }
1612 struct Foo {
1613     bar$0: u32,
1614 }
1615 fn foo() {
1616     foo!(Foo { bar: baz });
1617 }
1618 "#,
1619             r#"
1620 macro_rules! foo {
1621     ($pattern:pat) => {
1622         let $pattern = loop {};
1623     };
1624 }
1625 struct Foo {
1626     baz: u32,
1627 }
1628 fn foo() {
1629     foo!(Foo { baz: baz });
1630 }
1631 "#,
1632         )
1633     }
1634
1635     #[test]
1636     fn test_rename_tuple_field() {
1637         check(
1638             "foo",
1639             r#"
1640 struct Foo(i32);
1641
1642 fn baz() {
1643     let mut x = Foo(4);
1644     x.0$0 = 5;
1645 }
1646 "#,
1647             "error: No identifier available to rename",
1648         );
1649     }
1650
1651     #[test]
1652     fn test_rename_builtin() {
1653         check(
1654             "foo",
1655             r#"
1656 fn foo() {
1657     let x: i32$0 = 0;
1658 }
1659 "#,
1660             "error: Cannot rename builtin type",
1661         );
1662     }
1663
1664     #[test]
1665     fn test_rename_self() {
1666         check(
1667             "foo",
1668             r#"
1669 struct Foo {}
1670
1671 impl Foo {
1672     fn foo(self) -> Self$0 {
1673         self
1674     }
1675 }
1676 "#,
1677             "error: Cannot rename `Self`",
1678         );
1679     }
1680
1681     #[test]
1682     fn test_rename_ignores_self_ty() {
1683         check(
1684             "Fo0",
1685             r#"
1686 struct $0Foo;
1687
1688 impl Foo where Self: {}
1689 "#,
1690             r#"
1691 struct Fo0;
1692
1693 impl Fo0 where Self: {}
1694 "#,
1695         );
1696     }
1697
1698     #[test]
1699     fn test_rename_fails_on_aliases() {
1700         check(
1701             "Baz",
1702             r#"
1703 struct Foo;
1704 use Foo as Bar$0;
1705 "#,
1706             "error: Renaming aliases is currently unsupported",
1707         );
1708         check(
1709             "Baz",
1710             r#"
1711 struct Foo;
1712 use Foo as Bar;
1713 use Bar$0;
1714 "#,
1715             "error: Renaming aliases is currently unsupported",
1716         );
1717     }
1718
1719     #[test]
1720     fn test_rename_trait_method() {
1721         let res = r"
1722 trait Foo {
1723     fn foo(&self) {
1724         self.foo();
1725     }
1726 }
1727
1728 impl Foo for () {
1729     fn foo(&self) {
1730         self.foo();
1731     }
1732 }";
1733         check(
1734             "foo",
1735             r#"
1736 trait Foo {
1737     fn bar$0(&self) {
1738         self.bar();
1739     }
1740 }
1741
1742 impl Foo for () {
1743     fn bar(&self) {
1744         self.bar();
1745     }
1746 }"#,
1747             res,
1748         );
1749         check(
1750             "foo",
1751             r#"
1752 trait Foo {
1753     fn bar(&self) {
1754         self.bar$0();
1755     }
1756 }
1757
1758 impl Foo for () {
1759     fn bar(&self) {
1760         self.bar();
1761     }
1762 }"#,
1763             res,
1764         );
1765         check(
1766             "foo",
1767             r#"
1768 trait Foo {
1769     fn bar(&self) {
1770         self.bar();
1771     }
1772 }
1773
1774 impl Foo for () {
1775     fn bar$0(&self) {
1776         self.bar();
1777     }
1778 }"#,
1779             res,
1780         );
1781         check(
1782             "foo",
1783             r#"
1784 trait Foo {
1785     fn bar(&self) {
1786         self.bar();
1787     }
1788 }
1789
1790 impl Foo for () {
1791     fn bar(&self) {
1792         self.bar$0();
1793     }
1794 }"#,
1795             res,
1796         );
1797     }
1798
1799     #[test]
1800     fn test_rename_trait_method_prefix_of_second() {
1801         check(
1802             "qux",
1803             r#"
1804 trait Foo {
1805     fn foo$0() {}
1806     fn foobar() {}
1807 }
1808 "#,
1809             r#"
1810 trait Foo {
1811     fn qux() {}
1812     fn foobar() {}
1813 }
1814 "#,
1815         );
1816     }
1817
1818     #[test]
1819     fn test_rename_trait_const() {
1820         let res = r"
1821 trait Foo {
1822     const FOO: ();
1823 }
1824
1825 impl Foo for () {
1826     const FOO: ();
1827 }
1828 fn f() { <()>::FOO; }";
1829         check(
1830             "FOO",
1831             r#"
1832 trait Foo {
1833     const BAR$0: ();
1834 }
1835
1836 impl Foo for () {
1837     const BAR: ();
1838 }
1839 fn f() { <()>::BAR; }"#,
1840             res,
1841         );
1842         check(
1843             "FOO",
1844             r#"
1845 trait Foo {
1846     const BAR: ();
1847 }
1848
1849 impl Foo for () {
1850     const BAR$0: ();
1851 }
1852 fn f() { <()>::BAR; }"#,
1853             res,
1854         );
1855         check(
1856             "FOO",
1857             r#"
1858 trait Foo {
1859     const BAR: ();
1860 }
1861
1862 impl Foo for () {
1863     const BAR: ();
1864 }
1865 fn f() { <()>::BAR$0; }"#,
1866             res,
1867         );
1868     }
1869
1870     #[test]
1871     fn defs_from_macros_arent_renamed() {
1872         check(
1873             "lol",
1874             r#"
1875 macro_rules! m { () => { fn f() {} } }
1876 m!();
1877 fn main() { f$0()  }
1878 "#,
1879             "error: No identifier available to rename",
1880         )
1881     }
1882
1883     #[test]
1884     fn attributed_item() {
1885         check(
1886             "function",
1887             r#"
1888 //- proc_macros: identity
1889
1890 #[proc_macros::identity]
1891 fn func$0() {
1892     func();
1893 }
1894 "#,
1895             r#"
1896
1897 #[proc_macros::identity]
1898 fn function() {
1899     function();
1900 }
1901 "#,
1902         )
1903     }
1904
1905     #[test]
1906     fn in_macro_multi_mapping() {
1907         check(
1908             "a",
1909             r#"
1910 fn foo() {
1911     macro_rules! match_ast2 {
1912         ($node:ident {
1913             $( $res:expr, )*
1914         }) => {{
1915             $( if $node { $res } else )*
1916             { loop {} }
1917         }};
1918     }
1919     let $0d = 3;
1920     match_ast2! {
1921         d {
1922             d,
1923             d,
1924         }
1925     };
1926 }
1927 "#,
1928             r#"
1929 fn foo() {
1930     macro_rules! match_ast2 {
1931         ($node:ident {
1932             $( $res:expr, )*
1933         }) => {{
1934             $( if $node { $res } else )*
1935             { loop {} }
1936         }};
1937     }
1938     let a = 3;
1939     match_ast2! {
1940         a {
1941             a,
1942             a,
1943         }
1944     };
1945 }
1946 "#,
1947         )
1948     }
1949 }