about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2021-10-02 16:51:55 +0000
committerGitHub <noreply@github.com>2021-10-02 16:51:55 +0000
commite504f8ae8d7e63abd4926a4ea6b1344bba3157d1 (patch)
tree24f89ec1bef15d41100d178a968fdfe041339d22
parentc88277f67661957b9be5fd75a1cc1625e39746d7 (diff)
parent86e5406539d5eac8583a9442a1f5faca49d1094e (diff)
downloadrust-e504f8ae8d7e63abd4926a4ea6b1344bba3157d1.tar.gz
rust-e504f8ae8d7e63abd4926a4ea6b1344bba3157d1.zip
Merge #10430
10430: fix: Fix rename trying to edit the same range multiple times for certain macro inputs r=Veykril a=Veykril

Fixes https://github.com/rust-analyzer/rust-analyzer/issues/10324
bors r+

Co-authored-by: Lukas Wirth <lukastw97@gmail.com>
-rw-r--r--crates/ide/src/rename.rs45
-rw-r--r--crates/ide_db/src/rename.rs17
2 files changed, 55 insertions, 7 deletions
diff --git a/crates/ide/src/rename.rs b/crates/ide/src/rename.rs
index a495e6c5432..cce342272f7 100644
--- a/crates/ide/src/rename.rs
+++ b/crates/ide/src/rename.rs
@@ -1902,4 +1902,49 @@ fn 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 0ca0dc8c6b1..fcf1a654b04 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());
+            }
         }
     }