diff --git a/crates/ide/src/rename.rs b/crates/ide/src/rename.rs index a495e6c543..cce342272f 100644 --- a/crates/ide/src/rename.rs +++ b/crates/ide/src/rename.rs @@ -1899,6 +1899,51 @@ fn func$0() { fn function() { function(); } +"#, + ) + } + + #[test] + fn in_macro_multi_mapping() { + check( + "a", + r#" +fn foo() { + macro_rules! match_ast2 { + ($node:ident { + $( $res:expr, )* + }) => {{ + $( if $node { $res } else )* + { loop {} } + }}; + } + let $0d = 3; + match_ast2! { + d { + d, + d, + } + }; +} +"#, + r#" +fn foo() { + macro_rules! match_ast2 { + ($node:ident { + $( $res:expr, )* + }) => {{ + $( if $node { $res } else )* + { loop {} } + }}; + } + let a = 3; + match_ast2! { + a { + a, + a, + } + }; +} "#, ) } diff --git a/crates/ide_db/src/rename.rs b/crates/ide_db/src/rename.rs index 0ca0dc8c6b..fcf1a654b0 100644 --- a/crates/ide_db/src/rename.rs +++ b/crates/ide_db/src/rename.rs @@ -291,23 +291,26 @@ pub fn source_edit_from_references( new_name: &str, ) -> TextEdit { let mut edit = TextEdit::builder(); - for reference in references { - let has_emitted_edit = match &reference.name { + // macros can cause multiple refs to occur for the same text range, so keep track of what we have edited so far + let mut edited_ranges = Vec::new(); + for &FileReference { range, ref name, .. } in references { + let has_emitted_edit = match name { // if the ranges differ then the node is inside a macro call, we can't really attempt // to make special rewrites like shorthand syntax and such, so just rename the node in // the macro input - ast::NameLike::NameRef(name_ref) - if name_ref.syntax().text_range() == reference.range => - { + ast::NameLike::NameRef(name_ref) if name_ref.syntax().text_range() == range => { source_edit_from_name_ref(&mut edit, name_ref, new_name, def) } - ast::NameLike::Name(name) if name.syntax().text_range() == reference.range => { + ast::NameLike::Name(name) if name.syntax().text_range() == range => { source_edit_from_name(&mut edit, name, new_name) } _ => false, }; if !has_emitted_edit { - edit.replace(reference.range, new_name.to_string()); + if !edited_ranges.contains(&range.start()) { + edit.replace(range, new_name.to_string()); + edited_ranges.push(range.start()); + } } }