Skip to main content

ide/
rename.rs

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