Kapt: Support all kinds of constant types (KT-35536)
This commit is contained in:
+36
-36
@@ -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)
|
||||
}
|
||||
+63
-18
@@ -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<Any?>(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<Any?>(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"))
|
||||
|
||||
+11
@@ -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 {
|
||||
|
||||
+75
@@ -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<java.lang.String> stringList = null;
|
||||
@org.jetbrains.annotations.NotNull()
|
||||
private final java.lang.Integer[] intArray = {1};
|
||||
@org.jetbrains.annotations.NotNull()
|
||||
private final java.util.List<java.lang.Integer> 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<kotlin.UInt> uintList = null;
|
||||
@org.jetbrains.annotations.NotNull()
|
||||
private final kotlin.reflect.KClass<State> clazz = null;
|
||||
@org.jetbrains.annotations.NotNull()
|
||||
private final java.lang.Class<State> javaClass = null;
|
||||
@org.jetbrains.annotations.NotNull()
|
||||
private final kotlin.reflect.KClass<? extends java.lang.Object> 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<java.lang.String> getStringList() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@org.jetbrains.annotations.NotNull()
|
||||
public final java.lang.Integer[] getIntArray() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@org.jetbrains.annotations.NotNull()
|
||||
public final java.util.List<java.lang.Integer> 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<kotlin.UInt> getUintList() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@org.jetbrains.annotations.NotNull()
|
||||
public final kotlin.reflect.KClass<State> getClazz() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@org.jetbrains.annotations.NotNull()
|
||||
public final java.lang.Class<State> getJavaClass() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@org.jetbrains.annotations.NotNull()
|
||||
public final kotlin.reflect.KClass<? extends java.lang.Object> getAnonymous() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public HavingState() {
|
||||
super();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user