Merge "Consolidate behaviour of receiver parameter between KAPT and KSP" into snap-temp-L22400000952474417
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XMethodElement.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XMethodElement.kt
index c85e818..600520d 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XMethodElement.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XMethodElement.kt
@@ -98,11 +98,16 @@
     /**
      * Returns true if this is a suspend function.
      *
-     * @see XMethodType.getSuspendFunctionReturnType
+     * @see XSuspendMethodType
      */
     fun isSuspendFunction(): Boolean
 
     /**
+     * Returns true if this is an extension function.
+     */
+    fun isExtensionFunction(): Boolean
+
+    /**
      * Returns true if this method can be overridden without checking its enclosing [XElement].
      */
     fun isOverrideableIgnoringContainer(): Boolean {
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XSuspendMethodType.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XSuspendMethodType.kt
index 997efac..028c724 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XSuspendMethodType.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XSuspendMethodType.kt
@@ -18,7 +18,7 @@
 
 interface XSuspendMethodType : XMethodType {
     /**
-     * IfReturns the real return type as seen by Kotlin.
+     * Returns the real suspend function return type as seen by Kotlin.
      */
     fun getSuspendFunctionReturnType(): XType
 }
\ No newline at end of file
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacConstructorElement.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacConstructorElement.kt
index 1eae5ff..5bc60e7 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacConstructorElement.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacConstructorElement.kt
@@ -45,6 +45,19 @@
         element.requireEnclosingType(env)
     }
 
