Support kotlinx.collections.immutable in kotlin-parcelize plugin
#KT-57685 Fixed Co-authored-by: Ilya Gulya <ilyagulya@gmail.com>
This commit is contained in:
@@ -65,6 +65,7 @@ dependencies {
|
|||||||
|
|
||||||
parcelizeRuntimeForTests(project(":plugins:parcelize:parcelize-runtime")) { isTransitive = false }
|
parcelizeRuntimeForTests(project(":plugins:parcelize:parcelize-runtime")) { isTransitive = false }
|
||||||
parcelizeRuntimeForTests(project(":kotlin-android-extensions-runtime")) { isTransitive = false }
|
parcelizeRuntimeForTests(project(":kotlin-android-extensions-runtime")) { isTransitive = false }
|
||||||
|
parcelizeRuntimeForTests(commonDependency("org.jetbrains.kotlinx:kotlinx-collections-immutable-jvm")) { isTransitive = false }
|
||||||
|
|
||||||
layoutLib("org.jetbrains.intellij.deps.android.tools:layoutlib:26.5.0") { isTransitive = false }
|
layoutLib("org.jetbrains.intellij.deps.android.tools:layoutlib:26.5.0") { isTransitive = false }
|
||||||
layoutLibApi("com.android.tools.layoutlib:layoutlib-api:26.5.0") { isTransitive = false }
|
layoutLibApi("com.android.tools.layoutlib:layoutlib-api:26.5.0") { isTransitive = false }
|
||||||
|
|||||||
+35
-2
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.parcelize
|
package org.jetbrains.kotlin.parcelize
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
|
||||||
import org.jetbrains.kotlin.backend.common.ir.addExtensionReceiver
|
import org.jetbrains.kotlin.backend.common.ir.addExtensionReceiver
|
||||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||||
import org.jetbrains.kotlin.descriptors.InlineClassRepresentation
|
import org.jetbrains.kotlin.descriptors.InlineClassRepresentation
|
||||||
@@ -22,6 +23,7 @@ import org.jetbrains.kotlin.ir.symbols.*
|
|||||||
import org.jetbrains.kotlin.ir.types.*
|
import org.jetbrains.kotlin.ir.types.*
|
||||||
import org.jetbrains.kotlin.ir.util.createImplicitParameterDeclarationWithWrappedDescriptor
|
import org.jetbrains.kotlin.ir.util.createImplicitParameterDeclarationWithWrappedDescriptor
|
||||||
import org.jetbrains.kotlin.ir.util.defaultType
|
import org.jetbrains.kotlin.ir.util.defaultType
|
||||||
|
import org.jetbrains.kotlin.name.CallableId
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.parcelize.ParcelizeNames.CREATE_FROM_PARCEL_NAME
|
import org.jetbrains.kotlin.parcelize.ParcelizeNames.CREATE_FROM_PARCEL_NAME
|
||||||
@@ -32,10 +34,11 @@ import org.jetbrains.kotlin.parcelize.ParcelizeNames.WRITE_TO_PARCEL_NAME
|
|||||||
// hence contain just enough information to produce correct JVM bytecode for *calls*. In particular, we omit generic types and
|
// hence contain just enough information to produce correct JVM bytecode for *calls*. In particular, we omit generic types and
|
||||||
// supertypes, which are not needed to produce correct bytecode.
|
// supertypes, which are not needed to produce correct bytecode.
|
||||||
class AndroidSymbols(
|
class AndroidSymbols(
|
||||||
val irBuiltIns: IrBuiltIns,
|
private val pluginContext: IrPluginContext,
|
||||||
private val moduleFragment: IrModuleFragment
|
private val moduleFragment: IrModuleFragment,
|
||||||
) {
|
) {
|
||||||
private val irFactory: IrFactory = IrFactoryImpl
|
private val irFactory: IrFactory = IrFactoryImpl
|
||||||
|
val irBuiltIns: IrBuiltIns = pluginContext.irBuiltIns
|
||||||
|
|
||||||
private val javaIo: IrPackageFragment = createPackage("java.io")
|
private val javaIo: IrPackageFragment = createPackage("java.io")
|
||||||
private val javaLang: IrPackageFragment = createPackage("java.lang")
|
private val javaLang: IrPackageFragment = createPackage("java.lang")
|
||||||
@@ -499,6 +502,36 @@ class AndroidSymbols(
|
|||||||
isStatic = true
|
isStatic = true
|
||||||
}.symbol
|
}.symbol
|
||||||
|
|
||||||
|
private val kotlinxCollectionsImmutable = FqName(kotlinxImmutable())
|
||||||
|
private val kotlinCollections = FqName("kotlin.collections")
|
||||||
|
private val kotlinIterable: FqName = kotlinCollections.child(Name.identifier("Iterable"))
|
||||||
|
private val kotlinMap: FqName = kotlinCollections.child(Name.identifier("Map"))
|
||||||
|
|
||||||
|
private fun findKotlinxImmutableCollectionExtensionFunction(
|
||||||
|
receiver: FqName,
|
||||||
|
functionName: String,
|
||||||
|
): IrSimpleFunctionSymbol {
|
||||||
|
val callableId = CallableId(kotlinxCollectionsImmutable, Name.identifier(functionName))
|
||||||
|
return pluginContext.referenceFunctions(callableId)
|
||||||
|
.firstOrNull {
|
||||||
|
it.owner.extensionReceiverParameter?.type?.classFqName == receiver &&
|
||||||
|
it.owner.valueParameters.isEmpty()
|
||||||
|
}
|
||||||
|
?: error("Function from kotlinx.collections.immutable is not found on classpath: $callableId")
|
||||||
|
}
|
||||||
|
|
||||||
|
val kotlinIterableToPersistentListExtension: IrSimpleFunctionSymbol by lazy {
|
||||||
|
findKotlinxImmutableCollectionExtensionFunction(kotlinIterable, "toPersistentList")
|
||||||
|
}
|
||||||
|
|
||||||
|
val kotlinIterableToPersistentSetExtension: IrSimpleFunctionSymbol by lazy {
|
||||||
|
findKotlinxImmutableCollectionExtensionFunction(kotlinIterable, "toPersistentSet")
|
||||||
|
}
|
||||||
|
|
||||||
|
val kotlinMapToPersistentMapExtension: IrSimpleFunctionSymbol by lazy {
|
||||||
|
findKotlinxImmutableCollectionExtensionFunction(kotlinMap, "toPersistentMap")
|
||||||
|
}
|
||||||
|
|
||||||
val unsafeCoerceIntrinsic: IrSimpleFunctionSymbol =
|
val unsafeCoerceIntrinsic: IrSimpleFunctionSymbol =
|
||||||
irFactory.buildFun {
|
irFactory.buildFun {
|
||||||
name = Name.special("<unsafe-coerce>")
|
name = Name.special("<unsafe-coerce>")
|
||||||
|
|||||||
+91
-27
@@ -15,6 +15,35 @@ import org.jetbrains.kotlin.ir.util.*
|
|||||||
import org.jetbrains.kotlin.parcelize.ParcelizeNames.RAW_VALUE_ANNOTATION_FQ_NAMES
|
import org.jetbrains.kotlin.parcelize.ParcelizeNames.RAW_VALUE_ANNOTATION_FQ_NAMES
|
||||||
|
|
||||||
class IrParcelSerializerFactory(private val symbols: AndroidSymbols) {
|
class IrParcelSerializerFactory(private val symbols: AndroidSymbols) {
|
||||||
|
private val supportedBySimpleListSerializer = setOf(
|
||||||
|
"kotlin.collections.List", "kotlin.collections.MutableList", "kotlin.collections.ArrayList",
|
||||||
|
"java.util.List", "java.util.ArrayList",
|
||||||
|
*BuiltinParcelableTypes.IMMUTABLE_LIST_FQNAMES.toTypedArray()
|
||||||
|
)
|
||||||
|
|
||||||
|
// TODO: More java collections?
|
||||||
|
// TODO: Add tests for all of these types, not just some common ones...
|
||||||
|
private val supportedByListSerializer = setOf(
|
||||||
|
"kotlin.collections.MutableList", "kotlin.collections.List", "java.util.List",
|
||||||
|
"kotlin.collections.ArrayList", "java.util.ArrayList",
|
||||||
|
"kotlin.collections.ArrayDeque", "java.util.ArrayDeque",
|
||||||
|
"kotlin.collections.MutableSet", "kotlin.collections.Set", "java.util.Set",
|
||||||
|
"kotlin.collections.HashSet", "java.util.HashSet",
|
||||||
|
"kotlin.collections.LinkedHashSet", "java.util.LinkedHashSet",
|
||||||
|
"java.util.NavigableSet", "java.util.SortedSet",
|
||||||
|
*BuiltinParcelableTypes.IMMUTABLE_LIST_FQNAMES.toTypedArray(),
|
||||||
|
*BuiltinParcelableTypes.IMMUTABLE_SET_FQNAMES.toTypedArray(),
|
||||||
|
)
|
||||||
|
|
||||||
|
private val supportedByMapSerializer = setOf(
|
||||||
|
"kotlin.collections.MutableMap", "kotlin.collections.Map", "java.util.Map",
|
||||||
|
"kotlin.collections.HashMap", "java.util.HashMap",
|
||||||
|
"kotlin.collections.LinkedHashMap", "java.util.LinkedHashMap",
|
||||||
|
"java.util.SortedMap", "java.util.NavigableMap", "java.util.TreeMap",
|
||||||
|
"java.util.concurrent.ConcurrentHashMap",
|
||||||
|
*BuiltinParcelableTypes.IMMUTABLE_MAP_FQNAMES.toTypedArray(),
|
||||||
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolve the given [irType] to a corresponding [IrParcelSerializer]. This depends on the TypeParcelers which
|
* Resolve the given [irType] to a corresponding [IrParcelSerializer]. This depends on the TypeParcelers which
|
||||||
* are currently in [scope], as well as the type of the enclosing Parceleable class [parcelizeType], which is needed
|
* are currently in [scope], as well as the type of the enclosing Parceleable class [parcelizeType], which is needed
|
||||||
@@ -192,43 +221,56 @@ class IrParcelSerializerFactory(private val symbols: AndroidSymbols) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: More java collections?
|
in supportedByListSerializer -> {
|
||||||
// TODO: Add tests for all of these types, not just some common ones...
|
|
||||||
// FIXME: Is the support for ArrayDeque missing in the old BE?
|
|
||||||
"kotlin.collections.MutableList", "kotlin.collections.List", "java.util.List",
|
|
||||||
"kotlin.collections.ArrayList", "java.util.ArrayList",
|
|
||||||
"kotlin.collections.ArrayDeque", "java.util.ArrayDeque",
|
|
||||||
"kotlin.collections.MutableSet", "kotlin.collections.Set", "java.util.Set",
|
|
||||||
"kotlin.collections.HashSet", "java.util.HashSet",
|
|
||||||
"kotlin.collections.LinkedHashSet", "java.util.LinkedHashSet",
|
|
||||||
"java.util.NavigableSet", "java.util.SortedSet" -> {
|
|
||||||
val elementType = (irType as IrSimpleType).arguments.single().upperBound(irBuiltIns)
|
val elementType = (irType as IrSimpleType).arguments.single().upperBound(irBuiltIns)
|
||||||
if (!scope.hasCustomSerializer(elementType) && classifierFqName in setOf(
|
if (!scope.hasCustomSerializer(elementType) &&
|
||||||
"kotlin.collections.List", "kotlin.collections.MutableList", "kotlin.collections.ArrayList",
|
classifierFqName in supportedBySimpleListSerializer
|
||||||
"java.util.List", "java.util.ArrayList"
|
|
||||||
)
|
|
||||||
) {
|
) {
|
||||||
when (elementType.erasedUpperBound.fqNameWhenAvailable?.asString()) {
|
val elementTypeAsString = elementType.erasedUpperBound.fqNameWhenAvailable?.asString()
|
||||||
"android.os.IBinder" ->
|
val simpleSerializer =
|
||||||
return iBinderListSerializer
|
if (classifierFqName in BuiltinParcelableTypes.IMMUTABLE_LIST_FQNAMES) {
|
||||||
"kotlin.String", "java.lang.String" ->
|
when (elementTypeAsString) {
|
||||||
return stringListSerializer
|
"android.os.IBinder" -> iBinderPersistentListSerializer
|
||||||
|
"kotlin.String", "java.lang.String" -> stringPersistentListSerializer
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
when (elementTypeAsString) {
|
||||||
|
"android.os.IBinder" -> iBinderListSerializer
|
||||||
|
"kotlin.String", "java.lang.String" -> stringListSerializer
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (simpleSerializer != null) {
|
||||||
|
return simpleSerializer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val listSerializer = IrListParcelSerializer(classifier, elementType, get(elementType, scope, parcelizeType, strict()))
|
||||||
|
val actualSerializer =
|
||||||
|
when (classifierFqName) {
|
||||||
|
in BuiltinParcelableTypes.IMMUTABLE_LIST_FQNAMES -> IrExtensionFunctionOnReadCallingSerializer(
|
||||||
|
delegated = listSerializer,
|
||||||
|
converterExtensionFunction = symbols.kotlinIterableToPersistentListExtension
|
||||||
|
)
|
||||||
|
in BuiltinParcelableTypes.IMMUTABLE_SET_FQNAMES -> IrExtensionFunctionOnReadCallingSerializer(
|
||||||
|
delegated = listSerializer,
|
||||||
|
converterExtensionFunction = symbols.kotlinIterableToPersistentSetExtension
|
||||||
|
)
|
||||||
|
else -> listSerializer
|
||||||
|
}
|
||||||
|
|
||||||
return wrapNullableSerializerIfNeeded(
|
return wrapNullableSerializerIfNeeded(
|
||||||
irType,
|
irType,
|
||||||
IrListParcelSerializer(classifier, elementType, get(elementType, scope, parcelizeType, strict()))
|
actualSerializer
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
"kotlin.collections.MutableMap", "kotlin.collections.Map", "java.util.Map",
|
in supportedByMapSerializer -> {
|
||||||
"kotlin.collections.HashMap", "java.util.HashMap",
|
|
||||||
"kotlin.collections.LinkedHashMap", "java.util.LinkedHashMap",
|
|
||||||
"java.util.SortedMap", "java.util.NavigableMap", "java.util.TreeMap",
|
|
||||||
"java.util.concurrent.ConcurrentHashMap" -> {
|
|
||||||
val keyType = (irType as IrSimpleType).arguments[0].upperBound(irBuiltIns)
|
val keyType = (irType as IrSimpleType).arguments[0].upperBound(irBuiltIns)
|
||||||
val valueType = irType.arguments[1].upperBound(irBuiltIns)
|
val valueType = irType.arguments[1].upperBound(irBuiltIns)
|
||||||
val parceler =
|
val mapSerializer =
|
||||||
IrMapParcelSerializer(
|
IrMapParcelSerializer(
|
||||||
classifier,
|
classifier,
|
||||||
keyType,
|
keyType,
|
||||||
@@ -236,7 +278,17 @@ class IrParcelSerializerFactory(private val symbols: AndroidSymbols) {
|
|||||||
get(keyType, scope, parcelizeType, strict()),
|
get(keyType, scope, parcelizeType, strict()),
|
||||||
get(valueType, scope, parcelizeType, strict())
|
get(valueType, scope, parcelizeType, strict())
|
||||||
)
|
)
|
||||||
return wrapNullableSerializerIfNeeded(irType, parceler)
|
|
||||||
|
val actualSerializer =
|
||||||
|
if (classifierFqName in BuiltinParcelableTypes.IMMUTABLE_MAP_FQNAMES) {
|
||||||
|
IrExtensionFunctionOnReadCallingSerializer(
|
||||||
|
mapSerializer,
|
||||||
|
symbols.kotlinMapToPersistentMapExtension
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
mapSerializer
|
||||||
|
}
|
||||||
|
return wrapNullableSerializerIfNeeded(irType, actualSerializer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -297,9 +349,21 @@ class IrParcelSerializerFactory(private val symbols: AndroidSymbols) {
|
|||||||
|
|
||||||
private val stringArraySerializer = IrSimpleParcelSerializer(symbols.parcelCreateStringArray, symbols.parcelWriteStringArray)
|
private val stringArraySerializer = IrSimpleParcelSerializer(symbols.parcelCreateStringArray, symbols.parcelWriteStringArray)
|
||||||
private val stringListSerializer = IrSimpleParcelSerializer(symbols.parcelCreateStringArrayList, symbols.parcelWriteStringList)
|
private val stringListSerializer = IrSimpleParcelSerializer(symbols.parcelCreateStringArrayList, symbols.parcelWriteStringList)
|
||||||
|
private val stringPersistentListSerializer by lazy {
|
||||||
|
IrExtensionFunctionOnReadCallingSerializer(
|
||||||
|
delegated = stringListSerializer,
|
||||||
|
converterExtensionFunction = symbols.kotlinIterableToPersistentListExtension,
|
||||||
|
)
|
||||||
|
}
|
||||||
private val iBinderSerializer = IrSimpleParcelSerializer(symbols.parcelReadStrongBinder, symbols.parcelWriteStrongBinder)
|
private val iBinderSerializer = IrSimpleParcelSerializer(symbols.parcelReadStrongBinder, symbols.parcelWriteStrongBinder)
|
||||||
private val iBinderArraySerializer = IrSimpleParcelSerializer(symbols.parcelCreateBinderArray, symbols.parcelWriteBinderArray)
|
private val iBinderArraySerializer = IrSimpleParcelSerializer(symbols.parcelCreateBinderArray, symbols.parcelWriteBinderArray)
|
||||||
private val iBinderListSerializer = IrSimpleParcelSerializer(symbols.parcelCreateBinderArrayList, symbols.parcelWriteBinderList)
|
private val iBinderListSerializer = IrSimpleParcelSerializer(symbols.parcelCreateBinderArrayList, symbols.parcelWriteBinderList)
|
||||||
|
private val iBinderPersistentListSerializer by lazy {
|
||||||
|
IrExtensionFunctionOnReadCallingSerializer(
|
||||||
|
delegated = iBinderListSerializer,
|
||||||
|
converterExtensionFunction = symbols.kotlinIterableToPersistentListExtension,
|
||||||
|
)
|
||||||
|
}
|
||||||
private val serializableSerializer = IrSimpleParcelSerializer(symbols.parcelReadSerializable, symbols.parcelWriteSerializable)
|
private val serializableSerializer = IrSimpleParcelSerializer(symbols.parcelReadSerializable, symbols.parcelWriteSerializable)
|
||||||
private val stringSerializer = IrSimpleParcelSerializer(symbols.parcelReadString, symbols.parcelWriteString)
|
private val stringSerializer = IrSimpleParcelSerializer(symbols.parcelReadString, symbols.parcelWriteString)
|
||||||
private val byteSerializer = IrSimpleParcelSerializer(symbols.parcelReadByte, symbols.parcelWriteByte)
|
private val byteSerializer = IrSimpleParcelSerializer(symbols.parcelReadByte, symbols.parcelWriteByte)
|
||||||
|
|||||||
+64
-14
@@ -35,6 +35,20 @@ fun AndroidIrBuilder.writeParcelWith(
|
|||||||
return with(serializer) { writeParcel(parcel, flags, value) }
|
return with(serializer) { writeParcel(parcel, flags, value) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class IrExtensionFunctionOnReadCallingSerializer(
|
||||||
|
private val delegated: IrParcelSerializer,
|
||||||
|
private val converterExtensionFunction: IrSimpleFunctionSymbol
|
||||||
|
) : IrParcelSerializer by delegated {
|
||||||
|
override fun AndroidIrBuilder.readParcel(parcel: IrValueDeclaration): IrExpression {
|
||||||
|
val delegatedResult = with(delegated) {
|
||||||
|
readParcel(parcel)
|
||||||
|
}
|
||||||
|
return irCall(converterExtensionFunction).apply {
|
||||||
|
extensionReceiver = delegatedResult
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Creates a serializer from a pair of parcel methods of the form reader()T and writer(T)V.
|
// Creates a serializer from a pair of parcel methods of the form reader()T and writer(T)V.
|
||||||
class IrSimpleParcelSerializer(private val reader: IrSimpleFunctionSymbol, private val writer: IrSimpleFunctionSymbol) :
|
class IrSimpleParcelSerializer(private val reader: IrSimpleFunctionSymbol, private val writer: IrSimpleFunctionSymbol) :
|
||||||
IrParcelSerializer {
|
IrParcelSerializer {
|
||||||
@@ -412,7 +426,12 @@ class IrListParcelSerializer(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun listSymbols(symbols: AndroidSymbols): Pair<IrConstructorSymbol, IrSimpleFunctionSymbol> {
|
data class ListSymbols(
|
||||||
|
val constructor: IrConstructorSymbol,
|
||||||
|
val function: IrSimpleFunctionSymbol,
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun listSymbols(symbols: AndroidSymbols): ListSymbols {
|
||||||
// If the IrClass refers to a concrete type, try to find a constructor with capacity or fall back
|
// If the IrClass refers to a concrete type, try to find a constructor with capacity or fall back
|
||||||
// the the default constructor if none exist.
|
// the the default constructor if none exist.
|
||||||
if (!irClass.isJvmInterface) {
|
if (!irClass.isJvmInterface) {
|
||||||
@@ -424,16 +443,31 @@ class IrListParcelSerializer(
|
|||||||
function.name.asString() == "add" && function.valueParameters.size == 1
|
function.name.asString() == "add" && function.valueParameters.size == 1
|
||||||
}
|
}
|
||||||
|
|
||||||
return constructor.symbol to add.symbol
|
return ListSymbols(
|
||||||
|
constructor = constructor.symbol,
|
||||||
|
function = add.symbol
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return when (irClass.fqNameWhenAvailable?.asString()) {
|
return when (irClass.fqNameWhenAvailable?.asString()) {
|
||||||
"kotlin.collections.MutableList", "kotlin.collections.List", "java.util.List" ->
|
"kotlin.collections.MutableList",
|
||||||
symbols.arrayListConstructor to symbols.arrayListAdd
|
"kotlin.collections.List",
|
||||||
"kotlin.collections.MutableSet", "kotlin.collections.Set", "java.util.Set" ->
|
"java.util.List",
|
||||||
symbols.linkedHashSetConstructor to symbols.linkedHashSetAdd
|
in BuiltinParcelableTypes.IMMUTABLE_LIST_FQNAMES -> ListSymbols(
|
||||||
"java.util.NavigableSet", "java.util.SortedSet" ->
|
constructor = symbols.arrayListConstructor,
|
||||||
symbols.treeSetConstructor to symbols.treeSetAdd
|
function = symbols.arrayListAdd
|
||||||
|
)
|
||||||
|
"kotlin.collections.MutableSet",
|
||||||
|
"kotlin.collections.Set",
|
||||||
|
"java.util.Set",
|
||||||
|
in BuiltinParcelableTypes.IMMUTABLE_SET_FQNAMES -> ListSymbols(
|
||||||
|
constructor = symbols.linkedHashSetConstructor,
|
||||||
|
function = symbols.linkedHashSetAdd
|
||||||
|
)
|
||||||
|
"java.util.NavigableSet", "java.util.SortedSet" -> ListSymbols(
|
||||||
|
constructor = symbols.treeSetConstructor,
|
||||||
|
function = symbols.treeSetAdd
|
||||||
|
)
|
||||||
else -> error("Unknown list interface type: ${irClass.render()}")
|
else -> error("Unknown list interface type: ${irClass.render()}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -506,7 +540,12 @@ class IrMapParcelSerializer(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun mapSymbols(symbols: AndroidSymbols): Pair<IrConstructorSymbol, IrSimpleFunctionSymbol> {
|
data class MapSymbols(
|
||||||
|
val constructor: IrConstructorSymbol,
|
||||||
|
val function: IrSimpleFunctionSymbol,
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun mapSymbols(symbols: AndroidSymbols): MapSymbols {
|
||||||
// If the IrClass refers to a concrete type, try to find a constructor with capacity or fall back
|
// If the IrClass refers to a concrete type, try to find a constructor with capacity or fall back
|
||||||
// the the default constructor if none exist.
|
// the the default constructor if none exist.
|
||||||
if (!irClass.isJvmInterface) {
|
if (!irClass.isJvmInterface) {
|
||||||
@@ -520,14 +559,25 @@ class IrMapParcelSerializer(
|
|||||||
function.name.asString() == "put" && function.valueParameters.size == 2
|
function.name.asString() == "put" && function.valueParameters.size == 2
|
||||||
}
|
}
|
||||||
|
|
||||||
return constructor.symbol to put.symbol
|
return MapSymbols(
|
||||||
|
constructor = constructor.symbol,
|
||||||
|
function = put.symbol,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return when (irClass.fqNameWhenAvailable?.asString()) {
|
return when (irClass.fqNameWhenAvailable?.asString()) {
|
||||||
"kotlin.collections.MutableMap", "kotlin.collections.Map", "java.util.Map" ->
|
"kotlin.collections.MutableMap",
|
||||||
symbols.linkedHashMapConstructor to symbols.linkedHashMapPut
|
"kotlin.collections.Map",
|
||||||
"java.util.SortedMap", "java.util.NavigableMap" ->
|
"java.util.Map",
|
||||||
symbols.treeMapConstructor to symbols.treeMapPut
|
in BuiltinParcelableTypes.IMMUTABLE_MAP_FQNAMES -> MapSymbols(
|
||||||
|
constructor = symbols.linkedHashMapConstructor,
|
||||||
|
function = symbols.linkedHashMapPut,
|
||||||
|
)
|
||||||
|
"java.util.SortedMap",
|
||||||
|
"java.util.NavigableMap" -> MapSymbols(
|
||||||
|
constructor = symbols.treeMapConstructor,
|
||||||
|
function = symbols.treeMapPut
|
||||||
|
)
|
||||||
else -> error("Unknown map interface type: ${irClass.render()}")
|
else -> error("Unknown map interface type: ${irClass.render()}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -11,7 +11,7 @@ import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
|||||||
|
|
||||||
class ParcelizeFirIrGeneratorExtension : IrGenerationExtension {
|
class ParcelizeFirIrGeneratorExtension : IrGenerationExtension {
|
||||||
override fun generate(moduleFragment: IrModuleFragment, pluginContext: IrPluginContext) {
|
override fun generate(moduleFragment: IrModuleFragment, pluginContext: IrPluginContext) {
|
||||||
val androidSymbols = AndroidSymbols(pluginContext.irBuiltIns, moduleFragment)
|
val androidSymbols = AndroidSymbols(pluginContext, moduleFragment)
|
||||||
ParcelizeFirIrTransformer(pluginContext, androidSymbols).transform(moduleFragment)
|
ParcelizeFirIrTransformer(pluginContext, androidSymbols).transform(moduleFragment)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -11,7 +11,7 @@ import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
|||||||
|
|
||||||
class ParcelizeIrGeneratorExtension : IrGenerationExtension {
|
class ParcelizeIrGeneratorExtension : IrGenerationExtension {
|
||||||
override fun generate(moduleFragment: IrModuleFragment, pluginContext: IrPluginContext) {
|
override fun generate(moduleFragment: IrModuleFragment, pluginContext: IrPluginContext) {
|
||||||
val androidSymbols = AndroidSymbols(pluginContext.irBuiltIns, moduleFragment)
|
val androidSymbols = AndroidSymbols(pluginContext, moduleFragment)
|
||||||
ParcelizeIrTransformer(pluginContext, androidSymbols).transform(moduleFragment)
|
ParcelizeIrTransformer(pluginContext, androidSymbols).transform(moduleFragment)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+22
@@ -15,6 +15,27 @@ package org.jetbrains.kotlin.parcelize
|
|||||||
* reflection, as well as all objects, enums, and function types (since they are implicitly serializable).
|
* reflection, as well as all objects, enums, and function types (since they are implicitly serializable).
|
||||||
*/
|
*/
|
||||||
object BuiltinParcelableTypes {
|
object BuiltinParcelableTypes {
|
||||||
|
val IMMUTABLE_LIST_FQNAMES = setOf(
|
||||||
|
kotlinxImmutable("PersistentList"),
|
||||||
|
kotlinxImmutable("ImmutableList"),
|
||||||
|
)
|
||||||
|
|
||||||
|
val IMMUTABLE_SET_FQNAMES = setOf(
|
||||||
|
kotlinxImmutable("PersistentSet"),
|
||||||
|
kotlinxImmutable("ImmutableSet"),
|
||||||
|
)
|
||||||
|
|
||||||
|
val IMMUTABLE_MAP_FQNAMES = setOf(
|
||||||
|
kotlinxImmutable("PersistentMap"),
|
||||||
|
kotlinxImmutable("ImmutableMap"),
|
||||||
|
)
|
||||||
|
|
||||||
|
val IMMUTABLE_COLLECTIONS_FQNAMES = setOf(
|
||||||
|
*IMMUTABLE_LIST_FQNAMES.toTypedArray(),
|
||||||
|
*IMMUTABLE_SET_FQNAMES.toTypedArray(),
|
||||||
|
*IMMUTABLE_MAP_FQNAMES.toTypedArray()
|
||||||
|
)
|
||||||
|
|
||||||
val PARCELABLE_SUPERTYPE_FQNAMES = setOf(
|
val PARCELABLE_SUPERTYPE_FQNAMES = setOf(
|
||||||
"android.os.Parcelable",
|
"android.os.Parcelable",
|
||||||
"android.os.IBinder",
|
"android.os.IBinder",
|
||||||
@@ -97,5 +118,6 @@ object BuiltinParcelableTypes {
|
|||||||
"kotlin.collections.MutableMap",
|
"kotlin.collections.MutableMap",
|
||||||
"kotlin.collections.MutableSet",
|
"kotlin.collections.MutableSet",
|
||||||
"kotlin.collections.Set",
|
"kotlin.collections.Set",
|
||||||
|
*IMMUTABLE_COLLECTIONS_FQNAMES.toTypedArray(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
+16
@@ -0,0 +1,16 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2023 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.parcelize
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Required because :kotlin-compiler-embeddable performs package relocation
|
||||||
|
* If there's a "kotlinx.collections.immutable" string literal in bytecode
|
||||||
|
* it becomes "org.jetbrains.kotlin.kotlinx.collections.immutable" thus
|
||||||
|
* breaking target project class name matching
|
||||||
|
*/
|
||||||
|
fun kotlinxImmutable(name: String? = null): String {
|
||||||
|
return listOfNotNull("kotlinx", "collections", "immutable", name).joinToString(".")
|
||||||
|
}
|
||||||
+1
-1
@@ -44,7 +44,7 @@ interface ParcelSerializer {
|
|||||||
val frameMap: FrameMap
|
val frameMap: FrameMap
|
||||||
) {
|
) {
|
||||||
fun findParcelerClass(type: KotlinType): KotlinType? {
|
fun findParcelerClass(type: KotlinType): KotlinType? {
|
||||||
return typeParcelers.firstOrNull { it.first == type }?.second
|
return typeParcelers.firstOrNull { it.mappedType == type }?.parcelerType
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+4
-1
@@ -10,7 +10,10 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
|||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
import org.jetbrains.kotlin.types.TypeUtils
|
import org.jetbrains.kotlin.types.TypeUtils
|
||||||
|
|
||||||
typealias TypeParcelerMapping = Pair<KotlinType, KotlinType>
|
data class TypeParcelerMapping(
|
||||||
|
val mappedType: KotlinType,
|
||||||
|
val parcelerType: KotlinType,
|
||||||
|
)
|
||||||
|
|
||||||
fun KotlinType.isParcelable() = matchesFqNameWithSupertypes(ParcelizeNames.PARCELABLE_FQN.asString())
|
fun KotlinType.isParcelable() = matchesFqNameWithSupertypes(ParcelizeNames.PARCELABLE_FQN.asString())
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import kotlinx.parcelize.*
|
|||||||
import android.os.Parcel
|
import android.os.Parcel
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
import kotlinx.collections.immutable.*
|
||||||
|
|
||||||
@Parcelize
|
@Parcelize
|
||||||
data class Test(
|
data class Test(
|
||||||
@@ -21,7 +22,11 @@ data class Test(
|
|||||||
val h: HashSet<String>,
|
val h: HashSet<String>,
|
||||||
val i: LinkedHashSet<String>,
|
val i: LinkedHashSet<String>,
|
||||||
val j: NavigableSet<String>,
|
val j: NavigableSet<String>,
|
||||||
val k: SortedSet<String>
|
val k: SortedSet<String>,
|
||||||
|
val l: PersistentList<String>,
|
||||||
|
val m: PersistentSet<String>,
|
||||||
|
val n: ImmutableList<String>,
|
||||||
|
val o: ImmutableSet<String>,
|
||||||
) : Parcelable
|
) : Parcelable
|
||||||
|
|
||||||
fun box() = parcelTest { parcel ->
|
fun box() = parcelTest { parcel ->
|
||||||
@@ -36,7 +41,11 @@ fun box() = parcelTest { parcel ->
|
|||||||
h = HashSet<String>().apply { this += "H" },
|
h = HashSet<String>().apply { this += "H" },
|
||||||
i = LinkedHashSet<String>().apply { this += "I" },
|
i = LinkedHashSet<String>().apply { this += "I" },
|
||||||
j = TreeSet<String>().apply { this += "J" },
|
j = TreeSet<String>().apply { this += "J" },
|
||||||
k = TreeSet<String>().apply { this += "K" }
|
k = TreeSet<String>().apply { this += "K" },
|
||||||
|
l = persistentListOf("L"),
|
||||||
|
m = persistentSetOf("M"),
|
||||||
|
n = persistentListOf("N"),
|
||||||
|
o = persistentSetOf("O"),
|
||||||
)
|
)
|
||||||
|
|
||||||
first.writeToParcel(parcel, 0)
|
first.writeToParcel(parcel, 0)
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
// WITH_STDLIB
|
||||||
|
|
||||||
|
@file:JvmName("TestKt")
|
||||||
|
|
||||||
|
package test
|
||||||
|
|
||||||
|
import kotlinx.parcelize.*
|
||||||
|
import android.os.Parcel
|
||||||
|
import android.os.Parcelable
|
||||||
|
import kotlinx.collections.immutable.*
|
||||||
|
|
||||||
|
@Parcelize
|
||||||
|
data class Test(val a: PersistentList<String>) : Parcelable
|
||||||
|
|
||||||
|
fun box() = parcelTest { parcel ->
|
||||||
|
val first = Test(persistentListOf("A", "B"))
|
||||||
|
|
||||||
|
first.writeToParcel(parcel, 0)
|
||||||
|
|
||||||
|
val bytes = parcel.marshall()
|
||||||
|
parcel.unmarshall(bytes, 0, bytes.size)
|
||||||
|
parcel.setDataPosition(0)
|
||||||
|
|
||||||
|
val first2 = parcelableCreator<Test>().createFromParcel(parcel)
|
||||||
|
|
||||||
|
assert(first == first2)
|
||||||
|
}
|
||||||
@@ -8,6 +8,7 @@ import kotlinx.parcelize.*
|
|||||||
import android.os.Parcel
|
import android.os.Parcel
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
import kotlinx.collections.immutable.*
|
||||||
|
|
||||||
@Parcelize
|
@Parcelize
|
||||||
data class Test(
|
data class Test(
|
||||||
@@ -17,7 +18,9 @@ data class Test(
|
|||||||
val d: LinkedHashMap<String, String>,
|
val d: LinkedHashMap<String, String>,
|
||||||
val e: TreeMap<String, String>,
|
val e: TreeMap<String, String>,
|
||||||
val f: SortedMap<String, String>,
|
val f: SortedMap<String, String>,
|
||||||
val g: NavigableMap<String, String>
|
val g: NavigableMap<String, String>,
|
||||||
|
val h: PersistentMap<String, String>,
|
||||||
|
val i: ImmutableMap<String, String>,
|
||||||
) : Parcelable
|
) : Parcelable
|
||||||
|
|
||||||
fun box() = parcelTest { parcel ->
|
fun box() = parcelTest { parcel ->
|
||||||
@@ -28,7 +31,9 @@ fun box() = parcelTest { parcel ->
|
|||||||
d = LinkedHashMap<String, String>().apply { put("A", "B") },
|
d = LinkedHashMap<String, String>().apply { put("A", "B") },
|
||||||
e = TreeMap<String, String>().apply { put("A", "B") },
|
e = TreeMap<String, String>().apply { put("A", "B") },
|
||||||
f = TreeMap<String, String>().apply { put("A", "B") },
|
f = TreeMap<String, String>().apply { put("A", "B") },
|
||||||
g = TreeMap<String, String>().apply { put("A", "B") }
|
g = TreeMap<String, String>().apply { put("A", "B") },
|
||||||
|
h = persistentMapOf("A" to "B"),
|
||||||
|
i = persistentMapOf("A" to "B"),
|
||||||
)
|
)
|
||||||
|
|
||||||
first.writeToParcel(parcel, 0)
|
first.writeToParcel(parcel, 0)
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
// WITH_STDLIB
|
||||||
|
|
||||||
|
@file:JvmName("TestKt")
|
||||||
|
|
||||||
|
package test
|
||||||
|
|
||||||
|
import kotlinx.parcelize.*
|
||||||
|
import android.os.Parcel
|
||||||
|
import android.os.Parcelable
|
||||||
|
import kotlinx.collections.immutable.*
|
||||||
|
|
||||||
|
@Parcelize
|
||||||
|
data class Test(val a: PersistentMap<String, String>) : Parcelable
|
||||||
|
|
||||||
|
fun box() = parcelTest { parcel ->
|
||||||
|
val first = Test(persistentMapOf("A" to "B", "C" to "D"))
|
||||||
|
|
||||||
|
first.writeToParcel(parcel, 0)
|
||||||
|
|
||||||
|
val bytes = parcel.marshall()
|
||||||
|
parcel.unmarshall(bytes, 0, bytes.size)
|
||||||
|
parcel.setDataPosition(0)
|
||||||
|
|
||||||
|
val first2 = parcelableCreator<Test>().createFromParcel(parcel)
|
||||||
|
|
||||||
|
assert(first == first2)
|
||||||
|
}
|
||||||
+48
@@ -0,0 +1,48 @@
|
|||||||
|
public final class Test$Creator : java/lang/Object, android/os/Parcelable$Creator {
|
||||||
|
public void <init>()
|
||||||
|
|
||||||
|
public final Test createFromParcel(android.os.Parcel parcel) {
|
||||||
|
LABEL (L0)
|
||||||
|
ALOAD (1)
|
||||||
|
LDC (parcel)
|
||||||
|
INVOKESTATIC (kotlin/jvm/internal/Intrinsics, checkNotNullParameter, (Ljava/lang/Object;Ljava/lang/String;)V)
|
||||||
|
NEW (Test)
|
||||||
|
DUP
|
||||||
|
ALOAD (1)
|
||||||
|
INVOKEVIRTUAL (android/os/Parcel, createStringArrayList, ()Ljava/util/ArrayList;)
|
||||||
|
CHECKCAST (java/lang/Iterable)
|
||||||
|
INVOKESTATIC (kotlinx/collections/immutable/ExtensionsKt, toPersistentList, (Ljava/lang/Iterable;)Lkotlinx/collections/immutable/PersistentList;)
|
||||||
|
INVOKESPECIAL (Test, <init>, (Lkotlinx/collections/immutable/PersistentList;)V)
|
||||||
|
ARETURN
|
||||||
|
LABEL (L1)
|
||||||
|
}
|
||||||
|
|
||||||
|
public java.lang.Object createFromParcel(android.os.Parcel source) {
|
||||||
|
LABEL (L0)
|
||||||
|
ALOAD (0)
|
||||||
|
ALOAD (1)
|
||||||
|
INVOKEVIRTUAL (Test$Creator, createFromParcel, (Landroid/os/Parcel;)LTest;)
|
||||||
|
ARETURN
|
||||||
|
LABEL (L1)
|
||||||
|
}
|
||||||
|
|
||||||
|
public final Test[] newArray(int size)
|
||||||
|
|
||||||
|
public java.lang.Object[] newArray(int size)
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class Test : java/lang/Object, android/os/Parcelable {
|
||||||
|
public final static android.os.Parcelable$Creator CREATOR
|
||||||
|
|
||||||
|
private final kotlinx.collections.immutable.PersistentList names
|
||||||
|
|
||||||
|
static void <clinit>()
|
||||||
|
|
||||||
|
public void <init>(kotlinx.collections.immutable.PersistentList names)
|
||||||
|
|
||||||
|
public int describeContents()
|
||||||
|
|
||||||
|
public final kotlinx.collections.immutable.PersistentList getNames()
|
||||||
|
|
||||||
|
public void writeToParcel(android.os.Parcel out, int flags)
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
// CURIOUS_ABOUT: createFromParcel
|
||||||
|
// WITH_STDLIB
|
||||||
|
|
||||||
|
import kotlinx.parcelize.*
|
||||||
|
import android.os.Parcelable
|
||||||
|
import kotlinx.collections.immutable.*
|
||||||
|
|
||||||
|
@Parcelize
|
||||||
|
class Test(val names: PersistentList<String>): Parcelable
|
||||||
+12
@@ -283,6 +283,12 @@ public class ParcelizeFirLightTreeBoxTestGenerated extends AbstractParcelizeFirL
|
|||||||
runTest("plugins/parcelize/parcelize-compiler/testData/box/listSimple.kt");
|
runTest("plugins/parcelize/parcelize-compiler/testData/box/listSimple.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("listSimplePersistent.kt")
|
||||||
|
public void testListSimplePersistent() throws Exception {
|
||||||
|
runTest("plugins/parcelize/parcelize-compiler/testData/box/listSimplePersistent.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("lists.kt")
|
@TestMetadata("lists.kt")
|
||||||
public void testLists() throws Exception {
|
public void testLists() throws Exception {
|
||||||
@@ -301,6 +307,12 @@ public class ParcelizeFirLightTreeBoxTestGenerated extends AbstractParcelizeFirL
|
|||||||
runTest("plugins/parcelize/parcelize-compiler/testData/box/mapSimple.kt");
|
runTest("plugins/parcelize/parcelize-compiler/testData/box/mapSimple.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("mapSimplePersistent.kt")
|
||||||
|
public void testMapSimplePersistent() throws Exception {
|
||||||
|
runTest("plugins/parcelize/parcelize-compiler/testData/box/mapSimplePersistent.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("maps.kt")
|
@TestMetadata("maps.kt")
|
||||||
public void testMaps() throws Exception {
|
public void testMaps() throws Exception {
|
||||||
|
|||||||
+12
@@ -283,6 +283,12 @@ public class ParcelizeIrBoxTestGenerated extends AbstractParcelizeIrBoxTest {
|
|||||||
runTest("plugins/parcelize/parcelize-compiler/testData/box/listSimple.kt");
|
runTest("plugins/parcelize/parcelize-compiler/testData/box/listSimple.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("listSimplePersistent.kt")
|
||||||
|
public void testListSimplePersistent() throws Exception {
|
||||||
|
runTest("plugins/parcelize/parcelize-compiler/testData/box/listSimplePersistent.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("lists.kt")
|
@TestMetadata("lists.kt")
|
||||||
public void testLists() throws Exception {
|
public void testLists() throws Exception {
|
||||||
@@ -301,6 +307,12 @@ public class ParcelizeIrBoxTestGenerated extends AbstractParcelizeIrBoxTest {
|
|||||||
runTest("plugins/parcelize/parcelize-compiler/testData/box/mapSimple.kt");
|
runTest("plugins/parcelize/parcelize-compiler/testData/box/mapSimple.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("mapSimplePersistent.kt")
|
||||||
|
public void testMapSimplePersistent() throws Exception {
|
||||||
|
runTest("plugins/parcelize/parcelize-compiler/testData/box/mapSimplePersistent.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("maps.kt")
|
@TestMetadata("maps.kt")
|
||||||
public void testMaps() throws Exception {
|
public void testMaps() throws Exception {
|
||||||
|
|||||||
+6
@@ -151,6 +151,12 @@ public class ParcelizeIrBytecodeListingTestGenerated extends AbstractParcelizeIr
|
|||||||
runTest("plugins/parcelize/parcelize-compiler/testData/codegen/simpleList.kt");
|
runTest("plugins/parcelize/parcelize-compiler/testData/codegen/simpleList.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("simplePersistentList.kt")
|
||||||
|
public void testSimplePersistentList() throws Exception {
|
||||||
|
runTest("plugins/parcelize/parcelize-compiler/testData/codegen/simplePersistentList.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("size.kt")
|
@TestMetadata("size.kt")
|
||||||
public void testSize() throws Exception {
|
public void testSize() throws Exception {
|
||||||
|
|||||||
+21
-3
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.cli.jvm.config.addJvmClasspathRoots
|
|||||||
import org.jetbrains.kotlin.compiler.plugin.CompilerPluginRegistrar
|
import org.jetbrains.kotlin.compiler.plugin.CompilerPluginRegistrar
|
||||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||||
import org.jetbrains.kotlin.parcelize.ParcelizeComponentRegistrar
|
import org.jetbrains.kotlin.parcelize.ParcelizeComponentRegistrar
|
||||||
|
import org.jetbrains.kotlin.parcelize.kotlinxImmutable
|
||||||
import org.jetbrains.kotlin.test.model.FrontendKinds
|
import org.jetbrains.kotlin.test.model.FrontendKinds
|
||||||
import org.jetbrains.kotlin.test.model.TestModule
|
import org.jetbrains.kotlin.test.model.TestModule
|
||||||
import org.jetbrains.kotlin.test.services.EnvironmentConfigurator
|
import org.jetbrains.kotlin.test.services.EnvironmentConfigurator
|
||||||
@@ -17,12 +18,29 @@ import org.jetbrains.kotlin.test.util.KtTestUtil
|
|||||||
import org.jetbrains.kotlin.utils.PathUtil
|
import org.jetbrains.kotlin.utils.PathUtil
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
|
private fun getLibraryJar(classToDetect: String): File? = try {
|
||||||
|
PathUtil.getResourcePathForClass(Class.forName(classToDetect))
|
||||||
|
} catch (e: ClassNotFoundException) {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
||||||
class ParcelizeEnvironmentConfigurator(testServices: TestServices) : EnvironmentConfigurator(testServices) {
|
class ParcelizeEnvironmentConfigurator(testServices: TestServices) : EnvironmentConfigurator(testServices) {
|
||||||
override fun configureCompilerConfiguration(configuration: CompilerConfiguration, module: TestModule) {
|
override fun configureCompilerConfiguration(configuration: CompilerConfiguration, module: TestModule) {
|
||||||
val runtimeLibrary = File(PathUtil.kotlinPathsForCompiler.libPath, PathUtil.PARCELIZE_RUNTIME_PLUGIN_JAR_NAME)
|
val libPath = PathUtil.kotlinPathsForCompiler.libPath
|
||||||
val androidExtensionsRuntimeLibrary = File(PathUtil.kotlinPathsForCompiler.libPath, PathUtil.ANDROID_EXTENSIONS_RUNTIME_PLUGIN_JAR_NAME)
|
val runtimeLibrary = File(libPath, PathUtil.PARCELIZE_RUNTIME_PLUGIN_JAR_NAME)
|
||||||
|
val androidExtensionsRuntimeLibrary = File(libPath, PathUtil.ANDROID_EXTENSIONS_RUNTIME_PLUGIN_JAR_NAME)
|
||||||
val androidApiJar = KtTestUtil.findAndroidApiJar()
|
val androidApiJar = KtTestUtil.findAndroidApiJar()
|
||||||
configuration.addJvmClasspathRoots(listOf(runtimeLibrary, androidExtensionsRuntimeLibrary, androidApiJar))
|
val kotlinxCollectionsImmutable = getLibraryJar(kotlinxImmutable("ImmutableList"))
|
||||||
|
?: error("kotlinx-collections-immutable is not found on classpath")
|
||||||
|
|
||||||
|
configuration.addJvmClasspathRoots(
|
||||||
|
listOf(
|
||||||
|
runtimeLibrary,
|
||||||
|
androidExtensionsRuntimeLibrary,
|
||||||
|
androidApiJar,
|
||||||
|
kotlinxCollectionsImmutable
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun CompilerPluginRegistrar.ExtensionStorage.registerCompilerExtensions(
|
override fun CompilerPluginRegistrar.ExtensionStorage.registerCompilerExtensions(
|
||||||
|
|||||||
Reference in New Issue
Block a user