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