1use hir::{AsAssocItem, FindPathConfig, HasContainer, HirDisplay, InFile, Name, Semantics, sym};
8use ide_db::{
9 FileId, FileRange, RootDatabase,
10 defs::{Definition, NameClass, NameRefClass},
11 rename::{IdentifierKind, RenameDefinition, bail, format_err, source_edit_from_references},
12 source_change::SourceChangeBuilder,
13};
14use itertools::Itertools;
15use std::fmt::Write;
16use stdx::{always, format_to, never};
17use syntax::{
18 AstNode, SyntaxKind, SyntaxNode, TextRange, TextSize,
19 ast::{self, HasArgList, prec::ExprPrecedence},
20};
21
22use ide_db::text_edit::TextEdit;
23
24use crate::{FilePosition, RangeInfo, SourceChange};
25
26pub use ide_db::rename::RenameError;
27
28type RenameResult<T> = Result<T, RenameError>;
29
30pub struct RenameConfig {
31 pub prefer_no_std: bool,
32 pub prefer_prelude: bool,
33 pub prefer_absolute: bool,
34 pub show_conflicts: bool,
35}
36
37impl RenameConfig {
38 fn find_path_config(&self) -> FindPathConfig {
39 FindPathConfig {
40 prefer_no_std: self.prefer_no_std,
41 prefer_prelude: self.prefer_prelude,
42 prefer_absolute: self.prefer_absolute,
43 allow_unstable: true,
44 }
45 }
46
47 fn ide_db_config(&self) -> ide_db::rename::RenameConfig {
48 ide_db::rename::RenameConfig { show_conflicts: self.show_conflicts }
49 }
50}
51
52fn ok_if_any<T, E>(iter: impl Iterator<Item = Result<T, E>>) -> Result<Vec<T>, E> {
54 let mut err = None;
55 let oks = iter
56 .filter_map(|item| match item {
57 Ok(it) => Some(it),
58 Err(it) => {
59 err = Some(it);
60 None
61 }
62 })
63 .collect::<Vec<_>>();
64 if !oks.is_empty() {
65 Ok(oks)
66 } else if let Some(err) = err {
67 Err(err)
68 } else {
69 Ok(Vec::new())
70 }
71}
72
73pub(crate) fn prepare_rename(
76 db: &RootDatabase,
77 position: FilePosition,
78) -> RenameResult<RangeInfo<()>> {
79 let sema = Semantics::new(db);
80 let source_file = sema.parse_guess_edition(position.file_id);
81 let syntax = source_file.syntax();
82 if let Some(lifetime_token) = syntax.token_at_offset(position.offset).find(|t| t.text() == "'_")
83 {
84 return Ok(RangeInfo::new(lifetime_token.text_range(), ()));
85 }
86 let res = find_definitions(&sema, syntax, position, &Name::new_symbol_root(sym::underscore))?
87 .filter(|(_, _, def, _, _)| def.range_for_rename(&sema).is_some())
88 .map(|(frange, kind, _, _, _)| {
89 always!(
90 frange.range.contains_inclusive(position.offset)
91 && frange.file_id == position.file_id
92 );
93
94 Ok(match kind {
95 SyntaxKind::LIFETIME => {
96 TextRange::new(frange.range.start() + TextSize::from(1), frange.range.end())
97 }
98 _ => frange.range,
99 })
100 })
101 .reduce(|acc, cur| match (acc, cur) {
102 (Ok(acc_inner), Ok(cur_inner)) if acc_inner == cur_inner => Ok(acc_inner),
104 (e @ Err(_), _) | (_, e @ Err(_)) => e,
105 _ => bail!("inconsistent text range"),
106 });
107
108 match res {
109 Some(res) => res.map(|range| RangeInfo::new(range, ())),
111 None => bail!("No references found at position"),
112 }
113}
114
115pub(crate) fn rename(
125 db: &RootDatabase,
126 position: FilePosition,
127 new_name: &str,
128 config: &RenameConfig,
129) -> RenameResult<SourceChange> {
130 let sema = Semantics::new(db);
131 let file_id = sema
132 .attach_first_edition_opt(position.file_id)
133 .ok_or_else(|| format_err!("No references found at position"))?;
134 let source_file = sema.parse(file_id);
135 let syntax = source_file.syntax();
136
137 let edition = file_id.edition(db);
138 let (new_name, kind) = IdentifierKind::classify(edition, new_name)?;
139 if kind == IdentifierKind::Lifetime
140 && let Some(lifetime_token) =
141 syntax.token_at_offset(position.offset).find(|t| t.text() == "'_")
142 {
143 let new_name_str = new_name.display(db, edition).to_string();
144 return rename_elided_lifetime(position, lifetime_token, &new_name_str);
145 }
146
147 let defs = find_definitions(&sema, syntax, position, &new_name)?;
148 let alias_fallback =
149 alias_fallback(syntax, position, &new_name.display(db, edition).to_string());
150
151 let ops: RenameResult<Vec<SourceChange>> = match alias_fallback {
152 Some(_) => ok_if_any(
153 defs
154 .map(|(.., def, new_name, _)| {
157 match kind {
158 IdentifierKind::Ident => (),
159 IdentifierKind::Lifetime => {
160 bail!("Cannot alias reference to a lifetime identifier")
161 }
162 IdentifierKind::Underscore => bail!("Cannot alias reference to `_`"),
163 IdentifierKind::LowercaseSelf => {
164 bail!("Cannot rename alias reference to `self`")
165 }
166 };
167 let mut usages = def.usages(&sema).all();
168
169 match usages.references.get_mut(&file_id).and_then(|refs| {
171 refs.iter()
172 .position(|ref_| ref_.range.contains_inclusive(position.offset))
173 .map(|idx| refs.remove(idx))
174 }) {
175 Some(_) => (),
176 None => never!(),
177 };
178
179 let mut source_change = SourceChange::default();
180 source_change.extend(usages.references.get_mut(&file_id).iter().map(|refs| {
181 (
182 position.file_id,
183 source_edit_from_references(db, refs, def, &new_name, edition),
184 )
185 }));
186
187 Ok(source_change)
188 }),
189 ),
190 None => ok_if_any(defs.map(|(.., def, new_name, rename_def)| {
191 if let Definition::Local(local) = def {
192 if let Some(self_param) = local.as_self_param(sema.db) {
193 cov_mark::hit!(rename_self_to_param);
194 return rename_self_to_param(
195 &sema,
196 local,
197 self_param,
198 &new_name,
199 kind,
200 config.find_path_config(),
201 );
202 }
203 if kind == IdentifierKind::LowercaseSelf {
204 cov_mark::hit!(rename_to_self);
205 return rename_to_self(&sema, local);
206 }
207 }
208 def.rename(&sema, new_name.as_str(), rename_def, &config.ide_db_config())
209 })),
210 };
211
212 ops?.into_iter()
213 .chain(alias_fallback)
214 .reduce(|acc, elem| acc.merge(elem))
215 .ok_or_else(|| format_err!("No references found at position"))
216}
217
218pub(crate) fn will_rename_file(
220 db: &RootDatabase,
221 file_id: FileId,
222 new_name_stem: &str,
223 config: &RenameConfig,
224) -> Option<SourceChange> {
225 let sema = Semantics::new(db);
226 let module = sema.file_to_module_def(file_id)?;
227 let def = Definition::Module(module);
228 let mut change =
229 def.rename(&sema, new_name_stem, RenameDefinition::Yes, &config.ide_db_config()).ok()?;
230 change.file_system_edits.clear();
231 Some(change)
232}
233
234fn alias_fallback(
236 syntax: &SyntaxNode,
237 FilePosition { file_id, offset }: FilePosition,
238 new_name: &str,
239) -> Option<SourceChange> {
240 let use_tree = syntax
241 .token_at_offset(offset)
242 .flat_map(|syntax| syntax.parent_ancestors())
243 .find_map(ast::UseTree::cast)?;
244
245 let last_path_segment = use_tree.path()?.segments().last()?.name_ref()?;
246 if !last_path_segment.syntax().text_range().contains_inclusive(offset) {
247 return None;
248 };
249
250 let mut builder = SourceChangeBuilder::new(file_id);
251
252 match use_tree.rename() {
253 Some(rename) => {
254 let offset = rename.syntax().text_range();
255 builder.replace(offset, format!("as {new_name}"));
256 }
257 None => {
258 let offset = use_tree.syntax().text_range().end();
259 builder.insert(offset, format!(" as {new_name}"));
260 }
261 }
262
263 Some(builder.finish())
264}
265
266fn find_definitions(
267 sema: &Semantics<'_, RootDatabase>,
268 syntax: &SyntaxNode,
269 FilePosition { file_id, offset }: FilePosition,
270 new_name: &Name,
271) -> RenameResult<impl Iterator<Item = (FileRange, SyntaxKind, Definition, Name, RenameDefinition)>>
272{
273 let maybe_format_args =
274 syntax.token_at_offset(offset).find(|t| matches!(t.kind(), SyntaxKind::STRING));
275
276 if let Some((range, _, _, Some(resolution))) =
277 maybe_format_args.and_then(|token| sema.check_for_format_args_template(token, offset))
278 {
279 return Ok(vec![(
280 FileRange { file_id, range },
281 SyntaxKind::STRING,
282 Definition::from(resolution),
283 new_name.clone(),
284 RenameDefinition::Yes,
285 )]
286 .into_iter());
287 }
288
289 let original_ident = syntax
290 .token_at_offset(offset)
291 .max_by_key(|t| {
292 t.kind().is_any_identifier() || matches!(t.kind(), SyntaxKind::LIFETIME_IDENT)
293 })
294 .map(|t| {
295 if t.kind() == SyntaxKind::LIFETIME_IDENT {
296 Name::new_lifetime(t.text())
297 } else {
298 Name::new_root(t.text())
299 }
300 })
301 .ok_or_else(|| format_err!("No references found at position"))?;
302 let symbols =
303 sema.find_namelike_at_offset_with_descend(syntax, offset).map(|name_like| {
304 let kind = name_like.syntax().kind();
305 let range = sema
306 .original_range_opt(name_like.syntax())
307 .ok_or_else(|| format_err!("No references found at position"))?;
308 let res = match &name_like {
309 ast::NameLike::Name(name)
311 if name
312 .syntax()
313 .parent().is_some_and(|it| ast::Rename::can_cast(it.kind()))
314 =>
321 {
322 bail!("Renaming aliases is currently unsupported")
323 }
324 ast::NameLike::Name(name) => NameClass::classify(sema, name)
325 .map(|class| match class {
326 NameClass::Definition(it) | NameClass::ConstReference(it) => it,
327 NameClass::PatFieldShorthand { local_def, field_ref: _, adt_subst: _ } => {
328 Definition::Local(local_def)
329 }
330 })
331 .ok_or_else(|| format_err!("No references found at position")),
332 ast::NameLike::NameRef(name_ref) => {
333 NameRefClass::classify(sema, name_ref)
334 .map(|class| match class {
335 NameRefClass::Definition(def, _) => def,
336 NameRefClass::FieldShorthand { local_ref, field_ref: _, adt_subst: _ } => {
337 Definition::Local(local_ref)
338 }
339 NameRefClass::ExternCrateShorthand { decl, .. } => {
340 Definition::ExternCrateDecl(decl)
341 }
342 })
343 .filter(|def| !matches!(def, Definition::ExternCrateDecl(..)))
345 .ok_or_else(|| format_err!("No references found at position"))
346 .and_then(|def| {
347 if def
349 .name(sema.db).is_some_and(|it| it.as_str() != name_ref.text().trim_start_matches("r#"))
350 {
351 Err(format_err!("Renaming aliases is currently unsupported"))
352 } else {
353 Ok(def)
354 }
355 })
356 }
357 ast::NameLike::Lifetime(lifetime) => {
358 NameRefClass::classify_lifetime(sema, lifetime)
359 .and_then(|class| match class {
360 NameRefClass::Definition(def, _) => Some(def),
361 _ => None,
362 })
363 .or_else(|| {
364 NameClass::classify_lifetime(sema, lifetime).and_then(|it| match it {
365 NameClass::Definition(it) => Some(it),
366 _ => None,
367 })
368 })
369 .ok_or_else(|| format_err!("No references found at position"))
370 }
371 };
372 res.map(|def| {
373 let n = def.name(sema.db)?;
374 if n == original_ident {
375 Some((range, kind, def, new_name.clone(), RenameDefinition::Yes))
376 } else if let Some(suffix) = n.as_str().strip_prefix(original_ident.as_str()) {
377 Some((range, kind, def, Name::new_root(&format!("{}{suffix}", new_name.as_str())), RenameDefinition::No))
378 } else {
379 n.as_str().strip_suffix(original_ident.as_str().trim_start_matches('\''))
380 .map(|prefix| (range, kind, def, Name::new_root(&format!("{prefix}{}", new_name.as_str())), RenameDefinition::No))
381 }
382 })
383 });
384
385 let res: RenameResult<Vec<_>> = ok_if_any(symbols.filter_map(Result::transpose));
386 match res {
387 Ok(v) => {
388 Ok(v.into_iter()
390 .unique_by(|&(.., def, _, _)| def)
391 .map(|(a, b, c, d, e)| (a.into_file_id(sema.db), b, c, d, e))
392 .collect::<Vec<_>>()
393 .into_iter())
394 }
395 Err(e) => Err(e),
396 }
397}
398
399fn transform_assoc_fn_into_method_call(
400 sema: &Semantics<'_, RootDatabase>,
401 source_change: &mut SourceChange,
402 f: hir::Function,
403) {
404 let calls = Definition::Function(f).usages(sema).all();
405 for (_file_id, calls) in calls {
406 for call in calls {
407 let Some(fn_name) = call.name.as_name_ref() else { continue };
408 let Some(path) = fn_name.syntax().parent().and_then(ast::PathSegment::cast) else {
409 continue;
410 };
411 let path = path.parent_path();
412 let Some(call) =
414 path.syntax().parent().and_then(|it| ast::CallExpr::cast(it.parent()?))
415 else {
416 continue;
417 };
418
419 let Some(arg_list) = call.arg_list() else { continue };
420 let mut args = arg_list.args();
421 let Some(mut self_arg) = args.next() else { continue };
422 let second_arg = args.next();
423
424 loop {
426 let self_ = match &self_arg {
427 ast::Expr::RefExpr(self_) => self_.expr(),
428 ast::Expr::ParenExpr(self_) => self_.expr(),
429 ast::Expr::PrefixExpr(self_)
430 if self_.op_kind() == Some(ast::UnaryOp::Deref) =>
431 {
432 self_.expr()
433 }
434 _ => break,
435 };
436 self_arg = match self_ {
437 Some(it) => it,
438 None => break,
439 };
440 }
441
442 let self_needs_parens =
443 self_arg.precedence().needs_parentheses_in(ExprPrecedence::Postfix);
444
445 let replace_start = path.syntax().text_range().start();
446 let replace_end = match second_arg {
447 Some(second_arg) => second_arg.syntax().text_range().start(),
448 None => arg_list
449 .r_paren_token()
450 .map(|it| it.text_range().start())
451 .unwrap_or_else(|| arg_list.syntax().text_range().end()),
452 };
453 let replace_range = TextRange::new(replace_start, replace_end);
454 let macro_file = sema.hir_file_for(fn_name.syntax());
455 let Some((replace_range, _)) =
456 InFile::new(macro_file, replace_range).original_node_file_range_opt(sema.db)
457 else {
458 continue;
459 };
460
461 let Some(macro_mapped_self) = sema.original_range_opt(self_arg.syntax()) else {
462 continue;
463 };
464 let mut replacement = String::new();
465 if self_needs_parens {
466 replacement.push('(');
467 }
468 replacement.push_str(macro_mapped_self.text(sema.db));
469 if self_needs_parens {
470 replacement.push(')');
471 }
472 replacement.push('.');
473 format_to!(replacement, "{fn_name}");
474 replacement.push('(');
475
476 source_change.insert_source_edit(
477 replace_range.file_id.file_id(sema.db),
478 TextEdit::replace(replace_range.range, replacement),
479 );
480 }
481 }
482}
483
484fn rename_to_self(
485 sema: &Semantics<'_, RootDatabase>,
486 local: hir::Local,
487) -> RenameResult<SourceChange> {
488 if never!(local.is_self(sema.db)) {
489 bail!("rename_to_self invoked on self");
490 }
491
492 let fn_def = match local.parent(sema.db) {
493 hir::ExpressionStoreOwner::Body(hir::DefWithBody::Function(func)) => func,
494 _ => bail!("Cannot rename local to self outside of function"),
495 };
496
497 if fn_def.self_param(sema.db).is_some() {
498 bail!("Method already has a self parameter");
499 }
500
501 let params = fn_def.assoc_fn_params(sema.db);
502 let first_param = params
503 .first()
504 .ok_or_else(|| format_err!("Cannot rename local to self unless it is a parameter"))?;
505 match first_param.as_local(sema.db) {
506 Some(plocal) => {
507 if plocal != local {
508 bail!("Only the first parameter may be renamed to self");
509 }
510 }
511 None => bail!("rename_to_self invoked on destructuring parameter"),
512 }
513
514 let assoc_item = fn_def
515 .as_assoc_item(sema.db)
516 .ok_or_else(|| format_err!("Cannot rename parameter to self for free function"))?;
517 let impl_ = match assoc_item.container(sema.db) {
518 hir::AssocItemContainer::Trait(_) => {
519 bail!("Cannot rename parameter to self for trait functions");
520 }
521 hir::AssocItemContainer::Impl(impl_) => impl_,
522 };
523 let first_param_ty = first_param.ty();
524 let impl_ty = impl_.self_ty(sema.db);
525 let (ty, self_param) = if impl_ty.is_reference() {
526 (first_param_ty.clone(), "self")
528 } else {
529 first_param_ty.as_reference_inner().map_or((first_param_ty.clone(), "self"), |ty| {
530 (ty, if first_param_ty.is_mutable_reference() { "&mut self" } else { "&self" })
531 })
532 };
533
534 if ty != impl_ty {
535 bail!("Parameter type differs from impl block type");
536 }
537
538 let InFile { file_id, value: param_source } = sema
539 .source(first_param.clone())
540 .ok_or_else(|| format_err!("No source for parameter found"))?;
541
542 let def = Definition::Local(local);
543 let usages = def.usages(sema).all();
544 let mut source_change = SourceChange::default();
545 source_change.extend(usages.iter().map(|(file_id, references)| {
546 (
547 file_id.file_id(sema.db),
548 source_edit_from_references(
549 sema.db,
550 references,
551 def,
552 &Name::new_symbol_root(sym::self_),
553 file_id.edition(sema.db),
554 ),
555 )
556 }));
557 source_change.insert_source_edit(
558 file_id.original_file(sema.db).file_id(sema.db),
559 TextEdit::replace(param_source.syntax().text_range(), String::from(self_param)),
560 );
561 transform_assoc_fn_into_method_call(sema, &mut source_change, fn_def);
562 Ok(source_change)
563}
564
565#[derive(Debug, Clone, Copy, PartialEq, Eq)]
566enum CallReceiverAdjust {
567 Deref,
568 Ref,
569 RefMut,
570 None,
571}
572
573fn method_to_assoc_fn_call_self_adjust(
574 sema: &Semantics<'_, RootDatabase>,
575 self_arg: &ast::Expr,
576) -> CallReceiverAdjust {
577 let mut result = CallReceiverAdjust::None;
578 let self_adjust = sema.expr_adjustments(self_arg);
579 if let Some(self_adjust) = self_adjust {
580 let mut i = 0;
581 while i < self_adjust.len() {
582 if matches!(self_adjust[i].kind, hir::Adjust::Deref(..))
583 && matches!(
584 self_adjust.get(i + 1),
585 Some(hir::Adjustment { kind: hir::Adjust::Borrow(..), .. })
586 )
587 {
588 i += 2;
590 continue;
591 }
592
593 match self_adjust[i].kind {
594 hir::Adjust::Deref(_) if result == CallReceiverAdjust::None => {
595 result = CallReceiverAdjust::Deref;
598 }
599 hir::Adjust::Borrow(hir::AutoBorrow::Ref(mutability)) => {
600 match (result, mutability) {
601 (CallReceiverAdjust::RefMut, hir::Mutability::Shared) => {}
602 (_, hir::Mutability::Mut) => result = CallReceiverAdjust::RefMut,
603 (_, hir::Mutability::Shared) => result = CallReceiverAdjust::Ref,
604 }
605 }
606 _ => {}
607 }
608
609 i += 1;
610 }
611 }
612 result
613}
614
615fn transform_method_call_into_assoc_fn(
616 sema: &Semantics<'_, RootDatabase>,
617 source_change: &mut SourceChange,
618 f: hir::Function,
619 find_path_config: FindPathConfig,
620) {
621 let calls = Definition::Function(f).usages(sema).all();
622 for (_file_id, calls) in calls {
623 for call in calls {
624 let Some(fn_name) = call.name.as_name_ref() else { continue };
625 let Some(method_call) = fn_name.syntax().parent().and_then(ast::MethodCallExpr::cast)
626 else {
627 continue;
628 };
629 let Some(mut self_arg) = method_call.receiver() else {
630 continue;
631 };
632
633 let Some(scope) = sema.scope(fn_name.syntax()) else {
634 continue;
635 };
636 let self_adjust = method_to_assoc_fn_call_self_adjust(sema, &self_arg);
637
638 while let ast::Expr::ParenExpr(it) = &self_arg {
640 self_arg = match it.expr() {
641 Some(it) => it,
642 None => break,
643 };
644 }
645
646 let needs_comma = method_call.arg_list().is_some_and(|it| it.args().next().is_some());
647
648 let self_needs_parens = self_adjust != CallReceiverAdjust::None
649 && self_arg.precedence().needs_parentheses_in(ExprPrecedence::Prefix);
650
651 let replace_start = method_call.syntax().text_range().start();
652 let replace_end = method_call
653 .arg_list()
654 .and_then(|it| it.l_paren_token())
655 .map(|it| it.text_range().end())
656 .unwrap_or_else(|| method_call.syntax().text_range().end());
657 let replace_range = TextRange::new(replace_start, replace_end);
658 let macro_file = sema.hir_file_for(fn_name.syntax());
659 let Some((replace_range, _)) =
660 InFile::new(macro_file, replace_range).original_node_file_range_opt(sema.db)
661 else {
662 continue;
663 };
664
665 let fn_container_path = match f.container(sema.db) {
666 hir::ItemContainer::Trait(trait_) => {
667 let Some(path) = scope.module().find_path(
671 sema.db,
672 hir::ItemInNs::Types(trait_.into()),
673 find_path_config,
674 ) else {
675 continue;
676 };
677 path.display(sema.db, replace_range.file_id.edition(sema.db)).to_string()
678 }
679 hir::ItemContainer::Impl(impl_) => {
680 let ty = impl_.self_ty(sema.db);
681 match ty.as_adt() {
682 Some(adt) => {
683 let Some(path) = scope.module().find_path(
684 sema.db,
685 hir::ItemInNs::Types(adt.into()),
686 find_path_config,
687 ) else {
688 continue;
689 };
690 path.display(sema.db, replace_range.file_id.edition(sema.db))
691 .to_string()
692 }
693 None => {
694 let Ok(mut ty) =
695 ty.display_source_code(sema.db, scope.module().into(), false)
696 else {
697 continue;
698 };
699 ty.insert(0, '<');
700 ty.push('>');
701 ty
702 }
703 }
704 }
705 _ => continue,
706 };
707
708 let Some(macro_mapped_self) = sema.original_range_opt(self_arg.syntax()) else {
709 continue;
710 };
711 let mut replacement = String::new();
712 replacement.push_str(&fn_container_path);
713 replacement.push_str("::");
714 format_to!(replacement, "{fn_name}");
715 replacement.push('(');
716 replacement.push_str(match self_adjust {
717 CallReceiverAdjust::Deref => "*",
718 CallReceiverAdjust::Ref => "&",
719 CallReceiverAdjust::RefMut => "&mut ",
720 CallReceiverAdjust::None => "",
721 });
722 if self_needs_parens {
723 replacement.push('(');
724 }
725 replacement.push_str(macro_mapped_self.text(sema.db));
726 if self_needs_parens {
727 replacement.push(')');
728 }
729 if needs_comma {
730 replacement.push_str(", ");
731 }
732
733 source_change.insert_source_edit(
734 replace_range.file_id.file_id(sema.db),
735 TextEdit::replace(replace_range.range, replacement),
736 );
737 }
738 }
739}
740
741fn rename_self_to_param(
742 sema: &Semantics<'_, RootDatabase>,
743 local: hir::Local,
744 self_param: hir::SelfParam,
745 new_name: &Name,
746 identifier_kind: IdentifierKind,
747 find_path_config: FindPathConfig,
748) -> RenameResult<SourceChange> {
749 if identifier_kind == IdentifierKind::LowercaseSelf {
750 cov_mark::hit!(rename_self_to_self);
752 return Ok(SourceChange::default());
753 }
754
755 let fn_def = match local.parent(sema.db) {
756 hir::ExpressionStoreOwner::Body(hir::DefWithBody::Function(func)) => func,
757 _ => bail!("Cannot rename local to self outside of function"),
758 };
759
760 let InFile { file_id, value: self_param } =
761 sema.source(self_param).ok_or_else(|| format_err!("cannot find function source"))?;
762
763 let def = Definition::Local(local);
764 let usages = def.usages(sema).all();
765 let edit = text_edit_from_self_param(
766 &self_param,
767 new_name.display(sema.db, file_id.edition(sema.db)).to_string(),
768 )
769 .ok_or_else(|| format_err!("No target type found"))?;
770 if usages.len() > 1 && identifier_kind == IdentifierKind::Underscore {
771 bail!("Cannot rename reference to `_` as it is being referenced multiple times");
772 }
773 let mut source_change = SourceChange::default();
774 source_change.insert_source_edit(file_id.original_file(sema.db).file_id(sema.db), edit);
775 source_change.extend(usages.iter().map(|(file_id, references)| {
776 (
777 file_id.file_id(sema.db),
778 source_edit_from_references(
779 sema.db,
780 references,
781 def,
782 new_name,
783 file_id.edition(sema.db),
784 ),
785 )
786 }));
787 transform_method_call_into_assoc_fn(sema, &mut source_change, fn_def, find_path_config);
788 Ok(source_change)
789}
790
791fn text_edit_from_self_param(self_param: &ast::SelfParam, new_name: String) -> Option<TextEdit> {
792 let mut replacement_text = new_name;
793 replacement_text.push_str(": ");
794
795 if self_param.amp_token().is_some() {
796 replacement_text.push('&');
797 }
798 if let Some(lifetime) = self_param.lifetime() {
799 write!(replacement_text, "{lifetime} ").unwrap();
800 }
801 if self_param.amp_token().and(self_param.mut_token()).is_some() {
802 replacement_text.push_str("mut ");
803 }
804
805 replacement_text.push_str("Self");
806
807 Some(TextEdit::replace(self_param.syntax().text_range(), replacement_text))
808}
809
810fn rename_elided_lifetime(
811 position: FilePosition,
812 lifetime_token: syntax::SyntaxToken,
813 new_name: &str,
814) -> RenameResult<SourceChange> {
815 let parent = lifetime_token.parent().unwrap();
816 let root = parent.ancestors().last().unwrap();
817
818 let mut builder = SourceChangeBuilder::new(position.file_id);
819
820 let editor = builder.make_editor(&root);
821 let make = editor.make();
822
823 editor.replace(lifetime_token, make.lifetime(new_name).syntax().clone());
824
825 if let Some(has_generic_params) = parent.ancestors().find_map(ast::AnyHasGenericParams::cast) {
826 let lifetime_param = make.lifetime_param(make.lifetime(new_name));
827 editor.add_generic_param(&has_generic_params, lifetime_param.into());
828 }
829
830 builder.add_file_edits(position.file_id, editor);
831
832 Ok(builder.finish())
833}
834
835#[cfg(test)]
836mod tests {
837 use expect_test::{Expect, expect};
838 use ide_db::source_change::SourceChange;
839 use ide_db::text_edit::TextEdit;
840 use itertools::Itertools;
841 use stdx::trim_indent;
842 use test_utils::assert_eq_text;
843
844 use crate::fixture;
845
846 use super::{RangeInfo, RenameConfig, RenameError};
847
848 const TEST_CONFIG: RenameConfig = RenameConfig {
849 prefer_no_std: false,
850 prefer_prelude: true,
851 prefer_absolute: false,
852 show_conflicts: true,
853 };
854
855 #[track_caller]
856 fn check(
857 new_name: &str,
858 #[rust_analyzer::rust_fixture] ra_fixture_before: &str,
859 #[rust_analyzer::rust_fixture] ra_fixture_after: &str,
860 ) {
861 let ra_fixture_after = &trim_indent(ra_fixture_after);
862 let (analysis, position) = fixture::position(ra_fixture_before);
863 if !ra_fixture_after.starts_with("error: ")
864 && let Err(err) = analysis.prepare_rename(position).unwrap()
865 {
866 panic!("Prepare rename to '{new_name}' was failed: {err}")
867 }
868 let rename_result = analysis
869 .rename(position, new_name, &TEST_CONFIG)
870 .unwrap_or_else(|err| panic!("Rename to '{new_name}' was cancelled: {err}"));
871 match rename_result {
872 Ok(source_change) => {
873 let mut text_edit_builder = TextEdit::builder();
874 let (&file_id, edit) = match source_change.source_file_edits.len() {
875 0 => return,
876 1 => source_change.source_file_edits.iter().next().unwrap(),
877 _ => panic!(),
878 };
879 for indel in edit.0.iter() {
880 text_edit_builder.replace(indel.delete, indel.insert.clone());
881 }
882 let mut result = analysis.file_text(file_id).unwrap().to_string();
883 text_edit_builder.finish().apply(&mut result);
884 assert_eq_text!(ra_fixture_after, &*result);
885 }
886 Err(err) => {
887 if ra_fixture_after.starts_with("error:") {
888 let error_message =
889 ra_fixture_after.chars().skip("error:".len()).collect::<String>();
890 assert_eq!(error_message.trim(), err.to_string());
891 } else {
892 panic!("Rename to '{new_name}' failed unexpectedly: {err}")
893 }
894 }
895 };
896 }
897
898 #[track_caller]
899 fn check_conflicts(new_name: &str, #[rust_analyzer::rust_fixture] ra_fixture: &str) {
900 let (analysis, position, conflicts) = fixture::annotations(ra_fixture);
901 let source_change = analysis.rename(position, new_name, &TEST_CONFIG).unwrap().unwrap();
902 let expected_conflicts = conflicts
903 .into_iter()
904 .map(|(file_range, _)| (file_range.file_id, file_range.range))
905 .sorted_unstable_by_key(|(file_id, range)| (*file_id, range.start()))
906 .collect_vec();
907 let found_conflicts = source_change
908 .source_file_edits
909 .iter()
910 .filter(|(_, (edit, _))| edit.change_annotation().is_some())
911 .flat_map(|(file_id, (edit, _))| {
912 edit.into_iter().map(move |edit| (*file_id, edit.delete))
913 })
914 .sorted_unstable_by_key(|(file_id, range)| (*file_id, range.start()))
915 .collect_vec();
916 assert_eq!(
917 expected_conflicts, found_conflicts,
918 "rename conflicts mismatch: {source_change:#?}"
919 );
920 }
921
922 fn check_expect(
923 new_name: &str,
924 #[rust_analyzer::rust_fixture] ra_fixture: &str,
925 expect: Expect,
926 ) {
927 let (analysis, position) = fixture::position(ra_fixture);
928 let source_change = analysis
929 .rename(position, new_name, &TEST_CONFIG)
930 .unwrap()
931 .expect("Expect returned a RenameError");
932 expect.assert_eq(&filter_expect(source_change))
933 }
934
935 fn check_expect_will_rename_file(
936 new_name: &str,
937 #[rust_analyzer::rust_fixture] ra_fixture: &str,
938 expect: Expect,
939 ) {
940 let (analysis, position) = fixture::position(ra_fixture);
941 let source_change = analysis
942 .will_rename_file(position.file_id, new_name, &TEST_CONFIG)
943 .unwrap()
944 .expect("Expect returned a RenameError");
945 expect.assert_eq(&filter_expect(source_change))
946 }
947
948 fn check_prepare(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) {
949 let (analysis, position) = fixture::position(ra_fixture);
950 let result = analysis
951 .prepare_rename(position)
952 .unwrap_or_else(|err| panic!("PrepareRename was cancelled: {err}"));
953 match result {
954 Ok(RangeInfo { range, info: () }) => {
955 let source = analysis.file_text(position.file_id).unwrap();
956 expect.assert_eq(&format!("{range:?}: {}", &source[range]))
957 }
958 Err(RenameError(err)) => expect.assert_eq(&err),
959 };
960 }
961
962 fn filter_expect(source_change: SourceChange) -> String {
963 let source_file_edits = source_change
964 .source_file_edits
965 .into_iter()
966 .map(|(id, (text_edit, _))| (id, text_edit.into_iter().collect::<Vec<_>>()))
967 .collect::<Vec<_>>();
968
969 format!(
970 "source_file_edits: {:#?}\nfile_system_edits: {:#?}\n",
971 source_file_edits, source_change.file_system_edits
972 )
973 }
974
975 #[test]
976 fn rename_will_shadow() {
977 check_conflicts(
978 "new_name",
979 r#"
980fn foo() {
981 let mut new_name = 123;
982 let old_name$0 = 456;
983 // ^^^^^^^^
984 new_name = 789 + new_name;
985}
986 "#,
987 );
988 }
989
990 #[test]
991 fn rename_will_be_shadowed() {
992 check_conflicts(
993 "new_name",
994 r#"
995fn foo() {
996 let mut old_name$0 = 456;
997 // ^^^^^^^^
998 let new_name = 123;
999 old_name = 789 + old_name;
1000 // ^^^^^^^^ ^^^^^^^^
1001}
1002 "#,
1003 );
1004 }
1005
1006 #[test]
1007 fn test_prepare_rename_namelikes() {
1008 check_prepare(r"fn name$0<'lifetime>() {}", expect![[r#"3..7: name"#]]);
1009 check_prepare(r"fn name<'lifetime$0>() {}", expect![[r#"9..17: lifetime"#]]);
1010 check_prepare(r"fn name<'lifetime>() { name$0(); }", expect![[r#"23..27: name"#]]);
1011 }
1012
1013 #[test]
1014 fn test_prepare_rename_in_macro() {
1015 check_prepare(
1016 r"macro_rules! foo {
1017 ($ident:ident) => {
1018 pub struct $ident;
1019 }
1020}
1021foo!(Foo$0);",
1022 expect![[r#"83..86: Foo"#]],
1023 );
1024 }
1025
1026 #[test]
1027 fn test_prepare_rename_keyword() {
1028 check_prepare(r"struct$0 Foo;", expect![[r#"No references found at position"#]]);
1029 }
1030
1031 #[test]
1032 fn test_prepare_rename_tuple_field() {
1033 check_prepare(
1034 r#"
1035struct Foo(i32);
1036
1037fn baz() {
1038 let mut x = Foo(4);
1039 x.0$0 = 5;
1040}
1041"#,
1042 expect![[r#"No references found at position"#]],
1043 );
1044 }
1045
1046 #[test]
1047 fn test_prepare_rename_builtin() {
1048 check_prepare(
1049 r#"
1050fn foo() {
1051 let x: i32$0 = 0;
1052}
1053"#,
1054 expect![[r#"No references found at position"#]],
1055 );
1056 }
1057
1058 #[test]
1059 fn test_prepare_rename_self() {
1060 check_prepare(
1061 r#"
1062struct Foo {}
1063
1064impl Foo {
1065 fn foo(self) -> Self$0 {
1066 self
1067 }
1068}
1069"#,
1070 expect![[r#"No references found at position"#]],
1071 );
1072 }
1073
1074 #[test]
1075 fn test_rename_to_underscore() {
1076 check("_", r#"fn main() { let i$0 = 1; }"#, r#"fn main() { let _ = 1; }"#);
1077 }
1078
1079 #[test]
1080 fn test_rename_to_raw_identifier() {
1081 check("r#fn", r#"fn main() { let i$0 = 1; }"#, r#"fn main() { let r#fn = 1; }"#);
1082 }
1083
1084 #[test]
1085 fn test_rename_to_invalid_identifier1() {
1086 check(
1087 "invalid!",
1088 r#"fn main() { let i$0 = 1; }"#,
1089 "error: Invalid name `invalid!`: not an identifier",
1090 );
1091 }
1092
1093 #[test]
1094 fn test_rename_to_invalid_identifier2() {
1095 check(
1096 "multiple tokens",
1097 r#"fn main() { let i$0 = 1; }"#,
1098 "error: Invalid name `multiple tokens`: not an identifier",
1099 );
1100 }
1101
1102 #[test]
1103 fn test_rename_to_invalid_identifier3() {
1104 check(
1105 "super",
1106 r#"fn main() { let i$0 = 1; }"#,
1107 "error: Invalid name `super`: cannot rename to a keyword",
1108 );
1109 }
1110
1111 #[test]
1112 fn test_rename_to_invalid_identifier_lifetime() {
1113 cov_mark::check!(rename_not_an_ident_ref);
1114 check(
1115 "'foo",
1116 r#"fn main() { let i$0 = 1; }"#,
1117 "error: Invalid name `'foo`: not an identifier",
1118 );
1119 }
1120
1121 #[test]
1122 fn test_rename_to_invalid_identifier_lifetime2() {
1123 check(
1124 "_",
1125 r#"fn main<'a>(_: &'a$0 ()) {}"#,
1126 r#"error: Invalid name `_`: not a lifetime identifier"#,
1127 );
1128 }
1129
1130 #[test]
1131 fn test_rename_accepts_lifetime_without_apostrophe() {
1132 check("foo", r#"fn main<'a>(_: &'a$0 ()) {}"#, r#"fn main<'foo>(_: &'foo ()) {}"#);
1133 }
1134
1135 #[test]
1136 fn test_rename_to_underscore_invalid() {
1137 cov_mark::check!(rename_underscore_multiple);
1138 check(
1139 "_",
1140 r#"fn main(foo$0: ()) {foo;}"#,
1141 "error: Cannot rename reference to `_` as it is being referenced multiple times",
1142 );
1143 }
1144
1145 #[test]
1146 fn test_rename_mod_invalid() {
1147 check(
1148 "'foo",
1149 r#"mod foo$0 {}"#,
1150 "error: Invalid name `'foo`: cannot rename module to 'foo",
1151 );
1152 }
1153
1154 #[test]
1155 fn test_rename_mod_invalid_raw_ident() {
1156 check(
1157 "r#self",
1158 r#"mod foo$0 {}"#,
1159 "error: Invalid name `self`: cannot rename module to self",
1160 );
1161 }
1162
1163 #[test]
1164 fn test_rename_for_local() {
1165 check(
1166 "k",
1167 r#"
1168fn main() {
1169 let mut i = 1;
1170 let j = 1;
1171 i = i$0 + j;
1172
1173 { i = 0; }
1174
1175 i = 5;
1176}
1177"#,
1178 r#"
1179fn main() {
1180 let mut k = 1;
1181 let j = 1;
1182 k = k + j;
1183
1184 { k = 0; }
1185
1186 k = 5;
1187}
1188"#,
1189 );
1190 }
1191
1192 #[test]
1193 fn test_rename_unresolved_reference() {
1194 check(
1195 "new_name",
1196 r#"fn main() { let _ = unresolved_ref$0; }"#,
1197 "error: No references found at position",
1198 );
1199 }
1200
1201 #[test]
1202 fn test_rename_macro_multiple_occurrences() {
1203 check(
1204 "Baaah",
1205 r#"macro_rules! foo {
1206 ($ident:ident) => {
1207 const $ident: () = ();
1208 struct $ident {}
1209 };
1210}
1211
1212foo!($0Foo);
1213const _: () = Foo;
1214const _: Foo = Foo {};
1215 "#,
1216 r#"
1217macro_rules! foo {
1218 ($ident:ident) => {
1219 const $ident: () = ();
1220 struct $ident {}
1221 };
1222}
1223
1224foo!(Baaah);
1225const _: () = Baaah;
1226const _: Baaah = Baaah {};
1227 "#,
1228 )
1229 }
1230
1231 #[test]
1232 fn test_rename_for_macro_args() {
1233 check(
1234 "b",
1235 r#"
1236macro_rules! foo {($i:ident) => {$i} }
1237fn main() {
1238 let a$0 = "test";
1239 foo!(a);
1240}
1241"#,
1242 r#"
1243macro_rules! foo {($i:ident) => {$i} }
1244fn main() {
1245 let b = "test";
1246 foo!(b);
1247}
1248"#,
1249 );
1250 }
1251
1252 #[test]
1253 fn test_rename_for_macro_args_rev() {
1254 check(
1255 "b",
1256 r#"
1257macro_rules! foo {($i:ident) => {$i} }
1258fn main() {
1259 let a = "test";
1260 foo!(a$0);
1261}
1262"#,
1263 r#"
1264macro_rules! foo {($i:ident) => {$i} }
1265fn main() {
1266 let b = "test";
1267 foo!(b);
1268}
1269"#,
1270 );
1271 }
1272
1273 #[test]
1274 fn test_rename_for_macro_define_fn() {
1275 check(
1276 "bar",
1277 r#"
1278macro_rules! define_fn {($id:ident) => { fn $id{} }}
1279define_fn!(foo);
1280fn main() {
1281 fo$0o();
1282}
1283"#,
1284 r#"
1285macro_rules! define_fn {($id:ident) => { fn $id{} }}
1286define_fn!(bar);
1287fn main() {
1288 bar();
1289}
1290"#,
1291 );
1292 }
1293
1294 #[test]
1295 fn test_rename_for_macro_define_fn_rev() {
1296 check(
1297 "bar",
1298 r#"
1299macro_rules! define_fn {($id:ident) => { fn $id{} }}
1300define_fn!(fo$0o);
1301fn main() {
1302 foo();
1303}
1304"#,
1305 r#"
1306macro_rules! define_fn {($id:ident) => { fn $id{} }}
1307define_fn!(bar);
1308fn main() {
1309 bar();
1310}
1311"#,
1312 );
1313 }
1314
1315 #[test]
1316 fn test_rename_for_param_inside() {
1317 check("j", r#"fn foo(i : u32) -> u32 { i$0 }"#, r#"fn foo(j : u32) -> u32 { j }"#);
1318 }
1319
1320 #[test]
1321 fn test_rename_refs_for_fn_param() {
1322 check("j", r#"fn foo(i$0 : u32) -> u32 { i }"#, r#"fn foo(j : u32) -> u32 { j }"#);
1323 }
1324
1325 #[test]
1326 fn test_rename_for_mut_param() {
1327 check("j", r#"fn foo(mut i$0 : u32) -> u32 { i }"#, r#"fn foo(mut j : u32) -> u32 { j }"#);
1328 }
1329
1330 #[test]
1331 fn test_rename_struct_field() {
1332 check(
1333 "foo",
1334 r#"
1335struct Foo { field$0: i32 }
1336
1337impl Foo {
1338 fn new(i: i32) -> Self {
1339 Self { field: i }
1340 }
1341}
1342"#,
1343 r#"
1344struct Foo { foo: i32 }
1345
1346impl Foo {
1347 fn new(i: i32) -> Self {
1348 Self { foo: i }
1349 }
1350}
1351"#,
1352 );
1353 }
1354
1355 #[test]
1356 fn test_rename_field_in_field_shorthand() {
1357 cov_mark::check!(test_rename_field_in_field_shorthand);
1358 check(
1359 "field",
1360 r#"
1361struct Foo { foo$0: i32 }
1362
1363impl Foo {
1364 fn foo(foo: i32) {
1365 Self { foo };
1366 }
1367}
1368"#,
1369 r#"
1370struct Foo { field: i32 }
1371
1372impl Foo {
1373 fn foo(foo: i32) {
1374 Self { field: foo };
1375 }
1376}
1377"#,
1378 );
1379 }
1380
1381 #[test]
1382 fn test_rename_local_in_field_shorthand() {
1383 cov_mark::check!(test_rename_local_in_field_shorthand);
1384 check(
1385 "j",
1386 r#"
1387struct Foo { i: i32 }
1388
1389impl Foo {
1390 fn new(i$0: i32) -> Self {
1391 Self { i }
1392 }
1393}
1394"#,
1395 r#"
1396struct Foo { i: i32 }
1397
1398impl Foo {
1399 fn new(j: i32) -> Self {
1400 Self { i: j }
1401 }
1402}
1403"#,
1404 );
1405 }
1406
1407 #[test]
1408 fn test_field_shorthand_correct_struct() {
1409 check(
1410 "j",
1411 r#"
1412struct Foo { i$0: i32 }
1413struct Bar { i: i32 }
1414
1415impl Bar {
1416 fn new(i: i32) -> Self {
1417 Self { i }
1418 }
1419}
1420"#,
1421 r#"
1422struct Foo { j: i32 }
1423struct Bar { i: i32 }
1424
1425impl Bar {
1426 fn new(i: i32) -> Self {
1427 Self { i }
1428 }
1429}
1430"#,
1431 );
1432 }
1433
1434 #[test]
1435 fn test_shadow_local_for_struct_shorthand() {
1436 check(
1437 "j",
1438 r#"
1439struct Foo { i: i32 }
1440
1441fn baz(i$0: i32) -> Self {
1442 let x = Foo { i };
1443 {
1444 let i = 0;
1445 Foo { i }
1446 }
1447}
1448"#,
1449 r#"
1450struct Foo { i: i32 }
1451
1452fn baz(j: i32) -> Self {
1453 let x = Foo { i: j };
1454 {
1455 let i = 0;
1456 Foo { i }
1457 }
1458}
1459"#,
1460 );
1461 }
1462
1463 #[test]
1464 fn test_rename_mod() {
1465 check_expect(
1466 "foo2",
1467 r#"
1468//- /lib.rs
1469mod bar;
1470
1471//- /bar.rs
1472mod foo$0;
1473
1474//- /bar/foo.rs
1475// empty
1476"#,
1477 expect![[r#"
1478 source_file_edits: [
1479 (
1480 FileId(
1481 1,
1482 ),
1483 [
1484 Indel {
1485 insert: "foo2",
1486 delete: 4..7,
1487 },
1488 ],
1489 ),
1490 ]
1491 file_system_edits: [
1492 MoveFile {
1493 src: FileId(
1494 2,
1495 ),
1496 dst: AnchoredPathBuf {
1497 anchor: FileId(
1498 2,
1499 ),
1500 path: "foo2.rs",
1501 },
1502 },
1503 ]
1504 "#]],
1505 );
1506 }
1507
1508 #[test]
1509 fn test_rename_mod_in_use_tree() {
1510 check_expect(
1511 "quux",
1512 r#"
1513//- /main.rs
1514pub mod foo;
1515pub mod bar;
1516fn main() {}
1517
1518//- /foo.rs
1519pub struct FooContent;
1520
1521//- /bar.rs
1522use crate::foo$0::FooContent;
1523"#,
1524 expect![[r#"
1525 source_file_edits: [
1526 (
1527 FileId(
1528 0,
1529 ),
1530 [
1531 Indel {
1532 insert: "quux",
1533 delete: 8..11,
1534 },
1535 ],
1536 ),
1537 (
1538 FileId(
1539 2,
1540 ),
1541 [
1542 Indel {
1543 insert: "quux",
1544 delete: 11..14,
1545 },
1546 ],
1547 ),
1548 ]
1549 file_system_edits: [
1550 MoveFile {
1551 src: FileId(
1552 1,
1553 ),
1554 dst: AnchoredPathBuf {
1555 anchor: FileId(
1556 1,
1557 ),
1558 path: "quux.rs",
1559 },
1560 },
1561 ]
1562 "#]],
1563 );
1564 }
1565
1566 #[test]
1567 fn test_rename_mod_in_dir() {
1568 check_expect(
1569 "foo2",
1570 r#"
1571//- /lib.rs
1572mod fo$0o;
1573//- /foo/mod.rs
1574// empty
1575"#,
1576 expect![[r#"
1577 source_file_edits: [
1578 (
1579 FileId(
1580 0,
1581 ),
1582 [
1583 Indel {
1584 insert: "foo2",
1585 delete: 4..7,
1586 },
1587 ],
1588 ),
1589 ]
1590 file_system_edits: [
1591 MoveDir {
1592 src: AnchoredPathBuf {
1593 anchor: FileId(
1594 1,
1595 ),
1596 path: "../foo",
1597 },
1598 src_id: FileId(
1599 1,
1600 ),
1601 dst: AnchoredPathBuf {
1602 anchor: FileId(
1603 1,
1604 ),
1605 path: "../foo2",
1606 },
1607 },
1608 ]
1609 "#]],
1610 );
1611 }
1612
1613 #[test]
1614 fn test_rename_unusually_nested_mod() {
1615 check_expect(
1616 "bar",
1617 r#"
1618//- /lib.rs
1619mod outer { mod fo$0o; }
1620
1621//- /outer/foo.rs
1622// empty
1623"#,
1624 expect![[r#"
1625 source_file_edits: [
1626 (
1627 FileId(
1628 0,
1629 ),
1630 [
1631 Indel {
1632 insert: "bar",
1633 delete: 16..19,
1634 },
1635 ],
1636 ),
1637 ]
1638 file_system_edits: [
1639 MoveFile {
1640 src: FileId(
1641 1,
1642 ),
1643 dst: AnchoredPathBuf {
1644 anchor: FileId(
1645 1,
1646 ),
1647 path: "bar.rs",
1648 },
1649 },
1650 ]
1651 "#]],
1652 );
1653 }
1654
1655 #[test]
1656 fn test_module_rename_in_path() {
1657 check(
1658 "baz",
1659 r#"
1660mod $0foo {
1661 pub use self::bar as qux;
1662 pub fn bar() {}
1663}
1664
1665fn main() { foo::bar(); }
1666"#,
1667 r#"
1668mod baz {
1669 pub use self::bar as qux;
1670 pub fn bar() {}
1671}
1672
1673fn main() { baz::bar(); }
1674"#,
1675 );
1676 }
1677
1678 #[test]
1679 fn test_rename_mod_filename_and_path() {
1680 check_expect(
1681 "foo2",
1682 r#"
1683//- /lib.rs
1684mod bar;
1685fn f() {
1686 bar::foo::fun()
1687}
1688
1689//- /bar.rs
1690pub mod foo$0;
1691
1692//- /bar/foo.rs
1693// pub fn fun() {}
1694"#,
1695 expect![[r#"
1696 source_file_edits: [
1697 (
1698 FileId(
1699 0,
1700 ),
1701 [
1702 Indel {
1703 insert: "foo2",
1704 delete: 27..30,
1705 },
1706 ],
1707 ),
1708 (
1709 FileId(
1710 1,
1711 ),
1712 [
1713 Indel {
1714 insert: "foo2",
1715 delete: 8..11,
1716 },
1717 ],
1718 ),
1719 ]
1720 file_system_edits: [
1721 MoveFile {
1722 src: FileId(
1723 2,
1724 ),
1725 dst: AnchoredPathBuf {
1726 anchor: FileId(
1727 2,
1728 ),
1729 path: "foo2.rs",
1730 },
1731 },
1732 ]
1733 "#]],
1734 );
1735 }
1736
1737 #[test]
1738 fn test_rename_mod_recursive() {
1739 check_expect(
1740 "foo2",
1741 r#"
1742//- /lib.rs
1743mod foo$0;
1744
1745//- /foo.rs
1746mod bar;
1747mod corge;
1748
1749//- /foo/bar.rs
1750mod qux;
1751
1752//- /foo/bar/qux.rs
1753mod quux;
1754
1755//- /foo/bar/qux/quux/mod.rs
1756// empty
1757
1758//- /foo/corge.rs
1759// empty
1760"#,
1761 expect![[r#"
1762 source_file_edits: [
1763 (
1764 FileId(
1765 0,
1766 ),
1767 [
1768 Indel {
1769 insert: "foo2",
1770 delete: 4..7,
1771 },
1772 ],
1773 ),
1774 ]
1775 file_system_edits: [
1776 MoveFile {
1777 src: FileId(
1778 1,
1779 ),
1780 dst: AnchoredPathBuf {
1781 anchor: FileId(
1782 1,
1783 ),
1784 path: "foo2.rs",
1785 },
1786 },
1787 MoveDir {
1788 src: AnchoredPathBuf {
1789 anchor: FileId(
1790 1,
1791 ),
1792 path: "foo",
1793 },
1794 src_id: FileId(
1795 1,
1796 ),
1797 dst: AnchoredPathBuf {
1798 anchor: FileId(
1799 1,
1800 ),
1801 path: "foo2",
1802 },
1803 },
1804 ]
1805 "#]],
1806 )
1807 }
1808 #[test]
1809 fn test_rename_mod_ref_by_super() {
1810 check(
1811 "baz",
1812 r#"
1813 mod $0foo {
1814 struct X;
1815
1816 mod bar {
1817 use super::X;
1818 }
1819 }
1820 "#,
1821 r#"
1822 mod baz {
1823 struct X;
1824
1825 mod bar {
1826 use super::X;
1827 }
1828 }
1829 "#,
1830 )
1831 }
1832
1833 #[test]
1834 fn test_rename_mod_in_macro() {
1835 check(
1836 "bar",
1837 r#"
1838//- /foo.rs
1839
1840//- /lib.rs
1841macro_rules! submodule {
1842 ($name:ident) => {
1843 mod $name;
1844 };
1845}
1846
1847submodule!($0foo);
1848"#,
1849 r#"
1850macro_rules! submodule {
1851 ($name:ident) => {
1852 mod $name;
1853 };
1854}
1855
1856submodule!(bar);
1857"#,
1858 )
1859 }
1860
1861 #[test]
1862 fn test_rename_mod_for_crate_root() {
1863 check_expect_will_rename_file(
1864 "main",
1865 r#"
1866//- /lib.rs
1867use crate::foo as bar;
1868fn foo() {}
1869mod bar$0;
1870"#,
1871 expect![[r#"
1872 source_file_edits: []
1873 file_system_edits: []
1874 "#]],
1875 )
1876 }
1877
1878 #[test]
1879 fn test_rename_mod_to_raw_ident() {
1880 check_expect(
1881 "r#fn",
1882 r#"
1883//- /lib.rs
1884mod foo$0;
1885
1886fn main() { foo::bar::baz(); }
1887
1888//- /foo.rs
1889pub mod bar;
1890
1891//- /foo/bar.rs
1892pub fn baz() {}
1893"#,
1894 expect![[r#"
1895 source_file_edits: [
1896 (
1897 FileId(
1898 0,
1899 ),
1900 [
1901 Indel {
1902 insert: "r#fn",
1903 delete: 4..7,
1904 },
1905 Indel {
1906 insert: "r#fn",
1907 delete: 22..25,
1908 },
1909 ],
1910 ),
1911 ]
1912 file_system_edits: [
1913 MoveFile {
1914 src: FileId(
1915 1,
1916 ),
1917 dst: AnchoredPathBuf {
1918 anchor: FileId(
1919 1,
1920 ),
1921 path: "fn.rs",
1922 },
1923 },
1924 MoveDir {
1925 src: AnchoredPathBuf {
1926 anchor: FileId(
1927 1,
1928 ),
1929 path: "foo",
1930 },
1931 src_id: FileId(
1932 1,
1933 ),
1934 dst: AnchoredPathBuf {
1935 anchor: FileId(
1936 1,
1937 ),
1938 path: "fn",
1939 },
1940 },
1941 ]
1942 "#]],
1943 );
1944 }
1945
1946 #[test]
1947 fn test_rename_mod_from_raw_ident() {
1948 check_expect(
1949 "foo",
1950 r#"
1951//- /lib.rs
1952mod r#fn$0;
1953
1954fn main() { r#fn::bar::baz(); }
1955
1956//- /fn.rs
1957pub mod bar;
1958
1959//- /fn/bar.rs
1960pub fn baz() {}
1961"#,
1962 expect![[r#"
1963 source_file_edits: [
1964 (
1965 FileId(
1966 0,
1967 ),
1968 [
1969 Indel {
1970 insert: "foo",
1971 delete: 4..8,
1972 },
1973 Indel {
1974 insert: "foo",
1975 delete: 23..27,
1976 },
1977 ],
1978 ),
1979 ]
1980 file_system_edits: [
1981 MoveFile {
1982 src: FileId(
1983 1,
1984 ),
1985 dst: AnchoredPathBuf {
1986 anchor: FileId(
1987 1,
1988 ),
1989 path: "foo.rs",
1990 },
1991 },
1992 MoveDir {
1993 src: AnchoredPathBuf {
1994 anchor: FileId(
1995 1,
1996 ),
1997 path: "fn",
1998 },
1999 src_id: FileId(
2000 1,
2001 ),
2002 dst: AnchoredPathBuf {
2003 anchor: FileId(
2004 1,
2005 ),
2006 path: "foo",
2007 },
2008 },
2009 ]
2010 "#]],
2011 );
2012 }
2013
2014 #[test]
2015 fn test_rename_each_usage_gets_appropriate_rawness() {
2016 check_expect(
2017 "dyn",
2018 r#"
2019//- /a.rs crate:a edition:2015
2020pub fn foo() {}
2021
2022//- /b.rs crate:b edition:2018 deps:a new_source_root:local
2023fn bar() {
2024 a::foo$0();
2025}
2026 "#,
2027 expect![[r#"
2028 source_file_edits: [
2029 (
2030 FileId(
2031 0,
2032 ),
2033 [
2034 Indel {
2035 insert: "dyn",
2036 delete: 7..10,
2037 },
2038 ],
2039 ),
2040 (
2041 FileId(
2042 1,
2043 ),
2044 [
2045 Indel {
2046 insert: "r#dyn",
2047 delete: 18..21,
2048 },
2049 ],
2050 ),
2051 ]
2052 file_system_edits: []
2053 "#]],
2054 );
2055
2056 check_expect(
2057 "dyn",
2058 r#"
2059//- /a.rs crate:a edition:2018
2060pub fn foo() {}
2061
2062//- /b.rs crate:b edition:2015 deps:a new_source_root:local
2063fn bar() {
2064 a::foo$0();
2065}
2066 "#,
2067 expect![[r#"
2068 source_file_edits: [
2069 (
2070 FileId(
2071 0,
2072 ),
2073 [
2074 Indel {
2075 insert: "r#dyn",
2076 delete: 7..10,
2077 },
2078 ],
2079 ),
2080 (
2081 FileId(
2082 1,
2083 ),
2084 [
2085 Indel {
2086 insert: "dyn",
2087 delete: 18..21,
2088 },
2089 ],
2090 ),
2091 ]
2092 file_system_edits: []
2093 "#]],
2094 );
2095
2096 check_expect(
2097 "r#dyn",
2098 r#"
2099//- /a.rs crate:a edition:2018
2100pub fn foo$0() {}
2101
2102//- /b.rs crate:b edition:2015 deps:a new_source_root:local
2103fn bar() {
2104 a::foo();
2105}
2106 "#,
2107 expect![[r#"
2108 source_file_edits: [
2109 (
2110 FileId(
2111 0,
2112 ),
2113 [
2114 Indel {
2115 insert: "r#dyn",
2116 delete: 7..10,
2117 },
2118 ],
2119 ),
2120 (
2121 FileId(
2122 1,
2123 ),
2124 [
2125 Indel {
2126 insert: "dyn",
2127 delete: 18..21,
2128 },
2129 ],
2130 ),
2131 ]
2132 file_system_edits: []
2133 "#]],
2134 );
2135 }
2136
2137 #[test]
2138 fn rename_raw_identifier() {
2139 check_expect(
2140 "abc",
2141 r#"
2142//- /a.rs crate:a edition:2015
2143pub fn dyn() {}
2144
2145fn foo() {
2146 dyn$0();
2147}
2148
2149//- /b.rs crate:b edition:2018 deps:a new_source_root:local
2150fn bar() {
2151 a::r#dyn();
2152}
2153 "#,
2154 expect![[r#"
2155 source_file_edits: [
2156 (
2157 FileId(
2158 0,
2159 ),
2160 [
2161 Indel {
2162 insert: "abc",
2163 delete: 7..10,
2164 },
2165 Indel {
2166 insert: "abc",
2167 delete: 32..35,
2168 },
2169 ],
2170 ),
2171 (
2172 FileId(
2173 1,
2174 ),
2175 [
2176 Indel {
2177 insert: "abc",
2178 delete: 18..23,
2179 },
2180 ],
2181 ),
2182 ]
2183 file_system_edits: []
2184 "#]],
2185 );
2186
2187 check_expect(
2188 "abc",
2189 r#"
2190//- /a.rs crate:a edition:2018
2191pub fn r#dyn() {}
2192
2193fn foo() {
2194 r#dyn$0();
2195}
2196
2197//- /b.rs crate:b edition:2015 deps:a new_source_root:local
2198fn bar() {
2199 a::dyn();
2200}
2201 "#,
2202 expect![[r#"
2203 source_file_edits: [
2204 (
2205 FileId(
2206 0,
2207 ),
2208 [
2209 Indel {
2210 insert: "abc",
2211 delete: 7..12,
2212 },
2213 Indel {
2214 insert: "abc",
2215 delete: 34..39,
2216 },
2217 ],
2218 ),
2219 (
2220 FileId(
2221 1,
2222 ),
2223 [
2224 Indel {
2225 insert: "abc",
2226 delete: 18..21,
2227 },
2228 ],
2229 ),
2230 ]
2231 file_system_edits: []
2232 "#]],
2233 );
2234 }
2235
2236 #[test]
2237 fn test_enum_variant_from_module_1() {
2238 cov_mark::check!(rename_non_local);
2239 check(
2240 "Baz",
2241 r#"
2242mod foo {
2243 pub enum Foo { Bar$0 }
2244}
2245
2246fn func(f: foo::Foo) {
2247 match f {
2248 foo::Foo::Bar => {}
2249 }
2250}
2251"#,
2252 r#"
2253mod foo {
2254 pub enum Foo { Baz }
2255}
2256
2257fn func(f: foo::Foo) {
2258 match f {
2259 foo::Foo::Baz => {}
2260 }
2261}
2262"#,
2263 );
2264 }
2265
2266 #[test]
2267 fn test_enum_variant_from_module_2() {
2268 check(
2269 "baz",
2270 r#"
2271mod foo {
2272 pub struct Foo { pub bar$0: uint }
2273}
2274
2275fn foo(f: foo::Foo) {
2276 let _ = f.bar;
2277}
2278"#,
2279 r#"
2280mod foo {
2281 pub struct Foo { pub baz: uint }
2282}
2283
2284fn foo(f: foo::Foo) {
2285 let _ = f.baz;
2286}
2287"#,
2288 );
2289 }
2290
2291 #[test]
2292 fn test_parameter_to_self() {
2293 cov_mark::check!(rename_to_self);
2294 check(
2295 "self",
2296 r#"
2297struct Foo { i: i32 }
2298
2299impl Foo {
2300 fn f(foo$0: &mut Foo) -> i32 {
2301 foo.i
2302 }
2303}
2304"#,
2305 r#"
2306struct Foo { i: i32 }
2307
2308impl Foo {
2309 fn f(&mut self) -> i32 {
2310 self.i
2311 }
2312}
2313"#,
2314 );
2315 check(
2316 "self",
2317 r#"
2318struct Foo { i: i32 }
2319
2320impl Foo {
2321 fn f(foo$0: Foo) -> i32 {
2322 foo.i
2323 }
2324}
2325"#,
2326 r#"
2327struct Foo { i: i32 }
2328
2329impl Foo {
2330 fn f(self) -> i32 {
2331 self.i
2332 }
2333}
2334"#,
2335 );
2336 }
2337
2338 #[test]
2339 fn test_parameter_to_self_error_no_impl() {
2340 check(
2341 "self",
2342 r#"
2343struct Foo { i: i32 }
2344
2345fn f(foo$0: &mut Foo) -> i32 {
2346 foo.i
2347}
2348"#,
2349 "error: Cannot rename parameter to self for free function",
2350 );
2351 check(
2352 "self",
2353 r#"
2354struct Foo { i: i32 }
2355struct Bar;
2356
2357impl Bar {
2358 fn f(foo$0: &mut Foo) -> i32 {
2359 foo.i
2360 }
2361}
2362"#,
2363 "error: Parameter type differs from impl block type",
2364 );
2365 }
2366
2367 #[test]
2368 fn test_parameter_to_self_error_not_first() {
2369 check(
2370 "self",
2371 r#"
2372struct Foo { i: i32 }
2373impl Foo {
2374 fn f(x: (), foo$0: &mut Foo) -> i32 {
2375 foo.i
2376 }
2377}
2378"#,
2379 "error: Only the first parameter may be renamed to self",
2380 );
2381 }
2382
2383 #[test]
2384 fn test_parameter_to_self_impl_ref() {
2385 check(
2386 "self",
2387 r#"
2388struct Foo { i: i32 }
2389impl &Foo {
2390 fn f(foo$0: &Foo) -> i32 {
2391 foo.i
2392 }
2393}
2394"#,
2395 r#"
2396struct Foo { i: i32 }
2397impl &Foo {
2398 fn f(self) -> i32 {
2399 self.i
2400 }
2401}
2402"#,
2403 );
2404 }
2405
2406 #[test]
2407 fn test_self_to_parameter() {
2408 check(
2409 "foo",
2410 r#"
2411struct Foo { i: i32 }
2412
2413impl Foo {
2414 fn f(&mut $0self) -> i32 {
2415 self.i
2416 }
2417}
2418"#,
2419 r#"
2420struct Foo { i: i32 }
2421
2422impl Foo {
2423 fn f(foo: &mut Self) -> i32 {
2424 foo.i
2425 }
2426}
2427"#,
2428 );
2429 }
2430
2431 #[test]
2432 fn test_owned_self_to_parameter() {
2433 cov_mark::check!(rename_self_to_param);
2434 check(
2435 "foo",
2436 r#"
2437struct Foo { i: i32 }
2438
2439impl Foo {
2440 fn f($0self) -> i32 {
2441 self.i
2442 }
2443}
2444"#,
2445 r#"
2446struct Foo { i: i32 }
2447
2448impl Foo {
2449 fn f(foo: Self) -> i32 {
2450 foo.i
2451 }
2452}
2453"#,
2454 );
2455 }
2456
2457 #[test]
2458 fn test_owned_self_to_parameter_with_lifetime() {
2459 cov_mark::check!(rename_self_to_param);
2460 check(
2461 "foo",
2462 r#"
2463struct Foo<'a> { i: &'a i32 }
2464
2465impl<'a> Foo<'a> {
2466 fn f(&'a $0self) -> i32 {
2467 self.i
2468 }
2469}
2470"#,
2471 r#"
2472struct Foo<'a> { i: &'a i32 }
2473
2474impl<'a> Foo<'a> {
2475 fn f(foo: &'a Self) -> i32 {
2476 foo.i
2477 }
2478}
2479"#,
2480 );
2481 }
2482
2483 #[test]
2484 fn test_self_outside_of_methods() {
2485 check(
2486 "foo",
2487 r#"
2488fn f($0self) -> i32 {
2489 self.i
2490}
2491"#,
2492 r#"
2493fn f(foo: Self) -> i32 {
2494 foo.i
2495}
2496"#,
2497 );
2498 }
2499
2500 #[test]
2501 fn no_type_value_ns_confuse() {
2502 check(
2504 "bar",
2505 r#"
2506struct foo {}
2507fn f(foo$0: i32) -> i32 {
2508 use foo as _;
2509}
2510"#,
2511 r#"
2512struct foo {}
2513fn f(bar: i32) -> i32 {
2514 use foo as _;
2515}
2516"#,
2517 );
2518 }
2519
2520 #[test]
2521 fn test_self_in_path_to_parameter() {
2522 check(
2523 "foo",
2524 r#"
2525struct Foo { i: i32 }
2526
2527impl Foo {
2528 fn f(&self) -> i32 {
2529 let self_var = 1;
2530 self$0.i
2531 }
2532}
2533"#,
2534 r#"
2535struct Foo { i: i32 }
2536
2537impl Foo {
2538 fn f(foo: &Self) -> i32 {
2539 let self_var = 1;
2540 foo.i
2541 }
2542}
2543"#,
2544 );
2545 }
2546
2547 #[test]
2548 fn test_rename_field_put_init_shorthand() {
2549 cov_mark::check!(test_rename_field_put_init_shorthand);
2550 check(
2551 "bar",
2552 r#"
2553struct Foo { i$0: i32 }
2554
2555fn foo(bar: i32) -> Foo {
2556 Foo { i: bar }
2557}
2558"#,
2559 r#"
2560struct Foo { bar: i32 }
2561
2562fn foo(bar: i32) -> Foo {
2563 Foo { bar }
2564}
2565"#,
2566 );
2567 }
2568
2569 #[test]
2570 fn test_rename_local_simple() {
2571 check(
2572 "i",
2573 r#"
2574fn foo(bar$0: i32) -> i32 {
2575 bar
2576}
2577"#,
2578 r#"
2579fn foo(i: i32) -> i32 {
2580 i
2581}
2582"#,
2583 );
2584 }
2585
2586 #[test]
2587 fn test_rename_local_put_init_shorthand() {
2588 cov_mark::check!(test_rename_local_put_init_shorthand);
2589 check(
2590 "i",
2591 r#"
2592struct Foo { i: i32 }
2593
2594fn foo(bar$0: i32) -> Foo {
2595 Foo { i: bar }
2596}
2597"#,
2598 r#"
2599struct Foo { i: i32 }
2600
2601fn foo(i: i32) -> Foo {
2602 Foo { i }
2603}
2604"#,
2605 );
2606 }
2607
2608 #[test]
2609 fn test_struct_field_pat_into_shorthand() {
2610 cov_mark::check!(test_rename_field_put_init_shorthand_pat);
2611 check(
2612 "baz",
2613 r#"
2614struct Foo { i$0: i32 }
2615
2616fn foo(foo: Foo) {
2617 let Foo { i: ref baz @ qux } = foo;
2618 let _ = qux;
2619}
2620"#,
2621 r#"
2622struct Foo { baz: i32 }
2623
2624fn foo(foo: Foo) {
2625 let Foo { baz: ref baz @ qux } = foo;
2626 let _ = qux;
2627}
2628"#,
2629 );
2630 check(
2631 "baz",
2632 r#"
2633struct Foo { i$0: i32 }
2634
2635fn foo(foo: Foo) {
2636 let Foo { i: ref baz } = foo;
2637 let _ = qux;
2638}
2639"#,
2640 r#"
2641struct Foo { baz: i32 }
2642
2643fn foo(foo: Foo) {
2644 let Foo { ref baz } = foo;
2645 let _ = qux;
2646}
2647"#,
2648 );
2649 }
2650
2651 #[test]
2652 fn test_struct_local_pat_into_shorthand() {
2653 cov_mark::check!(test_rename_local_put_init_shorthand_pat);
2654 check(
2655 "field",
2656 r#"
2657struct Foo { field: i32 }
2658
2659fn foo(foo: Foo) {
2660 let Foo { field: qux$0 } = foo;
2661 let _ = qux;
2662}
2663"#,
2664 r#"
2665struct Foo { field: i32 }
2666
2667fn foo(foo: Foo) {
2668 let Foo { field } = foo;
2669 let _ = field;
2670}
2671"#,
2672 );
2673 check(
2674 "field",
2675 r#"
2676struct Foo { field: i32 }
2677
2678fn foo(foo: Foo) {
2679 let Foo { field: x @ qux$0 } = foo;
2680 let _ = qux;
2681}
2682"#,
2683 r#"
2684struct Foo { field: i32 }
2685
2686fn foo(foo: Foo) {
2687 let Foo { field: x @ field } = foo;
2688 let _ = field;
2689}
2690"#,
2691 );
2692 }
2693
2694 #[test]
2695 fn test_rename_binding_in_destructure_pat() {
2696 let expected_fixture = r#"
2697struct Foo {
2698 i: i32,
2699}
2700
2701fn foo(foo: Foo) {
2702 let Foo { i: bar } = foo;
2703 let _ = bar;
2704}
2705"#;
2706 check(
2707 "bar",
2708 r#"
2709struct Foo {
2710 i: i32,
2711}
2712
2713fn foo(foo: Foo) {
2714 let Foo { i: b } = foo;
2715 let _ = b$0;
2716}
2717"#,
2718 expected_fixture,
2719 );
2720 check(
2721 "bar",
2722 r#"
2723struct Foo {
2724 i: i32,
2725}
2726
2727fn foo(foo: Foo) {
2728 let Foo { i } = foo;
2729 let _ = i$0;
2730}
2731"#,
2732 expected_fixture,
2733 );
2734 }
2735
2736 #[test]
2737 fn test_rename_binding_in_destructure_param_pat() {
2738 check(
2739 "bar",
2740 r#"
2741struct Foo {
2742 i: i32
2743}
2744
2745fn foo(Foo { i }: Foo) -> i32 {
2746 i$0
2747}
2748"#,
2749 r#"
2750struct Foo {
2751 i: i32
2752}
2753
2754fn foo(Foo { i: bar }: Foo) -> i32 {
2755 bar
2756}
2757"#,
2758 )
2759 }
2760
2761 #[test]
2762 fn test_struct_field_complex_ident_pat() {
2763 cov_mark::check!(rename_record_pat_field_name_split);
2764 check(
2765 "baz",
2766 r#"
2767struct Foo { i$0: i32 }
2768
2769fn foo(foo: Foo) {
2770 let Foo { ref i } = foo;
2771}
2772"#,
2773 r#"
2774struct Foo { baz: i32 }
2775
2776fn foo(foo: Foo) {
2777 let Foo { baz: ref i } = foo;
2778}
2779"#,
2780 );
2781 }
2782
2783 #[test]
2784 fn test_rename_lifetimes() {
2785 check(
2786 "'yeeee",
2787 r#"
2788trait Foo<'a> {
2789 fn foo() -> &'a ();
2790}
2791impl<'a> Foo<'a> for &'a () {
2792 fn foo() -> &'a$0 () {
2793 unimplemented!()
2794 }
2795}
2796"#,
2797 r#"
2798trait Foo<'a> {
2799 fn foo() -> &'a ();
2800}
2801impl<'yeeee> Foo<'yeeee> for &'yeeee () {
2802 fn foo() -> &'yeeee () {
2803 unimplemented!()
2804 }
2805}
2806"#,
2807 )
2808 }
2809
2810 #[test]
2811 fn test_rename_bind_pat() {
2812 check(
2813 "new_name",
2814 r#"
2815fn main() {
2816 enum CustomOption<T> {
2817 None,
2818 Some(T),
2819 }
2820
2821 let test_variable = CustomOption::Some(22);
2822
2823 match test_variable {
2824 CustomOption::Some(foo$0) if foo == 11 => {}
2825 _ => (),
2826 }
2827}"#,
2828 r#"
2829fn main() {
2830 enum CustomOption<T> {
2831 None,
2832 Some(T),
2833 }
2834
2835 let test_variable = CustomOption::Some(22);
2836
2837 match test_variable {
2838 CustomOption::Some(new_name) if new_name == 11 => {}
2839 _ => (),
2840 }
2841}"#,
2842 );
2843 }
2844
2845 #[test]
2846 fn test_rename_label() {
2847 check(
2848 "'foo",
2849 r#"
2850fn foo<'a>() -> &'a () {
2851 'a: {
2852 'b: loop {
2853 break 'a$0;
2854 }
2855 }
2856}
2857"#,
2858 r#"
2859fn foo<'a>() -> &'a () {
2860 'foo: {
2861 'b: loop {
2862 break 'foo;
2863 }
2864 }
2865}
2866"#,
2867 )
2868 }
2869
2870 #[test]
2871 fn test_rename_label_new_name_without_apostrophe() {
2872 check(
2873 "foo",
2874 r#"
2875fn main() {
2876 'outer$0: loop {
2877 'inner: loop {
2878 break 'outer;
2879 }
2880 }
2881}
2882 "#,
2883 r#"
2884fn main() {
2885 'foo: loop {
2886 'inner: loop {
2887 break 'foo;
2888 }
2889 }
2890}
2891 "#,
2892 );
2893 }
2894
2895 #[test]
2896 fn test_self_to_self() {
2897 cov_mark::check!(rename_self_to_self);
2898 check(
2899 "self",
2900 r#"
2901struct Foo;
2902impl Foo {
2903 fn foo(self$0) {}
2904}
2905"#,
2906 r#"
2907struct Foo;
2908impl Foo {
2909 fn foo(self) {}
2910}
2911"#,
2912 )
2913 }
2914
2915 #[test]
2916 fn test_rename_field_in_pat_in_macro_doesnt_shorthand() {
2917 check(
2919 "baz",
2920 r#"
2921macro_rules! foo {
2922 ($pattern:pat) => {
2923 let $pattern = loop {};
2924 };
2925}
2926struct Foo {
2927 bar$0: u32,
2928}
2929fn foo() {
2930 foo!(Foo { bar: baz });
2931}
2932"#,
2933 r#"
2934macro_rules! foo {
2935 ($pattern:pat) => {
2936 let $pattern = loop {};
2937 };
2938}
2939struct Foo {
2940 baz: u32,
2941}
2942fn foo() {
2943 foo!(Foo { baz: baz });
2944}
2945"#,
2946 )
2947 }
2948
2949 #[test]
2950 fn test_rename_tuple_field() {
2951 check(
2952 "foo",
2953 r#"
2954struct Foo(i32);
2955
2956fn baz() {
2957 let mut x = Foo(4);
2958 x.0$0 = 5;
2959}
2960"#,
2961 "error: No references found at position",
2962 );
2963 }
2964
2965 #[test]
2966 fn test_rename_builtin() {
2967 check(
2968 "foo",
2969 r#"
2970fn foo() {
2971 let x: i32$0 = 0;
2972}
2973"#,
2974 "error: Cannot rename builtin type",
2975 );
2976 }
2977
2978 #[test]
2979 fn test_rename_self() {
2980 check(
2981 "foo",
2982 r#"
2983struct Foo {}
2984
2985impl Foo {
2986 fn foo(self) -> Self$0 {
2987 self
2988 }
2989}
2990"#,
2991 "error: No references found at position",
2992 );
2993 }
2994
2995 #[test]
2996 fn test_rename_ignores_self_ty() {
2997 check(
2998 "Fo0",
2999 r#"
3000struct $0Foo;
3001
3002impl Foo where Self: {}
3003"#,
3004 r#"
3005struct Fo0;
3006
3007impl Fo0 where Self: {}
3008"#,
3009 );
3010 }
3011
3012 #[test]
3013 fn test_rename_fails_on_aliases() {
3014 check(
3015 "Baz",
3016 r#"
3017struct Foo;
3018use Foo as Bar$0;
3019"#,
3020 "error: Renaming aliases is currently unsupported",
3021 );
3022 check(
3023 "Baz",
3024 r#"
3025struct Foo;
3026use Foo as Bar;
3027use Bar$0;
3028"#,
3029 "error: Renaming aliases is currently unsupported",
3030 );
3031 }
3032
3033 #[test]
3034 fn test_rename_trait_method() {
3035 let res = r"
3036trait Foo {
3037 fn foo(&self) {
3038 self.foo();
3039 }
3040}
3041
3042impl Foo for () {
3043 fn foo(&self) {
3044 self.foo();
3045 }
3046}";
3047 check(
3048 "foo",
3049 r#"
3050trait Foo {
3051 fn bar$0(&self) {
3052 self.bar();
3053 }
3054}
3055
3056impl Foo for () {
3057 fn bar(&self) {
3058 self.bar();
3059 }
3060}"#,
3061 res,
3062 );
3063 check(
3064 "foo",
3065 r#"
3066trait Foo {
3067 fn bar(&self) {
3068 self.bar$0();
3069 }
3070}
3071
3072impl Foo for () {
3073 fn bar(&self) {
3074 self.bar();
3075 }
3076}"#,
3077 res,
3078 );
3079 check(
3080 "foo",
3081 r#"
3082trait Foo {
3083 fn bar(&self) {
3084 self.bar();
3085 }
3086}
3087
3088impl Foo for () {
3089 fn bar$0(&self) {
3090 self.bar();
3091 }
3092}"#,
3093 res,
3094 );
3095 check(
3096 "foo",
3097 r#"
3098trait Foo {
3099 fn bar(&self) {
3100 self.bar();
3101 }
3102}
3103
3104impl Foo for () {
3105 fn bar(&self) {
3106 self.bar$0();
3107 }
3108}"#,
3109 res,
3110 );
3111 }
3112
3113 #[test]
3114 fn test_rename_trait_method_prefix_of_second() {
3115 check(
3116 "qux",
3117 r#"
3118trait Foo {
3119 fn foo$0() {}
3120 fn foobar() {}
3121}
3122"#,
3123 r#"
3124trait Foo {
3125 fn qux() {}
3126 fn foobar() {}
3127}
3128"#,
3129 );
3130 }
3131
3132 #[test]
3133 fn test_rename_trait_const() {
3134 let res = r"
3135trait Foo {
3136 const FOO: ();
3137}
3138
3139impl Foo for () {
3140 const FOO: ();
3141}
3142fn f() { <()>::FOO; }";
3143 check(
3144 "FOO",
3145 r#"
3146trait Foo {
3147 const BAR$0: ();
3148}
3149
3150impl Foo for () {
3151 const BAR: ();
3152}
3153fn f() { <()>::BAR; }"#,
3154 res,
3155 );
3156 check(
3157 "FOO",
3158 r#"
3159trait Foo {
3160 const BAR: ();
3161}
3162
3163impl Foo for () {
3164 const BAR$0: ();
3165}
3166fn f() { <()>::BAR; }"#,
3167 res,
3168 );
3169 check(
3170 "FOO",
3171 r#"
3172trait Foo {
3173 const BAR: ();
3174}
3175
3176impl Foo for () {
3177 const BAR: ();
3178}
3179fn f() { <()>::BAR$0; }"#,
3180 res,
3181 );
3182 }
3183
3184 #[test]
3185 fn defs_from_macros_arent_renamed() {
3186 check(
3187 "lol",
3188 r#"
3189macro_rules! m { () => { fn f() {} } }
3190m!();
3191fn main() { f$0() }
3192"#,
3193 "error: No identifier available to rename",
3194 )
3195 }
3196
3197 #[test]
3198 fn attributed_item() {
3199 check(
3200 "function",
3201 r#"
3202//- proc_macros: identity
3203
3204#[proc_macros::identity]
3205fn func$0() {
3206 func();
3207}
3208"#,
3209 r#"
3210
3211#[proc_macros::identity]
3212fn function() {
3213 function();
3214}
3215"#,
3216 )
3217 }
3218
3219 #[test]
3220 fn in_macro_multi_mapping() {
3221 check(
3222 "a",
3223 r#"
3224fn foo() {
3225 macro_rules! match_ast2 {
3226 ($node:ident {
3227 $( $res:expr, )*
3228 }) => {{
3229 $( if $node { $res } else )*
3230 { loop {} }
3231 }};
3232 }
3233 let $0d = 3;
3234 match_ast2! {
3235 d {
3236 d,
3237 d,
3238 }
3239 };
3240}
3241"#,
3242 r#"
3243fn foo() {
3244 macro_rules! match_ast2 {
3245 ($node:ident {
3246 $( $res:expr, )*
3247 }) => {{
3248 $( if $node { $res } else )*
3249 { loop {} }
3250 }};
3251 }
3252 let a = 3;
3253 match_ast2! {
3254 a {
3255 a,
3256 a,
3257 }
3258 };
3259}
3260"#,
3261 )
3262 }
3263
3264 #[test]
3265 fn rename_multi_local() {
3266 check(
3267 "bar",
3268 r#"
3269fn foo((foo$0 | foo | foo): ()) {
3270 foo;
3271 let foo;
3272}
3273"#,
3274 r#"
3275fn foo((bar | bar | bar): ()) {
3276 bar;
3277 let foo;
3278}
3279"#,
3280 );
3281 check(
3282 "bar",
3283 r#"
3284fn foo((foo | foo$0 | foo): ()) {
3285 foo;
3286 let foo;
3287}
3288"#,
3289 r#"
3290fn foo((bar | bar | bar): ()) {
3291 bar;
3292 let foo;
3293}
3294"#,
3295 );
3296 check(
3297 "bar",
3298 r#"
3299fn foo((foo | foo | foo): ()) {
3300 foo$0;
3301 let foo;
3302}
3303"#,
3304 r#"
3305fn foo((bar | bar | bar): ()) {
3306 bar;
3307 let foo;
3308}
3309"#,
3310 );
3311 }
3312
3313 #[test]
3314 fn regression_13498() {
3315 check(
3316 "Testing",
3317 r"
3318mod foo {
3319 pub struct Test$0;
3320}
3321
3322use foo::Test as Tester;
3323
3324fn main() {
3325 let t = Tester;
3326}
3327",
3328 r"
3329mod foo {
3330 pub struct Testing;
3331}
3332
3333use foo::Testing as Tester;
3334
3335fn main() {
3336 let t = Tester;
3337}
3338",
3339 )
3340 }
3341
3342 #[test]
3343 fn extern_crate() {
3344 check_prepare(
3345 r"
3346//- /lib.rs crate:main deps:foo
3347extern crate foo$0;
3348use foo as qux;
3349//- /foo.rs crate:foo
3350",
3351 expect![[r#"No references found at position"#]],
3352 );
3353 }
3368
3369 #[test]
3370 fn extern_crate_rename() {
3371 check_prepare(
3372 r"
3373//- /lib.rs crate:main deps:foo
3374extern crate foo as qux$0;
3375use qux as frob;
3376//- /foo.rs crate:foo
3377",
3378 expect!["Renaming aliases is currently unsupported"],
3379 );
3380 }
3396
3397 #[test]
3398 fn extern_crate_self() {
3399 check_prepare(
3400 r"
3401extern crate self$0;
3402use self as qux;
3403",
3404 expect!["No references found at position"],
3405 );
3406 }
3419
3420 #[test]
3421 fn extern_crate_self_rename() {
3422 check_prepare(
3423 r"
3424//- /lib.rs crate:main deps:foo
3425extern crate self as qux$0;
3426use qux as frob;
3427//- /foo.rs crate:foo
3428",
3429 expect!["Renaming aliases is currently unsupported"],
3430 );
3431 }
3446
3447 #[test]
3448 fn disallow_renaming_for_non_local_definition() {
3449 check(
3450 "Baz",
3451 r#"
3452//- /lib.rs crate:lib new_source_root:library
3453pub struct S;
3454//- /main.rs crate:main deps:lib new_source_root:local
3455use lib::S;
3456fn main() { let _: S$0; }
3457"#,
3458 "error: Cannot rename a non-local definition",
3459 );
3460 }
3461
3462 #[test]
3463 fn disallow_renaming_for_builtin_macros() {
3464 check(
3465 "Baz",
3466 r#"
3467//- minicore: derive, hash
3468//- /main.rs crate:main
3469use core::hash::Hash;
3470#[derive(H$0ash)]
3471struct A;
3472 "#,
3473 "error: Cannot rename a non-local definition",
3474 );
3475 }
3476
3477 #[test]
3478 fn implicit_format_args() {
3479 check(
3480 "fbar",
3481 r#"
3482//- minicore: fmt
3483fn test() {
3484 let foo = "foo";
3485 format_args!("hello {foo} {foo$0} {}", foo);
3486}
3487"#,
3488 r#"
3489fn test() {
3490 let fbar = "foo";
3491 format_args!("hello {fbar} {fbar} {}", fbar);
3492}
3493"#,
3494 );
3495 }
3496
3497 #[test]
3498 fn implicit_format_args2() {
3499 check(
3500 "fo",
3501 r#"
3502//- minicore: fmt
3503fn test() {
3504 let foo = "foo";
3505 format_args!("hello {foo} {foo$0} {}", foo);
3506}
3507"#,
3508 r#"
3509fn test() {
3510 let fo = "foo";
3511 format_args!("hello {fo} {fo} {}", fo);
3512}
3513"#,
3514 );
3515 }
3516
3517 #[test]
3518 fn asm_operand() {
3519 check(
3520 "bose",
3521 r#"
3522//- minicore: asm
3523fn test() {
3524 core::arch::asm!(
3525 "push {base}",
3526 base$0 = const 0
3527 );
3528}
3529"#,
3530 r#"
3531fn test() {
3532 core::arch::asm!(
3533 "push {bose}",
3534 bose = const 0
3535 );
3536}
3537"#,
3538 );
3539 }
3540
3541 #[test]
3542 fn asm_operand2() {
3543 check(
3544 "bose",
3545 r#"
3546//- minicore: asm
3547fn test() {
3548 core::arch::asm!(
3549 "push {base$0}",
3550 "push {base}",
3551 boo = const 0,
3552 virtual_free = sym VIRTUAL_FREE,
3553 base = const 0,
3554 boo = const 0,
3555 );
3556}
3557"#,
3558 r#"
3559fn test() {
3560 core::arch::asm!(
3561 "push {bose}",
3562 "push {bose}",
3563 boo = const 0,
3564 virtual_free = sym VIRTUAL_FREE,
3565 bose = const 0,
3566 boo = const 0,
3567 );
3568}
3569"#,
3570 );
3571 }
3572
3573 #[test]
3574 fn rename_path_inside_use_tree() {
3575 check(
3576 "Baz",
3577 r#"
3578//- /main.rs crate:main
3579mod module;
3580mod foo { pub struct Foo; }
3581mod bar { use super::Foo; }
3582
3583use foo::Foo$0;
3584
3585fn main() { let _: Foo; }
3586//- /module.rs
3587use crate::foo::Foo;
3588"#,
3589 r#"
3590mod module;
3591mod foo { pub struct Foo; }
3592mod bar { use super::Baz; }
3593
3594use foo::Foo as Baz;
3595
3596fn main() { let _: Baz; }
3597"#,
3598 )
3599 }
3600
3601 #[test]
3602 fn rename_path_inside_use_tree_foreign() {
3603 check(
3604 "Baz",
3605 r#"
3606//- /lib.rs crate:lib new_source_root:library
3607pub struct S;
3608//- /main.rs crate:main deps:lib new_source_root:local
3609use lib::S$0;
3610fn main() { let _: S; }
3611"#,
3612 r#"
3613use lib::S as Baz;
3614fn main() { let _: Baz; }
3615"#,
3616 );
3617 }
3618
3619 #[test]
3620 fn rename_type_param_ref_in_use_bound() {
3621 check(
3622 "U",
3623 r#"
3624fn foo<T>() -> impl use<T$0> Trait {}
3625"#,
3626 r#"
3627fn foo<U>() -> impl use<U> Trait {}
3628"#,
3629 );
3630 }
3631
3632 #[test]
3633 fn rename_type_param_in_use_bound() {
3634 check(
3635 "U",
3636 r#"
3637fn foo<T$0>() -> impl use<T> Trait {}
3638"#,
3639 r#"
3640fn foo<U>() -> impl use<U> Trait {}
3641"#,
3642 );
3643 }
3644
3645 #[test]
3646 fn rename_lifetime_param_ref_in_use_bound() {
3647 check(
3648 "u",
3649 r#"
3650fn foo<'t>() -> impl use<'t$0> Trait {}
3651"#,
3652 r#"
3653fn foo<'u>() -> impl use<'u> Trait {}
3654"#,
3655 );
3656 }
3657
3658 #[test]
3659 fn rename_lifetime_param_in_use_bound() {
3660 check(
3661 "u",
3662 r#"
3663fn foo<'t$0>() -> impl use<'t> Trait {}
3664"#,
3665 r#"
3666fn foo<'u>() -> impl use<'u> Trait {}
3667"#,
3668 );
3669 }
3670
3671 #[test]
3672 fn rename_parent_type_param_in_use_bound() {
3673 check(
3674 "U",
3675 r#"
3676trait Trait<T> {
3677 fn foo() -> impl use<T$0> Trait {}
3678}
3679"#,
3680 r#"
3681trait Trait<U> {
3682 fn foo() -> impl use<U> Trait {}
3683}
3684"#,
3685 );
3686 }
3687
3688 #[test]
3689 fn rename_macro_generated_type_from_type_with_a_suffix() {
3690 check(
3691 "Bar",
3692 r#"
3693//- proc_macros: generate_suffixed_type
3694#[proc_macros::generate_suffixed_type]
3695struct Foo$0;
3696fn usage(_: FooSuffix) {}
3697usage(FooSuffix);
3698"#,
3699 r#"
3700#[proc_macros::generate_suffixed_type]
3701struct Bar;
3702fn usage(_: BarSuffix) {}
3703usage(BarSuffix);
3704"#,
3705 );
3706 }
3707
3708 #[test]
3709 #[should_panic]
3711 fn rename_macro_generated_type_from_type_usage_with_a_suffix() {
3712 check(
3713 "Bar",
3714 r#"
3715//- proc_macros: generate_suffixed_type
3716#[proc_macros::generate_suffixed_type]
3717struct Foo;
3718fn usage(_: FooSuffix) {}
3719usage(FooSuffix);
3720fn other_place() { Foo$0; }
3721"#,
3722 r#"
3723#[proc_macros::generate_suffixed_type]
3724struct Bar;
3725fn usage(_: BarSuffix) {}
3726usage(BarSuffix);
3727fn other_place() { Bar; }
3728"#,
3729 );
3730 }
3731
3732 #[test]
3733 fn rename_macro_generated_type_from_variant_with_a_suffix() {
3734 check(
3735 "Bar",
3736 r#"
3737//- proc_macros: generate_suffixed_type
3738#[proc_macros::generate_suffixed_type]
3739enum Quux {
3740 Foo$0,
3741}
3742fn usage(_: FooSuffix) {}
3743usage(FooSuffix);
3744"#,
3745 r#"
3746#[proc_macros::generate_suffixed_type]
3747enum Quux {
3748 Bar,
3749}
3750fn usage(_: BarSuffix) {}
3751usage(BarSuffix);
3752"#,
3753 );
3754 }
3755
3756 #[test]
3757 #[should_panic]
3759 fn rename_macro_generated_type_from_variant_usage_with_a_suffix() {
3760 check(
3761 "Bar",
3762 r#"
3763//- proc_macros: generate_suffixed_type
3764#[proc_macros::generate_suffixed_type]
3765enum Quux {
3766 Foo,
3767}
3768fn usage(_: FooSuffix) {}
3769usage(FooSuffix);
3770fn other_place() { Quux::Foo$0; }
3771"#,
3772 r#"
3773#[proc_macros::generate_suffixed_type]
3774enum Quux {
3775 Bar,
3776}
3777fn usage(_: BarSuffix) {}
3778usage(BartSuffix);
3779fn other_place() { Quux::Bar$0; }
3780"#,
3781 );
3782 }
3783
3784 #[test]
3785 fn rename_to_self_callers() {
3786 check(
3787 "self",
3788 r#"
3789//- minicore: add
3790struct Foo;
3791impl core::ops::Add for Foo {
3792 type Target = Foo;
3793 fn add(self, _: Self) -> Foo { Foo }
3794}
3795
3796impl Foo {
3797 fn foo(th$0is: &Self) {}
3798}
3799
3800fn bar(v: &Foo) {
3801 Foo::foo(v);
3802}
3803
3804fn baz() {
3805 Foo::foo(&Foo);
3806 Foo::foo(Foo + Foo);
3807}
3808 "#,
3809 r#"
3810struct Foo;
3811impl core::ops::Add for Foo {
3812 type Target = Foo;
3813 fn add(self, _: Self) -> Foo { Foo }
3814}
3815
3816impl Foo {
3817 fn foo(&self) {}
3818}
3819
3820fn bar(v: &Foo) {
3821 v.foo();
3822}
3823
3824fn baz() {
3825 Foo.foo();
3826 (Foo + Foo).foo();
3827}
3828 "#,
3829 );
3830 check(
3832 "self",
3833 r#"
3834struct Foo;
3835
3836impl Foo {
3837 fn foo(th$0is: &Self, v: i32) {}
3838}
3839
3840fn bar(v: Foo) {
3841 Foo::foo(&v, 123);
3842}
3843 "#,
3844 r#"
3845struct Foo;
3846
3847impl Foo {
3848 fn foo(&self, v: i32) {}
3849}
3850
3851fn bar(v: Foo) {
3852 v.foo(123);
3853}
3854 "#,
3855 );
3856 }
3857
3858 #[test]
3859 fn rename_to_self_callers_in_macro() {
3860 check(
3861 "self",
3862 r#"
3863struct Foo;
3864
3865impl Foo {
3866 fn foo(th$0is: &Self, v: i32) {}
3867}
3868
3869macro_rules! m { ($it:expr) => { $it } }
3870fn bar(v: Foo) {
3871 m!(Foo::foo(&v, 123));
3872}
3873 "#,
3874 r#"
3875struct Foo;
3876
3877impl Foo {
3878 fn foo(&self, v: i32) {}
3879}
3880
3881macro_rules! m { ($it:expr) => { $it } }
3882fn bar(v: Foo) {
3883 m!(v.foo( 123));
3884}
3885 "#,
3886 );
3887 }
3888
3889 #[test]
3890 fn rename_from_self_callers() {
3891 check(
3892 "this",
3893 r#"
3894//- minicore: add
3895struct Foo;
3896impl Foo {
3897 fn foo(&sel$0f) {}
3898}
3899impl core::ops::Add for Foo {
3900 type Output = Foo;
3901
3902 fn add(self, _rhs: Self) -> Self::Output {
3903 Foo
3904 }
3905}
3906
3907fn bar(v: &Foo) {
3908 v.foo();
3909 (Foo + Foo).foo();
3910}
3911
3912mod baz {
3913 fn baz(v: super::Foo) {
3914 v.foo();
3915 }
3916}
3917 "#,
3918 r#"
3919struct Foo;
3920impl Foo {
3921 fn foo(this: &Self) {}
3922}
3923impl core::ops::Add for Foo {
3924 type Output = Foo;
3925
3926 fn add(self, _rhs: Self) -> Self::Output {
3927 Foo
3928 }
3929}
3930
3931fn bar(v: &Foo) {
3932 Foo::foo(v);
3933 Foo::foo(&(Foo + Foo));
3934}
3935
3936mod baz {
3937 fn baz(v: super::Foo) {
3938 crate::Foo::foo(&v);
3939 }
3940}
3941 "#,
3942 );
3943 check(
3945 "this",
3946 r#"
3947struct Foo;
3948impl Foo {
3949 fn foo(&sel$0f, _v: i32) {}
3950}
3951
3952fn bar() {
3953 Foo.foo(1);
3954}
3955 "#,
3956 r#"
3957struct Foo;
3958impl Foo {
3959 fn foo(this: &Self, _v: i32) {}
3960}
3961
3962fn bar() {
3963 Foo::foo(&Foo, 1);
3964}
3965 "#,
3966 );
3967 }
3968
3969 #[test]
3970 fn rename_constructor_locals() {
3971 check(
3972 "field",
3973 r#"
3974struct Struct {
3975 struct_field$0: String,
3976}
3977
3978impl Struct {
3979 fn new(struct_field: String) -> Self {
3980 if false {
3981 return Self { struct_field };
3982 }
3983 Self { struct_field }
3984 }
3985}
3986
3987mod foo {
3988 macro_rules! m {
3989 ($it:expr) => { return $it };
3990 }
3991
3992 impl crate::Struct {
3993 fn with_foo(struct_field: String) -> crate::Struct {
3994 m!(crate::Struct { struct_field });
3995 }
3996 }
3997}
3998 "#,
3999 r#"
4000struct Struct {
4001 field: String,
4002}
4003
4004impl Struct {
4005 fn new(field: String) -> Self {
4006 if false {
4007 return Self { field };
4008 }
4009 Self { field }
4010 }
4011}
4012
4013mod foo {
4014 macro_rules! m {
4015 ($it:expr) => { return $it };
4016 }
4017
4018 impl crate::Struct {
4019 fn with_foo(field: String) -> crate::Struct {
4020 m!(crate::Struct { field });
4021 }
4022 }
4023}
4024 "#,
4025 );
4026 }
4027
4028 #[test]
4029 fn test_rename_elided_lifetime_fn_no_generics() {
4030 check(
4031 "'a",
4032 r#"
4033fn foo(x: &'_$0 str) {}
4034"#,
4035 r#"
4036fn foo<'a>(x: &'a str) {}
4037"#,
4038 );
4039 }
4040
4041 #[test]
4042 fn test_rename_elided_lifetime_fn_with_generics() {
4043 check(
4044 "'a",
4045 r#"
4046fn foo<T>(x: &'_$0 str, y: T) {}
4047"#,
4048 r#"
4049fn foo<'a, T>(x: &'a str, y: T) {}
4050"#,
4051 );
4052 }
4053
4054 #[test]
4055 fn test_rename_elided_lifetime_impl_no_generics() {
4056 check(
4057 "'a",
4058 r#"
4059struct Foo<'a>(&'a str);
4060impl Foo<'_$0> {}
4061"#,
4062 r#"
4063struct Foo<'a>(&'a str);
4064impl<'a> Foo<'a> {}
4065"#,
4066 );
4067 }
4068
4069 #[test]
4070 fn test_rename_elided_lifetime_impl_with_generics() {
4071 check(
4072 "'a",
4073 r#"
4074struct Foo<'a, T>(&'a str, T);
4075impl<T> Foo<'_$0, T> {}
4076"#,
4077 r#"
4078struct Foo<'a, T>(&'a str, T);
4079impl<'a, T> Foo<'a, T> {}
4080"#,
4081 );
4082 }
4083
4084 #[test]
4085 fn test_rename_mut_pattern_with_macro() {
4086 check(
4087 "new",
4088 r#"
4089//- minicore: option
4090macro_rules! pat_macro {
4091 ($pat:pat) => {
4092 $pat
4093 };
4094}
4095
4096pub fn main() {
4097 match None {
4098 pat_macro!(Some(mut old$0)) => {
4099 old += 1,
4100 }
4101 None => {}
4102 }
4103}
4104"#,
4105 r#"
4106macro_rules! pat_macro {
4107 ($pat:pat) => {
4108 $pat
4109 };
4110}
4111
4112pub fn main() {
4113 match None {
4114 pat_macro!(Some(mut new)) => {
4115 new += 1,
4116 }
4117 None => {}
4118 }
4119}
4120"#,
4121 );
4122 }
4123 #[test]
4124 fn test_rename_ref_pattern_with_macro() {
4125 check(
4126 "new",
4127 r#"
4128//- minicore: option
4129macro_rules! pat_macro {
4130 ($pat:pat) => {
4131 $pat
4132 };
4133}
4134
4135pub fn main() {
4136 match None {
4137 pat_macro!(Some(ref old$0)) => {
4138 old += 1,
4139 }
4140 None => {}
4141 }
4142}
4143"#,
4144 r#"
4145macro_rules! pat_macro {
4146 ($pat:pat) => {
4147 $pat
4148 };
4149}
4150
4151pub fn main() {
4152 match None {
4153 pat_macro!(Some(ref new)) => {
4154 new += 1,
4155 }
4156 None => {}
4157 }
4158}
4159"#,
4160 );
4161 }
4162}