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 90a6f7a2edb..3c7a86e7132 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 @@ -31,44 +31,44 @@ class KaptAnonymousTypeTransformer( return convertPossiblyAnonymousType(type) } +} - private fun convertPossiblyAnonymousType(type: KotlinType): KotlinType { - val declaration = type.constructor.declarationDescriptor as? ClassDescriptor ?: return 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) - ) - } + 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) } + + 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 f234ffa0217..8852716bc82 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 @@ -25,6 +25,7 @@ import com.sun.tools.javac.tree.TreeMaker import com.sun.tools.javac.tree.TreeScanner import kotlinx.kapt.KaptIgnored import org.jetbrains.kotlin.base.kapt3.KaptFlag +import org.jetbrains.kotlin.codegen.AsmUtil import org.jetbrains.kotlin.codegen.coroutines.CONTINUATION_PARAMETER_NAME import org.jetbrains.kotlin.codegen.needsExperimentalCoroutinesWrapper import org.jetbrains.kotlin.config.LanguageFeature @@ -47,9 +48,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.name.ClassId import org.jetbrains.kotlin.name.FqName -import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.DelegatingBindingTrace @@ -667,7 +666,10 @@ class ClassFileToSourceStubConverter(val kaptContext: KaptContextForStubGenerati val trace = DelegatingBindingTrace(kaptContext.bindingContext, "Kapt") val const = evaluator.evaluateExpression(propertyInitializer, trace, propertyType) if (const != null && !const.isError && const.canBeUsedInAnnotations && !const.usesNonConstValAsConstant) { - return convertConstantValueArguments(const.getValue(propertyType), listOf(propertyInitializer)) + val asmValue = mapConstantValueToAsmRepresentation(const.toConstantValue(propertyType)) + if (asmValue !== UnknownConstantValue) { + return convertConstantValueArguments(asmValue, listOf(propertyInitializer)) + } } } @@ -679,6 +681,64 @@ class ClassFileToSourceStubConverter(val kaptContext: KaptContextForStubGenerati return null } + private object UnknownConstantValue + + private fun mapConstantValueToAsmRepresentation(value: ConstantValue<*>): Any? { + return when (value) { + is ByteValue -> value.value + is CharValue -> value.value + is IntValue -> value.value + is LongValue -> value.value + is ShortValue -> value.value + is UByteValue -> value.value + is UShortValue -> value.value + is UIntValue -> value.value + is ULongValue -> value.value + is AnnotationValue -> { + val annotationDescriptor = value.value + val annotationNode = AnnotationNode(typeMapper.mapType(annotationDescriptor.type).descriptor) + val values = ArrayList(annotationDescriptor.allValueArguments.size * 2) + for ((name, arg) in annotationDescriptor.allValueArguments) { + val mapped = mapConstantValueToAsmRepresentation(arg) + if (mapped === UnknownConstantValue) { + return UnknownConstantValue + } + + values += name.asString() + values += mapped + } + annotationNode.values = values + return annotationNode + } + is ArrayValue -> { + val children = value.value + val result = ArrayList(children.size) + for (child in children) { + val mapped = mapConstantValueToAsmRepresentation(child) + if (mapped === UnknownConstantValue) { + return UnknownConstantValue + } + result += mapped + } + return result + } + is BooleanValue -> value.value + is DoubleValue -> value.value + is EnumValue -> { + val (classId, name) = value.value + val enumType = AsmUtil.asmTypeByClassId(classId) + return arrayOf(enumType.descriptor, name.asString()) + } + is FloatValue -> value.value + is StringValue -> value.value + is NullValue -> null + else -> { + // KClassValue is intentionally omitted as incompatible with Java + UnknownConstantValue + } + } + } + private fun convertMethod( method: MethodNode, containingClass: ClassNode, @@ -1196,21 +1256,6 @@ class ClassFileToSourceStubConverter(val kaptContext: KaptContextForStubGenerati treeMaker.Select(treeMaker.Type(enumType), treeMaker.name(valueName)) } - is Pair<*, *> -> { - assert(value.first is ClassId) - assert(value.second is Name) - val valueName = with((value.second as Name).identifier) { - if (isValidIdentifier(this)) { - this - } else { - kaptContext.compiler.log.report(kaptContext.kaptError("'$this' is an invalid Java enum value name")) - "InvalidFieldName" - } - } - val asSingleFqName = (value.first as ClassId).asSingleFqName() - - treeMaker.Select(treeMaker.FqName(asSingleFqName), treeMaker.name(value.second.toString())) - } is List<*> -> treeMaker.NewArray(null, JavacList.nil(), mapJList(value) { convertLiteralExpression(it) }) is Type -> treeMaker.Select(treeMaker.Type(value), treeMaker.name("class")) diff --git a/plugins/kapt3/kapt3-compiler/testData/converter/unsafePropertyInitializers.kt b/plugins/kapt3/kapt3-compiler/testData/converter/unsafePropertyInitializers.kt index 6c4637b7bba..18c3992dd09 100644 --- a/plugins/kapt3/kapt3-compiler/testData/converter/unsafePropertyInitializers.kt +++ b/plugins/kapt3/kapt3-compiler/testData/converter/unsafePropertyInitializers.kt @@ -25,6 +25,17 @@ object Boo { class HavingState { val state = State.START + val stateArray = arrayOf(State.START) + val stringArray = arrayOf("foo") + val stringList = listOf("foo") + val intArray = arrayOf(1) + val intList = listOf(1) + val uint = 1U + val uintArray = arrayOf(1U) + val uintList = listOf(1U) + val clazz = State::class + val javaClass = State::class.java + val anonymous = (object {})::class } enum class State { diff --git a/plugins/kapt3/kapt3-compiler/testData/converter/unsafePropertyInitializers.txt b/plugins/kapt3/kapt3-compiler/testData/converter/unsafePropertyInitializers.txt index cc468684854..f977bce2b58 100644 --- a/plugins/kapt3/kapt3-compiler/testData/converter/unsafePropertyInitializers.txt +++ b/plugins/kapt3/kapt3-compiler/testData/converter/unsafePropertyInitializers.txt @@ -126,12 +126,87 @@ import java.lang.System; public final class HavingState { @org.jetbrains.annotations.NotNull() private final State state = State.START; + @org.jetbrains.annotations.NotNull() + private final State[] stateArray = {State.START}; + @org.jetbrains.annotations.NotNull() + private final java.lang.String[] stringArray = {"foo"}; + @org.jetbrains.annotations.NotNull() + private final java.util.List stringList = null; + @org.jetbrains.annotations.NotNull() + private final java.lang.Integer[] intArray = {1}; + @org.jetbrains.annotations.NotNull() + private final java.util.List intList = null; + private final int uint = 1; + @org.jetbrains.annotations.NotNull() + private final kotlin.UInt[] uintArray = {1}; + @org.jetbrains.annotations.NotNull() + private final java.util.List uintList = null; + @org.jetbrains.annotations.NotNull() + private final kotlin.reflect.KClass clazz = null; + @org.jetbrains.annotations.NotNull() + private final java.lang.Class javaClass = null; + @org.jetbrains.annotations.NotNull() + private final kotlin.reflect.KClass anonymous = null; @org.jetbrains.annotations.NotNull() public final State getState() { return null; } + @org.jetbrains.annotations.NotNull() + public final State[] getStateArray() { + return null; + } + + @org.jetbrains.annotations.NotNull() + public final java.lang.String[] getStringArray() { + return null; + } + + @org.jetbrains.annotations.NotNull() + public final java.util.List getStringList() { + return null; + } + + @org.jetbrains.annotations.NotNull() + public final java.lang.Integer[] getIntArray() { + return null; + } + + @org.jetbrains.annotations.NotNull() + public final java.util.List getIntList() { + return null; + } + + public final int getUint() { + return 0; + } + + @org.jetbrains.annotations.NotNull() + public final kotlin.UInt[] getUintArray() { + return null; + } + + @org.jetbrains.annotations.NotNull() + public final java.util.List getUintList() { + return null; + } + + @org.jetbrains.annotations.NotNull() + public final kotlin.reflect.KClass getClazz() { + return null; + } + + @org.jetbrains.annotations.NotNull() + public final java.lang.Class getJavaClass() { + return null; + } + + @org.jetbrains.annotations.NotNull() + public final kotlin.reflect.KClass getAnonymous() { + return null; + } + public HavingState() { super(); }