Simplify synthetic getter/setter methods

In the early days of KSP, it didn't create getter/setter accessors for
properties unless it was explicitly declared so we worked around it by
creating a synthetic one.

Now it does create it always, which means we can simplify our logic.
Note that these are still not KSFunctionDeclaration implementations so
we cannot simply use the declared function infra so we still have the
synthetics, just much simpler.

Bug: n/a
Test: existing tests
Change-Id: I8e059c1c6ca9c3a85471e0d87d8951e2567186fe
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspTypeElement.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspTypeElement.kt
index a9f8d83..9084059 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspTypeElement.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspTypeElement.kt
@@ -37,7 +37,6 @@
 import com.google.devtools.ksp.symbol.ClassKind
 import com.google.devtools.ksp.symbol.KSClassDeclaration
 import com.google.devtools.ksp.symbol.Modifier
-import com.google.devtools.ksp.symbol.Origin
 import com.squareup.javapoet.ClassName
 
 internal sealed class KspTypeElement(
@@ -132,62 +131,36 @@
     }
 
     private val syntheticGetterSetterMethods: List<XMethodElement> by lazy {
-        _declaredProperties.flatMap {
-            if (it.type.ksType.isInline()) {
-                // KAPT does not generate getters/setters for inlines, we'll hide them as well
-                // until room generates kotlin code
-                return@flatMap emptyList()
-            }
-
-            val setter = it.declaration.setter
-            val needsSetter = when {
-                it.declaration.hasJvmFieldAnnotation() -> {
-                    // jvm fields cannot have accessors but KSP generates synthetic accessors for
-                    // them. We check for JVM field first before checking the setter
-                    false
+        _declaredProperties.flatMap { field ->
+            when {
+                field.type.ksType.isInline() -> {
+                    // KAPT does not generate getters/setters for inlines, we'll hide them as well
+                    // until room generates kotlin code
+                    emptyList()
                 }
-                it.declaration.isPrivate() -> false
-                setter != null -> !setter.modifiers.contains(Modifier.PRIVATE)
-                it.declaration.origin != Origin.KOTLIN -> {
-                    // no reason to generate synthetics non kotlin code. If it had a setter, that
-                    // would show up as a setter
-                    false
-                }
-                else -> it.declaration.isMutable
-            }
-            val getter = it.declaration.getter
-            val needsGetter = when {
-                it.declaration.hasJvmFieldAnnotation() -> {
+                field.declaration.hasJvmFieldAnnotation() -> {
                     // jvm fields cannot have accessors but KSP generates synthetic accessors for
                     // them. We check for JVM field first before checking the getter
-                    false
+                    emptyList()
                 }
-                it.declaration.isPrivate() -> false
-                getter != null -> !getter.modifiers.contains(Modifier.PRIVATE)
-                it.declaration.origin != Origin.KOTLIN -> {
-                    // no reason to generate synthetics non kotlin code. If it had a getter, that
-                    // would show up as a getter
-                    false
-                }
-                else -> true
+                field.declaration.isPrivate() -> emptyList()
+
+                else ->
+                    sequenceOf(field.declaration.getter, field.declaration.setter)
+                        .filterNotNull()
+                        .filterNot {
+                            // KAPT does not generate methods for privates, KSP does so we filter
+                            // them out.
+                            it.modifiers.contains(Modifier.PRIVATE)
+                        }
+                        .map { accessor ->
+                            KspSyntheticPropertyMethodElement.create(
+                                env = env,
+                                field = field,
+                                accessor = accessor
+                            )
+                        }.toList()
             }
-            val setterElm = if (needsSetter) {
-                KspSyntheticPropertyMethodElement.Setter(
-                    env = env,
-                    field = it
-                )
-            } else {
-                null
-            }
-            val getterElm = if (needsGetter) {
-                KspSyntheticPropertyMethodElement.Getter(
-                    env = env,
-                    field = it
-                )
-            } else {
-                null
-            }
-            listOfNotNull(getterElm, setterElm)
         }
     }
 
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/synthetic/KspSyntheticPropertyMethodElement.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/synthetic/KspSyntheticPropertyMethodElement.kt
index b5636fa..4c0226b 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/synthetic/KspSyntheticPropertyMethodElement.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/synthetic/KspSyntheticPropertyMethodElement.kt
@@ -40,7 +40,6 @@
 import com.google.devtools.ksp.symbol.KSPropertyAccessor
 import com.google.devtools.ksp.symbol.KSPropertyGetter
 import com.google.devtools.ksp.symbol.KSPropertySetter
-import java.util.Locale
 
 /**
  * Kotlin properties don't have getters/setters in KSP. As Room expects Java code, we synthesize
@@ -53,13 +52,23 @@
 internal sealed class KspSyntheticPropertyMethodElement(
     val env: KspProcessingEnv,
     val field: KspFieldElement,
-    accessor: KSPropertyAccessor?
+    open val accessor: KSPropertyAccessor
 ) : XMethodElement,
     XEquality,
     XHasModifiers by KspHasModifiers.createForSyntheticAccessor(
         field.declaration,
         accessor
     ) {
+
+    @OptIn(KspExperimental::class)
+    override val name: String by lazy {
+        env.resolver.getJvmName(accessor) ?: error("Cannot find the name for accessor $accessor")
+    }
+
+    override val equalityItems: Array<out Any?> by lazy {
+        arrayOf(field, accessor)
+    }
+
     // NOTE: modifiers of the property are not necessarily my modifiers.
     //  that being said, it only matters if it is private in which case KAPT does not generate the
     //  synthetic hence we don't either.
@@ -103,29 +112,29 @@
         return env.resolver.overrides(this, other)
     }
 
-    internal class Getter(
+    override fun copyTo(newContainer: XTypeElement): XMethodElement {
+        check(newContainer is KspTypeElement)
+        return create(
+            env = env,
+            field = field.copyTo(newContainer),
+            accessor = accessor
+        )
+    }
+
+    private class Getter(
         env: KspProcessingEnv,
-        field: KspFieldElement
+        field: KspFieldElement,
+        override val accessor: KSPropertyGetter
     ) : KspSyntheticPropertyMethodElement(
         env = env,
         field = field,
-        accessor = field.declaration.getter
+        accessor = accessor
     ),
         XAnnotated by KspAnnotated.create(
             env = env,
-            delegate = field.declaration.getter,
+            delegate = accessor,
             filter = NO_USE_SITE_OR_GETTER
         ) {
-        override val equalityItems: Array<out Any?> by lazy {
-            arrayOf(field, "getter")
-        }
-
-        @OptIn(KspExperimental::class)
-        override val name: String by lazy {
-            field.declaration.getter?.let {
-                env.resolver.getJvmName(it)
-            } ?: computeGetterName(field.name)
-        }
 
         override val returnType: XType by lazy {
             field.type
@@ -137,55 +146,22 @@
         override fun kindName(): String {
             return "synthetic property getter"
         }
-
-        override fun copyTo(newContainer: XTypeElement): XMethodElement {
-            check(newContainer is KspTypeElement)
-            return Getter(
-                env = env,
-                field = field.copyTo(newContainer)
-            )
-        }
-
-        companion object {
-            private fun computeGetterName(propName: String): String {
-                // see https://kotlinlang.org/docs/reference/java-to-kotlin-interop.html#properties
-                return if (propName.startsWith("is")) {
-                    propName
-                } else {
-                    val capitalizedName = propName.replaceFirstChar {
-                        if (it.isLowerCase()) it.titlecase(
-                            Locale.US
-                        ) else it.toString()
-                    }
-                    "get$capitalizedName"
-                }
-            }
-        }
     }
 
-    internal class Setter(
+    private class Setter(
         env: KspProcessingEnv,
-        field: KspFieldElement
+        field: KspFieldElement,
+        override val accessor: KSPropertySetter
     ) : KspSyntheticPropertyMethodElement(
         env = env,
         field = field,
-        accessor = field.declaration.setter
+        accessor = accessor
     ),
         XAnnotated by KspAnnotated.create(
             env = env,
             delegate = field.declaration.setter,
             filter = NO_USE_SITE_OR_SETTER
         ) {
-        override val equalityItems: Array<out Any?> by lazy {
-            arrayOf(field, "setter")
-        }
-
-        @OptIn(KspExperimental::class)
-        override val name: String by lazy {
-            field.declaration.setter?.let {
-                env.resolver.getJvmName(it)
-            } ?: computeSetterName(field.name)
-        }
 
         override val returnType: XType by lazy {
             env.voidType
@@ -204,14 +180,6 @@
             return "synthetic property getter"
         }
 
-        override fun copyTo(newContainer: XTypeElement): XMethodElement {
-            check(newContainer is KspTypeElement)
-            return Setter(
-                env = env,
-                field = field.copyTo(newContainer)
-            )
-        }
-
         private class SyntheticExecutableParameterElement(
             env: KspProcessingEnv,
             private val origin: Setter
@@ -223,7 +191,7 @@
             ) {
 
             override val name: String by lazy {
-                val originalName = origin.field.declaration.setter?.parameter?.name?.asString()
+                val originalName = origin.accessor.parameter.name?.asString()
                 originalName.sanitizeAsJavaParameterName(0)
             }
             override val type: XType
@@ -243,51 +211,53 @@
                 return "method parameter"
             }
         }
-
-        companion object {
-            private fun computeSetterName(propName: String): String {
-                // see https://kotlinlang.org/docs/reference/java-to-kotlin-interop.html#properties
-                return if (propName.startsWith("is")) {
-                    "set${propName.substring(2)}"
-                } else {
-                    val capitalizedName = propName.replaceFirstChar {
-                        if (it.isLowerCase()) it.titlecase(
-                            Locale.US
-                        ) else it.toString()
-                    }
-                    "set$capitalizedName"
-                }
-            }
-        }
     }
 
     companion object {
-
         fun create(
             env: KspProcessingEnv,
-            propertyAccessor: KSPropertyAccessor
+            accessor: KSPropertyAccessor
         ): KspSyntheticPropertyMethodElement {
-            val enclosingType = propertyAccessor.receiver.findEnclosingMemberContainer(env)
+            val enclosingType = accessor.receiver.findEnclosingMemberContainer(env)
 
             checkNotNull(enclosingType) {
                 "XProcessing does not currently support annotations on top level " +
-                    "properties with KSP. Cannot process $propertyAccessor."
+                    "properties with KSP. Cannot process $accessor."
             }
 
             val field = KspFieldElement(
                 env,
-                propertyAccessor.receiver,
+                accessor.receiver,
                 enclosingType
             )
+            return create(
+                env = env,
+                field = field,
+                accessor = accessor
+            )
+        }
 
-            return when (propertyAccessor) {
+        fun create(
+            env: KspProcessingEnv,
+            field: KspFieldElement,
+            accessor: KSPropertyAccessor
+        ): KspSyntheticPropertyMethodElement {
+            return when (accessor) {
                 is KSPropertyGetter -> {
-                    Getter(env, field)
+                    Getter(
+                        env = env,
+                        field = field,
+                        accessor = accessor
+                    )
                 }
                 is KSPropertySetter -> {
-                    Setter(env, field)
+                    Setter(
+                        env = env,
+                        field = field,
+                        accessor = accessor
+                    )
                 }
-                else -> error("Unsupported property accessor $propertyAccessor")
+                else -> error("Unsupported property accessor $accessor")
             }
         }
     }
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/synthetic/KspSyntheticPropertyMethodType.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/synthetic/KspSyntheticPropertyMethodType.kt
index 8d442b5..e45e505 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/synthetic/KspSyntheticPropertyMethodType.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/synthetic/KspSyntheticPropertyMethodType.kt
@@ -18,6 +18,8 @@
 
 import androidx.room.compiler.processing.XMethodType
 import androidx.room.compiler.processing.XType
+import com.google.devtools.ksp.symbol.KSPropertyGetter
+import com.google.devtools.ksp.symbol.KSPropertySetter
 import com.squareup.javapoet.TypeVariableName
 
 /**
@@ -48,23 +50,24 @@
             element: KspSyntheticPropertyMethodElement,
             container: XType?
         ): XMethodType {
-            return when (element) {
-                is KspSyntheticPropertyMethodElement.Getter ->
+            return when (element.accessor) {
+                is KSPropertyGetter ->
                     Getter(
                         origin = element,
                         containingType = container
                     )
-                is KspSyntheticPropertyMethodElement.Setter ->
+                is KSPropertySetter ->
                     Setter(
                         origin = element,
                         containingType = container
                     )
+                else -> error("Unexpected accessor type for $element (${element.accessor})")
             }
         }
     }
 
     private class Getter(
-        origin: KspSyntheticPropertyMethodElement.Getter,
+        origin: KspSyntheticPropertyMethodElement,
         containingType: XType?
     ) : KspSyntheticPropertyMethodType(
         origin = origin,
@@ -80,7 +83,7 @@
     }
 
     private class Setter(
-        origin: KspSyntheticPropertyMethodElement.Setter,
+        origin: KspSyntheticPropertyMethodElement,
         containingType: XType?
     ) : KspSyntheticPropertyMethodType(
         origin = origin,
@@ -90,4 +93,4 @@
             // setters always return Unit, no need to get it as type of
             get() = origin.returnType
     }
-}
+}
\ No newline at end of file