Value classes: Allow unsigned arrays in annotations

including varargs, apparently.
So, we allow unsigned types and unsigned arrays in annotations,
but disallow user-defined inline classes.
 #KT-23816 Fixed
This commit is contained in:
Ilmir Usmanov
2020-12-02 20:14:43 +01:00
parent a9c072f826
commit 516fce37db
16 changed files with 229 additions and 8 deletions
@@ -153,6 +153,10 @@ object StandardNames {
@JvmField val uShort: ClassId = ClassId.topLevel(uShortFqName)
@JvmField val uInt: ClassId = ClassId.topLevel(uIntFqName)
@JvmField val uLong: ClassId = ClassId.topLevel(uLongFqName)
@JvmField val uByteArrayFqName: FqName = fqName("UByteArray")
@JvmField val uShortArrayFqName: FqName = fqName("UShortArray")
@JvmField val uIntArrayFqName: FqName = fqName("UIntArray")
@JvmField val uLongArrayFqName: FqName = fqName("ULongArray")
@JvmField val primitiveTypeShortNames: Set<Name> = newHashSetWithExpectedSize<Name>(PrimitiveType.values().size).apply {
PrimitiveType.values().mapTo(this) { it.typeName }
@@ -819,6 +819,26 @@ public abstract class KotlinBuiltIns {
return isConstructedFromGivenClassAndNotNullable(type, FqNames.uLongFqName.toUnsafe());
}
public static boolean isUByteArray(@NotNull KotlinType type) {
return isConstructedFromGivenClassAndNotNullable(type, FqNames.uByteArrayFqName.toUnsafe());
}
public static boolean isUShortArray(@NotNull KotlinType type) {
return isConstructedFromGivenClassAndNotNullable(type, FqNames.uShortArrayFqName.toUnsafe());
}
public static boolean isUIntArray(@NotNull KotlinType type) {
return isConstructedFromGivenClassAndNotNullable(type, FqNames.uIntArrayFqName.toUnsafe());
}
public static boolean isULongArray(@NotNull KotlinType type) {
return isConstructedFromGivenClassAndNotNullable(type, FqNames.uLongArrayFqName.toUnsafe());
}
public static boolean isUnsignedArrayType(@NotNull KotlinType type) {
return isUByteArray(type) || isUShortArray(type) || isUIntArray(type) || isULongArray(type);
}
public static boolean isDoubleOrNullableDouble(@NotNull KotlinType type) {
return isConstructedFromGivenClass(type, FqNames._double);
}
@@ -23,10 +23,26 @@ enum class UnsignedType(val classId: ClassId) {
val arrayClassId = ClassId(classId.packageFqName, Name.identifier(typeName.asString() + "Array"))
}
enum class UnsignedArrayType(val classId: ClassId) {
UBYTEARRAY(ClassId.fromString("kotlin/UByteArray")),
USHORTARRAY(ClassId.fromString("kotlin/UShortArray")),
UINTARRAY(ClassId.fromString("kotlin/UIntArray")),
ULONGARRAY(ClassId.fromString("kotlin/ULongArray"));
val typeName = classId.shortClassName
}
object UnsignedTypes {
private val unsignedTypeNames = enumValues<UnsignedType>().map { it.typeName }.toSet()
private val unsignedArrayTypeNames = enumValues<UnsignedArrayType>().map { it.typeName }.toSet()
private val arrayClassIdToUnsignedClassId = hashMapOf<ClassId, ClassId>()
private val unsignedClassIdToArrayClassId = hashMapOf<ClassId, ClassId>()
val unsignedArrayTypeToArrayCall = hashMapOf(
UnsignedArrayType.UBYTEARRAY to Name.identifier("ubyteArrayOf"),
UnsignedArrayType.USHORTARRAY to Name.identifier("ushortArrayOf"),
UnsignedArrayType.UINTARRAY to Name.identifier("uintArrayOf"),
UnsignedArrayType.ULONGARRAY to Name.identifier("ulongArrayOf"),
)
private val arrayClassesShortNames: Set<Name> = UnsignedType.values().mapTo(mutableSetOf()) { it.arrayClassId.shortClassName }
@@ -66,4 +82,40 @@ object UnsignedTypes {
container.fqName == StandardNames.BUILT_INS_PACKAGE_FQ_NAME &&
descriptor.name in UnsignedTypes.unsignedTypeNames
}
@JvmStatic
fun isUnsignedArrayType(type: KotlinType): Boolean {
if (TypeUtils.noExpectedType(type)) return false
val descriptor = type.constructor.declarationDescriptor ?: return false
return isUnsignedArrayClass(descriptor)
}
@JvmStatic
fun toUnsignedArrayType(type: KotlinType): UnsignedArrayType? =
when {
KotlinBuiltIns.isUByteArray(type) -> UnsignedArrayType.UBYTEARRAY
KotlinBuiltIns.isUShortArray(type) -> UnsignedArrayType.USHORTARRAY
KotlinBuiltIns.isUIntArray(type) -> UnsignedArrayType.UINTARRAY
KotlinBuiltIns.isULongArray(type) -> UnsignedArrayType.ULONGARRAY
else -> null
}
@JvmStatic
fun toUnsignedArrayType(descriptor: DeclarationDescriptor): UnsignedArrayType? =
if (!isUnsignedArrayClass(descriptor)) null
else when (descriptor.name.asString()) {
"UByteArray" -> UnsignedArrayType.UBYTEARRAY
"UShortArray" -> UnsignedArrayType.USHORTARRAY
"UIntArray" -> UnsignedArrayType.UINTARRAY
"ULongArray" -> UnsignedArrayType.ULONGARRAY
else -> null
}
fun isUnsignedArrayClass(descriptor: DeclarationDescriptor): Boolean {
val container = descriptor.containingDeclaration
return container is PackageFragmentDescriptor &&
container.fqName == StandardNames.BUILT_INS_PACKAGE_FQ_NAME &&
descriptor.name in unsignedArrayTypeNames
}
}
@@ -56,11 +56,13 @@ class AnnotationValue(value: AnnotationDescriptor) : ConstantValue<AnnotationDes
}
class ArrayValue(
value: List<ConstantValue<*>>,
private val computeType: (ModuleDescriptor) -> KotlinType
value: List<ConstantValue<*>>,
private val computeType: (ModuleDescriptor) -> KotlinType
) : ConstantValue<List<ConstantValue<*>>>(value) {
override fun getType(module: ModuleDescriptor): KotlinType = computeType(module).also { type ->
assert(KotlinBuiltIns.isArray(type) || KotlinBuiltIns.isPrimitiveArray(type)) { "Type should be an array, but was $type: $value" }
assert(KotlinBuiltIns.isArray(type) || KotlinBuiltIns.isPrimitiveArray(type) || KotlinBuiltIns.isUnsignedArrayType(type)) {
"Type should be an array, but was $type: $value"
}
}
override fun <R, D> accept(visitor: AnnotationArgumentVisitor<R, D>, data: D) = visitor.visitArrayValue(this, data)