Deprecate XTypeElement.superType in favor of superClass.

The function name superType was misleading and the behaviour more precisely reflected that of javac's getSuperClass(). Specifically since XTypeElement also represent interfaces, the super types of those when no super interface is present is Object / Any. Meanwhile the super class of interfaces is null, they have none since they are not classes.

Test: XTypeElementTest
Change-Id: Ie0cd5418c05cdadebf2f2c55cd883ff9fd949a66
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/DeclarationCollector.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/DeclarationCollector.kt
index f5bbf53..038f117 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/DeclarationCollector.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/DeclarationCollector.kt
@@ -36,7 +36,7 @@
                 }
             }
             // visit all declared fields on super types
-            type.superType?.typeElement?.let { parent ->
+            type.superClass?.typeElement?.let { parent ->
                 yieldAllFields(parent)
             }
         }
@@ -66,7 +66,7 @@
                 }
             }
             // Next, visit all super class methods.
-            type.superType?.typeElement?.let {
+            type.superClass?.typeElement?.let {
                 collectAllMethodsByName(it)
             }
             // Finally, visit all methods declared in this type.
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XTypeElement.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XTypeElement.kt
index 650a183..7a16840 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XTypeElement.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XTypeElement.kt
@@ -44,7 +44,24 @@
     /**
      * The super type of this element if it represents a class.
      */
+    @Deprecated(
+        message = "Function name was misleading.",
+        replaceWith = ReplaceWith("superClass")
+    )
     val superType: XType?
+        get() = superClass
+
+    /**
+     * The direct super types of this element.
+     *
+     * See [JLS 4.10.2](https://docs.oracle.com/javase/specs/jls/se18/html/jls-4.html#jls-4.10.2)
+     */
+    val superTypes: List<XType>
+
+    /**
+     * The super class of this element if it represents a class.
+     */
+    val superClass: XType?
 
     /**
      * The super interfaces implemented by this class.
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacTypeElement.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacTypeElement.kt
index 7fdfbc9..9a5fa0a 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacTypeElement.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacTypeElement.kt
@@ -22,6 +22,7 @@
 import androidx.room.compiler.processing.XHasModifiers
 import androidx.room.compiler.processing.XMethodElement
 import androidx.room.compiler.processing.XMemberContainer
+import androidx.room.compiler.processing.XType
 import androidx.room.compiler.processing.XTypeElement
 import androidx.room.compiler.processing.collectAllMethods
 import androidx.room.compiler.processing.collectFieldsIncludingPrivateSupers
@@ -31,6 +32,7 @@
 import com.google.auto.common.MoreElements
 import com.google.auto.common.MoreTypes
 import com.squareup.javapoet.ClassName
+import com.squareup.javapoet.TypeName
 import javax.lang.model.element.ElementKind
 import javax.lang.model.element.TypeElement
 import javax.lang.model.type.TypeKind
@@ -175,7 +177,18 @@
         )
     }
 
-    override val superType: JavacType? by lazy {
+    override val superTypes: List<XType> by lazy {
+        buildList {
+            if (isInterface() && superInterfaces.isEmpty()) {
+                add(env.requireType(TypeName.OBJECT))
+            } else {
+                superClass?.let { add(it) }
+                addAll(superInterfaces)
+            }
+        }
+    }
+
+    override val superClass: JavacType? by lazy {
         // javac models non-existing types as TypeKind.NONE but we prefer to make it nullable.
         // just makes more sense and safer as we don't need to check for none.
 
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 36983be..4133789 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
@@ -42,6 +42,7 @@
 import com.google.devtools.ksp.symbol.KSPropertyDeclaration
 import com.google.devtools.ksp.symbol.Modifier
 import com.squareup.javapoet.ClassName
+import com.squareup.javapoet.TypeName
 
 internal sealed class KspTypeElement(
     env: KspProcessingEnv,
@@ -83,15 +84,32 @@
         )
     }
 
-    override val superType: XType? by lazy {
-        declaration.superTypes.firstOrNull {
-            val type = it.resolve().declaration as? KSClassDeclaration ?: return@firstOrNull false
-            type.classKind == ClassKind.CLASS
-        }?.let {
-            env.wrap(
-                ksType = it.resolve(),
-                allowPrimitives = false
-            )
+    override val superTypes: List<XType> by lazy {
+        buildList {
+            if (isInterface() && superInterfaces.isEmpty()) {
+                add(env.requireType(TypeName.OBJECT))
+            } else {
+                superClass?.let { add(it) }
+                addAll(superInterfaces)
+            }
+        }
+    }
+
+    override val superClass: XType? by lazy {
+        if (isInterface()) {
+            // interfaces don't have super classes (they do have super types)
+            null
+        } else {
+            declaration.superTypes.firstOrNull {
+                val type =
+                    it.resolve().declaration as? KSClassDeclaration ?: return@firstOrNull false
+                type.classKind == ClassKind.CLASS
+            }?.let {
+                env.wrap(
+                    ksType = it.resolve(),
+                    allowPrimitives = false
+                )
+            }
         }
     }
 
diff --git a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XElementTest.kt b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XElementTest.kt
index c071a0c..a607bcc 100644
--- a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XElementTest.kt
+++ b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XElementTest.kt
@@ -469,7 +469,7 @@
         ) {
             val element = it.processingEnv.requireTypeElement("java.lang.Object")
             // make sure we return null for not existing types
-            assertThat(element.superType).isNull()
+            assertThat(element.superClass).isNull()
         }
     }
 
diff --git a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XProcessingEnvTest.kt b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XProcessingEnvTest.kt
index 5e567bb..a66452a 100644
--- a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XProcessingEnvTest.kt
+++ b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XProcessingEnvTest.kt
@@ -123,7 +123,7 @@
             assertThat(element.getDeclaredMethods()).hasSize(2)
             assertThat(element.kindName()).isEqualTo("class")
             assertThat(element.isInterface()).isFalse()
-            assertThat(element.superType?.typeName).isEqualTo(TypeName.OBJECT)
+            assertThat(element.superClass?.typeName).isEqualTo(TypeName.OBJECT)
         }
     }
 
diff --git a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XTypeElementTest.kt b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XTypeElementTest.kt
index 79b7dd2..0c1d116 100644
--- a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XTypeElementTest.kt
+++ b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XTypeElementTest.kt
@@ -118,13 +118,18 @@
             }
             abstract class AbstractClass {}
             interface MyInterface {}
+            interface AnotherInterface : MyInterface {}
             """.trimIndent()
         )
         runProcessorTest(sources = listOf(src)) { invocation ->
             invocation.processingEnv.requireTypeElement("foo.bar.Baz").let {
-                assertThat(it.superType).isEqualTo(
+                assertThat(it.superClass).isEqualTo(
                     invocation.processingEnv.requireType("foo.bar.AbstractClass")
                 )
+                assertThat(it.superTypes).containsExactly(
+                    invocation.processingEnv.requireType("foo.bar.AbstractClass"),
+                    invocation.processingEnv.requireType("foo.bar.MyInterface")
+                )
                 assertThat(it.type).isEqualTo(
                     invocation.processingEnv.requireType("foo.bar.Baz")
                 )
@@ -133,11 +138,12 @@
                 assertThat(it.isAbstract()).isFalse()
             }
             invocation.processingEnv.requireTypeElement("foo.bar.AbstractClass").let {
-                assertThat(it.superType).let {
-                    it.isEqualTo(
-                        invocation.processingEnv.requireType(TypeName.OBJECT)
-                    )
-                }
+                assertThat(it.superClass).isEqualTo(
+                    invocation.processingEnv.requireType(TypeName.OBJECT)
+                )
+                assertThat(it.superTypes).containsExactly(
+                    invocation.processingEnv.requireType(TypeName.OBJECT)
+                )
                 assertThat(it.isAbstract()).isTrue()
                 assertThat(it.isInterface()).isFalse()
                 assertThat(it.type).isEqualTo(
@@ -145,8 +151,8 @@
                 )
             }
             invocation.processingEnv.requireTypeElement("foo.bar.MyInterface").let {
-                assertThat(it.superType).isAnyOf(
-                    null,
+                assertThat(it.superClass).isNull()
+                assertThat(it.superTypes).containsExactly(
                     invocation.processingEnv.requireType(TypeName.OBJECT)
                 )
                 assertThat(it.isInterface()).isTrue()
@@ -154,6 +160,16 @@
                     invocation.processingEnv.requireType("foo.bar.MyInterface")
                 )
             }
+            invocation.processingEnv.requireTypeElement("foo.bar.AnotherInterface").let {
+                assertThat(it.superClass).isNull()
+                assertThat(it.superTypes).containsExactly(
+                    invocation.processingEnv.requireType("foo.bar.MyInterface")
+                )
+                assertThat(it.isInterface()).isTrue()
+                assertThat(it.type).isEqualTo(
+                    invocation.processingEnv.requireType("foo.bar.AnotherInterface")
+                )
+            }
         }
     }
 
@@ -810,7 +826,7 @@
         runProcessorTest(sources = listOf(src)) { invocation ->
             val base = invocation.processingEnv.requireTypeElement("DerivedInterface")
             val methodNames = base.getAllMethods().toList().jvmNames()
-            assertThat(methodNames).containsAtLeast(
+            assertThat(methodNames).containsExactly(
                 "get", "getAll", "putAll", "getAllWithDefault"
             )
         }
@@ -1211,21 +1227,21 @@
                 assertThat(base.getDeclaredMethods().jvmNames()).containsExactly(
                     "getX"
                 )
-                assertThat(base.getAllMethods().jvmNames()).contains(
+                assertThat(base.getAllMethods().jvmNames()).containsExactly(
                     "getX"
                 )
-                assertThat(base.getAllNonPrivateInstanceMethods().jvmNames()).contains(
+                assertThat(base.getAllNonPrivateInstanceMethods().jvmNames()).containsExactly(
                     "getX"
                 )
             }
             invocation.processingEnv.requireTypeElement("GetterSetter").let { sub ->
-                assertThat(sub.getDeclaredMethods().jvmNames()).containsAtLeast(
+                assertThat(sub.getDeclaredMethods().jvmNames()).containsExactly(
                     "getY", "setY"
                 )
-                assertThat(sub.getAllMethods().jvmNames()).containsAtLeast(
+                assertThat(sub.getAllMethods().jvmNames()).containsExactly(
                     "getX", "getY", "setY"
                 )
-                assertThat(sub.getAllNonPrivateInstanceMethods().jvmNames()).containsAtLeast(
+                assertThat(sub.getAllNonPrivateInstanceMethods().jvmNames()).containsExactly(
                     "getX", "getY", "setY"
                 )
             }
diff --git a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XTypeTest.kt b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XTypeTest.kt
index e9105f8..9f0364c 100644
--- a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XTypeTest.kt
+++ b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XTypeTest.kt
@@ -270,7 +270,7 @@
             sources = listOf(missingTypeRef)
         ) {
             val element = it.processingEnv.requireTypeElement("foo.bar.Baz")
-            assertThat(element.superType?.isError()).isTrue()
+            assertThat(element.superClass?.isError()).isTrue()
             it.assertCompilationResult {
                 compilationDidFail()
             }
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/ext/xtype_ext.kt b/room/room-compiler/src/main/kotlin/androidx/room/ext/xtype_ext.kt
index b9e1dd7..315afe6 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/ext/xtype_ext.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/ext/xtype_ext.kt
@@ -95,7 +95,7 @@
 
     if (hasEquals && hasHashCode) return true
 
-    return typeElement.superType?.let { it.implementsEqualsAndHashcode() } ?: false
+    return typeElement.superClass?.implementsEqualsAndHashcode() ?: false
 }
 
 /**
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/processor/DaoProcessor.kt b/room/room-compiler/src/main/kotlin/androidx/room/processor/DaoProcessor.kt
index 0a4a532..7e90b44 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/processor/DaoProcessor.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/processor/DaoProcessor.kt
@@ -172,9 +172,7 @@
         // Kotlin.
         val unannotatedMethods = methods[Any::class] ?: emptyList<XMethodElement>()
         val delegatingMethods =
-            if (element.superType != null ||
-                element.getSuperInterfaceElements().isNotEmpty()
-            ) {
+            if (element.superClass != null || element.getSuperInterfaceElements().isNotEmpty()) {
                 matchKotlinBoxedPrimitiveMethods(
                     unannotatedMethods,
                     methods.values.flatten() - unannotatedMethods
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/processor/TableEntityProcessor.kt b/room/room-compiler/src/main/kotlin/androidx/room/processor/TableEntityProcessor.kt
index 73f549f..1c17c65 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/processor/TableEntityProcessor.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/processor/TableEntityProcessor.kt
@@ -123,7 +123,7 @@
                     )
                 }
             }
-        val superIndices = loadSuperIndices(element.superType, tableName, inheritSuperIndices)
+        val superIndices = loadSuperIndices(element.superClass, tableName, inheritSuperIndices)
         val indexInputs = entityIndices + fieldIndices + superIndices
         val indices = validateAndCreateIndices(indexInputs, pojo)
 
@@ -387,7 +387,7 @@
             }
         } ?: emptyList()
         // checks supers.
-        val mySuper = typeElement.superType
+        val mySuper = typeElement.superClass
         val superPKeys = if (mySuper != null && mySuper.isNotNone()) {
             // my super cannot see my fields so remove them.
             val remainingFields = availableFields.filterNot {
@@ -444,7 +444,7 @@
             myPKeys.first()
         } else if (myPKeys.isEmpty()) {
             // i have not declared anything, delegate to super
-            val mySuper = typeElement.superType
+            val mySuper = typeElement.superClass
             if (mySuper != null && mySuper.isNotNone()) {
                 return choosePrimaryKey(candidates, mySuper.typeElement!!)
             }
@@ -567,6 +567,6 @@
                     emptyList()
                 }
             } ?: emptyList()
-        return myIndices + loadSuperIndices(parentTypeElement.superType, tableName, inherit)
+        return myIndices + loadSuperIndices(parentTypeElement.superClass, tableName, inherit)
     }
 }