Repository: intellij-rust/intellij-rust
Issue: Exception occurred. java.io.IOException: Directory already contains a file named rust-macros

## Environment

* **IntelliJ Rust plugin version:** 0.4.175.4729-222-nightly
* **Rust toolchain version:** 1.63.0-nightly (1f34da9ec 2022-06-14) x86_64-apple-darwin
* **IDE name and version:** CLion 2022.2 EAP (CL-222.3244.6)
* **Operating system:** macOS 11.5.1
* **Macro expansion engine:** new
* **Name resolution engine:** new
* **Additional experimental features:** org.rust.cargo.features.settings.gutter, org.rust.cargo.emulate.terminal, org.rust.cargo.evaluate.build.scripts, org.rust.macros.proc

## Problem description
```
java.io.IOException: Directory already contains a file named rust-macros:///rust_expanded_macros/sr21qqz7/16/a/b/ab01781829760c77bacd9df61e5d63ac9cccf42d_1_23.rs.name
    at org.rust.lang.core.macros.MacroExpansionFileSystem.moveFile([MacroExpansionFileSystem.kt:140](jetbrains://idea/navigate/reference?project=intellij&fqn=org.rust.lang.core.macros.MacroExpansionFileSystem:139))
    at com.intellij.openapi.vfs.newvfs.persistent.PersistentFSImpl.moveFile([PersistentFSImpl.java:834]
```

## Steps to reproduce

1. Open a project with macros
2. Editing macros body

<details> 
    <summary> Exception occurs </summary>

