[go: nahoru, domu]

Work around for KAPT bug for receiver parameter names.

This CL works around a bug in KAPT where the receiver parameter names
are incorrect in the java stubs. Rather than rely on the given name,
we build the name based on the enclosing method to match KSP.

Test: XExecutableElementTest.kt
Change-Id: Ie04351fd0c1dc74cd53a8e9fe7d24bf9f9731b06
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacMethodParameter.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacMethodParameter.kt
index 8c78886..66c3ea0 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacMethodParameter.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacMethodParameter.kt
@@ -51,9 +51,14 @@
     override val kotlinMetadata by lazy { kotlinMetadataFactory() }
 
     override val name: String
-        get() = (kotlinMetadata?.name ?: super.name).sanitizeAsJavaParameterName(
-            argIndex = argIndex
-        )
+        get() = if (isReceiverParam() && enclosingElement.isAbstract()) {
+            // Receiver parameter names for abstract methods are not reliable across different
+            // versions of KAPT so we just build the name ourselves to match KSP.
+            // https://youtrack.jetbrains.com/issue/KT-18048/kapt-drops-method-parameter-names
+            "\$this\$${enclosingElement.name}"
+        } else {
+            (kotlinMetadata?.name ?: super.name)
+        }.sanitizeAsJavaParameterName(argIndex)
 
     override val kotlinType: KmTypeContainer?
         get() = kotlinMetadata?.type
diff --git a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XExecutableElementTest.kt b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XExecutableElementTest.kt
index db2aa22..181265e6 100644
--- a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XExecutableElementTest.kt
+++ b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XExecutableElementTest.kt
@@ -1429,4 +1429,52 @@
                 )
         }
     }
+
+    @Test
+    fun receiverParameterNames(@TestParameter isPrecompiled: Boolean) {
+        val kotlinSource = Source.kotlin(
+            "foo.bar.Subject.kt",
+            """
+            package foo.bar
+            abstract class Subject {
+                fun Bar.method(): Unit = TODO()
+                fun Bar.methodWithParam(name: String): Unit = TODO()
+                abstract fun Bar.abstractMethod()
+                abstract fun Bar.abstractMethodWithParam(name: String)
+                @JvmName("newMethodWithJvmName")
+                fun Bar.methodWithJvmName(): Unit = TODO()
+                @JvmName("newMethodWithJvmNameAndParam")
+                fun Bar.methodWithJvmNameAndParam(name: String): Unit = TODO()
+            }
+            class Bar
+            """.trimIndent())
+        runProcessorTest(
+            sources = if (isPrecompiled) {
+                emptyList()
+            } else {
+                listOf(kotlinSource)
+            },
+            classpath = if (isPrecompiled) {
+                compileFiles(listOf(kotlinSource))
+            } else {
+                emptyList()
+            }
+        ) { invocation ->
+            val subject = invocation.processingEnv.requireTypeElement("foo.bar.Subject")
+
+            // Assert on the method and parameter names of each declared method.
+            assertThat(
+                subject.getDeclaredMethods().map { method ->
+                    "${method.name}(${method.parameters.joinToString(", ") { it.name }})"
+                }
+            ).containsExactly(
+                "method(\$this\$method)",
+                "methodWithParam(\$this\$methodWithParam, name)",
+                "abstractMethod(\$this\$abstractMethod)",
+                "abstractMethodWithParam(\$this\$abstractMethodWithParam, name)",
+                "methodWithJvmName(\$this\$methodWithJvmName)",
+                "methodWithJvmNameAndParam(\$this\$methodWithJvmNameAndParam, name)",
+            ).inOrder()
+        }
+    }
 }