Skip to main content

ide/
rename.rs

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