```
java.io.IOException: Directory already contains a file named rust-macros:///rust_expanded_macros/sr21qqz7/16/a/b/ab01781829760c77bacd9df61e5d63ac9cccf42d_1_23.rs.name
    at org.rust.lang.core.macros.MacroExpansionFileSystem.moveFile([MacroExpansionFileSystem.kt:140](jetbrains://idea/navigate/reference?project=intellij&fqn=org.rust.lang.core.macros.MacroExpansionFileSystem:139))
    at com.intellij.openapi.vfs.newvfs.persistent.PersistentFSImpl.moveFile([PersistentFSImpl.java:834](jetbrains://idea/navigate/reference?project=intellij&fqn=com.intellij.openapi.vfs.newvfs.persistent.PersistentFSImpl:833))
    at com.intellij.openapi.vfs.newvfs.impl.VirtualFileSystemEntry.lambda$move$1([VirtualFileSystemEntry.java:340](jetbrains://idea/navigate/reference?project=intellij&fqn=com.intellij.openapi.vfs.newvfs.impl.VirtualFileSystemEntry:339))
    at com.intellij.openapi.vfs.encoding.EncodingRegistry.doActionAndRestoreEncoding([EncodingRegistry.java:54](jetbrains://idea/navigate/reference?project=intellij&fqn=com.intellij.openapi.vfs.encoding.EncodingRegistry:53))
    at com.intellij.openapi.vfs.newvfs.impl.VirtualFileSystemEntry.move([VirtualFileSystemEntry.java:339](jetbrains://idea/navigate/reference?project=intellij&fqn=com.intellij.openapi.vfs.newvfs.impl.VirtualFileSystemEntry:338))
    at org.rust.lang.core.macros.MacroExpansionTask$applySingleChange$1$1$1.invoke([MacroExpansionTask.kt:188](jetbrains://idea/navigate/reference?project=intellij&fqn=org.rust.lang.core.macros.MacroExpansionTask$applySingleChange$1$1$1:187))
    at org.rust.lang.core.macros.MacroExpansionTask$applySingleChange$1$1$1.invoke([MacroExpansionTask.kt:187](jetbrains://idea/navigate/reference?project=intellij&fqn=org.rust.lang.core.macros.MacroExpansionTask$applySingleChange$1$1$1:186))
    at org.rust.lang.core.psi.RsPsiManager$Companion.withIgnoredPsiEvents([RsPsiManager.kt:88](jetbrains://idea/navigate/reference?project=intellij&fqn=org.rust.lang.core.psi.RsPsiManager$Companion:87))
    at org.rust.lang.core.macros.MacroExpansionTask$applySingleChange$1$invoke$$inlined$runWriteAction$1.compute([actions.kt:65](jetbrains://idea/navigate/reference?project=intellij&fqn=org.rust.lang.core.macros.MacroExpansionTask$applySingleChange$1$invoke$$inlined$runWriteAction$1:64))
    at com.intellij.openapi.application.impl.ApplicationImpl.lambda$runWriteAction$13([ApplicationImpl.java:1032](jetbrains://idea/navigate/reference?project=intellij&fqn=com.intellij.openapi.application.impl.ApplicationImpl:1031))
    at com.intellij.openapi.application.impl.ApplicationImpl.runWriteActionWithClass([ApplicationImpl.java:1011](jetbrains://idea/navigate/reference?project=intellij&fqn=com.intellij.openapi.application.impl.ApplicationImpl:1010))
    at com.intellij.openapi.application.impl.ApplicationImpl.runWriteAction([ApplicationImpl.java:1032](jetbrains://idea/navigate/reference?project=intellij&fqn=com.intellij.openapi.application.impl.ApplicationImpl:1031))
    at org.rust.lang.core.macros.MacroExpansionTask$applySingleChange$1.invoke([MacroExpansionTask.kt:288](jetbrains://idea/navigate/reference?project=intellij&fqn=org.rust.lang.core.macros.MacroExpansionTask$applySingleChange$1:287))
    at org.rust.lang.core.macros.MacroExpansionTask$applySingleChange$1.invoke([MacroExpansionTask.kt:174](jetbrains://idea/navigate/reference?project=intellij&fqn=org.rust.lang.core.macros.MacroExpansionTask$applySingleChange$1:173))
    at com.intellij.openapi.application.ActionsKt$invokeAndWaitIfNeeded$$inlined$computeDelegated$lambda$1.run([actions.kt:33](jetbrains://idea/navigate/reference?project=intellij&fqn=com.intellij.openapi.application.ActionsKt$invokeAndWaitIfNeeded$$inlined$computeDelegated$lambda$1:32))
    at com.intellij.openapi.application.TransactionGuardImpl.runWithWritingAllowed([TransactionGuardImpl.java:209](jetbrains://idea/navigate/reference?project=intellij&fqn=com.intellij.openapi.application.TransactionGuardImpl:208))
    at com.intellij.openapi.application.TransactionGuardImpl.access$100([TransactionGuardImpl.java:21](jetbrains://idea/navigate/reference?project=intellij&fqn=com.intellij.openapi.application.TransactionGuardImpl:20))
    at com.intellij.openapi.application.TransactionGuardImpl$1.run([TransactionGuardImpl.java:191](jetbrains://idea/navigate/reference?project=intellij&fqn=com.intellij.openapi.application.TransactionGuardImpl$1:190))
    at com.intellij.openapi.application.impl.ApplicationImpl.runIntendedWriteActionOnCurrentThread([ApplicationImpl.java:881](jetbrains://idea/navigate/reference?project=intellij&fqn=com.intellij.openapi.application.impl.ApplicationImpl:880))
    at com.intellij.openapi.application.impl.ApplicationImpl$3.run([ApplicationImpl.java:513](jetbrains://idea/navigate/reference?project=intellij&fqn=com.intellij.openapi.application.impl.ApplicationImpl$3:512))
    at com.intellij.openapi.application.impl.LaterInvocator$1.run([LaterInvocator.java:95](jetbrains://idea/navigate/reference?project=intellij&fqn=com.intellij.openapi.application.impl.LaterInvocator$1:94))
    at com.intellij.openapi.application.impl.FlushQueue.doRun([FlushQueue.java:75](jetbrains://idea/navigate/reference?project=intellij&fqn=com.intellij.openapi.application.impl.FlushQueue:74))
    at com.intellij.openapi.application.impl.FlushQueue.runNextEvent([FlushQueue.java:118](jetbrains://idea/navigate/reference?project=intellij&fqn=com.intellij.openapi.application.impl.FlushQueue:117))
    at com.intellij.openapi.application.impl.FlushQueue.flushNow([FlushQueue.java:42](jetbrains://idea/navigate/reference?project=intellij&fqn=com.intellij.openapi.application.impl.FlushQueue:41))
    at java.desktop/java.awt.event.InvocationEvent.dispatch([InvocationEvent.java:318](jetbrains://idea/navigate/reference?project=intellij&fqn=java.awt.event.InvocationEvent:317))
    at java.desktop/java.awt.EventQueue.dispatchEventImpl([EventQueue.java:779](jetbrains://idea/navigate/reference?project=intellij&fqn=java.awt.EventQueue:778))
    at java.desktop/java.awt.EventQueue$4.run([EventQueue.java:730](jetbrains://idea/navigate/reference?project=intellij&fqn=java.awt.EventQueue$4:729))
    at java.desktop/java.awt.EventQueue$4.run([EventQueue.java:724](jetbrains://idea/navigate/reference?project=intellij&fqn=java.awt.EventQueue$4:723))
    at java.base/java.security.AccessController.doPrivileged([AccessController.java:399](jetbrains://idea/navigate/reference?project=intellij&fqn=java.security.AccessController:398))
    at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege([ProtectionDomain.java:86](jetbrains://idea/navigate/reference?project=intellij&fqn=java.security.ProtectionDomain$JavaSecurityAccessImpl:85))
    at java.desktop/java.awt.EventQueue.dispatchEvent([EventQueue.java:749](jetbrains://idea/navigate/reference?project=intellij&fqn=java.awt.EventQueue:748))
    at com.intellij.ide.IdeEventQueue.defaultDispatchEvent([IdeEventQueue.java:898](jetbrains://idea/navigate/reference?project=intellij&fqn=com.intellij.ide.IdeEventQueue:897))
    at com.intellij.ide.IdeEventQueue._dispatchEvent([IdeEventQueue.java:746](jetbrains://idea/navigate/reference?project=intellij&fqn=com.intellij.ide.IdeEventQueue:745))
    at com.intellij.ide.IdeEventQueue.lambda$dispatchEvent$6([IdeEventQueue.java:439](jetbrains://idea/navigate/reference?project=intellij&fqn=com.intellij.ide.IdeEventQueue:438))
    at com.intellij.openapi.progress.impl.CoreProgressManager.computePrioritized([CoreProgressManager.java:791](jetbrains://idea/navigate/reference?project=intellij&fqn=com.intellij.openapi.progress.impl.CoreProgressManager:790))
    at com.intellij.ide.IdeEventQueue.lambda$dispatchEvent$7([IdeEventQueue.java:438](jetbrains://idea/navigate/reference?project=intellij&fqn=com.intellij.ide.IdeEventQueue:437))
    at com.intellij.openapi.application.TransactionGuardImpl.performActivity([TransactionGuardImpl.java:105](jetbrains://idea/navigate/reference?project=intellij&fqn=com.intellij.openapi.application.TransactionGuardImpl:104))
    at com.intellij.ide.IdeEventQueue.performActivity([IdeEventQueue.java:604](jetbrains://idea/navigate/reference?project=intellij&fqn=com.intellij.ide.IdeEventQueue:603))
    at com.intellij.ide.IdeEventQueue.lambda$dispatchEvent$8([IdeEventQueue.java:436](jetbrains://idea/navigate/reference?project=intellij&fqn=com.intellij.ide.IdeEventQueue:435))
    at com.intellij.openapi.application.impl.ApplicationImpl.runIntendedWriteActionOnCurrentThread([ApplicationImpl.java:881](jetbrains://idea/navigate/reference?project=intellij&fqn=com.intellij.openapi.application.impl.ApplicationImpl:880))
    at com.intellij.ide.IdeEventQueue.dispatchEvent([IdeEventQueue.java:484](jetbrains://idea/navigate/reference?project=intellij&fqn=com.intellij.ide.IdeEventQueue:483))
    at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters([EventDispatchThread.java:207](jetbrains://idea/navigate/reference?project=intellij&fqn=java.awt.EventDispatchThread:206))
    at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter([EventDispatchThread.java:128](jetbrains://idea/navigate/reference?project=intellij&fqn=java.awt.EventDispatchThread:127))
    at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy([EventDispatchThread.java:117](jetbrains://idea/navigate/reference?project=intellij&fqn=java.awt.EventDispatchThread:116))
    at java.desktop/java.awt.EventDispatchThread.pumpEvents([EventDispatchThread.java:113](jetbrains://idea/navigate/reference?project=intellij&fqn=java.awt.EventDispatchThread:112))
    at java.desktop/java.awt.EventDispatchThread.pumpEvents([EventDispatchThread.java:105](jetbrains://idea/navigate/reference?project=intellij&fqn=java.awt.EventDispatchThread:104))
    at java.desktop/java.awt.EventDispatchThread.run([EventDispatchThread.java:92](jetbrains://idea/navigate/reference?project=intellij&fqn=java.awt.EventDispatchThread:91))
```
</details>

