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)
|
return convertPossiblyAnonymousType(type)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun convertPossiblyAnonymousType(type: KotlinType): KotlinType {
|
internal fun convertPossiblyAnonymousType(type: KotlinType): KotlinType {
|
||||||
val declaration = type.constructor.declarationDescriptor as? ClassDescriptor ?: return type
|
val declaration = type.constructor.declarationDescriptor as? ClassDescriptor ?: return type
|
||||||
|
|
||||||
if (KotlinBuiltIns.isArray(type)) {
|
if (KotlinBuiltIns.isArray(type)) {
|
||||||
val elementTypeProjection = type.arguments.singleOrNull()
|
val elementTypeProjection = type.arguments.singleOrNull()
|
||||||
if (elementTypeProjection != null && !elementTypeProjection.isStarProjection) {
|
if (elementTypeProjection != null && !elementTypeProjection.isStarProjection) {
|
||||||
return type.builtIns.getArrayType(
|
return type.builtIns.getArrayType(
|
||||||
elementTypeProjection.projectionKind,
|
elementTypeProjection.projectionKind,
|
||||||
convertPossiblyAnonymousType(elementTypeProjection.type)
|
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 com.sun.tools.javac.tree.TreeScanner
|
||||||
import kotlinx.kapt.KaptIgnored
|
import kotlinx.kapt.KaptIgnored
|
||||||
import org.jetbrains.kotlin.base.kapt3.KaptFlag
|
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.coroutines.CONTINUATION_PARAMETER_NAME
|
||||||
import org.jetbrains.kotlin.codegen.needsExperimentalCoroutinesWrapper
|
import org.jetbrains.kotlin.codegen.needsExperimentalCoroutinesWrapper
|
||||||
import org.jetbrains.kotlin.config.LanguageFeature
|
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.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.name.ClassId
|
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.name.Name
|
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
import org.jetbrains.kotlin.resolve.DelegatingBindingTrace
|
import org.jetbrains.kotlin.resolve.DelegatingBindingTrace
|
||||||
@@ -667,7 +666,10 @@ class ClassFileToSourceStubConverter(val kaptContext: KaptContextForStubGenerati
|
|||||||
val trace = DelegatingBindingTrace(kaptContext.bindingContext, "Kapt")
|
val trace = DelegatingBindingTrace(kaptContext.bindingContext, "Kapt")
|
||||||
val const = evaluator.evaluateExpression(propertyInitializer, trace, propertyType)
|
val const = evaluator.evaluateExpression(propertyInitializer, trace, propertyType)
|
||||||
if (const != null && !const.isError && const.canBeUsedInAnnotations && !const.usesNonConstValAsConstant) {
|
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
|
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(
|
private fun convertMethod(
|
||||||
method: MethodNode,
|
method: MethodNode,
|
||||||
containingClass: ClassNode,
|
containingClass: ClassNode,
|
||||||
@@ -1196,21 +1256,6 @@ class ClassFileToSourceStubConverter(val kaptContext: KaptContextForStubGenerati
|
|||||||
|
|
||||||
treeMaker.Select(treeMaker.Type(enumType), treeMaker.name(valueName))
|
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 List<*> -> treeMaker.NewArray(null, JavacList.nil(), mapJList(value) { convertLiteralExpression(it) })
|
||||||
|
|
||||||
is Type -> treeMaker.Select(treeMaker.Type(value), treeMaker.name("class"))
|
is Type -> treeMaker.Select(treeMaker.Type(value), treeMaker.name("class"))
|
||||||
|
|||||||
+11
@@ -25,6 +25,17 @@ object Boo {
|
|||||||
|
|
||||||
class HavingState {
|
class HavingState {
|
||||||
val state = State.START
|
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 {
|
enum class State {
|
||||||
|
|||||||
+75
@@ -126,12 +126,87 @@ import java.lang.System;
|
|||||||
public final class HavingState {
|
public final class HavingState {
|
||||||
@org.jetbrains.annotations.NotNull()
|
@org.jetbrains.annotations.NotNull()
|
||||||
private final State state = State.START;
|
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()
|
@org.jetbrains.annotations.NotNull()
|
||||||
public final State getState() {
|
public final State getState() {
|
||||||
return null;
|
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() {
|
public HavingState() {
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user