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