Changed files:
src/main/kotlin/org/rust/lang/core/macros/MacroExpansionFileSystem.kt, src/main/kotlin/org/rust/lang/core/macros/MacroExpansionTask.kt, src/test/kotlin/org/rust/lang/core/macros/RsMacroExpansionCachingTest.kt

diff --git a/src/main/kotlin/org/rust/lang/core/macros/MacroExpansionFileSystem.kt b/src/main/kotlin/org/rust/lang/core/macros/MacroExpansionFileSystem.kt
index 5183ec4b8..98b024404 100644
--- a/src/main/kotlin/org/rust/lang/core/macros/MacroExpansionFileSystem.kt
+++ b/src/main/kotlin/org/rust/lang/core/macros/MacroExpansionFileSystem.kt
@@ -134,11 +134,14 @@ class MacroExpansionFileSystem : NewVirtualFileSystem() {
         if (requestor != TrustedRequestor) {
             throw UnsupportedOperationException()
         }
+        if (file.parent == newParent) {
+            throw IOException("Cannot move file `${file.path}` to the same directory where it is already located")
+        }
         val fsItem = convert(file) ?: throw FileNotFoundException("${file.path} (No such file or directory)")
         val newParentFsDir = convert(newParent) ?: throw FileNotFoundException("${newParent.path} (No such file or directory)")
         if (newParentFsDir !is FSDir) throw IOException("${newParent.path} is not a directory")
         if (newParentFsDir.findChild(file.name) != null) {
-            throw IOException("Directory already contains a file named $file.name")
+            throw IOException("Directory already contains a file named ${file.name}")
         }
         val oldParentFsDir = fsItem.parent ?: throw IOException("Can't move root (${file.path})")
         oldParentFsDir.removeChild(fsItem.name, bump = true)
diff --git a/src/main/kotlin/org/rust/lang/core/macros/MacroExpansionTask.kt b/src/main/kotlin/org/rust/lang/core/macros/MacroExpansionTask.kt
index 835f3c568..f90baef4d 100644
--- a/src/main/kotlin/org/rust/lang/core/macros/MacroExpansionTask.kt
+++ b/src/main/kotlin/org/rust/lang/core/macros/MacroExpansionTask.kt
@@ -186,7 +186,11 @@ class MacroExpansionTask(
                         newFileParent = newFileParent.createChildDirectory(TrustedRequestor, segment)
                     }
                     RsPsiManager.withIgnoredPsiEvents(oldPsiFile) {
-                        oldFile.move(TrustedRequestor, newFileParent)
+                        if (newFileParent != oldFile.parent) {
+                            oldFile.move(TrustedRequestor, newFileParent)
+                        } else {
+                            MoveToTheSameDir.hit()
+                        }
                         oldFile.rename(TrustedRequestor, newName)
                     }
                     val doc = FileDocumentManager.getInstance().getCachedDocument(oldFile)
@@ -289,6 +293,8 @@ class MacroExpansionTask(
 
     override val runSyncInUnitTests: Boolean
         get() = true
+
+    object MoveToTheSameDir: Testmark()
 }
 
 // "<mixHash>_<order>.rs" → "<mixHash>"
diff --git a/src/test/kotlin/org/rust/lang/core/macros/RsMacroExpansionCachingTest.kt b/src/test/kotlin/org/rust/lang/core/macros/RsMacroExpansionCachingTest.kt
index d530594b5..6d29c26a7 100644
--- a/src/test/kotlin/org/rust/lang/core/macros/RsMacroExpansionCachingTest.kt
+++ b/src/test/kotlin/org/rust/lang/core/macros/RsMacroExpansionCachingTest.kt
@@ -13,6 +13,7 @@ import com.intellij.psi.PsiFile
 import com.intellij.psi.impl.PsiManagerEx
 import com.intellij.util.io.storage.HeavyProcessLatch
 import org.intellij.lang.annotations.Language
+import org.rust.CheckTestmarkHit
 import org.rust.ExpandMacros
 import org.rust.TestProject
 import org.rust.fileTreeFromText
@@ -66,7 +67,7 @@ class RsMacroExpansionCachingTest : RsMacroExpansionTestBase() {
         vararg names: String,
         allowDumbMode: Boolean = true,
     ) {
-        InlineFile(code).withCaret()
+        InlineFile(code.trimIndent()).withCaret()
         val oldStamps = myFixture.file.collectMacros().collectStamps()
         val dumbModeCounter = countDumbModeEnters()
         action()
@@ -269,6 +270,15 @@ class RsMacroExpansionCachingTest : RsMacroExpansionTestBase() {
         struct S3;
     """)
 
+    // Issue https://github.com/intellij-rust/intellij-rust/issues/9023, we're checking there are no exceptions
+    @CheckTestmarkHit(MacroExpansionTask.MoveToTheSameDir::class)
+    fun `test a macro change that leaves the first 2 letters of mixHash the same as before the change`() = checkReExpanded(type("\\b"), """
+        macro_rules! foo {
+            (${'$'}l:literal) => {fn foo() { ${'$'}l; }};
+        }
+        foo!(18/*caret*/);
+    """, "foo", allowDumbMode = false)
+
     private class DumbModeCounter : HeavyProcessLatch.HeavyProcessListener {
         var count = 0