Merge "Migrate DaoWriter raw query codegen to XPoet" into androidx-main
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/ext/javapoet_ext.kt b/room/room-compiler/src/main/kotlin/androidx/room/ext/javapoet_ext.kt
index 4b78ec0..a88bb07 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/ext/javapoet_ext.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/ext/javapoet_ext.kt
@@ -22,6 +22,8 @@
 import androidx.room.compiler.codegen.XCodeBlock
 import androidx.room.compiler.codegen.XFunSpec
 import androidx.room.compiler.codegen.XFunSpec.Builder.Companion.apply
+import androidx.room.compiler.codegen.XMemberName.Companion.companionMember
+import androidx.room.compiler.codegen.XMemberName.Companion.packageMember
 import androidx.room.compiler.codegen.XTypeName
 import androidx.room.compiler.codegen.XTypeSpec
 import androidx.room.compiler.codegen.asClassName
@@ -57,8 +59,7 @@
         ClassName.get("$SQLITE_PACKAGE.db", "SupportSQLiteOpenHelper.Callback")
     val SQLITE_OPEN_HELPER_CONFIG: ClassName =
         ClassName.get("$SQLITE_PACKAGE.db", "SupportSQLiteOpenHelper.Configuration")
-    val QUERY: ClassName =
-        ClassName.get("$SQLITE_PACKAGE.db", "SupportSQLiteQuery")
+    val QUERY = XClassName.get("$SQLITE_PACKAGE.db", "SupportSQLiteQuery")
 }
 
 object RoomTypeNames {
@@ -254,6 +255,13 @@
     val FLOW = ClassName.get("kotlinx.coroutines.flow", "Flow")
 }
 
+object RoomMemberNames {
+    val CURSOR_UTIL_GET_COLUMN_INDEX =
+        RoomTypeNames.CURSOR_UTIL.packageMember("getColumnIndex")
+    val ROOM_SQL_QUERY_ACQUIRE =
+        RoomTypeNames.ROOM_SQL_QUERY.companionMember("acquire", isJvmStatic = true)
+}
+
 val DEFERRED_TYPES = listOf(
     LifecyclesTypeNames.LIVE_DATA,
     LifecyclesTypeNames.COMPUTABLE_LIVE_DATA,
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/processor/ProcessorErrors.kt b/room/room-compiler/src/main/kotlin/androidx/room/processor/ProcessorErrors.kt
index 5e293f9..9cc2640 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/processor/ProcessorErrors.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/processor/ProcessorErrors.kt
@@ -723,7 +723,7 @@
     }
 
     val RAW_QUERY_STRING_PARAMETER_REMOVED = "RawQuery does not allow passing a string anymore." +
-        " Please use ${SupportDbTypeNames.QUERY}."
+        " Please use ${SupportDbTypeNames.QUERY.canonicalName}."
 
     val MISSING_COPY_ANNOTATIONS = "Annotated property getter is missing " +
         "@AutoValue.CopyAnnotations."
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/processor/RawQueryMethodProcessor.kt b/room/room-compiler/src/main/kotlin/androidx/room/processor/RawQueryMethodProcessor.kt
index 7e59ed5..ec08a3d 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/processor/RawQueryMethodProcessor.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/processor/RawQueryMethodProcessor.kt
@@ -18,13 +18,13 @@
 
 import androidx.room.RawQuery
 import androidx.room.Transaction
-import androidx.room.ext.SupportDbTypeNames
-import androidx.room.ext.isEntityElement
-import androidx.room.parser.SqlParser
 import androidx.room.compiler.processing.XMethodElement
 import androidx.room.compiler.processing.XNullability
 import androidx.room.compiler.processing.XType
 import androidx.room.compiler.processing.XVariableElement
+import androidx.room.ext.SupportDbTypeNames
+import androidx.room.ext.isEntityElement
+import androidx.room.parser.SqlParser
 import androidx.room.processor.ProcessorErrors.RAW_QUERY_STRING_PARAMETER_REMOVED
 import androidx.room.vo.MapInfo
 import androidx.room.vo.RawQueryMethod
