Merge "Fix Java TypeName for @JvmInline types" into androidx-main am: 257b611f22

Original change: https://android-review.googlesource.com/c/platform/frameworks/support/+/2591592

Change-Id: I3c3d9f7a9602b8748c3dd4c8b6505ba14265a2da
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KSTypeJavaPoetExt.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KSTypeJavaPoetExt.kt
index 1aaaee0..6bcc71f 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KSTypeJavaPoetExt.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KSTypeJavaPoetExt.kt
@@ -21,6 +21,7 @@
 import androidx.room.compiler.processing.tryBox
 import androidx.room.compiler.processing.util.ISSUE_TRACKER_LINK
 import com.google.devtools.ksp.KspExperimental
+import com.google.devtools.ksp.isAnnotationPresent
 import com.google.devtools.ksp.processing.Resolver
 import com.google.devtools.ksp.symbol.KSDeclaration
 import com.google.devtools.ksp.symbol.KSName
@@ -29,6 +30,7 @@
 import com.google.devtools.ksp.symbol.KSTypeArgument
 import com.google.devtools.ksp.symbol.KSTypeParameter
 import com.google.devtools.ksp.symbol.KSTypeReference
+import com.google.devtools.ksp.symbol.Modifier
 import com.google.devtools.ksp.symbol.Variance
 import com.squareup.kotlinpoet.javapoet.JClassName
 import com.squareup.kotlinpoet.javapoet.JParameterizedTypeName
@@ -45,7 +47,10 @@
  * To handle self referencing types and avoid infinite recursion, we keep a lookup map for
  * TypeVariables.
  */
-private typealias JTypeArgumentTypeLookup = LinkedHashMap<KSName, JTypeName>
+private class TypeResolutionContext(
+    val originalType: KSType? = null,
+    val typeArgumentTypeLookup: MutableMap<KSName, JTypeName> = LinkedHashMap(),
+)
 
 /**
  * Turns a KSTypeReference into a TypeName in java's type system.
@@ -53,17 +58,17 @@
 internal fun KSTypeReference?.asJTypeName(resolver: Resolver): JTypeName =
     asJTypeName(
         resolver = resolver,
-        typeArgumentTypeLookup = JTypeArgumentTypeLookup()
+        typeResolutionContext = TypeResolutionContext()
     )
 
 private fun KSTypeReference?.asJTypeName(
     resolver: Resolver,
-    typeArgumentTypeLookup: JTypeArgumentTypeLookup
+    typeResolutionContext: TypeResolutionContext
 ): JTypeName {
     return if (this == null) {
         ERROR_JTYPE_NAME
     } else {
-        resolve().asJTypeName(resolver, typeArgumentTypeLookup)
+        resolve().asJTypeName(resolver, typeResolutionContext)
     }
 }
 
@@ -73,27 +78,37 @@
 internal fun KSDeclaration.asJTypeName(resolver: Resolver): JTypeName =
     asJTypeName(
         resolver = resolver,
-        typeArgumentTypeLookup = JTypeArgumentTypeLookup()
+        typeResolutionContext = TypeResolutionContext()
     )
 
 @OptIn(KspExperimental::class)
 private fun KSDeclaration.asJTypeName(
     resolver: Resolver,
-    typeArgumentTypeLookup: JTypeArgumentTypeLookup
+    typeResolutionContext: TypeResolutionContext
 ): JTypeName {
     if (this is KSTypeAlias) {
-        return this.type.asJTypeName(resolver, typeArgumentTypeLookup)
+        return this.type.asJTypeName(resolver, typeResolutionContext)
     }
     if (this is KSTypeParameter) {
-        return this.asJTypeName(resolver, typeArgumentTypeLookup)
+        return this.asJTypeName(resolver, typeResolutionContext)
     }
     // if there is no qualified name, it is a resolution error so just return shared instance
     // KSP may improve that later and if not, we can improve it in Room
     // TODO: https://issuetracker.google.com/issues/168639183
     val qualified = qualifiedName?.asString() ?: return ERROR_JTYPE_NAME
-    val jvmSignature = resolver.mapToJvmSignature(this)
-    if (jvmSignature != null && jvmSignature.isNotBlank()) {
-        return jvmSignature.typeNameFromJvmSignature()
+
+    // Note: To match KAPT behavior, a type annotated with @JvmInline is only replaced with the
+    // underlying type if the inline type is used directly (e.g. MyInlineType) rather than in the
+    // type args of another type, (e.g. List<MyInlineType>).
+    val isInline = isAnnotationPresent(JvmInline::class) || modifiers.contains(Modifier.INLINE)
+    val isOriginalType =
+        typeResolutionContext.originalType?.declaration?.qualifiedName?.asString() == qualified
+    if (!isInline || isOriginalType) {
+        resolver.mapToJvmSignature(this).let { jvmSignature ->
+            if (!jvmSignature.isNullOrBlank()) {
+                return jvmSignature.typeNameFromJvmSignature()
+            }
+        }
     }
 
     // fallback to custom generation, it is very likely that this is an unresolved type
@@ -112,40 +127,38 @@
 /**
  * Turns a KSTypeArgument into a TypeName in java's type system.
  */
