1 //! FIXME: write short doc here
2 use std::fmt::{self, Display};
4 use hir::{Module, ModuleDef, ModuleSource, Semantics};
6 base_db::{AnchoredPathBuf, FileId, FileRange},
7 defs::{Definition, NameClass, NameRefClass},
12 algo::find_node_at_offset,
13 ast::{self, NameOwner},
14 lex_single_syntax_kind, match_ast, AstNode, SyntaxKind, SyntaxNode, T,
17 use text_edit::TextEdit;
20 FilePosition, FileSystemEdit, RangeInfo, ReferenceKind, ReferenceSearchResult, SourceChange,
24 type RenameResult<T> = Result<T, RenameError>;
26 pub struct RenameError(pub(crate) String);
28 impl fmt::Display for RenameError {
29 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
30 Display::fmt(&self.0, f)
34 macro_rules! format_err {
35 ($fmt:expr) => {RenameError(format!($fmt))};
36 ($fmt:expr, $($arg:tt)+) => {RenameError(format!($fmt, $($arg)+))}
40 ($($tokens:tt)*) => {return Err(format_err!($($tokens)*))}
43 pub(crate) fn prepare_rename(
45 position: FilePosition,
46 ) -> RenameResult<RangeInfo<()>> {
47 let sema = Semantics::new(db);
48 let source_file = sema.parse(position.file_id);
49 let syntax = source_file.syntax();
50 if let Some(module) = find_module_at_offset(&sema, position, syntax) {
51 rename_mod(&sema, position, module, "dummy")
53 let RangeInfo { range, .. } = find_all_refs(&sema, position)?;
54 Ok(RangeInfo::new(range, SourceChange::default()))
56 .map(|info| RangeInfo::new(info.range, ()))
61 position: FilePosition,
63 ) -> RenameResult<RangeInfo<SourceChange>> {
64 let sema = Semantics::new(db);
65 rename_with_semantics(&sema, position, new_name)
68 pub(crate) fn rename_with_semantics(
69 sema: &Semantics<RootDatabase>,
70 position: FilePosition,
72 ) -> RenameResult<RangeInfo<SourceChange>> {
73 let source_file = sema.parse(position.file_id);
74 let syntax = source_file.syntax();
76 if let Some(module) = find_module_at_offset(&sema, position, syntax) {
77 rename_mod(&sema, position, module, new_name)
79 rename_reference(&sema, position, new_name)
83 pub(crate) fn will_rename_file(
87 ) -> Option<SourceChange> {
88 let sema = Semantics::new(db);
89 let module = sema.to_module_def(file_id)?;
91 let decl = module.declaration_source(db)?;
92 let range = decl.value.name()?.syntax().text_range();
94 let position = FilePosition { file_id: decl.file_id.original_file(db), offset: range.start() };
95 let mut change = rename_mod(&sema, position, module, new_name_stem).ok()?.info;
96 change.file_system_edits.clear();
100 #[derive(Copy, Clone, Debug, PartialEq)]
101 enum IdentifierKind {
108 fn check_identifier(new_name: &str) -> RenameResult<IdentifierKind> {
109 match lex_single_syntax_kind(new_name) {
110 Some(res) => match res {
111 (SyntaxKind::IDENT, _) => Ok(IdentifierKind::Ident),
112 (T![_], _) => Ok(IdentifierKind::Underscore),
113 (T![self], _) => Ok(IdentifierKind::ToSelf),
114 (SyntaxKind::LIFETIME_IDENT, _) if new_name != "'static" && new_name != "'_" => {
115 Ok(IdentifierKind::Lifetime)
117 (SyntaxKind::LIFETIME_IDENT, _) => {
118 bail!("Invalid name `{0}`: Cannot rename lifetime to {0}", new_name)
120 (_, Some(syntax_error)) => bail!("Invalid name `{}`: {}", new_name, syntax_error),
121 (_, None) => bail!("Invalid name `{}`: not an identifier", new_name),
123 None => bail!("Invalid name `{}`: not an identifier", new_name),
127 fn find_module_at_offset(
128 sema: &Semantics<RootDatabase>,
129 position: FilePosition,
131 ) -> Option<Module> {
132 let ident = syntax.token_at_offset(position.offset).find(|t| t.kind() == SyntaxKind::IDENT)?;
134 let module = match_ast! {
135 match (ident.parent()) {
136 ast::NameRef(name_ref) => {
137 match NameRefClass::classify(sema, &name_ref)? {
138 NameRefClass::Definition(Definition::ModuleDef(ModuleDef::Module(module))) => module,
143 match NameClass::classify(&sema, &name)? {
144 NameClass::Definition(Definition::ModuleDef(ModuleDef::Module(module))) => module,
156 sema: &Semantics<RootDatabase>,
157 position: FilePosition,
158 ) -> RenameResult<RangeInfo<ReferenceSearchResult>> {
159 crate::references::find_all_refs(sema, position, None)
160 .ok_or_else(|| format_err!("No references found at position"))
163 fn source_edit_from_references(
164 sema: &Semantics<RootDatabase>,
166 references: &[FileReference],
168 ) -> (FileId, TextEdit) {
169 let mut edit = TextEdit::builder();
170 for reference in references {
171 let mut replacement_text = String::new();
172 let range = match reference.kind {
173 ReferenceKind::FieldShorthandForField => {
174 mark::hit!(test_rename_struct_field_for_shorthand);
175 replacement_text.push_str(new_name);
176 replacement_text.push_str(": ");
177 TextRange::new(reference.range.start(), reference.range.start())
179 ReferenceKind::FieldShorthandForLocal => {
180 mark::hit!(test_rename_local_for_field_shorthand);
181 replacement_text.push_str(": ");
182 replacement_text.push_str(new_name);
183 TextRange::new(reference.range.end(), reference.range.end())
185 ReferenceKind::RecordFieldExprOrPat => {
186 mark::hit!(test_rename_field_expr_pat);
187 replacement_text.push_str(new_name);
188 edit_text_range_for_record_field_expr_or_pat(
190 FileRange { file_id, range: reference.range },
195 replacement_text.push_str(new_name);
199 edit.replace(range, replacement_text);
201 (file_id, edit.finish())
204 fn edit_text_range_for_record_field_expr_or_pat(
205 sema: &Semantics<RootDatabase>,
206 file_range: FileRange,
209 let source_file = sema.parse(file_range.file_id);
210 let file_syntax = source_file.syntax();
211 let original_range = file_range.range;
213 syntax::algo::find_node_at_range::<ast::RecordExprField>(file_syntax, original_range)
214 .and_then(|field_expr| match field_expr.expr().and_then(|e| e.name_ref()) {
215 Some(name) if &name.to_string() == new_name => Some(field_expr.syntax().text_range()),
219 syntax::algo::find_node_at_range::<ast::RecordPatField>(file_syntax, original_range)
220 .and_then(|field_pat| match field_pat.pat() {
221 Some(ast::Pat::IdentPat(pat))
222 if pat.name().map(|n| n.to_string()).as_deref() == Some(new_name) =>
224 Some(field_pat.syntax().text_range())
229 .unwrap_or(original_range)
233 sema: &Semantics<RootDatabase>,
234 position: FilePosition,
237 ) -> RenameResult<RangeInfo<SourceChange>> {
238 if IdentifierKind::Ident != check_identifier(new_name)? {
239 bail!("Invalid name `{0}`: cannot rename module to {0}", new_name);
242 let mut source_change = SourceChange::default();
244 let src = module.definition_source(sema.db);
245 let file_id = src.file_id.original_file(sema.db);
247 ModuleSource::SourceFile(..) => {
248 // mod is defined in path/to/dir/mod.rs
249 let path = if module.is_mod_rs(sema.db) {
250 format!("../{}/mod.rs", new_name)
252 format!("{}.rs", new_name)
254 let dst = AnchoredPathBuf { anchor: file_id, path };
255 let move_file = FileSystemEdit::MoveFile { src: file_id, dst };
256 source_change.push_file_system_edit(move_file);
258 ModuleSource::Module(..) => {}
261 if let Some(src) = module.declaration_source(sema.db) {
262 let file_id = src.file_id.original_file(sema.db);
263 let name = src.value.name().unwrap();
264 source_change.insert_source_edit(
266 TextEdit::replace(name.syntax().text_range(), new_name.into()),
270 let RangeInfo { range, info: refs } = find_all_refs(sema, position)?;
271 let ref_edits = refs.references().iter().map(|(&file_id, references)| {
272 source_edit_from_references(sema, file_id, references, new_name)
274 source_change.extend(ref_edits);
276 Ok(RangeInfo::new(range, source_change))
280 sema: &Semantics<RootDatabase>,
281 position: FilePosition,
282 ) -> Result<RangeInfo<SourceChange>, RenameError> {
283 let source_file = sema.parse(position.file_id);
284 let syn = source_file.syntax();
286 let (fn_def, fn_ast) = find_node_at_offset::<ast::Fn>(syn, position.offset)
287 .and_then(|fn_ast| sema.to_def(&fn_ast).zip(Some(fn_ast)))
288 .ok_or_else(|| format_err!("No surrounding method declaration found"))?;
289 let param_range = fn_ast
291 .and_then(|p| p.params().next())
292 .ok_or_else(|| format_err!("Method has no parameters"))?
295 if !param_range.contains(position.offset) {
296 bail!("Only the first parameter can be self");
299 let impl_block = find_node_at_offset::<ast::Impl>(syn, position.offset)
300 .and_then(|def| sema.to_def(&def))
301 .ok_or_else(|| format_err!("No impl block found for function"))?;
302 if fn_def.self_param(sema.db).is_some() {
303 bail!("Method already has a self parameter");
306 let params = fn_def.assoc_fn_params(sema.db);
307 let first_param = params.first().ok_or_else(|| format_err!("Method has no parameters"))?;
308 let first_param_ty = first_param.ty();
309 let impl_ty = impl_block.target_ty(sema.db);
310 let (ty, self_param) = if impl_ty.remove_ref().is_some() {
311 // if the impl is a ref to the type we can just match the `&T` with self directly
312 (first_param_ty.clone(), "self")
314 first_param_ty.remove_ref().map_or((first_param_ty.clone(), "self"), |ty| {
315 (ty, if first_param_ty.is_mutable_reference() { "&mut self" } else { "&self" })
320 bail!("Parameter type differs from impl block type");
323 let RangeInfo { range, info: refs } = find_all_refs(sema, position)?;
325 let mut source_change = SourceChange::default();
326 source_change.extend(refs.references().iter().map(|(&file_id, references)| {
327 source_edit_from_references(sema, file_id, references, "self")
329 source_change.insert_source_edit(
331 TextEdit::replace(param_range, String::from(self_param)),
334 Ok(RangeInfo::new(range, source_change))
337 fn text_edit_from_self_param(
339 self_param: &ast::SelfParam,
341 ) -> Option<TextEdit> {
342 fn target_type_name(impl_def: &ast::Impl) -> Option<String> {
343 if let Some(ast::Type::PathType(p)) = impl_def.self_ty() {
344 return Some(p.path()?.segment()?.name_ref()?.text().to_string());
349 let impl_def = find_node_at_offset::<ast::Impl>(syn, self_param.syntax().text_range().start())?;
350 let type_name = target_type_name(&impl_def)?;
352 let mut replacement_text = String::from(new_name);
353 replacement_text.push_str(": ");
354 match (self_param.amp_token(), self_param.mut_token()) {
356 (Some(_), None) => replacement_text.push('&'),
357 (_, Some(_)) => replacement_text.push_str("&mut "),
359 replacement_text.push_str(type_name.as_str());
361 Some(TextEdit::replace(self_param.syntax().text_range(), replacement_text))
364 fn rename_self_to_param(
365 sema: &Semantics<RootDatabase>,
366 position: FilePosition,
368 ident_kind: IdentifierKind,
370 refs: ReferenceSearchResult,
371 ) -> Result<RangeInfo<SourceChange>, RenameError> {
373 IdentifierKind::Lifetime => bail!("Invalid name `{}`: not an identifier", new_name),
374 IdentifierKind::ToSelf => {
376 mark::hit!(rename_self_to_self);
377 return Ok(RangeInfo::new(range, SourceChange::default()));
381 let source_file = sema.parse(position.file_id);
382 let syn = source_file.syntax();
384 let fn_def = find_node_at_offset::<ast::Fn>(syn, position.offset)
385 .ok_or_else(|| format_err!("No surrounding method declaration found"))?;
387 let mut source_change = SourceChange::default();
388 if let Some(self_param) = fn_def.param_list().and_then(|it| it.self_param()) {
392 .contains_range(refs.declaration().nav.focus_or_full_range())
394 let edit = text_edit_from_self_param(syn, &self_param, new_name)
395 .ok_or_else(|| format_err!("No target type found"))?;
396 source_change.insert_source_edit(position.file_id, edit);
398 source_change.extend(refs.references().iter().map(|(&file_id, references)| {
399 source_edit_from_references(sema, file_id, &references, new_name)
402 if source_change.source_file_edits.len() > 1 && ident_kind == IdentifierKind::Underscore
404 bail!("Cannot rename reference to `_` as it is being referenced multiple times");
407 return Ok(RangeInfo::new(range, source_change));
410 Err(format_err!("Method has no self param"))
414 sema: &Semantics<RootDatabase>,
415 position: FilePosition,
417 ) -> Result<RangeInfo<SourceChange>, RenameError> {
418 let ident_kind = check_identifier(new_name)?;
419 let RangeInfo { range, info: refs } = find_all_refs(sema, position)?;
421 match (ident_kind, &refs.declaration.kind) {
422 (IdentifierKind::ToSelf, ReferenceKind::Lifetime)
423 | (IdentifierKind::Underscore, ReferenceKind::Lifetime)
424 | (IdentifierKind::Ident, ReferenceKind::Lifetime) => {
425 mark::hit!(rename_not_a_lifetime_ident_ref);
426 bail!("Invalid name `{}`: not a lifetime identifier", new_name)
428 (IdentifierKind::Lifetime, ReferenceKind::Lifetime) => mark::hit!(rename_lifetime),
429 (IdentifierKind::Lifetime, _) => {
430 mark::hit!(rename_not_an_ident_ref);
431 bail!("Invalid name `{}`: not an identifier", new_name)
433 (_, ReferenceKind::SelfParam) => {
434 mark::hit!(rename_self_to_param);
435 return rename_self_to_param(sema, position, new_name, ident_kind, range, refs);
437 (IdentifierKind::ToSelf, _) => {
438 mark::hit!(rename_to_self);
439 return rename_to_self(sema, position);
441 (IdentifierKind::Underscore, _) if !refs.references.is_empty() => {
442 mark::hit!(rename_underscore_multiple);
443 bail!("Cannot rename reference to `_` as it is being referenced multiple times")
445 (IdentifierKind::Ident, _) | (IdentifierKind::Underscore, _) => mark::hit!(rename_ident),
448 let mut source_change = SourceChange::default();
449 source_change.extend(refs.into_iter().map(|(file_id, references)| {
450 source_edit_from_references(sema, file_id, &references, new_name)
453 Ok(RangeInfo::new(range, source_change))
458 use expect_test::{expect, Expect};
459 use stdx::trim_indent;
460 use test_utils::{assert_eq_text, mark};
461 use text_edit::TextEdit;
463 use crate::{fixture, FileId};
465 fn check(new_name: &str, ra_fixture_before: &str, ra_fixture_after: &str) {
466 let ra_fixture_after = &trim_indent(ra_fixture_after);
467 let (analysis, position) = fixture::position(ra_fixture_before);
468 let rename_result = analysis
469 .rename(position, new_name)
470 .unwrap_or_else(|err| panic!("Rename to '{}' was cancelled: {}", new_name, err));
471 match rename_result {
472 Ok(source_change) => {
473 let mut text_edit_builder = TextEdit::builder();
474 let mut file_id: Option<FileId> = None;
475 for edit in source_change.info.source_file_edits {
476 file_id = Some(edit.0);
477 for indel in edit.1.into_iter() {
478 text_edit_builder.replace(indel.delete, indel.insert);
481 if let Some(file_id) = file_id {
482 let mut result = analysis.file_text(file_id).unwrap().to_string();
483 text_edit_builder.finish().apply(&mut result);
484 assert_eq_text!(ra_fixture_after, &*result);
488 if ra_fixture_after.starts_with("error:") {
489 let error_message = ra_fixture_after
492 .skip("error:".len())
493 .collect::<String>();
494 assert_eq!(error_message.trim(), err.to_string());
497 panic!("Rename to '{}' failed unexpectedly: {}", new_name, err)
503 fn check_expect(new_name: &str, ra_fixture: &str, expect: Expect) {
504 let (analysis, position) = fixture::position(ra_fixture);
505 let source_change = analysis
506 .rename(position, new_name)
508 .expect("Expect returned RangeInfo to be Some, but was None");
509 expect.assert_debug_eq(&source_change)
513 fn test_rename_to_underscore() {
514 check("_", r#"fn main() { let i$0 = 1; }"#, r#"fn main() { let _ = 1; }"#);
518 fn test_rename_to_raw_identifier() {
519 check("r#fn", r#"fn main() { let i$0 = 1; }"#, r#"fn main() { let r#fn = 1; }"#);
523 fn test_rename_to_invalid_identifier1() {
526 r#"fn main() { let i$0 = 1; }"#,
527 "error: Invalid name `invalid!`: not an identifier",
532 fn test_rename_to_invalid_identifier2() {
535 r#"fn main() { let i$0 = 1; }"#,
536 "error: Invalid name `multiple tokens`: not an identifier",
541 fn test_rename_to_invalid_identifier3() {
544 r#"fn main() { let i$0 = 1; }"#,
545 "error: Invalid name `let`: not an identifier",
550 fn test_rename_to_invalid_identifier_lifetime() {
551 mark::check!(rename_not_an_ident_ref);
554 r#"fn main() { let i$0 = 1; }"#,
555 "error: Invalid name `'foo`: not an identifier",
560 fn test_rename_to_invalid_identifier_lifetime2() {
561 mark::check!(rename_not_a_lifetime_ident_ref);
564 r#"fn main<'a>(_: &'a$0 ()) {}"#,
565 "error: Invalid name `foo`: not a lifetime identifier",
570 fn test_rename_to_underscore_invalid() {
571 mark::check!(rename_underscore_multiple);
574 r#"fn main(foo$0: ()) {foo;}"#,
575 "error: Cannot rename reference to `_` as it is being referenced multiple times",
580 fn test_rename_mod_invalid() {
584 "error: Invalid name `'foo`: cannot rename module to 'foo",
589 fn test_rename_for_local() {
590 mark::check!(rename_ident);
619 fn test_rename_unresolved_reference() {
622 r#"fn main() { let _ = unresolved_ref$0; }"#,
623 "error: No references found at position",
628 fn test_rename_for_macro_args() {
632 macro_rules! foo {($i:ident) => {$i} }
639 macro_rules! foo {($i:ident) => {$i} }
649 fn test_rename_for_macro_args_rev() {
653 macro_rules! foo {($i:ident) => {$i} }
660 macro_rules! foo {($i:ident) => {$i} }
670 fn test_rename_for_macro_define_fn() {
674 macro_rules! define_fn {($id:ident) => { fn $id{} }}
681 macro_rules! define_fn {($id:ident) => { fn $id{} }}
691 fn test_rename_for_macro_define_fn_rev() {
695 macro_rules! define_fn {($id:ident) => { fn $id{} }}
702 macro_rules! define_fn {($id:ident) => { fn $id{} }}
712 fn test_rename_for_param_inside() {
713 check("j", r#"fn foo(i : u32) -> u32 { i$0 }"#, r#"fn foo(j : u32) -> u32 { j }"#);
717 fn test_rename_refs_for_fn_param() {
718 check("j", r#"fn foo(i$0 : u32) -> u32 { i }"#, r#"fn foo(j : u32) -> u32 { j }"#);
722 fn test_rename_for_mut_param() {
723 check("j", r#"fn foo(mut i$0 : u32) -> u32 { i }"#, r#"fn foo(mut j : u32) -> u32 { j }"#);
727 fn test_rename_struct_field() {
731 struct Foo { i$0: i32 }
734 fn new(i: i32) -> Self {
740 struct Foo { j: i32 }
743 fn new(i: i32) -> Self {
752 fn test_rename_struct_field_for_shorthand() {
753 mark::check!(test_rename_struct_field_for_shorthand);
757 struct Foo { i$0: i32 }
760 fn new(i: i32) -> Self {
766 struct Foo { j: i32 }
769 fn new(i: i32) -> Self {
778 fn test_rename_local_for_field_shorthand() {
779 mark::check!(test_rename_local_for_field_shorthand);
783 struct Foo { i: i32 }
786 fn new(i$0: i32) -> Self {
792 struct Foo { i: i32 }
795 fn new(j: i32) -> Self {
804 fn test_field_shorthand_correct_struct() {
808 struct Foo { i$0: i32 }
809 struct Bar { i: i32 }
812 fn new(i: i32) -> Self {
818 struct Foo { j: i32 }
819 struct Bar { i: i32 }
822 fn new(i: i32) -> Self {
831 fn test_shadow_local_for_struct_shorthand() {
835 struct Foo { i: i32 }
837 fn baz(i$0: i32) -> Self {
846 struct Foo { i: i32 }
848 fn baz(j: i32) -> Self {
849 let x = Foo { i: j };
860 fn test_rename_mod() {
894 dst: AnchoredPathBuf {
910 fn test_rename_mod_in_use_tree() {
920 pub struct FooContent;
923 use crate::foo$0::FooContent;
956 dst: AnchoredPathBuf {
972 fn test_rename_mod_in_dir() {
1002 dst: AnchoredPathBuf {
1006 path: "../foo2/mod.rs",
1018 fn test_rename_unusually_nested_mod() {
1023 mod outer { mod fo$0o; }
1031 info: SourceChange {
1032 source_file_edits: {
1044 file_system_edits: [
1049 dst: AnchoredPathBuf {
1065 fn test_module_rename_in_path() {
1069 mod $0foo { pub fn bar() {} }
1071 fn main() { foo::bar(); }
1074 mod baz { pub fn bar() {} }
1076 fn main() { baz::bar(); }
1082 fn test_rename_mod_filename_and_path() {
1101 info: SourceChange {
1102 source_file_edits: {
1124 file_system_edits: [
1129 dst: AnchoredPathBuf {
1145 fn test_enum_variant_from_module_1() {
1150 pub enum Foo { Bar$0 }
1153 fn func(f: foo::Foo) {
1161 pub enum Foo { Baz }
1164 fn func(f: foo::Foo) {
1174 fn test_enum_variant_from_module_2() {
1179 pub struct Foo { pub bar$0: uint }
1182 fn foo(f: foo::Foo) {
1188 pub struct Foo { pub baz: uint }
1191 fn foo(f: foo::Foo) {
1199 fn test_parameter_to_self() {
1200 mark::check!(rename_to_self);
1204 struct Foo { i: i32 }
1207 fn f(foo$0: &mut Foo) -> i32 {
1213 struct Foo { i: i32 }
1216 fn f(&mut self) -> i32 {
1225 struct Foo { i: i32 }
1228 fn f(foo$0: Foo) -> i32 {
1234 struct Foo { i: i32 }
1246 fn test_parameter_to_self_error_no_impl() {
1250 struct Foo { i: i32 }
1252 fn f(foo$0: &mut Foo) -> i32 {
1256 "error: No impl block found for function",
1261 struct Foo { i: i32 }
1265 fn f(foo$0: &mut Foo) -> i32 {
1270 "error: Parameter type differs from impl block type",
1275 fn test_parameter_to_self_error_not_first() {
1279 struct Foo { i: i32 }
1281 fn f(x: (), foo$0: &mut Foo) -> i32 {
1286 "error: Only the first parameter can be self",
1291 fn test_parameter_to_self_impl_ref() {
1295 struct Foo { i: i32 }
1297 fn f(foo$0: &Foo) -> i32 {
1303 struct Foo { i: i32 }
1314 fn test_self_to_parameter() {
1318 struct Foo { i: i32 }
1321 fn f(&mut $0self) -> i32 {
1327 struct Foo { i: i32 }
1330 fn f(foo: &mut Foo) -> i32 {
1339 fn test_owned_self_to_parameter() {
1340 mark::check!(rename_self_to_param);
1344 struct Foo { i: i32 }
1347 fn f($0self) -> i32 {
1353 struct Foo { i: i32 }
1356 fn f(foo: Foo) -> i32 {
1365 fn test_self_in_path_to_parameter() {
1369 struct Foo { i: i32 }
1372 fn f(&self) -> i32 {
1379 struct Foo { i: i32 }
1382 fn f(foo: &Foo) -> i32 {
1392 fn test_initializer_use_field_init_shorthand() {
1393 mark::check!(test_rename_field_expr_pat);
1397 struct Foo { i$0: i32 }
1399 fn foo(bar: i32) -> Foo {
1404 struct Foo { bar: i32 }
1406 fn foo(bar: i32) -> Foo {
1414 fn test_struct_field_destructure_into_shorthand() {
1418 struct Foo { i$0: i32 }
1421 let Foo { i: baz } = foo;
1426 struct Foo { baz: i32 }
1429 let Foo { baz } = foo;
1437 fn test_rename_binding_in_destructure_pat() {
1438 let expected_fixture = r#"
1444 let Foo { i: bar } = foo;
1456 let Foo { i: b } = foo;
1470 let Foo { i } = foo;
1479 fn test_rename_binding_in_destructure_param_pat() {
1487 fn foo(Foo { i }: foo) -> i32 {
1496 fn foo(Foo { i: bar }: foo) -> i32 {
1504 fn test_rename_lifetimes() {
1505 mark::check!(rename_lifetime);
1512 impl<'a> Foo<'a> for &'a () {
1513 fn foo() -> &'a$0 () {
1522 impl<'yeeee> Foo<'yeeee> for &'yeeee () {
1523 fn foo() -> &'yeeee () {
1532 fn test_rename_bind_pat() {
1537 enum CustomOption<T> {
1542 let test_variable = CustomOption::Some(22);
1544 match test_variable {
1545 CustomOption::Some(foo$0) if foo == 11 => {}
1551 enum CustomOption<T> {
1556 let test_variable = CustomOption::Some(22);
1558 match test_variable {
1559 CustomOption::Some(new_name) if new_name == 11 => {}
1567 fn test_rename_label() {
1571 fn foo<'a>() -> &'a () {
1580 fn foo<'a>() -> &'a () {
1592 fn test_self_to_self() {
1593 mark::check!(rename_self_to_self);