Repository: yandex/yatagan (kotlin)

Issue:
[KSP2] Component getter not generated if it's present in two interfaces with the same method signature
```kotlin
  @Test
  fun reproduce() {
      givenKotlinSource("test.TestCase", """
          import com.yandex.yatagan.*
          import javax.inject.*

          class TestClass @Inject constructor()

          interface Deps1 {
              val testClass: TestClass
          }
          
          interface Deps2 {   
              val testClass: TestClass
          }

          @Component
          interface RootComponent: Deps1, Deps2
      """.trimIndent())

      compileRunAndValidate()
  }
```

Pull request:
Fixes #189

Patch:
diff --git a/lang/ksp/src/main/kotlin/com/yandex/yatagan/lang/ksp/KspTypeDeclarationImpl.kt b/lang/ksp/src/main/kotlin/com/yandex/yatagan/lang/ksp/KspTypeDeclarationImpl.kt
index 5815348b..133dd7ae 100644
--- a/lang/ksp/src/main/kotlin/com/yandex/yatagan/lang/ksp/KspTypeDeclarationImpl.kt
+++ b/lang/ksp/src/main/kotlin/com/yandex/yatagan/lang/ksp/KspTypeDeclarationImpl.kt
@@ -207,8 +207,19 @@ internal class KspTypeDeclarationImpl private constructor(
         filter: FunctionFilter,
         isStatic: (KSAnnotated) -> Boolean,
     ) {
-        val isPropertyStatic = isStatic(property)
-        property.getter?.let { getter ->
+        val refinedProperty = if (
+            property.getter == null && property.setter == null &&
+            /* not a java field */ property.isFromKotlin && Utils.isKsp2
+        ) {
+            // In the cases where the property is overriding multiple identical properties from the supertypes,
+            // KSP2 returns a property without getter and setter.
+            // We detect it and try to use `findOverridee()` instead,
+            // which returns the actual property from one of the bases
+            property.findOverridee() ?: property
+        } else property
+
+        val isPropertyStatic = isStatic(refinedProperty)
+        refinedProperty.getter?.let { getter ->
             if (filter.filterAccessor(getter)) {
                 yield(KspPropertyGetterImpl(
                     owner = owner, getter = getter,
@@ -216,7 +227,7 @@ internal class KspTypeDeclarationImpl private constructor(
                 ))
             }
         }
-        property.setter?.let { setter ->
+        refinedProperty.setter?.let { setter ->
             val modifiers = setter.modifiers
             if (Modifier.PRIVATE !in modifiers && Modifier.PROTECTED !in modifiers && filter.filterAccessor(setter)) {
                 yield(KspPropertySetterImpl(


Test patch:
diff --git a/testing/tests/src/test/kotlin/com/yandex/yatagan/testing/tests/CoreBindingsKotlinTest.kt b/testing/tests/src/test/kotlin/com/yandex/yatagan/testing/tests/CoreBindingsKotlinTest.kt
index b2bcb4a0..002f369c 100644
--- a/testing/tests/src/test/kotlin/com/yandex/yatagan/testing/tests/CoreBindingsKotlinTest.kt
+++ b/testing/tests/src/test/kotlin/com/yandex/yatagan/testing/tests/CoreBindingsKotlinTest.kt
@@ -914,5 +914,28 @@ class CoreBindingsKotlinTest(
 
         compileRunAndValidate()
     }
+
+    @Test
+    fun `reproduce #189`() {
+        givenKotlinSource("test.TestCase", """
+          import com.yandex.yatagan.*
+          import javax.inject.*
+
+          class TestClass @Inject constructor()
+
+          interface Deps1 {
+              val testClass: TestClass
+          }
+          
+          interface Deps2 {   
+              val testClass: TestClass
+          }
+
+          @Component
+          interface RootComponent: Deps1, Deps2
+      """.trimIndent())
+
+        compileRunAndValidate()
+    }
 }
 
diff --git a/testing/tests/src/test/resources/golden/CoreBindingsKotlinTest/reproduce-189.golden-code.txt b/testing/tests/src/test/resources/golden/CoreBindingsKotlinTest/reproduce-189.golden-code.txt
new file mode 100644
index 00000000..d74cc234
--- /dev/null
+++ b/testing/tests/src/test/resources/golden/CoreBindingsKotlinTest/reproduce-189.golden-code.txt
@@ -0,0 +1,44 @@
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Name: test/Yatagan$RootComponent.java
+package test;
+
+import com.yandex.yatagan.AutoBuilder;
+import com.yandex.yatagan.internal.Checks;
+import com.yandex.yatagan.internal.YataganGenerated;
+import java.lang.Class;
+import java.lang.Override;
+import java.lang.SuppressWarnings;
+import java.util.Collections;
+import javax.annotation.processing.Generated;
+
+@SuppressWarnings({"unchecked", "rawtypes", "NullableProblems"})
+@YataganGenerated
+@Generated("com.yandex.yatagan.codegen.impl.ComponentGenerator")
+public final class Yatagan$RootComponent implements RootComponent {
+  private Yatagan$RootComponent() {
+  }
+
+  @Override
+  public TestClass getTestClass() {
+    return new TestClass();
+  }
+
+  public static AutoBuilder<Yatagan$RootComponent> autoBuilder() {
+    return new AutoBuilderImpl();
+  }
+
+  private static final class AutoBuilderImpl implements AutoBuilder<Yatagan$RootComponent> {
+    @Override
+    public final <I> AutoBuilder<Yatagan$RootComponent> provideInput(I input, Class<I> inputClass) {
+      Checks.reportUnexpectedAutoBuilderInput(input.getClass(), Collections.emptyList());
+      return this;
+    }
+
+    @Override
+    public final Yatagan$RootComponent create() {
+      return new Yatagan$RootComponent();
+    }
+  }
+}
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~