-internal fun KSTypeArgument.asJTypeName(
-    resolver: Resolver
-): JTypeName = asJTypeName(
+internal fun KSTypeArgument.asJTypeName(resolver: Resolver): JTypeName = asJTypeName(
     resolver = resolver,
-    typeArgumentTypeLookup = JTypeArgumentTypeLookup()
+    typeResolutionContext = TypeResolutionContext()
 )
 
 private fun KSTypeParameter.asJTypeName(
     resolver: Resolver,
-    typeArgumentTypeLookup: JTypeArgumentTypeLookup
+    typeResolutionContext: TypeResolutionContext
 ): JTypeName {
     // see https://github.com/square/javapoet/issues/842
-    typeArgumentTypeLookup[name]?.let {
+    typeResolutionContext.typeArgumentTypeLookup[name]?.let {
         return it
     }
     val mutableBounds = mutableListOf<JTypeName>()
     val typeName = createModifiableTypeVariableName(name = name.asString(), bounds = mutableBounds)
-    typeArgumentTypeLookup[name] = typeName
+    typeResolutionContext.typeArgumentTypeLookup[name] = typeName
     val resolvedBounds = bounds.map {
-        it.asJTypeName(resolver, typeArgumentTypeLookup).tryBox()
+        it.asJTypeName(resolver, typeResolutionContext).tryBox()
     }.toList()
     if (resolvedBounds.isNotEmpty()) {
         mutableBounds.addAll(resolvedBounds)
         mutableBounds.remove(JTypeName.OBJECT)
     }
-    typeArgumentTypeLookup.remove(name)
+    typeResolutionContext.typeArgumentTypeLookup.remove(name)
     return typeName
 }
 
 private fun KSTypeArgument.asJTypeName(
     resolver: Resolver,
-    typeArgumentTypeLookup: JTypeArgumentTypeLookup
+    typeResolutionContext: TypeResolutionContext
 ): JTypeName {
-    fun resolveTypeName() = type.asJTypeName(resolver, typeArgumentTypeLookup).tryBox()
+    fun resolveTypeName() = type.asJTypeName(resolver, typeResolutionContext).tryBox()
     return when (variance) {
         Variance.CONTRAVARIANT -> JWildcardTypeName.supertypeOf(resolveTypeName())
         Variance.COVARIANT -> JWildcardTypeName.subtypeOf(resolveTypeName())
@@ -160,29 +173,29 @@
 internal fun KSType.asJTypeName(resolver: Resolver): JTypeName =
     asJTypeName(
         resolver = resolver,
-        typeArgumentTypeLookup = JTypeArgumentTypeLookup()
+        typeResolutionContext = TypeResolutionContext(this)
     )
 
 @OptIn(KspExperimental::class)
 private fun KSType.asJTypeName(
     resolver: Resolver,
-    typeArgumentTypeLookup: JTypeArgumentTypeLookup
+    typeResolutionContext: TypeResolutionContext,
 ): JTypeName {
     return if (declaration is KSTypeAlias) {
-        replaceTypeAliases(resolver).asJTypeName(resolver, typeArgumentTypeLookup)
+        replaceTypeAliases(resolver).asJTypeName(resolver, typeResolutionContext)
     } else if (this.arguments.isNotEmpty() && !resolver.isJavaRawType(this)) {
         val args: Array<JTypeName> = this.arguments
-            .map { typeArg -> typeArg.asJTypeName(resolver, typeArgumentTypeLookup) }
+            .map { typeArg -> typeArg.asJTypeName(resolver, typeResolutionContext) }
             .map { it.tryBox() }
             .toTypedArray()
 
-        when (val typeName = declaration.asJTypeName(resolver, typeArgumentTypeLookup).tryBox()) {
+        when (val typeName = declaration.asJTypeName(resolver, typeResolutionContext).tryBox()) {
             is JArrayTypeName -> JArrayTypeName.of(args.single())
             is JClassName -> JParameterizedTypeName.get(typeName, *args)
             else -> error("Unexpected type name for KSType: $typeName")
         }
     } else {
-        this.declaration.asJTypeName(resolver, typeArgumentTypeLookup)
+        this.declaration.asJTypeName(resolver, typeResolutionContext)
     }
 }
 
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspClassFileUtility.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspClassFileUtility.kt
deleted file mode 100644
index f01c0fd..0000000
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspClassFileUtility.kt
+++ /dev/null
@@ -1,333 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.room.compiler.processing.ksp
-
-import androidx.room.compiler.processing.XMethodElement
-import androidx.room.compiler.processing.XProcessingConfig
-import com.google.devtools.ksp.symbol.ClassKind
-import com.google.devtools.ksp.symbol.KSClassDeclaration
-import com.google.devtools.ksp.symbol.KSFunctionDeclaration
-import com.google.devtools.ksp.symbol.KSNode
-import com.google.devtools.ksp.symbol.KSPropertyDeclaration
-import com.google.devtools.ksp.symbol.Origin
-import java.lang.reflect.InvocationHandler
-import java.lang.reflect.Method
-import java.lang.reflect.Proxy
-
-/**
- * When a compiled kotlin class is loaded from a `.class` file, its fields are not ordered in the
- * same way they are declared in code.
- * This particularly hurts Room where we generate the table structure in that order.
- *
- * This class implements a port of https://github.com/google/ksp/pull/260 via reflection until KSP
- * (or kotlin compiler) fixes the problem. As this uses reflection, it is fail safe such that if it
- * cannot find the correct order, it will just return in the order KSP returned instead of crashing.
- *
- * KSP Bugs:
- *  * https://github.com/google/ksp/issues/250
- */
-internal object KspClassFileUtility {
-    /**
-     * Sorts the given fields in the order they are declared in the backing class declaration.
-     */
-    fun orderFields(
-        owner: KSClassDeclaration,
-        fields: List<KspFieldElement>
-    ): List<KspFieldElement> {
-        // no reason to try to load .class if we don't have any fields to sort
-        if (fields.isEmpty()) return fields
-        if (owner.origin == Origin.KOTLIN) {
-            // this is simple and temporary case that KSP can fix. No reason to create a more
-            // complicated comparator for it since it will be removed
-            // https://github.com/google/ksp/issues/727
-            return orderKotlinSourceFields(owner, fields)
-        }
-        val comparator = getNamesComparator(owner, Type.FIELD, KspFieldElement::name)
-        return if (comparator == null) {
-            fields
-        } else {
-            fields.forEach {
-                // make sure each name gets registered so that if we didn't find it in .class for
-                // whatever reason, we keep the order given from KSP.
-                comparator.register(it.name)
-            }
-            fields.sortedWith(comparator)
-        }
-    }
-
-    /**
-     * KSP returns properties from primary constructor last instead of first.
-     * https://github.com/google/ksp/issues/727
-     * This function reverts that. This method traverses declaration hierarchy instead of looking at
-     * the primary constructor's fields as some of them may not be fields.
-     */
-    private fun orderKotlinSourceFields(
-        owner: KSClassDeclaration,
-        fields: List<KspFieldElement>
-    ): List<KspFieldElement> {
-        val primaryConstructor = owner.primaryConstructor ?: return fields
-        return fields.sortedBy {
-            if (it.declaration.isDeclaredInside(primaryConstructor)) {
-                0
-            } else {
-                1
-            }
-        }
-    }
-
-    private fun KSPropertyDeclaration.isDeclaredInside(
-        functionDeclaration: KSFunctionDeclaration
-    ): Boolean {
-        var current: KSNode? = this
-        while (current != null) {
-            if (current == functionDeclaration) {
-                return true
-            }
-            current = current.parent
-        }
-        return false
-    }
-
-    /**
-     * Sorts the given methods in the order they are declared in the backing class declaration.
-     */
-    fun orderMethods(
-        owner: KSClassDeclaration,
-        methods: List<KspMethodElement>
-    ): List<KspMethodElement> {
-        // no reason to try to load .class if we don't have any fields to sort
-        if (methods.isEmpty()) return methods
-        val comparator = getNamesComparator(owner, Type.METHOD, XMethodElement::jvmDescriptor)
-        return if (comparator == null) {
-            methods
-        } else {
-            methods.forEach {
-                // make sure each descriptor gets registered so that if we didn't find it in .class
-                // for whatever reason, we keep the order given from KSP.
-                comparator.register(it.jvmDescriptor())
-            }
-            methods.sortedWith(comparator)
-        }
-    }
-
-    /**
-     * Builds a field names comparator from the given class declaration if and only if its origin
-     * is Kotlin .class.
-     * If it fails to find the order, returns null.
-     */
-    @Suppress("BanUncheckedReflection")
-    private fun <T> getNamesComparator(
-        ksClassDeclaration: KSClassDeclaration,
-        type: Type,
-        getName: T.() -> String,
-    ): MemberNameComparator<T>? {
-        return try {
-            // this is needed only for compiled kotlin classes
-            // https://github.com/google/ksp/issues/250#issuecomment-761108924
-            if (ksClassDeclaration.origin != Origin.KOTLIN_LIB) return null
-
-            // A companion object's `declarations` contains fields declared in the object in KSP,
-            // while KotlinJvmBinaryClass.visitMembers() does not. This leads to unsorted fields.
-            // As a workaround we register all the fields of an enclosing type in hope that we
-            // cover every field in a companion object's KSDeclarationContainer.declarations.
-            val classDeclaration = if (
-                    ksClassDeclaration.isCompanionObject &&
-                    type == Type.FIELD &&
-                    ksClassDeclaration.parentDeclaration is KSClassDeclaration) {
-                ksClassDeclaration.parentDeclaration as KSClassDeclaration
-            } else {
-                ksClassDeclaration
-            }
-
-            val typeReferences = ReflectionReferences.getInstance(classDeclaration) ?: return null
-            val binarySource = getBinarySource(typeReferences, classDeclaration) ?: return null
-
-            val memberNameComparator = MemberNameComparator(
-                getName = getName,
-                // we can do strict mode only in classes. For Interfaces, private methods won't
-                // show up in the binary.
-                strictMode = XProcessingConfig.STRICT_MODE &&
-                    classDeclaration.classKind != ClassKind.INTERFACE
-            )
-            val invocationHandler = InvocationHandler { _, method, args ->
-                if (method.name == type.visitorName) {
-                    val nameAsString = typeReferences.asStringMethod.invoke(args[0])
-                    if (nameAsString is String) {
-                        when (type) {
-                            Type.FIELD -> memberNameComparator.register(nameAsString)
-                            Type.METHOD -> {
-                                val methodTypeDescriptor = args[1]
-                                memberNameComparator.register(nameAsString + methodTypeDescriptor)
-                            }
-                        }
-                    }
-                }
-                null
-            }
-
-            val proxy = Proxy.newProxyInstance(
-                classDeclaration.javaClass.classLoader,
-                arrayOf(typeReferences.memberVisitor),
-                invocationHandler
-            )
-
-            typeReferences.visitMembersMethod.invoke(binarySource, proxy, null)
-            memberNameComparator.seal()
-            memberNameComparator
-        } catch (ignored: Throwable) {
-            // this is best effort, if it failed, just ignore
-            if (XProcessingConfig.STRICT_MODE) {
-                throw RuntimeException("failed to get fields", ignored)
-            }
-            null
-        }
-    }
-
-    private fun getBinarySource(
-        typeReferences: ReflectionReferences,
-        ksClassDeclaration: KSClassDeclaration
-    ): Any? {
-        val descriptor = typeReferences.getDescriptorMethod.invoke(ksClassDeclaration)
-            ?: return null
-        if (!typeReferences.deserializedClassDescriptor.isInstance(descriptor)) {
-            return null
-        }
-        val descriptorSrc = typeReferences.descriptorSourceMethod.invoke(descriptor)
-            ?: return null
-        if (!typeReferences.kotlinJvmBinarySourceElement.isInstance(descriptorSrc)) {
-            return null
-        }
-        return typeReferences.binaryClassMethod.invoke(descriptorSrc)
-            ?: return null
-    }
-
-    /**
-     * Holder object to keep references to class/method instances.
-     */
-    private class ReflectionReferences private constructor(
-        classLoader: ClassLoader
-    ) {
-
-        val deserializedClassDescriptor: Class<*> = classLoader.loadClass(
-            "org.jetbrains.kotlin.serialization.deserialization.descriptors" +
-                ".DeserializedClassDescriptor"
-        )
-
-        val ksClassDeclarationDescriptorImpl: Class<*> = classLoader.loadClass(
-            "com.google.devtools.ksp.symbol.impl.binary.KSClassDeclarationDescriptorImpl"
-        )
-        val kotlinJvmBinarySourceElement: Class<*> = classLoader.loadClass(
-            "org.jetbrains.kotlin.load.kotlin.KotlinJvmBinarySourceElement"
-        )
-
-        val kotlinJvmBinaryClass: Class<*> = classLoader.loadClass(
-            "org.jetbrains.kotlin.load.kotlin.KotlinJvmBinaryClass"
-        )
-
-        val memberVisitor: Class<*> = classLoader.loadClass(
-            "org.jetbrains.kotlin.load.kotlin.KotlinJvmBinaryClass\$MemberVisitor"
-        )
-
-        val name: Class<*> = classLoader.loadClass(
-            "org.jetbrains.kotlin.name.Name"
-        )
-
-        val getDescriptorMethod: Method = ksClassDeclarationDescriptorImpl
-            .getDeclaredMethod("getDescriptor")
-
-        val descriptorSourceMethod: Method = deserializedClassDescriptor.getMethod("getSource")
-
-        val binaryClassMethod: Method = kotlinJvmBinarySourceElement.getMethod("getBinaryClass")
-
-        val visitMembersMethod: Method = kotlinJvmBinaryClass.getDeclaredMethod(
-            "visitMembers",
-            memberVisitor, ByteArray::class.java
-        )
-
-        val asStringMethod: Method = name.getDeclaredMethod("asString")
-
-        companion object {
-            private val FAILED = Any()
-            private var instance: Any? = null
-
-            /**
-             * Gets the cached instance or create a new one using the class loader of the given
-             * [ref] parameter.
-             */
-            fun getInstance(ref: Any): ReflectionReferences? {
-                if (instance == null) {
-                    instance = try {
-                        ReflectionReferences(ref::class.java.classLoader)
-                    } catch (ignored: Throwable) {
-                        FAILED
-                    }
-                }
-                return instance as? ReflectionReferences
-            }
-        }
-    }
-
-    private class MemberNameComparator<T>(
-        val getName: T.() -> String,
-        val strictMode: Boolean
-    ) : Comparator<T> {
-        private var nextOrder: Int = 0
-        private var sealed: Boolean = false
-        private val orders = mutableMapOf<String, Int>()
-
-        /**
-         * Called when fields are read to lock the ordering.
-         * This is only relevant in tests as at runtime, we just do a best effort (add a new id
-         * for it) and continue.
-         */
-        fun seal() {
-            sealed = true
-        }
-
-        /**
-         * Registers the name with the next order id
-         */
-        fun register(name: String) {
-            getOrder(name)
-        }
-
-        /**
-         * Gets the order of the name. If it was not seen before, adds it to the list, giving it a
-         * new ID.
-         */
-        private fun getOrder(name: String) = orders.getOrPut(name) {
-            if (sealed && strictMode) {
-                error("expected to find field/method $name but it is non-existent: $orders")
-            }
-            nextOrder++
-        }
-
-        override fun compare(elm1: T, elm2: T): Int {
-            return getOrder(elm1.getName()).compareTo(getOrder(elm2.getName()))
-        }
-    }
-
-    /**
-     * The type of declaration that we want to extract from class descriptor.
-     */
-    private enum class Type(
-        val visitorName: String
-    ) {
-        FIELD("visitField"),
-        METHOD("visitMethod")
-    }
-}
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 8fb91f6..2318b4d 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
@@ -35,13 +35,14 @@
 import androidx.room.compiler.processing.ksp.KspAnnotated.UseSiteFilter.Companion.NO_USE_SITE
 import androidx.room.compiler.processing.tryBox
 import androidx.room.compiler.processing.util.MemoizedSequence
+import com.google.devtools.ksp.KspExperimental
 import com.google.devtools.ksp.getConstructors
-import com.google.devtools.ksp.getDeclaredFunctions
-import com.google.devtools.ksp.getDeclaredProperties
 import com.google.devtools.ksp.isConstructor
 import com.google.devtools.ksp.isOpen
 import com.google.devtools.ksp.symbol.ClassKind
 import com.google.devtools.ksp.symbol.KSClassDeclaration
+import com.google.devtools.ksp.symbol.KSDeclarationContainer
+import com.google.devtools.ksp.symbol.KSFunctionDeclaration
 import com.google.devtools.ksp.symbol.KSPropertyDeclaration
 import com.google.devtools.ksp.symbol.Modifier
 import com.squareup.javapoet.ClassName
@@ -162,34 +163,19 @@
      * properties. They are not necessarily fields as it might include properties of interfaces.
      */
     private val _declaredProperties by lazy {
-        val declaredProperties = declaration.getDeclaredProperties()
+        buildList {
+            addAll(declaration.getDeclarationsInSourceOrder())
+            addAll(
+                declaration.findCompanionObject().getDeclarationsInSourceOrder()
+                    .filter { it.isStatic() }
+            )
+        }.filterIsInstance(KSPropertyDeclaration::class.java)
             .map {
                 KspFieldElement(
                     env = env,
-                    declaration = it,
-                )
-            }.let {
-                // only order instance properties with backing fields, we don't care about the order
-                // of companion properties or properties without backing fields.
-                val (withBackingField, withoutBackingField) = it.partition {
-                    it.declaration.hasBackingFieldFixed
-                }
-                KspClassFileUtility.orderFields(declaration, withBackingField) + withoutBackingField
-            }
-
-        val companionProperties = declaration
-            .findCompanionObject()
-            ?.getDeclaredProperties()
-            ?.filter {
-                it.isStatic()
-            }.orEmpty()
-            .map {
-                KspFieldElement(
-                    env = env,
-                    declaration = it,
+                    declaration = it
                 )
             }
-        declaredProperties + companionProperties
     }
 
     private val _declaredFields by lazy {
@@ -280,29 +266,22 @@
     }
 
     private val _declaredMethods by lazy {
-        val instanceMethods = declaration.getDeclaredFunctions().asSequence()
+        val declaredMethods = buildList {
+            addAll(declaration.getDeclarationsInSourceOrder())
+            addAll(
+                declaration.findCompanionObject().getDeclarationsInSourceOrder()
+                    .filter { it.hasJvmStaticAnnotation() }
+            )
+        }.filterIsInstance(KSFunctionDeclaration::class.java)
             .filterNot { it.isConstructor() }
-        val companionMethods = declaration.findCompanionObject()
-            ?.getDeclaredFunctions()
-            ?.filterNot {
-                it.isConstructor()
-            }
-            ?.filter {
-                it.hasJvmStaticAnnotation()
-            } ?: emptySequence()
-        val declaredMethods = (instanceMethods + companionMethods)
-            .filterNot {
-                // filter out constructors
-                it.simpleName.asString() == name
-            }.map {
+            .map {
                 KspMethodElement.create(
                     env = env,
                     declaration = it
                 )
-            }.toList()
+            }
             .filterMethodsByConfig(env)
-        KspClassFileUtility.orderMethods(declaration, declaredMethods) +
-            syntheticGetterSetterMethods
+        declaredMethods + syntheticGetterSetterMethods
     }
 
     override fun getDeclaredMethods(): List<XMethodElement> {
@@ -319,14 +298,11 @@
     }
 
     override fun getSuperInterfaceElements(): List<XTypeElement> {
-        return declaration.superTypes.asSequence().mapNotNull {
-            it.resolve().declaration
-        }.filterIsInstance<KSClassDeclaration>()
-            .filter {
-                it.classKind == ClassKind.INTERFACE
-            }.mapTo(mutableListOf()) {
-                env.wrapClassDeclaration(it)
-            }
+        return declaration.superTypes
+            .mapNotNull { it.resolve().declaration }
+            .filterIsInstance<KSClassDeclaration>()
+            .filter { it.classKind == ClassKind.INTERFACE }
+            .mapTo(mutableListOf()) { env.wrapClassDeclaration(it) }
     }
 
     override fun getEnclosedTypeElements(): List<XTypeElement> {
@@ -362,6 +338,11 @@
     private val KSPropertyDeclaration.hasBackingFieldFixed
         get() = hasBackingField || modifiers.contains(Modifier.LATEINIT)
 
+    @OptIn(KspExperimental::class)
+    fun KSDeclarationContainer?.getDeclarationsInSourceOrder() = this?.let {
+        env.resolver.getDeclarationsInSourceOrder(it)
+    } ?: emptySequence()
+
     companion object {
         fun create(
             env: KspProcessingEnv,
diff --git a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/ksp/KspTypeNamesGoldenTest.kt b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/ksp/KspTypeNamesGoldenTest.kt
index b0c73fd..c793faf 100644
--- a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/ksp/KspTypeNamesGoldenTest.kt
+++ b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/ksp/KspTypeNamesGoldenTest.kt
@@ -184,6 +184,7 @@
                 typealias JSW = JvmSuppressWildcards
                 typealias JW = JvmWildcard
                 typealias MyLambdaTypeAlias = (@JvmWildcard MyType) -> @JvmWildcard MyType
+                @JvmInline value class MyInlineType(val value: MyType)
                 enum class MyEnum {
                     VAL1,
                     VAL2;
@@ -364,6 +365,10 @@
                         fun method52(
                             param: MyGenericIn<MyGeneric2ParametersAlias<MyGenericOut<MyType>, MyGenericIn<MyType>>>
                         ): MyGenericIn<MyGeneric2ParametersAlias<MyGenericOut<MyType>, MyGenericIn<MyType>>> = TODO()
+                        @JvmName("method53") // Needed to prevent obfuscation due to inline type.
+                        fun method53(param: MyInlineType): MyInlineType = TODO()
+                        fun method54(param: MyGenericOut<MyInlineType>): MyGenericOut<MyInlineType> = TODO()
+                        fun method55(param: MyGenericIn<MyInlineType>): MyGenericIn<MyInlineType> = TODO()
                     }
                 """.trimIndent()
             ), listOf("Subject")