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