Remove Element.asType calls

These calls are not really reasonable as Element can be anything
(e.g. package) where type would be a NoType.
Instead of that undefined case, this CL replace asType calls with
an extension property (.type) and certain element where it makes
sense.

Even though we cannot enforse it right now, after the migration,
these fields will only exist in specific XElement subclasses so
we'll be able to enforse never getting type from XElement.

Bug: 160323720
Test: existing test suite
Change-Id: Ide734f49b3f6fe25c3022530927407cf10a5d857
diff --git a/room/compiler/src/main/kotlin/androidx/room/ext/element_ext.kt b/room/compiler/src/main/kotlin/androidx/room/ext/element_ext.kt
index 89ab8c2..57119b5 100644
--- a/room/compiler/src/main/kotlin/androidx/room/ext/element_ext.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/ext/element_ext.kt
@@ -404,7 +404,7 @@
         }
         ourParams.forEachIndexed { i, variableElement ->
             // Plus 1 to their index because their first param is a self object.
-            if (!typeUtils.isSameType(theirParams[i + 1].asType(), variableElement.asType())) {
+            if (!typeUtils.isSameType(theirParams[i + 1].type, variableElement.type)) {
                 return false
             }
         }
@@ -523,4 +523,16 @@
 /**
  * Returns the string representation of the element kind.
  */
-fun Element.kindName() = kind.name.toLowerCase(Locale.US)
\ No newline at end of file
+fun Element.kindName() = kind.name.toLowerCase(Locale.US)
+
+// instead of using asType on Element, we should use a specific Element subclass's  .type
+// it is not enforce-able until migrating to the abstraction but still a step in the right direction
+// of safety
+val VariableElement.type: TypeMirror
+    get() = asType()
+
+val TypeElement.type: DeclaredType
+    get() = MoreTypes.asDeclared(asType())
+
+val ExecutableElement.executableType: ExecutableType
+    get() = MoreTypes.asExecutable(asType())
\ No newline at end of file
diff --git a/room/compiler/src/main/kotlin/androidx/room/ext/processing_env_ext.kt b/room/compiler/src/main/kotlin/androidx/room/ext/processing_env_ext.kt
index 4ab6d2b..0e0626a 100644
--- a/room/compiler/src/main/kotlin/androidx/room/ext/processing_env_ext.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/ext/processing_env_ext.kt
@@ -87,7 +87,7 @@
  */
 fun ProcessingEnvironment.requireTypeMirror(
     qName: String
-): TypeMirror = requireTypeElement(qName).asType()
+): TypeMirror = requireTypeElement(qName).type
 
 /**
  * Query a type mirror by KClass and return null if it does not exist
@@ -108,7 +108,7 @@
  */
 fun ProcessingEnvironment.findTypeMirror(
     qName: String
-): TypeMirror? = findTypeElement(qName)?.asType()
+): TypeMirror? = findTypeElement(qName)?.type
 
 fun ProcessingEnvironment.getGeneratedAnnotation(): TypeElement? {
     val element = GeneratedAnnotations.generatedAnnotation(elementUtils, sourceVersion)
diff --git a/room/compiler/src/main/kotlin/androidx/room/kotlin/JvmDescriptorUtils.kt b/room/compiler/src/main/kotlin/androidx/room/kotlin/JvmDescriptorUtils.kt
index 7757f79..09cf3f2 100644
--- a/room/compiler/src/main/kotlin/androidx/room/kotlin/JvmDescriptorUtils.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/kotlin/JvmDescriptorUtils.kt
@@ -16,6 +16,8 @@
 
 package androidx.room.kotlin
 
+import androidx.room.ext.executableType
+import androidx.room.ext.type
 import javax.lang.model.element.Element
 import javax.lang.model.element.ExecutableElement
 import javax.lang.model.element.NestingKind
@@ -42,14 +44,14 @@
  *
  * For reference, see the [JVM specification, section 4.3.2](https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.3.2)
  */
-fun VariableElement.descriptor() = "$simpleName:${asType().descriptor()}"
+fun VariableElement.descriptor() = "$simpleName:${type.descriptor()}"
 
 /**
  * Returns the method descriptor of this [ExecutableElement].
  *
  * For reference, see the [JVM specification, section 4.3.3](https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.3.3)
  */
-fun ExecutableElement.descriptor() = "$simpleName${asType().descriptor()}"
+fun ExecutableElement.descriptor() = "$simpleName${executableType.descriptor()}"
 
 /**
  * Returns the name of this [TypeElement] in its "internal form".
diff --git a/room/compiler/src/main/kotlin/androidx/room/parser/SqlParser.kt b/room/compiler/src/main/kotlin/androidx/room/parser/SqlParser.kt
index 4d817c7..2843611 100644
--- a/room/compiler/src/main/kotlin/androidx/room/parser/SqlParser.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/parser/SqlParser.kt
@@ -18,6 +18,7 @@
 
 import androidx.room.ColumnInfo
 import androidx.room.ext.requireTypeMirror
+import androidx.room.ext.type
 import org.antlr.v4.runtime.tree.ParseTree
 import org.antlr.v4.runtime.tree.TerminalNode
 import javax.annotation.processing.ProcessingEnvironment
@@ -211,7 +212,7 @@
             List<TypeMirror> {
         return primitives.flatMap {
             val primitiveType = env.typeUtils.getPrimitiveType(it)
-            listOf(primitiveType, env.typeUtils.boxedClass(primitiveType).asType())
+            listOf(primitiveType, env.typeUtils.boxedClass(primitiveType).type)
         }
     }
 
diff --git a/room/compiler/src/main/kotlin/androidx/room/processor/DaoProcessor.kt b/room/compiler/src/main/kotlin/androidx/room/processor/DaoProcessor.kt
index 4f3518c..0badc78 100644
--- a/room/compiler/src/main/kotlin/androidx/room/processor/DaoProcessor.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/processor/DaoProcessor.kt
@@ -30,6 +30,7 @@
 import androidx.room.ext.hasAnnotation
 import androidx.room.ext.isAbstract
 import androidx.room.ext.isInterface
+import androidx.room.ext.type
 import androidx.room.ext.typeName
 import androidx.room.verifier.DatabaseVerifier
 import androidx.room.vo.Dao
@@ -158,10 +159,10 @@
         val typeUtils = context.processingEnv.typeUtils
         val goodConstructor = constructors.firstOrNull {
             it.parameters.size == 1 &&
-                    it.parameters[0].asType().isAssignableFrom(typeUtils, dbType)
+                    it.parameters[0].type.isAssignableFrom(typeUtils, dbType)
         }
         val constructorParamType = if (goodConstructor != null) {
-            goodConstructor.parameters[0].asType().typeName()
+            goodConstructor.parameters[0].type.typeName()
         } else {
             validateEmptyConstructor(constructors)
             null
diff --git a/room/compiler/src/main/kotlin/androidx/room/processor/DatabaseProcessor.kt b/room/compiler/src/main/kotlin/androidx/room/processor/DatabaseProcessor.kt
index cb7cb70..e74899c 100644
--- a/room/compiler/src/main/kotlin/androidx/room/processor/DatabaseProcessor.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/processor/DatabaseProcessor.kt
@@ -28,6 +28,7 @@
 import androidx.room.ext.isType
 import androidx.room.ext.requireTypeMirror
 import androidx.room.ext.toAnnotationBox
+import androidx.room.ext.type
 import androidx.room.ext.typeName
 import androidx.room.verifier.DatabaseVerificationErrors
 import androidx.room.verifier.DatabaseVerifier
@@ -74,7 +75,7 @@
         val typeUtils = context.processingEnv.typeUtils
         val extendsRoomDb = roomDatabaseType.isAssignableFrom(
             typeUtils,
-            element.asTypeElement().asType()
+            element.type
         )
         context.checker.check(extendsRoomDb, element, ProcessorErrors.DB_MUST_EXTEND_ROOM_DB)
 
@@ -98,7 +99,7 @@
             // remove methods that belong to room
             val containing = it.enclosingElement
             containing.isType() &&
-                    containing.asType().typeName() == RoomTypeNames.ROOM_DB
+                    containing.type.typeName() == RoomTypeNames.ROOM_DB
         }.map {
             val executable = it.asExecutableElement()
             // TODO when we add support for non Dao return types (e.g. database), this code needs
@@ -117,7 +118,7 @@
         val database = Database(
                 version = dbAnnotation.value.version,
                 element = element,
-                type = element.asTypeElement().asType(),
+                type = element.type,
                 entities = entities,
                 views = views,
                 daoMethods = daoMethods,
diff --git a/room/compiler/src/main/kotlin/androidx/room/processor/EntityOrViewProcessor.kt b/room/compiler/src/main/kotlin/androidx/room/processor/EntityOrViewProcessor.kt
index 0ebde8c..f2326e1 100644
--- a/room/compiler/src/main/kotlin/androidx/room/processor/EntityOrViewProcessor.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/processor/EntityOrViewProcessor.kt
@@ -19,6 +19,7 @@
 import androidx.room.DatabaseView
 import androidx.room.Entity
 import androidx.room.ext.hasAnnotation
+import androidx.room.ext.type
 import androidx.room.ext.typeName
 import androidx.room.vo.EntityOrView
 import androidx.room.vo.Fields
@@ -54,7 +55,7 @@
             override val tableName: String
                 get() = typeName.toString()
             override val typeName: TypeName
-                get() = element.asType().typeName()
+                get() = element.type.typeName()
         }
     }
 }
diff --git a/room/compiler/src/main/kotlin/androidx/room/processor/MethodProcessorDelegate.kt b/room/compiler/src/main/kotlin/androidx/room/processor/MethodProcessorDelegate.kt
index 8a00f05..0df183a 100644
--- a/room/compiler/src/main/kotlin/androidx/room/processor/MethodProcessorDelegate.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/processor/MethodProcessorDelegate.kt
@@ -25,6 +25,7 @@
 import androidx.room.ext.findTypeElement
 import androidx.room.ext.getSuspendFunctionReturnType
 import androidx.room.ext.requireTypeMirror
+import androidx.room.ext.type
 import androidx.room.kotlin.KotlinMetadataElement
 import androidx.room.parser.ParsedQuery
 import androidx.room.solver.prepared.binder.CallablePreparedQueryResultBinder.Companion.createPreparedBinder
@@ -182,7 +183,7 @@
                 .requireTypeMirror(KotlinTypeNames.CONTINUATION.toString())
         )
         executableElement.parameters.last {
-            typesUtil.isSameType(typesUtil.erasure(it.asType()), continuationType)
+            typesUtil.isSameType(typesUtil.erasure(it.type), continuationType)
         }
     }
 
diff --git a/room/compiler/src/main/kotlin/androidx/room/processor/PojoProcessor.kt b/room/compiler/src/main/kotlin/androidx/room/processor/PojoProcessor.kt
index a0d959d..c6614a5 100644
--- a/room/compiler/src/main/kotlin/androidx/room/processor/PojoProcessor.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/processor/PojoProcessor.kt
@@ -41,6 +41,7 @@
 import androidx.room.ext.isTransient
 import androidx.room.ext.kindName
 import androidx.room.ext.toAnnotationBox
+import androidx.room.ext.type
 import androidx.room.ext.typeName
 import androidx.room.kotlin.KotlinMetadataElement
 import androidx.room.kotlin.descriptor
@@ -304,7 +305,7 @@
             val parameterNames = getParamNames(constructor)
             val params = constructor.parameters.mapIndexed param@{ index, param ->
                 val paramName = parameterNames[index]
-                val paramType = param.asType()
+                val paramType = param.type
 
                 val matches = fun(field: Field?): Boolean {
                     return if (field == null) {
@@ -730,7 +731,7 @@
                 element = field.element,
                 msg = ProcessorErrors.mismatchedGetter(
                     fieldName = field.name,
-                    ownerType = element.asType().typeName(),
+                    ownerType = element.type.typeName(),
                     getterType = field.getter.type.typeName(),
                     fieldType = field.typeName
                 ))
@@ -798,7 +799,7 @@
                 element = field.element,
                 msg = ProcessorErrors.mismatchedSetter(
                     fieldName = field.name,
-                    ownerType = element.asType().typeName(),
+                    ownerType = element.type.typeName(),
                     setterType = field.setter.type.typeName(),
                     fieldType = field.typeName
                 ))
diff --git a/room/compiler/src/main/kotlin/androidx/room/processor/RawQueryMethodProcessor.kt b/room/compiler/src/main/kotlin/androidx/room/processor/RawQueryMethodProcessor.kt
index 084b19e..832af1e 100644
--- a/room/compiler/src/main/kotlin/androidx/room/processor/RawQueryMethodProcessor.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/processor/RawQueryMethodProcessor.kt
@@ -24,6 +24,7 @@
 import androidx.room.ext.isEntityElement
 import androidx.room.ext.requireTypeMirror
 import androidx.room.ext.toAnnotationBox
+import androidx.room.ext.type
 import androidx.room.ext.typeName
 import androidx.room.parser.SqlParser
 import androidx.room.processor.ProcessorErrors.RAW_QUERY_STRING_PARAMETER_REMOVED
@@ -96,7 +97,7 @@
                         // if it is empty, report error as it does not make sense
                         if (tableNames.isEmpty()) {
                             context.logger.e(executableElement,
-                                    ProcessorErrors.rawQueryBadEntity(it.asType().typeName()))
+                                    ProcessorErrors.rawQueryBadEntity(it.type.typeName()))
                         }
                         tableNames
                     }
diff --git a/room/compiler/src/main/kotlin/androidx/room/processor/autovalue/AutoValuePojoProcessorDelegate.kt b/room/compiler/src/main/kotlin/androidx/room/processor/autovalue/AutoValuePojoProcessorDelegate.kt
index baa79ca..aa2d9a3 100644
--- a/room/compiler/src/main/kotlin/androidx/room/processor/autovalue/AutoValuePojoProcessorDelegate.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/processor/autovalue/AutoValuePojoProcessorDelegate.kt
@@ -27,6 +27,7 @@
 import androidx.room.ext.isPrivate
 import androidx.room.ext.isStatic
 import androidx.room.ext.kindName
+import androidx.room.ext.type
 import androidx.room.ext.typeName
 import androidx.room.processor.Context
 import androidx.room.processor.PojoProcessor
@@ -88,7 +89,7 @@
             it.isStatic() &&
                     !it.hasAnnotation(Ignore::class) &&
                     !it.isPrivate() &&
-                    typeUtils.isSameType(it.returnType, autoValueElement.asType())
+                    typeUtils.isSameType(it.returnType, autoValueElement.type)
         }
     }
 
diff --git a/room/compiler/src/main/kotlin/androidx/room/solver/types/BoxedPrimitiveColumnTypeAdapter.kt b/room/compiler/src/main/kotlin/androidx/room/solver/types/BoxedPrimitiveColumnTypeAdapter.kt
index 49b4780..b3034af 100644
--- a/room/compiler/src/main/kotlin/androidx/room/solver/types/BoxedPrimitiveColumnTypeAdapter.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/solver/types/BoxedPrimitiveColumnTypeAdapter.kt
@@ -17,6 +17,7 @@
 package androidx.room.solver.types
 
 import androidx.room.ext.L
+import androidx.room.ext.type
 import androidx.room.solver.CodeGenScope
 import asPrimitive
 import javax.annotation.processing.ProcessingEnvironment
@@ -38,7 +39,7 @@
             return primitiveAdapters.map {
                 BoxedPrimitiveColumnTypeAdapter(
                         processingEnvironment.typeUtils
-                                .boxedClass(it.out.asPrimitive()).asType(),
+                                .boxedClass(it.out.asPrimitive()).type,
                         it
                 )
             }
diff --git a/room/compiler/src/main/kotlin/androidx/room/vo/Constructor.kt b/room/compiler/src/main/kotlin/androidx/room/vo/Constructor.kt
index d1e7852..45b2fde 100644
--- a/room/compiler/src/main/kotlin/androidx/room/vo/Constructor.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/vo/Constructor.kt
@@ -18,6 +18,7 @@
 
 import androidx.room.ext.L
 import androidx.room.ext.T
+import androidx.room.ext.asDeclaredType
 import androidx.room.ext.isConstructor
 import androidx.room.ext.isMethod
 import androidx.room.ext.kindName
@@ -46,11 +47,11 @@
         when {
             element.isConstructor() -> {
                 builder.addStatement("$L = new $T($L)", outVar,
-                        element.enclosingElement.asType().typeName(), args)
+                        element.enclosingElement.asDeclaredType().typeName(), args)
             }
             element.isMethod() -> {
                 builder.addStatement("$L = $T.$L($L)", outVar,
-                        element.enclosingElement.asType().typeName(),
+                        element.enclosingElement.asDeclaredType().typeName(),
                         element.simpleName.toString(), args)
             }
             else -> throw IllegalStateException("Invalid constructor kind ${element.kindName()}")
diff --git a/room/compiler/src/test/kotlin/androidx/room/ext/ElementExtTest.kt b/room/compiler/src/test/kotlin/androidx/room/ext/ElementExtTest.kt
index b61b312..40c776e 100644
--- a/room/compiler/src/test/kotlin/androidx/room/ext/ElementExtTest.kt
+++ b/room/compiler/src/test/kotlin/androidx/room/ext/ElementExtTest.kt
@@ -18,6 +18,8 @@
 
 import com.google.common.truth.Truth.assertThat
 import com.google.testing.compile.JavaFileObjects
+import com.squareup.javapoet.ClassName
+import com.squareup.javapoet.TypeName
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.JUnit4
@@ -170,6 +172,38 @@
         }.compilesWithoutError()
     }
 
+    @Test
+    fun types() {
+        val testCode = JavaFileObjects.forSourceLines(
+            "foo.bar.Baz", """
+            package foo.bar;
+
+            public class Baz {
+                public int field;
+                public int method() {
+                    return 3;
+                }
+            }
+        """.trimIndent()
+        )
+        simpleRun(
+            jfos = *arrayOf(testCode)
+        ) {
+            val element = it.processingEnv.requireTypeElement("foo.bar.Baz")
+            val field = element.getAllFieldsIncludingPrivateSupers(it.processingEnv)
+                .first {
+                    it.simpleName.toString() == "field"
+                }
+            val method = element.getDeclaredMethods()
+                .first {
+                    it.simpleName.toString() == "method"
+                }
+            assertThat(field.type.typeName()).isEqualTo(TypeName.INT)
+            assertThat(method.returnType.typeName()).isEqualTo(TypeName.INT)
+            assertThat(element.type.typeName()).isEqualTo(ClassName.get("foo.bar", "Baz"))
+        }.compilesWithoutError()
+    }
+
     private fun assertThat(executables: Iterable<ExecutableElement>) = assertThat(
         executables.map { it.simpleName.toString() }
     )
diff --git a/room/compiler/src/test/kotlin/androidx/room/solver/BasicColumnTypeAdaptersTest.kt b/room/compiler/src/test/kotlin/androidx/room/solver/BasicColumnTypeAdaptersTest.kt
index 583aa37..2053565 100644
--- a/room/compiler/src/test/kotlin/androidx/room/solver/BasicColumnTypeAdaptersTest.kt
+++ b/room/compiler/src/test/kotlin/androidx/room/solver/BasicColumnTypeAdaptersTest.kt
@@ -17,6 +17,7 @@
 package androidx.room.solver
 
 import androidx.room.ext.requireTypeMirror
+import androidx.room.ext.type
 import androidx.room.ext.typeName
 import androidx.room.processor.Context
 import androidx.room.testing.TestInvocation
@@ -186,7 +187,7 @@
             return if (typeKind.isPrimitive) {
                 processingEnv.typeUtils
                         .boxedClass(getTypeMirror(processingEnv) as PrimitiveType)
-                        .asType()
+                        .type
             } else {
                 getTypeMirror(processingEnv)
             }
diff --git a/room/compiler/src/test/kotlin/androidx/room/solver/TypeAssignmentTest.kt b/room/compiler/src/test/kotlin/androidx/room/solver/TypeAssignmentTest.kt
index 8596df1..00f55d1 100644
--- a/room/compiler/src/test/kotlin/androidx/room/solver/TypeAssignmentTest.kt
+++ b/room/compiler/src/test/kotlin/androidx/room/solver/TypeAssignmentTest.kt
@@ -19,6 +19,7 @@
 import androidx.room.ext.getAllFieldsIncludingPrivateSupers
 import androidx.room.ext.isAssignableFromWithoutVariance
 import androidx.room.ext.requireTypeElement
+import androidx.room.ext.type
 import androidx.room.testing.TestInvocation
 import com.google.testing.compile.JavaFileObjects
 import org.hamcrest.CoreMatchers.`is`
@@ -55,8 +56,8 @@
             val testObject = processingEnv.requireTypeElement("foo.bar.MyObject")
             val string = testObject.getField(processingEnv, "mString")
             val integer = testObject.getField(processingEnv, "mInteger")
-            assertThat( integer.asType()
-                .isAssignableFromWithoutVariance(typeUtils, string.asType()),
+            assertThat( integer.type
+                .isAssignableFromWithoutVariance(typeUtils, string.type),
                     `is`(false))
         }
     }
@@ -65,8 +66,8 @@
     fun generics() {
         runTest {
             val testObject = processingEnv.requireTypeElement("foo.bar.MyObject")
-            val set = testObject.getField(processingEnv, "mSet").asType()
-            val hashSet = testObject.getField(processingEnv, "mHashSet").asType()
+            val set = testObject.getField(processingEnv, "mSet").type
+            val hashSet = testObject.getField(processingEnv, "mHashSet").type
             assertThat(hashSet.isAssignableFromWithoutVariance(typeUtils, set), `is`(false))
             assertThat(set.isAssignableFromWithoutVariance(typeUtils, hashSet), `is`(true))
         }
@@ -82,8 +83,8 @@
          */
         runTest {
             val testObject = processingEnv.requireTypeElement("foo.bar.MyObject")
-            val set = testObject.getField(processingEnv, "mSet").asType()
-            val varianceSet = testObject.getField(processingEnv, "mVarianceSet").asType()
+            val set = testObject.getField(processingEnv, "mSet").type
+            val varianceSet = testObject.getField(processingEnv, "mVarianceSet").type
             assertThat(varianceSet.isAssignableFromWithoutVariance(typeUtils, set), `is`(true))
             assertThat(set.isAssignableFromWithoutVariance(typeUtils, varianceSet), `is`(true))
         }
@@ -93,8 +94,8 @@
     fun unboundedVariance() {
         runTest {
             val testObject = processingEnv.requireTypeElement("foo.bar.MyObject")
-            val unbounded = testObject.getField(processingEnv, "mUnboundedMap").asType()
-            val objectMap = testObject.getField(processingEnv, "mStringMap").asType()
+            val unbounded = testObject.getField(processingEnv, "mUnboundedMap").type
+            val objectMap = testObject.getField(processingEnv, "mStringMap").type
             assertThat(objectMap.isAssignableFromWithoutVariance(typeUtils, unbounded), `is`(false))
             assertThat(unbounded.isAssignableFromWithoutVariance(typeUtils, objectMap), `is`(true))
         }