Repository: intellij-rust/intellij-rust
Issue: "Apply same member order" generates wrong code

**Steps to reproduce:**
Apply `Apply same member order` quick fix for the following code
```rust
trait Foo {
    type T;
    const C: i32;
    fn foo();
}

struct S;

impl Foo for S/*caret*/ {
    fn foo() { unimplemented!() }
    const C: i32 = unimplemented!();
}
```

**Expected:**
```rust
impl Foo for S {
    const C: i32 = unimplemented!();
    fn foo() { unimplemented!() }
}
```

**Actual:**
```rust
impl Foo for S {
    const C: i32 = unimplemented!();
    const C: i32 = unimplemented!();
}
```

See code of the corresponding inspection and quick fix [here](https://github.com/intellij-rust/intellij-rust/blob/master/src/main/kotlin/org/rust/ide/inspections/RsSortImplTraitMembersInspection.kt)

Changed files:
src/test/kotlin/org/rust/ide/inspections/RsSortImplTraitMembersInspectionTest.kt, src/main/kotlin/org/rust/ide/inspections/RsSortImplTraitMembersInspection.kt

diff --git a/src/main/kotlin/org/rust/ide/inspections/RsSortImplTraitMembersInspection.kt b/src/main/kotlin/org/rust/ide/inspections/RsSortImplTraitMembersInspection.kt
index 4eb20969d..7684b0d63 100644
--- a/src/main/kotlin/org/rust/ide/inspections/RsSortImplTraitMembersInspection.kt
+++ b/src/main/kotlin/org/rust/ide/inspections/RsSortImplTraitMembersInspection.kt
@@ -15,6 +15,7 @@ import org.rust.lang.core.psi.ext.RsItemElement
 import org.rust.lang.core.psi.ext.RsTraitOrImpl
 import org.rust.lang.core.psi.ext.elementType
 import org.rust.lang.core.psi.ext.resolveToTrait
+import org.rust.openapiext.Testmark
 
 class RsSortImplTraitMembersInspection : RsLocalInspectionTool() {
     override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean) = object : RsVisitor() {
@@ -33,9 +34,13 @@ class RsSortImplTraitMembersInspection : RsLocalInspectionTool() {
 
     companion object {
         private fun sortedImplItems(implItems: List<RsItemElement>, traitItems: List<RsItemElement>): List<RsItemElement>? {
-            val implItemMap = implItems.associate { it.key() to it }
-            val sortedImplItems = traitItems.mapNotNull { implItemMap[it.key()] }
-            if (sortedImplItems.size != implItems.size || sortedImplItems == implItems) return null
+            val traitItemMap = traitItems.withIndex().associate { it.value.key() to it.index }
+            if (implItems.any { it.key() !in traitItemMap }) {
+                Testmarks.implMemberNotInTrait.hit()
+                return null
+            }
+            val sortedImplItems = implItems.sortedBy { traitItemMap[it.key()] }
+            if (sortedImplItems == implItems) return null
             return sortedImplItems
         }
     }
@@ -48,12 +53,19 @@ class RsSortImplTraitMembersInspection : RsLocalInspectionTool() {
             val trait = impl.traitRef?.resolveToTrait ?: return
             val implItems = impl.items()
             val traitItems = trait.items()
-            val sortedImplItems = sortedImplItems(implItems, traitItems)?.map { it.copy() } ?: return
-            traitItems.zip(implItems).forEachIndexed { index, (traitItem, implItem) ->
-                if (traitItem.key() != implItem.key()) implItem.replace(sortedImplItems[index])
+
+            // As we're applying the fix, this will be non-null.
+            val sortedImplItems = sortedImplItems(implItems, traitItems) ?: return
+            implItems.zip(sortedImplItems).forEachIndexed { index, (implItem, expectedImplItem) ->
+                if (implItem.key() != expectedImplItem.key())
+                    implItem.replace(sortedImplItems[index].copy())
             }
         }
     }
+
+    object Testmarks {
+        val implMemberNotInTrait = Testmark("implMemberNotInTrait")
+    }
 }
 
 private fun RsTraitOrImpl.items(): List<RsItemElement> = members?.children?.mapNotNull {
diff --git a/src/test/kotlin/org/rust/ide/inspections/RsSortImplTraitMembersInspectionTest.kt b/src/test/kotlin/org/rust/ide/inspections/RsSortImplTraitMembersInspectionTest.kt
index ee22609b5..a20be50f3 100644
--- a/src/test/kotlin/org/rust/ide/inspections/RsSortImplTraitMembersInspectionTest.kt
+++ b/src/test/kotlin/org/rust/ide/inspections/RsSortImplTraitMembersInspectionTest.kt
@@ -67,7 +67,6 @@ class RsSortImplTraitMembersInspectionTest : RsInspectionsTestBase(RsSortImplTra
         }
     """)
 
-
     fun `test different impl`() = checkFixIsUnavailable("Apply same member order", """
         trait Foo {
             type x;
@@ -77,6 +76,18 @@ class RsSortImplTraitMembersInspectionTest : RsInspectionsTestBase(RsSortImplTra
         }
     """)
 
+    fun `test impl with unknown members`() = checkFixIsUnavailable("Apply same member order", """
+        trait Foo {
+            fn f();
+            fn g();
+        }
+        /*caret*/impl Foo for () {
+            fn g() {}
+            fn f() {}
+            fn <error descr="Method `h` is not a member of trait `Foo` [E0407]">h</error>() {}
+        }
+    """, testmark = RsSortImplTraitMembersInspection.Testmarks.implMemberNotInTrait)
+
     fun `test different order`() = checkFixByText("Apply same member order", """
         struct Struct {
             i: i32
@@ -141,7 +152,7 @@ class RsSortImplTraitMembersInspectionTest : RsInspectionsTestBase(RsSortImplTra
                 self.i * 3
             }
         }
-    """)
+    """, checkWeakWarn = true)
 
 
     fun `test different order with same name`() = checkFixByText("Apply same member order", """
@@ -166,7 +177,7 @@ class RsSortImplTraitMembersInspectionTest : RsInspectionsTestBase(RsSortImplTra
             fn bar() {
             }
         }
-    """)
+    """, checkWeakWarn = true)
 
     fun `test different order with different files`() = checkFixByFileTree("Apply same member order", """
         //- foo.rs
@@ -233,5 +244,33 @@ class RsSortImplTraitMembersInspectionTest : RsInspectionsTestBase(RsSortImplTra
                 self.i * 3
             }
         }
-    """)
+    """, checkWeakWarn = true)
+
+    fun `test does the right thing when the impl is missing some of the members`() = checkFixByText("Apply same member order", """
+        trait Foo {
+            type T;
+            const C: i32;
+            fn foo();
+        }
+
+        struct S;
+
+        <error descr="Not all trait items implemented, missing: `T` [E0046]"><weak_warning descr="Different impl member order from the trait">impl Foo for S/*caret*/</weak_warning></error> {
+            fn foo() { unimplemented!() }
+            const C: i32 = unimplemented!();
+        }
+    """, """
+        trait Foo {
+            type T;
+            const C: i32;
+            fn foo();
+        }
+
+        struct S;
+
+        impl Foo for S {
+            const C: i32 = unimplemented!();
+            fn foo() { unimplemented!() }
+        }
+    """, checkWeakWarn = true)
 }