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