[go: nahoru, domu]

Disallow blocking transaction wrapper DAO function for non-Android targets.

This check was missed as part of aosp/2816483.

Bug: 329827977
Test: RoomKmpGradlePluginTest
Change-Id: Ia3fbcbe881d460f1f203d6e819af6205a70e3731
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/processor/TransactionMethodProcessor.kt b/room/room-compiler/src/main/kotlin/androidx/room/processor/TransactionMethodProcessor.kt
index 59ca629..1d59ad0 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/processor/TransactionMethodProcessor.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/processor/TransactionMethodProcessor.kt
@@ -44,16 +44,33 @@
         val returnType = delegate.extractReturnType()
         val rawReturnType = returnType.rawType
 
-        DEFERRED_TYPES.firstOrNull { className ->
+        val deferredReturnTypeName = DEFERRED_TYPES.firstOrNull { className ->
             context.processingEnv.findType(className.canonicalName)
                 ?.rawType?.isAssignableFrom(rawReturnType) ?: false
-        }?.let { returnTypeName ->
+        }
+        if (deferredReturnTypeName != null) {
             context.logger.e(
-                ProcessorErrors.transactionMethodAsync(returnTypeName.toString()),
+                ProcessorErrors.transactionMethodAsync(
+                    deferredReturnTypeName.toString(context.codeLanguage)
+                ),
                 executableElement
             )
         }
 
+        val isSuspendFunction = delegate.executableElement.isSuspendFunction()
+        if (
+            !isSuspendFunction &&
+            deferredReturnTypeName == null &&
+            !context.isAndroidOnlyTarget()
+        ) {
+            // A blocking transaction wrapper function is not allowed if the target platforms
+            // include non-Android targets.
+            context.logger.e(
+                executableElement,
+                ProcessorErrors.INVALID_BLOCKING_DAO_FUNCTION_NON_ANDROID
+            )
+        }
+
         val callType = when {
             containingElement.isInterface() && executableElement.isJavaDefault() ->
                 TransactionMethod.CallType.DEFAULT_JAVA8
diff --git a/room/room-compiler/src/test/kotlin/androidx/room/processor/TransactionMethodProcessorTest.kt b/room/room-compiler/src/test/kotlin/androidx/room/processor/TransactionMethodProcessorTest.kt
index 8dd1492..10e43f7 100644
--- a/room/room-compiler/src/test/kotlin/androidx/room/processor/TransactionMethodProcessorTest.kt
+++ b/room/room-compiler/src/test/kotlin/androidx/room/processor/TransactionMethodProcessorTest.kt
@@ -19,6 +19,7 @@
 import COMMON
 import androidx.room.Dao
 import androidx.room.Transaction
+import androidx.room.compiler.codegen.CodeLanguage
 import androidx.room.compiler.processing.XTypeElement
 import androidx.room.compiler.processing.util.Source
 import androidx.room.compiler.processing.util.XTestInvocation
@@ -114,7 +115,7 @@
             invocation.assertCompilationResult {
                 hasErrorContaining(
                     ProcessorErrors.transactionMethodAsync(
-                        FLOW.rawTypeName.toString()
+                        FLOW.rawTypeName.toString(CodeLanguage.JAVA)
                     )
                 )
             }
@@ -133,7 +134,7 @@
             invocation.assertCompilationResult {
                 hasErrorContaining(
                     ProcessorErrors.transactionMethodAsync(
-                        LIVE_DATA.rawTypeName.toString()
+                        LIVE_DATA.rawTypeName.toString(CodeLanguage.JAVA)
                     )
                 )
             }
@@ -152,7 +153,7 @@
             invocation.assertCompilationResult {
                 hasErrorContaining(
                     ProcessorErrors.transactionMethodAsync(
-                        COMPUTABLE_LIVE_DATA.rawTypeName.toString()
+                        COMPUTABLE_LIVE_DATA.rawTypeName.toString(CodeLanguage.JAVA)
                     )
                 )
             }
@@ -171,7 +172,7 @@
             invocation.assertCompilationResult {
                 hasErrorContaining(
                     ProcessorErrors.transactionMethodAsync(
-                        RxJava2TypeNames.FLOWABLE.rawTypeName.toString()
+                        RxJava2TypeNames.FLOWABLE.rawTypeName.toString(CodeLanguage.JAVA)
                     )
                 )
             }
@@ -192,7 +193,7 @@
             invocation.assertCompilationResult {
                 hasErrorContaining(
                     ProcessorErrors.transactionMethodAsync(
-                        RxJava3TypeNames.FLOWABLE.rawTypeName.toString()
+                        RxJava3TypeNames.FLOWABLE.rawTypeName.toString(CodeLanguage.JAVA)
                     )
                 )
             }
@@ -211,7 +212,7 @@
             invocation.assertCompilationResult {
                 hasErrorContaining(
                     ProcessorErrors.transactionMethodAsync(
-                        RxJava2TypeNames.COMPLETABLE.rawTypeName.toString()
+                        RxJava2TypeNames.COMPLETABLE.rawTypeName.toString(CodeLanguage.JAVA)
                     )
                 )
             }
@@ -232,7 +233,7 @@
             invocation.assertCompilationResult {
                 hasErrorContaining(
                     ProcessorErrors.transactionMethodAsync(
-                        RxJava3TypeNames.COMPLETABLE.rawTypeName.toString()
+                        RxJava3TypeNames.COMPLETABLE.rawTypeName.toString(CodeLanguage.JAVA)
                     )
                 )
             }
@@ -251,7 +252,7 @@
             invocation.assertCompilationResult {
                 hasErrorContaining(
                     ProcessorErrors.transactionMethodAsync(
-                        RxJava2TypeNames.SINGLE.rawTypeName.toString()
+                        RxJava2TypeNames.SINGLE.rawTypeName.toString(CodeLanguage.JAVA)
                     )
                 )
             }
@@ -272,7 +273,7 @@
             invocation.assertCompilationResult {
                 hasErrorContaining(
                     ProcessorErrors.transactionMethodAsync(
-                        RxJava3TypeNames.SINGLE.rawTypeName.toString()
+                        RxJava3TypeNames.SINGLE.rawTypeName.toString(CodeLanguage.JAVA)
                     )
                 )
             }
@@ -291,7 +292,7 @@
             invocation.assertCompilationResult {
                 hasErrorContaining(
                     ProcessorErrors.transactionMethodAsync(
-                        LISTENABLE_FUTURE.rawTypeName.toString()
+                        LISTENABLE_FUTURE.rawTypeName.toString(CodeLanguage.JAVA)
                     )
                 )
             }
@@ -310,7 +311,7 @@
             invocation.assertCompilationResult {
                 hasErrorContaining(
                     ProcessorErrors.transactionMethodAsync(
-                        PUBLISHER.rawTypeName.toString()
+                        PUBLISHER.rawTypeName.toString(CodeLanguage.JAVA)
                     )
                 )
             }
@@ -336,7 +337,8 @@
             COMMON.RX3_SINGLE, COMMON.LISTENABLE_FUTURE, COMMON.FLOW
         )
         runProcessorTest(
-            sources = inputSource + otherSources
+            sources = inputSource + otherSources,
+            options = mapOf(Context.BooleanProcessorOptions.GENERATE_KOTLIN.argName to "false")
         ) { invocation ->
             val (owner, methods) = invocation.roundEnv
                 .getElementsAnnotatedWith(Dao::class.qualifiedName!!)
diff --git a/room/room-gradle-plugin/src/test/java/androidx/room/gradle/RoomKmpGradlePluginTest.kt b/room/room-gradle-plugin/src/test/java/androidx/room/gradle/RoomKmpGradlePluginTest.kt
index bc7b632..1537e8f 100644
--- a/room/room-gradle-plugin/src/test/java/androidx/room/gradle/RoomKmpGradlePluginTest.kt
+++ b/room/room-gradle-plugin/src/test/java/androidx/room/gradle/RoomKmpGradlePluginTest.kt
@@ -178,10 +178,33 @@
     }
 
     @Test
-    fun `Blocking DAO function in non-Android source set`() {
+    fun `Blocking query DAO function in non-Android source set`() {
         setup(generateKotlin = "true")
 
-        // Make a change that changes the schema at version 1
+        searchAndReplace(
+            file = projectSetup.rootDir.resolve("src/nativeMain/kotlin/room/testapp/MyDatabase.kt"),
+            search = "// Insert-change",
+            replace = """
+                @Query("SELECT * FROM NativeEntity")
+                fun blockingQuery(): NativeEntity
+            """.trimIndent()
+        )
+
+        runGradle(
+            NATIVE_COMPILE_TASK,
+            projectDir = projectSetup.rootDir,
+            expectFailure = true
+        ).let { result ->
+            result.assertTaskOutcome(NATIVE_KSP_TASK, TaskOutcome.FAILED)
+            result.output.contains("Only suspend functions are allowed in DAOs" +
+                " declared in non-Android platforms.")
+        }
+    }
+
+    @Test
+    fun `Blocking shortcut DAO function in non-Android source set`() {
+        setup(generateKotlin = "true")
+
         searchAndReplace(
             file = projectSetup.rootDir.resolve("src/nativeMain/kotlin/room/testapp/MyDatabase.kt"),
             search = "// Insert-change",
@@ -202,6 +225,30 @@
         }
     }
 
+    @Test
+    fun `Blocking transaction wrapper DAO function in non-Android source set`() {
+        setup(generateKotlin = "true")
+
+        searchAndReplace(
+            file = projectSetup.rootDir.resolve("src/nativeMain/kotlin/room/testapp/MyDatabase.kt"),
+            search = "// Insert-change",
+            replace = """
+                @Transaction
+                fun blockingTransaction() { }
+            """.trimIndent()
+        )
+
+        runGradle(
+            NATIVE_COMPILE_TASK,
+            projectDir = projectSetup.rootDir,
+            expectFailure = true
+        ).let { result ->
+            result.assertTaskOutcome(NATIVE_KSP_TASK, TaskOutcome.FAILED)
+            result.output.contains("Only suspend functions are allowed in DAOs" +
+                " declared in non-Android platforms.")
+        }
+    }
+
     companion object {
         private const val CLEAN_TASK = ":clean"
         private const val COMMON_KSP_TASK = ":kspCommonMainKotlinMetadata"