+    override val parameters: List<JavacMethodParameter> by lazy {
+        element.parameters.mapIndexed { index, variable ->
+            JavacMethodParameter(
+                env = env,
+                enclosingMethodElement = this,
+                containing = containing,
+                element = variable,
+                kotlinMetadataFactory = { kotlinMetadata?.parameters?.getOrNull(index) },
+                argIndex = index
+            )
+        }
+    }
+
     override val executableType: XConstructorType by lazy {
         val asMemberOf = env.typeUtils.asMemberOf(containing.type.typeMirror, element)
         JavacConstructorType(
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacExecutableElement.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacExecutableElement.kt
index c578727c..929fb02 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacExecutableElement.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacExecutableElement.kt
@@ -39,18 +39,7 @@
         element.descriptor()
     }
 
-    override val parameters: List<JavacMethodParameter> by lazy {
-        element.parameters.mapIndexed { index, variable ->
-            JavacMethodParameter(
-                env = env,
-                enclosingMethodElement = this,
-                containing = containing,
-                element = variable,
-                kotlinMetadataFactory = { kotlinMetadata?.parameters?.getOrNull(index) },
-                argIndex = index
-            )
-        }
-    }
+    abstract override val parameters: List<JavacMethodParameter>
 
     override val equalityItems: Array<out Any?> by lazy {
         arrayOf(element, containing)
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacMethodElement.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacMethodElement.kt
index 66093c0..6337406 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacMethodElement.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacMethodElement.kt
@@ -56,6 +56,22 @@
         element.requireEnclosingType(env)
     }
 
+    override val parameters: List<JavacMethodParameter> by lazy {
+        element.parameters.mapIndexed { index, variable ->
+            JavacMethodParameter(
+                env = env,
+                enclosingMethodElement = this,
+                containing = containing,
+                element = variable,
+                kotlinMetadataFactory = {
+                    val metadataParamIndex = if (isExtensionFunction()) index - 1 else index
+                    kotlinMetadata?.parameters?.getOrNull(metadataParamIndex)
+                },
+                argIndex = index
+            )
+        }
+    }
+
     override val kotlinMetadata: KmFunction? by lazy {
         (enclosingElement as? JavacTypeElement)?.kotlinMetadata?.getFunctionMetadata(element)
     }
@@ -104,6 +120,8 @@
 
     override fun isSuspendFunction() = kotlinMetadata?.isSuspend() == true
 
+    override fun isExtensionFunction() = kotlinMetadata?.isExtension() == true
+
     override fun overrides(other: XMethodElement, owner: XTypeElement): Boolean {
         check(other is JavacMethodElement)
         check(owner is JavacTypeElement)
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/kotlin/KotlinClassMetadataUtils.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/kotlin/KotlinClassMetadataUtils.kt
index d597e66..d2d1588 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/kotlin/KotlinClassMetadataUtils.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/kotlin/KotlinClassMetadataUtils.kt
@@ -20,6 +20,7 @@
 import kotlinx.metadata.ClassName
 import kotlinx.metadata.Flag
 import kotlinx.metadata.Flags
+import kotlinx.metadata.KmAnnotation
 import kotlinx.metadata.KmClassVisitor
 import kotlinx.metadata.KmConstructorExtensionVisitor
 import kotlinx.metadata.KmConstructorVisitor
@@ -28,6 +29,7 @@
 import kotlinx.metadata.KmFunctionVisitor
 import kotlinx.metadata.KmPropertyExtensionVisitor
 import kotlinx.metadata.KmPropertyVisitor
+import kotlinx.metadata.KmTypeExtensionVisitor
 import kotlinx.metadata.KmTypeParameterVisitor
 import kotlinx.metadata.KmTypeVisitor
 import kotlinx.metadata.KmValueParameterVisitor
@@ -37,6 +39,7 @@
 import kotlinx.metadata.jvm.JvmFunctionExtensionVisitor
 import kotlinx.metadata.jvm.JvmMethodSignature
 import kotlinx.metadata.jvm.JvmPropertyExtensionVisitor
+import kotlinx.metadata.jvm.JvmTypeExtensionVisitor
 import kotlinx.metadata.jvm.KotlinClassMetadata
 import java.util.Locale
 
@@ -60,9 +63,11 @@
     val descriptor: String,
     private val flags: Flags,
     override val parameters: List<KmValueParameter>,
-    val returnType: KmType
+    val returnType: KmType,
+    val receiverType: KmType?
 ) : KmExecutable {
     fun isSuspend() = Flag.Function.IS_SUSPEND(flags)
+    fun isExtension() = receiverType != null
 }
 
 /**
@@ -91,10 +96,11 @@
 internal data class KmType(
     val flags: Flags,
     val typeArguments: List<KmType>,
-    val extendsBound: KmType?
+    val extendsBound: KmType?,
+    val isExtensionType: Boolean
 ) {
     fun isNullable() = Flag.Type.IS_NULLABLE(flags)
-    fun erasure(): KmType = KmType(flags, emptyList(), extendsBound?.erasure())
+    fun erasure(): KmType = KmType(flags, emptyList(), extendsBound?.erasure(), isExtensionType)
 }
 
 private data class KmTypeParameter(
@@ -105,7 +111,8 @@
     fun asKmType() = KmType(
         flags = flags,
         typeArguments = emptyList(),
-        extendsBound = extendsBound
+        extendsBound = extendsBound,
+        isExtensionType = false
     )
 }
 
@@ -136,6 +143,7 @@
             lateinit var methodSignature: JvmMethodSignature
             val parameters = mutableListOf<KmValueParameter>()
             lateinit var returnType: KmType
+            var receiverType: KmType? = null
 
             override fun visitValueParameter(
                 flags: Flags,
@@ -146,6 +154,12 @@
                 }
             }
 
+            override fun visitReceiverParameterType(flags: Flags): KmTypeVisitor? {
+                return TypeReader(flags) {
+                    receiverType = it
+                }
+            }
+
             override fun visitExtensions(type: KmExtensionType): KmFunctionExtensionVisitor {
                 if (type != JvmFunctionExtensionVisitor.TYPE) {
                     error("Unsupported extension type: $type")
@@ -171,7 +185,8 @@
                         descriptor = methodSignature.asString(),
                         flags = flags,
                         parameters = parameters,
-                        returnType = returnType
+                        returnType = returnType,
+                        receiverType = receiverType
                     )
                 )
             }
@@ -289,7 +304,8 @@
                                 descriptor = setterSignature.asString(),
                                 flags = 0,
                                 parameters = listOf(param),
-                                returnType = KM_VOID_TYPE
+                                returnType = KM_VOID_TYPE,
+                                receiverType = null
                             )
                         },
                         getter = getter?.let { getterSignature ->
@@ -299,7 +315,8 @@
                                 descriptor = getterSignature.asString(),
                                 flags = flags,
                                 parameters = emptyList(),
-                                returnType = returnType
+                                returnType = returnType,
+                                receiverType = null
                             )
                         }
                     )
@@ -353,6 +370,7 @@
 ) : KmTypeVisitor() {
     private val typeArguments = mutableListOf<KmType>()
     private var extendsBound: KmType? = null
+    private var isExtensionType = false
     override fun visitArgument(flags: Flags, variance: KmVariance): KmTypeVisitor {
         return TypeReader(flags) {
             typeArguments.add(it)
@@ -368,12 +386,24 @@
         }
     }
 
+    override fun visitExtensions(type: KmExtensionType): KmTypeExtensionVisitor? {
+        if (type != JvmTypeExtensionVisitor.TYPE) return null
+        return object : JvmTypeExtensionVisitor() {
+            override fun visitAnnotation(annotation: KmAnnotation) {
+                if (annotation.className == "kotlin/ExtensionFunctionType") {
+                    isExtensionType = true
+                }
+            }
+        }
+    }
+
     override fun visitEnd() {
         output(
             KmType(
                 flags = flags,
                 typeArguments = typeArguments,
-                extendsBound = extendsBound
+                extendsBound = extendsBound,
+                isExtensionType = isExtensionType
             )
         )
     }
@@ -443,7 +473,8 @@
                     typeArguments = typeParameters.map {
                         it.asKmType()
                     },
-                    extendsBound = null
+                    extendsBound = null,
+                    isExtensionType = false
                 ),
                 superType = superType
             )
@@ -515,5 +546,6 @@
 private val KM_VOID_TYPE = KmType(
     flags = 0,
     typeArguments = emptyList(),
-    extendsBound = null
+    extendsBound = null,
+    isExtensionType = false
 )
\ No newline at end of file
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspConstructorElement.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspConstructorElement.kt
index e8ff39e..f3d3fa0 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspConstructorElement.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspConstructorElement.kt
@@ -18,6 +18,7 @@
 
 import androidx.room.compiler.processing.XConstructorElement
 import androidx.room.compiler.processing.XConstructorType
+import androidx.room.compiler.processing.XExecutableParameterElement
 import androidx.room.compiler.processing.XType
 import com.google.devtools.ksp.symbol.KSFunctionDeclaration
 
@@ -36,6 +37,17 @@
             ?: error("Constructor parent must be a type element $this")
     }
 
+    override val parameters: List<XExecutableParameterElement> by lazy {
+        declaration.parameters.mapIndexed { index, param ->
+            KspExecutableParameterElement(
+                env = env,
+                enclosingMethodElement = this,
+                parameter = param,
+                parameterIndex = index
+            )
+        }
+    }
+
     override val executableType: XConstructorType by lazy {
         KspConstructorType(
             env = env,
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspExecutableElement.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspExecutableElement.kt
index 2361bb7..50f23d0 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspExecutableElement.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspExecutableElement.kt
@@ -18,7 +18,6 @@
 
 import androidx.room.compiler.processing.XAnnotated
 import androidx.room.compiler.processing.XExecutableElement
-import androidx.room.compiler.processing.XExecutableParameterElement
 import androidx.room.compiler.processing.XHasModifiers
 import androidx.room.compiler.processing.XType
 import androidx.room.compiler.processing.ksp.KspAnnotated.UseSiteFilter.Companion.NO_USE_SITE
@@ -52,17 +51,6 @@
         declaration.requireEnclosingMemberContainer(env)
     }
 
-    override val parameters: List<XExecutableParameterElement> by lazy {
-        declaration.parameters.mapIndexed { index, param ->
-            KspExecutableParameterElement(
-                env = env,
-                enclosingMethodElement = this,
-                parameter = param,
-                parameterIndex = index
-            )
-        }
-    }
-
     @OptIn(KspExperimental::class)
     override val thrownTypes: List<XType> by lazy {
         env.resolver.getJvmCheckedException(declaration).map {
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspMethodElement.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspMethodElement.kt
index dfa6955..2db3a0b 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspMethodElement.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspMethodElement.kt
@@ -22,6 +22,7 @@
 import androidx.room.compiler.processing.XType
 import androidx.room.compiler.processing.XTypeElement
 import androidx.room.compiler.processing.ksp.synthetic.KspSyntheticContinuationParameterElement
+import androidx.room.compiler.processing.ksp.synthetic.KspSyntheticReceiverParameterElement
 import com.google.devtools.ksp.KspExperimental
 import com.google.devtools.ksp.closestClassDeclaration
 import com.google.devtools.ksp.symbol.ClassKind
@@ -52,6 +53,32 @@
         jvmName.getOrNull() ?: declaration.simpleName.asString()
     }
 
+    override val parameters: List<XExecutableParameterElement> by lazy {
+        buildList<XExecutableParameterElement> {
+            val extensionReceiver = declaration.extensionReceiver
+            if (extensionReceiver != null) {
+                // Synthesize the receiver parameter to be consistent with KAPT
+                add(
+                    KspSyntheticReceiverParameterElement(
+                        env = env,
+                        enclosingMethodElement = this@KspMethodElement,
+                        receiverType = extensionReceiver,
+                    )
+                )
+            }
+            addAll(
+                declaration.parameters.mapIndexed { index, param ->
+                    KspExecutableParameterElement(
+                        env = env,
+                        enclosingMethodElement = this@KspMethodElement,
+                        parameter = param,
+                        parameterIndex = index
+                    )
+                }
+            )
+        }
+    }
+
     override val executableType: XMethodType by lazy {
         KspMethodType.create(
             env = env,
@@ -101,6 +128,8 @@
             !isPrivate()
     }
 
+    override fun isExtensionFunction() = declaration.extensionReceiver != null
+
     override fun overrides(other: XMethodElement, owner: XTypeElement): Boolean {
         return env.resolver.overrides(this, other)
     }
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/synthetic/KspSyntheticPropertyMethodElement.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/synthetic/KspSyntheticPropertyMethodElement.kt
index 6f11ebc..71675b6 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/synthetic/KspSyntheticPropertyMethodElement.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/synthetic/KspSyntheticPropertyMethodElement.kt
@@ -82,6 +82,8 @@
 
     final override fun isSuspendFunction() = false
 
+    final override fun isExtensionFunction() = false
+
     final override val enclosingElement: XMemberContainer
         get() = this.field.enclosingElement
 
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/synthetic/KspSyntheticReceiverParameterElement.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/synthetic/KspSyntheticReceiverParameterElement.kt
new file mode 100644
index 0000000..3748728
--- /dev/null
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/synthetic/KspSyntheticReceiverParameterElement.kt
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.room.compiler.processing.ksp.synthetic
+
+import androidx.room.compiler.processing.XAnnotated
+import androidx.room.compiler.processing.XEquality
+import androidx.room.compiler.processing.XExecutableParameterElement
+import androidx.room.compiler.processing.XType
+import androidx.room.compiler.processing.ksp.KspAnnotated
+import androidx.room.compiler.processing.ksp.KspJvmTypeResolutionScope
+import androidx.room.compiler.processing.ksp.KspMethodElement
+import androidx.room.compiler.processing.ksp.KspProcessingEnv
+import androidx.room.compiler.processing.ksp.KspType
+import com.google.devtools.ksp.symbol.KSTypeReference
+
+internal class KspSyntheticReceiverParameterElement(
+    val env: KspProcessingEnv,
+    override val enclosingMethodElement: KspMethodElement,
+    val receiverType: KSTypeReference,
+) : XExecutableParameterElement,
+    XEquality,
+    XAnnotated by KspAnnotated.create(
+        env = env,
+        delegate = null, // does not matter, this is synthetic and has no annotations.
+        filter = KspAnnotated.UseSiteFilter.NO_USE_SITE
+    ) {
+
+    override val name: String by lazy {
+        // KAPT uses `$this$<functionName>`
+        "$" + "this" + "$" + enclosingMethodElement.name
+    }
+
+    override val equalityItems: Array<out Any?> by lazy {
+        arrayOf(enclosingMethodElement, receiverType)
+    }
+
+    override val hasDefaultValue: Boolean
+        get() = false
+
+    private val jvmTypeResolutionScope by lazy {
+        KspJvmTypeResolutionScope.MethodParameter(
+            kspExecutableElement = enclosingMethodElement,
+            parameterIndex = 0, // Receiver param is the 1st one
+            annotated = enclosingMethodElement.declaration
+        )
+    }
+
+    override val type: XType by lazy {
+        env.wrap(receiverType).withJvmTypeResolver(jvmTypeResolutionScope)
+    }
+
+    override val fallbackLocationText: String
+        get() = "receiver parameter of ${enclosingMethodElement.fallbackLocationText}"
+
+    // Not applicable
+    override val docComment: String? get() = null
+
+    override fun asMemberOf(other: XType): KspType {
+        check(other is KspType)
+        val asMemberReceiverType = receiverType.resolve().let {
+            if (it.isError) {
+                return@let it
+            }
+            val asMember = enclosingMethodElement.declaration.asMemberOf(other.ksType)
+            checkNotNull(asMember.extensionReceiverType)
+        }
+        return env.wrap(
+            originatingReference = receiverType,
+            ksType = asMemberReceiverType,
+        ).withJvmTypeResolver(jvmTypeResolutionScope)
+    }
+
+    override fun kindName(): String {
+        return "synthetic receiver parameter"
+    }
+
+    override fun validate(): Boolean {
+        return true
+    }
+
+    override fun equals(other: Any?): Boolean {
+        return XEquality.equals(this, other)
+    }
+
+    override fun hashCode(): Int {
+        return XEquality.hashCode(equalityItems)
+    }
+}
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 6c599c4..f069c60 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
@@ -31,6 +31,7 @@
 import com.squareup.javapoet.ClassName
 import com.squareup.javapoet.ParameterizedTypeName
 import com.squareup.javapoet.TypeName
+import com.squareup.javapoet.TypeVariableName
 import com.squareup.javapoet.WildcardTypeName
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -963,6 +964,106 @@
         }
     }
 
+    @Test
+    fun extensionFun() {
+        fun buildSource(pkg: String) = Source.kotlin(
+            "Foo.kt",
+            """
+            package $pkg
+            abstract class Foo<T> {
+                fun String.ext1(): String = TODO()
+                fun String.ext2(inputParam: Int): String = TODO()
+                fun Foo<String>.ext3(): String = TODO()
+                fun Foo<T>.ext4(): String = TODO()
+                fun T.ext5(): String = TODO()
+                suspend fun String.ext6(): String = TODO()
+                abstract fun T.ext7(): String
+            }
+            class FooImpl : Foo<Int>() {
+                override fun Int.ext7(): String = TODO()
+            }
+            """.trimIndent()
+        )
+        runProcessorTest(
+            sources = listOf(buildSource(pkg = "app")),
+            classpath = compileFiles(listOf(buildSource(pkg = "lib")))
+        ) {
+            listOf("app", "lib").forEach { pkg ->
+                val element = it.processingEnv.requireTypeElement("$pkg.Foo")
+                element.getDeclaredMethodByJvmName("ext1").let { method ->
+                    assertThat(method.isExtensionFunction()).isTrue()
+                    assertThat(method.parameters.size).isEqualTo(1)
+                    assertThat(method.parameters[0].name).isEqualTo("\$this\$ext1")
+                    assertThat(method.parameters[0].type.typeName)
+                        .isEqualTo(String::class.typeName())
+                }
+                element.getDeclaredMethodByJvmName("ext2").let { method ->
+                    assertThat(method.parameters.size).isEqualTo(2)
+                    assertThat(method.parameters[0].name).isEqualTo("\$this\$ext2")
+                    assertThat(method.parameters[0].type.typeName)
+                        .isEqualTo(String::class.typeName())
+                    assertThat(method.parameters[1].name).isEqualTo("inputParam")
+                }
+                element.getDeclaredMethodByJvmName("ext3").let { method ->
+                    assertThat(method.parameters[0].type.typeName).isEqualTo(
+                        ParameterizedTypeName.get(
+                            ClassName.get(pkg, "Foo"),
+                            String::class.typeName()
+                        )
+                    )
+                }
+                element.getDeclaredMethodByJvmName("ext4").let { method ->
+                    assertThat(method.parameters[0].type.typeName).isEqualTo(
+                        ParameterizedTypeName.get(
+                            ClassName.get(pkg, "Foo"),
+                            TypeVariableName.get("T")
+                        )
+                    )
+                }
+                element.getDeclaredMethodByJvmName("ext5").let { method ->
+                    assertThat(method.parameters[0].type.typeName)
+                        .isEqualTo(TypeVariableName.get("T"))
+                }
+                element.getDeclaredMethodByJvmName("ext6").let { method ->
+                    assertThat(method.isSuspendFunction()).isTrue()
+                    assertThat(method.isExtensionFunction()).isTrue()
+                    assertThat(method.parameters.size).isEqualTo(2)
+                    assertThat(method.parameters[0].type.typeName)
+                        .isEqualTo(String::class.typeName())
+                    assertThat(method.parameters[1].type.typeName).isEqualTo(
+                        ParameterizedTypeName.get(
+                            ClassName.get("kotlin.coroutines", "Continuation"),
+                            WildcardTypeName.supertypeOf(String::class.typeName())
+                        )
+                    )
+                }
+                // Verify overridden Foo.ext7() asMemberOf FooImpl
+                element.getDeclaredMethodByJvmName("ext7").let { method ->
+                    assertThat(method.isAbstract()).isTrue()
+                    assertThat(method.isExtensionFunction()).isTrue()
+                    assertThat(method.parameters[0].type.typeName)
+                        .isEqualTo(TypeVariableName.get("T"))
+
+                    val fooImpl = it.processingEnv.requireTypeElement("$pkg.FooImpl")
+                    assertThat(method.parameters[0].asMemberOf(fooImpl.type).typeName)
+                        .isEqualTo(TypeName.INT.box())
+                }
+                // Verify non-overridden Foo.ext1() asMemberOf FooImpl
+                element.getDeclaredMethodByJvmName("ext1").let { method ->
+                    val fooImpl = it.processingEnv.requireTypeElement("$pkg.FooImpl")
+                    assertThat(method.parameters[0].asMemberOf(fooImpl.type).typeName)
+                        .isEqualTo(String::class.typeName())
+                }
+                // Verify non-overridden Foo.ext5() asMemberOf FooImpl
+                element.getDeclaredMethodByJvmName("ext5").let { method ->
+                    val fooImpl = it.processingEnv.requireTypeElement("$pkg.FooImpl")
+                    assertThat(method.parameters[0].asMemberOf(fooImpl.type).typeName)
+                        .isEqualTo(TypeName.INT.box())
+                }
+            }
+        }
+    }
+
     // see b/160258066
     private fun genericToPrimitiveOverrides(asMemberOf: Boolean) {
         val source = Source.kotlin(