[KAPT] Fix stub generation for anonymous delegates
Replace anonymous classes with superclass in delegate properties #KT-34838 Fixed
This commit is contained in:
+3
-48
@@ -5,17 +5,12 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.kapt3
|
package org.jetbrains.kotlin.kapt3
|
||||||
|
|
||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
|
||||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
|
||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithVisibility
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithVisibility
|
||||||
|
import org.jetbrains.kotlin.kapt3.util.replaceAnonymousTypeWithSuperType
|
||||||
import org.jetbrains.kotlin.resolve.DeclarationSignatureAnonymousTypeTransformer
|
import org.jetbrains.kotlin.resolve.DeclarationSignatureAnonymousTypeTransformer
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
import org.jetbrains.kotlin.resolve.DescriptorUtils.isLocal
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorUtils.*
|
|
||||||
import org.jetbrains.kotlin.resolve.jvm.extensions.PartialAnalysisHandlerExtension
|
import org.jetbrains.kotlin.resolve.jvm.extensions.PartialAnalysisHandlerExtension
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
import org.jetbrains.kotlin.types.TypeProjectionImpl
|
|
||||||
import org.jetbrains.kotlin.types.replace
|
|
||||||
import org.jetbrains.kotlin.types.typeUtil.builtIns
|
|
||||||
|
|
||||||
class KaptAnonymousTypeTransformer(
|
class KaptAnonymousTypeTransformer(
|
||||||
private val analysisExtension: PartialAnalysisHandlerExtension
|
private val analysisExtension: PartialAnalysisHandlerExtension
|
||||||
@@ -29,46 +24,6 @@ class KaptAnonymousTypeTransformer(
|
|||||||
return type
|
return type
|
||||||
}
|
}
|
||||||
|
|
||||||
return convertPossiblyAnonymousType(type)
|
return replaceAnonymousTypeWithSuperType(type)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
internal fun convertPossiblyAnonymousType(type: KotlinType): KotlinType {
|
|
||||||
val declaration = type.constructor.declarationDescriptor as? ClassDescriptor ?: return type
|
|
||||||
|
|
||||||
if (KotlinBuiltIns.isArray(type)) {
|
|
||||||
val elementTypeProjection = type.arguments.singleOrNull()
|
|
||||||
if (elementTypeProjection != null && !elementTypeProjection.isStarProjection) {
|
|
||||||
return type.builtIns.getArrayType(
|
|
||||||
elementTypeProjection.projectionKind,
|
|
||||||
convertPossiblyAnonymousType(elementTypeProjection.type)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val actualType = when {
|
|
||||||
isAnonymousObject(declaration) || DescriptorUtils.isLocal(declaration) -> {
|
|
||||||
if (type.constructor.supertypes.size == 1) {
|
|
||||||
convertPossiblyAnonymousType(type.constructor.supertypes.iterator().next())
|
|
||||||
} else {
|
|
||||||
/*
|
|
||||||
Frontend reports an error on public properties in this case,
|
|
||||||
but we ignore errors when making stubs, so there should be a reasonable fallback.
|
|
||||||
*/
|
|
||||||
type.builtIns.anyType
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else -> type
|
|
||||||
}
|
|
||||||
|
|
||||||
if (actualType.arguments.isEmpty()) return actualType
|
|
||||||
|
|
||||||
val arguments = actualType.arguments.map { typeArg ->
|
|
||||||
if (typeArg.isStarProjection)
|
|
||||||
return@map typeArg
|
|
||||||
|
|
||||||
TypeProjectionImpl(typeArg.projectionKind, convertPossiblyAnonymousType(typeArg.type))
|
|
||||||
}
|
|
||||||
|
|
||||||
return actualType.replace(newArguments = arguments)
|
|
||||||
}
|
}
|
||||||
+23
-1
@@ -49,6 +49,7 @@ import org.jetbrains.kotlin.kapt3.stubs.ErrorTypeCorrector.TypeKind.METHOD_PARAM
|
|||||||
import org.jetbrains.kotlin.kapt3.stubs.ErrorTypeCorrector.TypeKind.RETURN_TYPE
|
import org.jetbrains.kotlin.kapt3.stubs.ErrorTypeCorrector.TypeKind.RETURN_TYPE
|
||||||
import org.jetbrains.kotlin.kapt3.util.*
|
import org.jetbrains.kotlin.kapt3.util.*
|
||||||
import org.jetbrains.kotlin.load.java.sources.JavaSourceElement
|
import org.jetbrains.kotlin.load.java.sources.JavaSourceElement
|
||||||
|
import org.jetbrains.kotlin.load.kotlin.TypeMappingMode
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
@@ -62,6 +63,7 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameOrNull
|
|||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny
|
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.isCompanionObject
|
import org.jetbrains.kotlin.resolve.descriptorUtil.isCompanionObject
|
||||||
|
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
|
||||||
import org.jetbrains.kotlin.resolve.source.PsiSourceElement
|
import org.jetbrains.kotlin.resolve.source.PsiSourceElement
|
||||||
import org.jetbrains.kotlin.types.ErrorUtils
|
import org.jetbrains.kotlin.types.ErrorUtils
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
@@ -690,7 +692,8 @@ class ClassFileToSourceStubConverter(val kaptContext: KaptContextForStubGenerati
|
|||||||
val name = field.name
|
val name = field.name
|
||||||
if (!isValidIdentifier(name)) return null
|
if (!isValidIdentifier(name)) return null
|
||||||
|
|
||||||
val type = Type.getType(field.desc)
|
val type = getFieldType(field, origin)
|
||||||
|
|
||||||
if (!checkIfValidTypeName(containingClass, type)) {
|
if (!checkIfValidTypeName(containingClass, type)) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
@@ -1420,6 +1423,25 @@ class ClassFileToSourceStubConverter(val kaptContext: KaptContextForStubGenerati
|
|||||||
lineMappings.registerSignature(this, node)
|
lineMappings.registerSignature(this, node)
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun getFieldType(field: FieldNode, origin: JvmDeclarationOrigin?): Type {
|
||||||
|
val fieldType = Type.getType(field.desc)
|
||||||
|
return when (val declaration = origin?.element) {
|
||||||
|
is KtProperty -> {
|
||||||
|
//replace anonymous type in delegate (if any)
|
||||||
|
val delegateType = kaptContext.bindingContext[BindingContext.EXPRESSION_TYPE_INFO, declaration.delegateExpression]?.type
|
||||||
|
delegateType?.let {
|
||||||
|
val replaced = replaceAnonymousTypeWithSuperType(it)
|
||||||
|
//not changed => not anonymous type => use type from field
|
||||||
|
if (replaced != it) replaced else null
|
||||||
|
}?.let(::convertKotlinType) ?: fieldType
|
||||||
|
}
|
||||||
|
else -> fieldType
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun convertKotlinType(type: KotlinType): Type = typeMapper.mapType(type, null, TypeMappingMode.GENERIC_ARGUMENT)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun Any?.isOfPrimitiveType(): Boolean = when (this) {
|
private fun Any?.isOfPrimitiveType(): Boolean = when (this) {
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.kapt3.util
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||||
|
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||||
|
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||||
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
|
import org.jetbrains.kotlin.types.TypeProjectionImpl
|
||||||
|
import org.jetbrains.kotlin.types.replace
|
||||||
|
import org.jetbrains.kotlin.types.typeUtil.builtIns
|
||||||
|
|
||||||
|
fun replaceAnonymousTypeWithSuperType(type: KotlinType): KotlinType {
|
||||||
|
val declaration = type.constructor.declarationDescriptor as? ClassDescriptor ?: return type
|
||||||
|
|
||||||
|
if (KotlinBuiltIns.isArray(type)) {
|
||||||
|
val elementTypeProjection = type.arguments.singleOrNull()
|
||||||
|
if (elementTypeProjection != null && !elementTypeProjection.isStarProjection) {
|
||||||
|
return type.builtIns.getArrayType(
|
||||||
|
elementTypeProjection.projectionKind,
|
||||||
|
replaceAnonymousTypeWithSuperType(elementTypeProjection.type)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val actualType = when {
|
||||||
|
DescriptorUtils.isAnonymousObject(declaration) || DescriptorUtils.isLocal(declaration) -> {
|
||||||
|
if (type.constructor.supertypes.size == 1) {
|
||||||
|
replaceAnonymousTypeWithSuperType(type.constructor.supertypes.iterator().next())
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
Frontend reports an error on public properties in this case,
|
||||||
|
but we ignore errors when making stubs, so there should be a reasonable fallback.
|
||||||
|
*/
|
||||||
|
type.builtIns.anyType
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else -> type
|
||||||
|
}
|
||||||
|
|
||||||
|
if (actualType.arguments.isEmpty()) return actualType
|
||||||
|
|
||||||
|
val arguments = actualType.arguments.map { typeArg ->
|
||||||
|
if (typeArg.isStarProjection)
|
||||||
|
return@map typeArg
|
||||||
|
|
||||||
|
TypeProjectionImpl(typeArg.projectionKind, replaceAnonymousTypeWithSuperType(typeArg.type))
|
||||||
|
}
|
||||||
|
|
||||||
|
return actualType.replace(newArguments = arguments)
|
||||||
|
}
|
||||||
+5
@@ -69,6 +69,11 @@ public class ClassFileToSourceStubConverterTestGenerated extends AbstractClassFi
|
|||||||
runTest("plugins/kapt3/kapt3-compiler/testData/converter/annotationsWithTargets.kt");
|
runTest("plugins/kapt3/kapt3-compiler/testData/converter/annotationsWithTargets.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("anonymousDelegate.kt")
|
||||||
|
public void testAnonymousDelegate() throws Exception {
|
||||||
|
runTest("plugins/kapt3/kapt3-compiler/testData/converter/anonymousDelegate.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("comments.kt")
|
@TestMetadata("comments.kt")
|
||||||
public void testComments() throws Exception {
|
public void testComments() throws Exception {
|
||||||
runTest("plugins/kapt3/kapt3-compiler/testData/converter/comments.kt");
|
runTest("plugins/kapt3/kapt3-compiler/testData/converter/comments.kt");
|
||||||
|
|||||||
+5
@@ -70,6 +70,11 @@ public class IrClassFileToSourceStubConverterTestGenerated extends AbstractIrCla
|
|||||||
runTest("plugins/kapt3/kapt3-compiler/testData/converter/annotationsWithTargets.kt");
|
runTest("plugins/kapt3/kapt3-compiler/testData/converter/annotationsWithTargets.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("anonymousDelegate.kt")
|
||||||
|
public void testAnonymousDelegate() throws Exception {
|
||||||
|
runTest("plugins/kapt3/kapt3-compiler/testData/converter/anonymousDelegate.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("comments.kt")
|
@TestMetadata("comments.kt")
|
||||||
public void testComments() throws Exception {
|
public void testComments() throws Exception {
|
||||||
runTest("plugins/kapt3/kapt3-compiler/testData/converter/comments.kt");
|
runTest("plugins/kapt3/kapt3-compiler/testData/converter/comments.kt");
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
import kotlin.reflect.KProperty
|
||||||
|
|
||||||
|
class Test {
|
||||||
|
|
||||||
|
var broken by object {
|
||||||
|
operator fun getValue(obj: Test, property: KProperty<*>) = Any()
|
||||||
|
|
||||||
|
operator fun setValue(obj: Test, property: KProperty<*>, any: Any) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var overridden by object : java.io.Serializable {
|
||||||
|
operator fun getValue(obj: Test, property: KProperty<*>) = Any()
|
||||||
|
|
||||||
|
operator fun setValue(obj: Test, property: KProperty<*>, any: Any) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val lazyProp by lazy {
|
||||||
|
object : Runnable {
|
||||||
|
override fun run() {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
var delegate by object {
|
||||||
|
operator fun getValue(nothing: Nothing?, property: KProperty<*>) = Any()
|
||||||
|
operator fun setValue(nothing: Nothing?, property: KProperty<*>, any: Any) {
|
||||||
|
//empty
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
import java.lang.System;
|
||||||
|
|
||||||
|
@kotlin.Metadata()
|
||||||
|
public final class AnonymousDelegateKt {
|
||||||
|
|
||||||
|
public AnonymousDelegateKt() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
@org.jetbrains.annotations.NotNull()
|
||||||
|
private static final java.lang.Object delegate$delegate = null;
|
||||||
|
|
||||||
|
@org.jetbrains.annotations.NotNull()
|
||||||
|
public static final java.lang.Object getDelegate() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final void setDelegate(@org.jetbrains.annotations.NotNull()
|
||||||
|
java.lang.Object p0) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
import java.lang.System;
|
||||||
|
|
||||||
|
@kotlin.Metadata()
|
||||||
|
public final class Test {
|
||||||
|
@org.jetbrains.annotations.NotNull()
|
||||||
|
private final java.lang.Object broken$delegate = null;
|
||||||
|
@org.jetbrains.annotations.NotNull()
|
||||||
|
private final java.io.Serializable overridden$delegate = null;
|
||||||
|
private final kotlin.Lazy lazyProp$delegate = null;
|
||||||
|
|
||||||
|
public Test() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
@org.jetbrains.annotations.NotNull()
|
||||||
|
public final java.lang.Object getBroken() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void setBroken(@org.jetbrains.annotations.NotNull()
|
||||||
|
java.lang.Object p0) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@org.jetbrains.annotations.NotNull()
|
||||||
|
public final java.lang.Object getOverridden() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void setOverridden(@org.jetbrains.annotations.NotNull()
|
||||||
|
java.lang.Object p0) {
|
||||||
|
}
|
||||||
|
|
||||||
|
private final java.lang.Runnable getLazyProp() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user