diff --git a/plugins/kapt3/kapt3-compiler/src/org/jetbrains/kotlin/kapt3/KaptAnonymousTypeTransformer.kt b/plugins/kapt3/kapt3-compiler/src/org/jetbrains/kotlin/kapt3/KaptAnonymousTypeTransformer.kt index 3c7a86e7132..91140fbc707 100644 --- a/plugins/kapt3/kapt3-compiler/src/org/jetbrains/kotlin/kapt3/KaptAnonymousTypeTransformer.kt +++ b/plugins/kapt3/kapt3-compiler/src/org/jetbrains/kotlin/kapt3/KaptAnonymousTypeTransformer.kt @@ -5,17 +5,12 @@ 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.kapt3.util.replaceAnonymousTypeWithSuperType import org.jetbrains.kotlin.resolve.DeclarationSignatureAnonymousTypeTransformer -import org.jetbrains.kotlin.resolve.DescriptorUtils -import org.jetbrains.kotlin.resolve.DescriptorUtils.* +import org.jetbrains.kotlin.resolve.DescriptorUtils.isLocal import org.jetbrains.kotlin.resolve.jvm.extensions.PartialAnalysisHandlerExtension 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( private val analysisExtension: PartialAnalysisHandlerExtension @@ -29,46 +24,6 @@ class KaptAnonymousTypeTransformer( 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) } \ No newline at end of file diff --git a/plugins/kapt3/kapt3-compiler/src/org/jetbrains/kotlin/kapt3/stubs/ClassFileToSourceStubConverter.kt b/plugins/kapt3/kapt3-compiler/src/org/jetbrains/kotlin/kapt3/stubs/ClassFileToSourceStubConverter.kt index c6b0cf5bff8..a305142b50e 100644 --- a/plugins/kapt3/kapt3-compiler/src/org/jetbrains/kotlin/kapt3/stubs/ClassFileToSourceStubConverter.kt +++ b/plugins/kapt3/kapt3-compiler/src/org/jetbrains/kotlin/kapt3/stubs/ClassFileToSourceStubConverter.kt @@ -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.util.* 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.psi.* 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.getSuperClassOrAny 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.types.ErrorUtils import org.jetbrains.kotlin.types.KotlinType @@ -690,7 +692,8 @@ class ClassFileToSourceStubConverter(val kaptContext: KaptContextForStubGenerati val name = field.name if (!isValidIdentifier(name)) return null - val type = Type.getType(field.desc) + val type = getFieldType(field, origin) + if (!checkIfValidTypeName(containingClass, type)) { return null } @@ -1420,6 +1423,25 @@ class ClassFileToSourceStubConverter(val kaptContext: KaptContextForStubGenerati lineMappings.registerSignature(this, node) 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) { diff --git a/plugins/kapt3/kapt3-compiler/src/org/jetbrains/kotlin/kapt3/util/typeUtils.kt b/plugins/kapt3/kapt3-compiler/src/org/jetbrains/kotlin/kapt3/util/typeUtils.kt new file mode 100644 index 00000000000..534b6e1f68d --- /dev/null +++ b/plugins/kapt3/kapt3-compiler/src/org/jetbrains/kotlin/kapt3/util/typeUtils.kt @@ -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) +} diff --git a/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/ClassFileToSourceStubConverterTestGenerated.java b/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/ClassFileToSourceStubConverterTestGenerated.java index 5c4b619d774..90cbc6b0d38 100644 --- a/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/ClassFileToSourceStubConverterTestGenerated.java +++ b/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/ClassFileToSourceStubConverterTestGenerated.java @@ -69,6 +69,11 @@ public class ClassFileToSourceStubConverterTestGenerated extends AbstractClassFi 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") public void testComments() throws Exception { runTest("plugins/kapt3/kapt3-compiler/testData/converter/comments.kt"); diff --git a/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/IrClassFileToSourceStubConverterTestGenerated.java b/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/IrClassFileToSourceStubConverterTestGenerated.java index d9de74b45ed..752f8d3aae8 100644 --- a/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/IrClassFileToSourceStubConverterTestGenerated.java +++ b/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/IrClassFileToSourceStubConverterTestGenerated.java @@ -70,6 +70,11 @@ public class IrClassFileToSourceStubConverterTestGenerated extends AbstractIrCla 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") public void testComments() throws Exception { runTest("plugins/kapt3/kapt3-compiler/testData/converter/comments.kt"); diff --git a/plugins/kapt3/kapt3-compiler/testData/converter/anonymousDelegate.kt b/plugins/kapt3/kapt3-compiler/testData/converter/anonymousDelegate.kt new file mode 100644 index 00000000000..e289ea94614 --- /dev/null +++ b/plugins/kapt3/kapt3-compiler/testData/converter/anonymousDelegate.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 + } +} diff --git a/plugins/kapt3/kapt3-compiler/testData/converter/anonymousDelegate.txt b/plugins/kapt3/kapt3-compiler/testData/converter/anonymousDelegate.txt new file mode 100644 index 00000000000..1db03cc8f11 --- /dev/null +++ b/plugins/kapt3/kapt3-compiler/testData/converter/anonymousDelegate.txt @@ -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; + } +}