@@ -155,7 +155,7 @@
             if (isSupportSql) {
                 return RawQueryMethod.RuntimeQueryParameter(
                     paramName = extractParams[0].name,
-                    type = supportQueryType.typeName
+                    typeName = supportQueryType.asTypeName()
                 )
             }
             val stringType = processingEnv.requireType("java.lang.String")
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/vo/RawQueryMethod.kt b/room/room-compiler/src/main/kotlin/androidx/room/vo/RawQueryMethod.kt
index 95948ef..3aafee5 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/vo/RawQueryMethod.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/vo/RawQueryMethod.kt
@@ -16,14 +16,14 @@
 
 package androidx.room.vo
 
-import androidx.room.ext.CommonTypeNames
-import androidx.room.ext.SupportDbTypeNames
+import androidx.room.compiler.codegen.XTypeName
+import androidx.room.compiler.codegen.asClassName
 import androidx.room.compiler.processing.XMethodElement
 import androidx.room.compiler.processing.XType
 import androidx.room.compiler.processing.isKotlinUnit
+import androidx.room.ext.SupportDbTypeNames
 import androidx.room.ext.isNotVoid
 import androidx.room.solver.query.result.QueryResultBinder
-import com.squareup.javapoet.TypeName
 
 /**
  * A class that holds information about a method annotated with RawQuery.
@@ -44,9 +44,9 @@
 
     data class RuntimeQueryParameter(
         val paramName: String,
-        val type: TypeName
+        val typeName: XTypeName
     ) {
-        fun isString() = CommonTypeNames.STRING == type
-        fun isSupportQuery() = SupportDbTypeNames.QUERY == type
+        fun isString() = String::class.asClassName() == typeName
+        fun isSupportQuery() = SupportDbTypeNames.QUERY == typeName
     }
 }
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/writer/DaoWriter.kt b/room/room-compiler/src/main/kotlin/androidx/room/writer/DaoWriter.kt
index 392f5a3..fd6511f 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/writer/DaoWriter.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/writer/DaoWriter.kt
@@ -35,11 +35,11 @@
 import androidx.room.compiler.processing.XType
 import androidx.room.compiler.processing.isVoid
 import androidx.room.ext.L
-import androidx.room.ext.N
+import androidx.room.ext.RoomMemberNames
+import androidx.room.ext.RoomTypeNames
 import androidx.room.ext.RoomTypeNames.DELETE_OR_UPDATE_ADAPTER
 import androidx.room.ext.RoomTypeNames.INSERTION_ADAPTER
 import androidx.room.ext.RoomTypeNames.ROOM_DB
-import androidx.room.ext.RoomTypeNames.ROOM_SQL_QUERY
 import androidx.room.ext.RoomTypeNames.SHARED_SQLITE_STMT
 import androidx.room.ext.RoomTypeNames.UPSERTION_ADAPTER
 import androidx.room.ext.SupportDbTypeNames
@@ -355,42 +355,36 @@
             val roomSQLiteQueryVar: String
             val queryParam = method.runtimeQueryParam
             val shouldReleaseQuery: Boolean
-            when {
-                queryParam?.isString() == true -> {
-                    roomSQLiteQueryVar = scope.getTmpVar("_statement")
-                    shouldReleaseQuery = true
-                    addStatement(
-                        "$T $L = $T.acquire($L, 0)",
-                        ROOM_SQL_QUERY.toJavaPoet(),
-                        roomSQLiteQueryVar,
-                        ROOM_SQL_QUERY.toJavaPoet(),
+            if (queryParam?.isSupportQuery() == true) {
+                roomSQLiteQueryVar = queryParam.paramName
+                shouldReleaseQuery = false
+            } else if (queryParam?.isString() == true) {
+                roomSQLiteQueryVar = scope.getTmpVar("_statement")
+                shouldReleaseQuery = true
+                addLocalVariable(
+                    name = roomSQLiteQueryVar,
+                    typeName = RoomTypeNames.ROOM_SQL_QUERY,
+                    assignExpr = XCodeBlock.of(
+                        codeLanguage,
+                        "%M(%L, 0)",
+                        RoomMemberNames.ROOM_SQL_QUERY_ACQUIRE,
                         queryParam.paramName
-                    )
-                }
-                queryParam?.isSupportQuery() == true -> {
-                    shouldReleaseQuery = false
-                    roomSQLiteQueryVar = scope.getTmpVar("_internalQuery")
-                    // move it to a final variable so that the generated code can use it inside
-                    // callback blocks in java 7
-                    addStatement(
-                        "final $T $L = $N",
-                        queryParam.type,
-                        roomSQLiteQueryVar,
-                        queryParam.paramName
-                    )
-                }
-                else -> {
-                    // try to generate compiling code. we would've already reported this error
-                    roomSQLiteQueryVar = scope.getTmpVar("_statement")
-                    shouldReleaseQuery = false
-                    addStatement(
-                        "$T $L = $T.acquire($L, 0)",
-                        ROOM_SQL_QUERY.toJavaPoet(),
-                        roomSQLiteQueryVar,
-                        ROOM_SQL_QUERY.toJavaPoet(),
+                    ),
+                )
+            } else {
+                // try to generate compiling code. we would've already reported this error
+                roomSQLiteQueryVar = scope.getTmpVar("_statement")
+                shouldReleaseQuery = false
+                addLocalVariable(
+                    name = roomSQLiteQueryVar,
+                    typeName = RoomTypeNames.ROOM_SQL_QUERY,
+                    assignExpr = XCodeBlock.of(
+                        codeLanguage,
+                        "%M(%S, 0)",
+                        RoomMemberNames.ROOM_SQL_QUERY_ACQUIRE,
                         "missing query parameter"
-                    )
-                }
+                    ),
+                )
             }
             if (method.returnsValue) {
                 // don't generate code because it will create 1 more error. The original error is
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/writer/EntityCursorConverterWriter.kt b/room/room-compiler/src/main/kotlin/androidx/room/writer/EntityCursorConverterWriter.kt
index 941e011..399a208 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/writer/EntityCursorConverterWriter.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/writer/EntityCursorConverterWriter.kt
@@ -21,7 +21,7 @@
 import androidx.room.compiler.codegen.XTypeName
 import androidx.room.compiler.codegen.toJavaPoet
 import androidx.room.ext.AndroidTypeNames.CURSOR
-import androidx.room.ext.RoomTypeNames.CURSOR_UTIL
+import androidx.room.ext.RoomMemberNames
 import androidx.room.ext.capitalize
 import androidx.room.ext.stripNonJava
 import androidx.room.solver.CodeGenScope
@@ -62,8 +62,8 @@
                     typeName = XTypeName.PRIMITIVE_INT,
                     assignExpr = XCodeBlock.of(
                         language,
-                        "%T.getColumnIndex(%N, %S)",
-                        CURSOR_UTIL,
+                        "%M(%N, %S)",
+                        RoomMemberNames.CURSOR_UTIL_GET_COLUMN_INDEX,
                         cursorParamName,
                         it.columnName
                     )
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/writer/QueryWriter.kt b/room/room-compiler/src/main/kotlin/androidx/room/writer/QueryWriter.kt
index c2a8745..ec8031f 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/writer/QueryWriter.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/writer/QueryWriter.kt
@@ -18,10 +18,10 @@
 
 import androidx.room.compiler.codegen.XCodeBlock
 import androidx.room.compiler.codegen.XCodeBlock.Builder.Companion.addLocalVal
-import androidx.room.compiler.codegen.XMemberName.Companion.companionMember
 import androidx.room.compiler.codegen.XMemberName.Companion.packageMember
 import androidx.room.compiler.codegen.XTypeName
 import androidx.room.compiler.codegen.asClassName
+import androidx.room.ext.RoomMemberNames
 import androidx.room.ext.RoomTypeNames
 import androidx.room.parser.ParsedQuery
 import androidx.room.parser.Section
@@ -131,8 +131,7 @@
                         assignExpr = XCodeBlock.of(
                             language,
                             "%M(%L, %L)",
-                            RoomTypeNames.ROOM_SQL_QUERY
-                                .companionMember("acquire", isJvmStatic = true),
+                            RoomMemberNames.ROOM_SQL_QUERY_ACQUIRE,
                             outSqlQueryName,
                             argCount
                         )
@@ -152,8 +151,7 @@
                         assignExpr = XCodeBlock.of(
                             language,
                             "%M(%L, %L)",
-                            RoomTypeNames.ROOM_SQL_QUERY
-                                .companionMember("acquire", isJvmStatic = true),
+                            RoomMemberNames.ROOM_SQL_QUERY_ACQUIRE,
                             outSqlQueryName,
                             knownQueryArgsCount
                         )
diff --git a/room/room-compiler/src/test/kotlin/androidx/room/processor/RawQueryMethodProcessorTest.kt b/room/room-compiler/src/test/kotlin/androidx/room/processor/RawQueryMethodProcessorTest.kt
index 78d8ba7..7942588 100644
--- a/room/room-compiler/src/test/kotlin/androidx/room/processor/RawQueryMethodProcessorTest.kt
+++ b/room/room-compiler/src/test/kotlin/androidx/room/processor/RawQueryMethodProcessorTest.kt
@@ -57,7 +57,7 @@
                 `is`(
                     RawQueryMethod.RuntimeQueryParameter(
                         paramName = "query",
-                        type = SupportDbTypeNames.QUERY
+                        typeName = SupportDbTypeNames.QUERY
                     )
                 )
             )
@@ -96,7 +96,7 @@
                 `is`(
                     RawQueryMethod.RuntimeQueryParameter(
                         paramName = "query",
-                        type = SupportDbTypeNames.QUERY
+                        typeName = SupportDbTypeNames.QUERY
                     )
                 )
             )
@@ -119,7 +119,7 @@
                 `is`(
                     RawQueryMethod.RuntimeQueryParameter(
                         paramName = "query",
-                        type = SupportDbTypeNames.QUERY
+                        typeName = SupportDbTypeNames.QUERY
                     )
                 )
             )
@@ -197,7 +197,7 @@
                 `is`(
                     RawQueryMethod.RuntimeQueryParameter(
                         paramName = "query",
-                        type = SupportDbTypeNames.QUERY
+                        typeName = SupportDbTypeNames.QUERY
                     )
                 )
             )
diff --git a/room/room-compiler/src/test/kotlin/androidx/room/writer/KotlinCodeGenTest.kt b/room/room-compiler/src/test/kotlin/androidx/room/writer/KotlinCodeGenTest.kt
index ac68dd6..a17ced3 100644
--- a/room/room-compiler/src/test/kotlin/androidx/room/writer/KotlinCodeGenTest.kt
+++ b/room/room-compiler/src/test/kotlin/androidx/room/writer/KotlinCodeGenTest.kt
@@ -649,6 +649,34 @@
         )
     }
 
+    @Test
+    fun rawQuery() {
+        val testName = object {}.javaClass.enclosingMethod!!.name
+        val src = Source.kotlin(
+            "MyDao.kt",
+            """
+            import androidx.room.*
+            import androidx.sqlite.db.SupportSQLiteQuery
+
+            @Dao
+            interface MyDao {
+              @RawQuery(observedEntities = [MyEntity::class])
+              fun getEntity(sql: SupportSQLiteQuery): MyEntity
+            }
+
+            @Entity
+            data class MyEntity(
+                @PrimaryKey
+                val pk: Long,
+            )
+            """.trimIndent()
+        )
+        runTest(
+            sources = listOf(src, databaseSrc),
+            expectedFilePath = getTestGoldenPath(testName)
+        )
+    }
+
     private fun getTestGoldenPath(testName: String): String {
         return "kotlinCodeGen/$testName.kt"
     }
diff --git a/room/room-compiler/src/test/test-data/daoWriter/output/javac/ComplexDao.java b/room/room-compiler/src/test/test-data/daoWriter/output/javac/ComplexDao.java
index 9868e0a..7b158a9 100644
--- a/room/room-compiler/src/test/test-data/daoWriter/output/javac/ComplexDao.java
+++ b/room/room-compiler/src/test/test-data/daoWriter/output/javac/ComplexDao.java
@@ -665,9 +665,8 @@
 
     @Override
     public User getUserViaRawQuery(final SupportSQLiteQuery rawQuery) {
-        final SupportSQLiteQuery _internalQuery = rawQuery;
         __db.assertNotSuspendingTransaction();
-        final Cursor _cursor = DBUtil.query(__db, _internalQuery, false, null);
+        final Cursor _cursor = DBUtil.query(__db, rawQuery, false, null);
         try {
             final User _result;
             if (_cursor.moveToFirst()) {
diff --git a/room/room-compiler/src/test/test-data/daoWriter/output/ksp/ComplexDao.java b/room/room-compiler/src/test/test-data/daoWriter/output/ksp/ComplexDao.java
index 74d05fa..8a7f450 100644
--- a/room/room-compiler/src/test/test-data/daoWriter/output/ksp/ComplexDao.java
+++ b/room/room-compiler/src/test/test-data/daoWriter/output/ksp/ComplexDao.java
@@ -585,9 +585,8 @@
 
     @Override
     public User getUserViaRawQuery(final SupportSQLiteQuery rawQuery) {
-        final SupportSQLiteQuery _internalQuery = rawQuery;
         __db.assertNotSuspendingTransaction();
-        final Cursor _cursor = DBUtil.query(__db, _internalQuery, false, null);
+        final Cursor _cursor = DBUtil.query(__db, rawQuery, false, null);
         try {
             final User _result;
             if (_cursor.moveToFirst()) {
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/rawQuery.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/rawQuery.kt
new file mode 100644
index 0000000..688d74c
--- /dev/null
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/rawQuery.kt
@@ -0,0 +1,56 @@
+import android.database.Cursor
+import androidx.room.RoomDatabase
+import androidx.room.util.getColumnIndex
+import androidx.room.util.query
+import androidx.sqlite.db.SupportSQLiteQuery
+import java.lang.Class
+import javax.`annotation`.processing.Generated
+import kotlin.Int
+import kotlin.Long
+import kotlin.Suppress
+import kotlin.collections.List
+import kotlin.jvm.JvmStatic
+
+@Generated(value = ["androidx.room.RoomProcessor"])
+@Suppress(names = ["unchecked", "deprecation"])
+public class MyDao_Impl : MyDao {
+    private val __db: RoomDatabase
+
+    public constructor(__db: RoomDatabase) {
+        this.__db = __db
+    }
+
+    public override fun getEntity(sql: SupportSQLiteQuery): MyEntity {
+        __db.assertNotSuspendingTransaction()
+        val _cursor: Cursor = query(__db, sql, false, null)
+        try {
+            val _result: MyEntity
+            if (_cursor.moveToFirst()) {
+                _result = __entityCursorConverter_MyEntity(_cursor)
+            } else {
+                error("Cursor was empty, but expected a single item.")
+            }
+            return _result
+        } finally {
+            _cursor.close()
+        }
+    }
+
+    private fun __entityCursorConverter_MyEntity(cursor: Cursor): MyEntity {
+        val _entity: MyEntity
+        val _cursorIndexOfPk: Int = getColumnIndex(cursor, "pk")
+        val _tmpPk: Long
+        if (_cursorIndexOfPk == -1) {
+            _tmpPk = 0
+        } else {
+            _tmpPk = cursor.getLong(_cursorIndexOfPk)
+        }
+        _entity = MyEntity(_tmpPk)
+        return _entity
+    }
+
+    public companion object {
+        @JvmStatic
+        public fun getRequiredConverters(): List<Class<*>> = emptyList()
+    }
+}
\ No newline at end of file