[kotlin-tooling-core] Allow nullable extra values
The change is binary compatible, but not source compatible. Potential clients like Google might need to adapt a potential `IdeaKotlinExtrasSerializationExtension` implementaiton. Right now, no such implementation is known
This commit is contained in:
committed by
Space Team
parent
622a88ff26
commit
704379934e
+5
-3
@@ -11,9 +11,11 @@ import com.google.protobuf.ByteString
|
|||||||
import com.google.protobuf.InvalidProtocolBufferException
|
import com.google.protobuf.InvalidProtocolBufferException
|
||||||
import org.jetbrains.kotlin.gradle.idea.proto.generated.IdeaExtrasProto
|
import org.jetbrains.kotlin.gradle.idea.proto.generated.IdeaExtrasProto
|
||||||
import org.jetbrains.kotlin.gradle.idea.proto.generated.ideaExtrasProto
|
import org.jetbrains.kotlin.gradle.idea.proto.generated.ideaExtrasProto
|
||||||
import org.jetbrains.kotlin.gradle.idea.serialize.IdeaKotlinExtrasSerializer
|
|
||||||
import org.jetbrains.kotlin.gradle.idea.serialize.IdeaKotlinSerializationContext
|
import org.jetbrains.kotlin.gradle.idea.serialize.IdeaKotlinSerializationContext
|
||||||
import org.jetbrains.kotlin.tooling.core.*
|
import org.jetbrains.kotlin.tooling.core.Extras
|
||||||
|
import org.jetbrains.kotlin.tooling.core.MutableExtras
|
||||||
|
import org.jetbrains.kotlin.tooling.core.toMutableExtras
|
||||||
|
import org.jetbrains.kotlin.tooling.core.withValue
|
||||||
|
|
||||||
fun Extras.toByteArray(context: IdeaKotlinSerializationContext): ByteArray {
|
fun Extras.toByteArray(context: IdeaKotlinSerializationContext): ByteArray {
|
||||||
return context.IdeaExtrasProto(this).toByteArray()
|
return context.IdeaExtrasProto(this).toByteArray()
|
||||||
@@ -35,8 +37,8 @@ internal fun IdeaKotlinSerializationContext.IdeaExtrasProto(extras: Extras): Ide
|
|||||||
val context = this
|
val context = this
|
||||||
return ideaExtrasProto {
|
return ideaExtrasProto {
|
||||||
extras.entries.forEach { (key, value) ->
|
extras.entries.forEach { (key, value) ->
|
||||||
|
key as Extras.Key<Any?>
|
||||||
val serializer = context.extrasSerializationExtension.serializer(key) ?: return@forEach
|
val serializer = context.extrasSerializationExtension.serializer(key) ?: return@forEach
|
||||||
serializer as IdeaKotlinExtrasSerializer<Any>
|
|
||||||
val serialized = runCatching { serializer.serialize(context, value) ?: return@forEach }.getOrElse { exception ->
|
val serialized = runCatching { serializer.serialize(context, value) ?: return@forEach }.getOrElse { exception ->
|
||||||
logger.error("Failed to serialize $key, using ${serializer.javaClass.simpleName}", exception)
|
logger.error("Failed to serialize $key, using ${serializer.javaClass.simpleName}", exception)
|
||||||
return@forEach
|
return@forEach
|
||||||
|
|||||||
+3
-3
@@ -18,10 +18,10 @@ import org.jetbrains.kotlin.tooling.core.Extras
|
|||||||
* inside the implementation of the given [IdeaKotlinExtrasSerializer]
|
* inside the implementation of the given [IdeaKotlinExtrasSerializer]
|
||||||
*/
|
*/
|
||||||
interface IdeaKotlinExtrasSerializationExtension {
|
interface IdeaKotlinExtrasSerializationExtension {
|
||||||
fun <T : Any> serializer(key: Extras.Key<T>): IdeaKotlinExtrasSerializer<T>?
|
fun <T> serializer(key: Extras.Key<T>): IdeaKotlinExtrasSerializer<T>?
|
||||||
|
|
||||||
object Empty : IdeaKotlinExtrasSerializationExtension {
|
object Empty : IdeaKotlinExtrasSerializationExtension {
|
||||||
override fun <T : Any> serializer(key: Extras.Key<T>): IdeaKotlinExtrasSerializer<T>? = null
|
override fun <T> serializer(key: Extras.Key<T>): IdeaKotlinExtrasSerializer<T>? = null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,7 +48,7 @@ private class IdeaKotlinExtrasSerializationExtensionBuilderImpl : IdeaKotlinExtr
|
|||||||
private class IdeaKotlinExtrasSerializationExtensionImpl(
|
private class IdeaKotlinExtrasSerializationExtensionImpl(
|
||||||
private val map: Map<Extras.Key<*>, IdeaKotlinExtrasSerializer<*>>
|
private val map: Map<Extras.Key<*>, IdeaKotlinExtrasSerializer<*>>
|
||||||
) : IdeaKotlinExtrasSerializationExtension {
|
) : IdeaKotlinExtrasSerializationExtension {
|
||||||
override fun <T : Any> serializer(key: Extras.Key<T>): IdeaKotlinExtrasSerializer<T>? {
|
override fun <T> serializer(key: Extras.Key<T>): IdeaKotlinExtrasSerializer<T>? {
|
||||||
@Suppress("unchecked_cast")
|
@Suppress("unchecked_cast")
|
||||||
return map[key] as? IdeaKotlinExtrasSerializer<T>
|
return map[key] as? IdeaKotlinExtrasSerializer<T>
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -8,7 +8,7 @@ package org.jetbrains.kotlin.gradle.idea.serialize
|
|||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
|
|
||||||
interface IdeaKotlinExtrasSerializer<T : Any> {
|
interface IdeaKotlinExtrasSerializer<T> {
|
||||||
fun serialize(context: IdeaKotlinSerializationContext, value: T): ByteArray?
|
fun serialize(context: IdeaKotlinSerializationContext, value: T): ByteArray?
|
||||||
fun deserialize(context: IdeaKotlinSerializationContext, data: ByteArray): T?
|
fun deserialize(context: IdeaKotlinSerializationContext, data: ByteArray): T?
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -16,7 +16,7 @@ object TestIdeaExtrasSerializationExtension : IdeaKotlinExtrasSerializationExten
|
|||||||
val ignoredStringKey = extrasKeyOf<String>("ignored")
|
val ignoredStringKey = extrasKeyOf<String>("ignored")
|
||||||
val anySerializableKey = extrasKeyOf<Any>("serializable")
|
val anySerializableKey = extrasKeyOf<Any>("serializable")
|
||||||
|
|
||||||
override fun <T : Any> serializer(key: Extras.Key<T>): IdeaKotlinExtrasSerializer<T>? = when {
|
override fun <T> serializer(key: Extras.Key<T>): IdeaKotlinExtrasSerializer<T>? = when {
|
||||||
key == ignoredStringKey -> null
|
key == ignoredStringKey -> null
|
||||||
key == anySerializableKey -> IdeaKotlinExtrasSerializer.javaIoSerializable<Any>()
|
key == anySerializableKey -> IdeaKotlinExtrasSerializer.javaIoSerializable<Any>()
|
||||||
key.type == extrasTypeOf<String>() -> IdeaKotlinStringExtrasSerializer
|
key.type == extrasTypeOf<String>() -> IdeaKotlinStringExtrasSerializer
|
||||||
|
|||||||
+5
-5
@@ -6,14 +6,14 @@
|
|||||||
package org.jetbrains.kotlin.gradle.plugin.ide
|
package org.jetbrains.kotlin.gradle.plugin.ide
|
||||||
|
|
||||||
import org.gradle.api.logging.Logger
|
import org.gradle.api.logging.Logger
|
||||||
import org.jetbrains.kotlin.gradle.idea.serialize.IdeaKotlinExtrasSerializer
|
|
||||||
import org.jetbrains.kotlin.gradle.idea.serialize.IdeaKotlinExtrasSerializationExtension
|
import org.jetbrains.kotlin.gradle.idea.serialize.IdeaKotlinExtrasSerializationExtension
|
||||||
|
import org.jetbrains.kotlin.gradle.idea.serialize.IdeaKotlinExtrasSerializer
|
||||||
import org.jetbrains.kotlin.gradle.idea.serialize.IdeaKotlinSerializationContext
|
import org.jetbrains.kotlin.gradle.idea.serialize.IdeaKotlinSerializationContext
|
||||||
import org.jetbrains.kotlin.gradle.idea.serialize.IdeaKotlinSerializationLogger
|
import org.jetbrains.kotlin.gradle.idea.serialize.IdeaKotlinSerializationLogger
|
||||||
import org.jetbrains.kotlin.tooling.core.Extras
|
import org.jetbrains.kotlin.tooling.core.Extras
|
||||||
|
|
||||||
internal fun IdeaKotlinSerializationContext(
|
internal fun IdeaKotlinSerializationContext(
|
||||||
logger: Logger, extrasSerializationExtensions: List<IdeaKotlinExtrasSerializationExtension>
|
logger: Logger, extrasSerializationExtensions: List<IdeaKotlinExtrasSerializationExtension>,
|
||||||
): IdeaKotlinSerializationContext {
|
): IdeaKotlinSerializationContext {
|
||||||
return IdeaKotlinSerializationContextImpl(
|
return IdeaKotlinSerializationContextImpl(
|
||||||
extrasSerializationExtension = IdeaKotlinExtrasSerializationExtensionImpl(logger, extrasSerializationExtensions),
|
extrasSerializationExtension = IdeaKotlinExtrasSerializationExtensionImpl(logger, extrasSerializationExtensions),
|
||||||
@@ -23,7 +23,7 @@ internal fun IdeaKotlinSerializationContext(
|
|||||||
|
|
||||||
private class IdeaKotlinSerializationContextImpl(
|
private class IdeaKotlinSerializationContextImpl(
|
||||||
override val extrasSerializationExtension: IdeaKotlinExtrasSerializationExtension,
|
override val extrasSerializationExtension: IdeaKotlinExtrasSerializationExtension,
|
||||||
override val logger: IdeaKotlinSerializationLogger
|
override val logger: IdeaKotlinSerializationLogger,
|
||||||
) : IdeaKotlinSerializationContext
|
) : IdeaKotlinSerializationContext
|
||||||
|
|
||||||
|
|
||||||
@@ -31,9 +31,9 @@ private class IdeaKotlinSerializationContextImpl(
|
|||||||
|
|
||||||
private class IdeaKotlinExtrasSerializationExtensionImpl(
|
private class IdeaKotlinExtrasSerializationExtensionImpl(
|
||||||
private val logger: Logger,
|
private val logger: Logger,
|
||||||
private val extensions: List<IdeaKotlinExtrasSerializationExtension>
|
private val extensions: List<IdeaKotlinExtrasSerializationExtension>,
|
||||||
) : IdeaKotlinExtrasSerializationExtension {
|
) : IdeaKotlinExtrasSerializationExtension {
|
||||||
override fun <T : Any> serializer(key: Extras.Key<T>): IdeaKotlinExtrasSerializer<T>? {
|
override fun <T> serializer(key: Extras.Key<T>): IdeaKotlinExtrasSerializer<T>? {
|
||||||
val serializers = extensions.mapNotNull { it.serializer(key) }
|
val serializers = extensions.mapNotNull { it.serializer(key) }
|
||||||
|
|
||||||
if (serializers.size == 1) {
|
if (serializers.size == 1) {
|
||||||
|
|||||||
@@ -127,6 +127,7 @@ public final class org/jetbrains/kotlin/tooling/core/ExtrasUtilsKt {
|
|||||||
public static final fun extrasOf ()Lorg/jetbrains/kotlin/tooling/core/Extras;
|
public static final fun extrasOf ()Lorg/jetbrains/kotlin/tooling/core/Extras;
|
||||||
public static final fun extrasOf ([Lorg/jetbrains/kotlin/tooling/core/Extras$Entry;)Lorg/jetbrains/kotlin/tooling/core/Extras;
|
public static final fun extrasOf ([Lorg/jetbrains/kotlin/tooling/core/Extras$Entry;)Lorg/jetbrains/kotlin/tooling/core/Extras;
|
||||||
public static final fun getOrPut (Lorg/jetbrains/kotlin/tooling/core/MutableExtras;Lorg/jetbrains/kotlin/tooling/core/Extras$Key;Lkotlin/jvm/functions/Function0;)Ljava/lang/Object;
|
public static final fun getOrPut (Lorg/jetbrains/kotlin/tooling/core/MutableExtras;Lorg/jetbrains/kotlin/tooling/core/Extras$Key;Lkotlin/jvm/functions/Function0;)Ljava/lang/Object;
|
||||||
|
public static final fun getOrPutNullable (Lorg/jetbrains/kotlin/tooling/core/MutableExtras;Lorg/jetbrains/kotlin/tooling/core/Extras$Key;Lkotlin/jvm/functions/Function0;)Ljava/lang/Object;
|
||||||
public static final fun mutableExtrasOf ()Lorg/jetbrains/kotlin/tooling/core/MutableExtras;
|
public static final fun mutableExtrasOf ()Lorg/jetbrains/kotlin/tooling/core/MutableExtras;
|
||||||
public static final fun mutableExtrasOf ([Lorg/jetbrains/kotlin/tooling/core/Extras$Entry;)Lorg/jetbrains/kotlin/tooling/core/MutableExtras;
|
public static final fun mutableExtrasOf ([Lorg/jetbrains/kotlin/tooling/core/Extras$Entry;)Lorg/jetbrains/kotlin/tooling/core/MutableExtras;
|
||||||
public static final fun plus (Lorg/jetbrains/kotlin/tooling/core/Extras;Ljava/lang/Iterable;)Lorg/jetbrains/kotlin/tooling/core/Extras;
|
public static final fun plus (Lorg/jetbrains/kotlin/tooling/core/Extras;Ljava/lang/Iterable;)Lorg/jetbrains/kotlin/tooling/core/Extras;
|
||||||
|
|||||||
+11
-11
@@ -62,9 +62,9 @@ import java.io.Serializable
|
|||||||
* .toExtras()
|
* .toExtras()
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
interface Extras : Collection<Entry<out Any>> {
|
interface Extras : Collection<Entry<*>> {
|
||||||
class Type<T> @UnsafeApi("Use 'extrasTypeOf()' instead") @PublishedApi internal constructor(
|
class Type<T> @UnsafeApi("Use 'extrasTypeOf()' instead") @PublishedApi internal constructor(
|
||||||
internal val signature: String
|
internal val signature: String,
|
||||||
) : Serializable {
|
) : Serializable {
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
if (this === other) return true
|
if (this === other) return true
|
||||||
@@ -85,7 +85,7 @@ interface Extras : Collection<Entry<out Any>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Not implemented as data class to ensure more controllable binary compatibility */
|
/* Not implemented as data class to ensure more controllable binary compatibility */
|
||||||
class Key<T : Any> @PublishedApi internal constructor(
|
class Key<T> @PublishedApi internal constructor(
|
||||||
val type: Type<T>,
|
val type: Type<T>,
|
||||||
val name: String? = null,
|
val name: String? = null,
|
||||||
) : Serializable {
|
) : Serializable {
|
||||||
@@ -116,8 +116,8 @@ interface Extras : Collection<Entry<out Any>> {
|
|||||||
fun fromString(stableString: String): Key<*> {
|
fun fromString(stableString: String): Key<*> {
|
||||||
@OptIn(UnsafeApi::class) return if (stableString.contains(';')) {
|
@OptIn(UnsafeApi::class) return if (stableString.contains(';')) {
|
||||||
val split = stableString.split(';', limit = 2)
|
val split = stableString.split(';', limit = 2)
|
||||||
Key(Type(split[0]), split[1])
|
Key<Any?>(Type(split[0]), split[1])
|
||||||
} else Key(Type(stableString))
|
} else Key<Any?>(Type(stableString))
|
||||||
}
|
}
|
||||||
|
|
||||||
private const val serialVersionUID = 0L
|
private const val serialVersionUID = 0L
|
||||||
@@ -125,7 +125,7 @@ interface Extras : Collection<Entry<out Any>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Not implemented as data class to ensure more controllable binary compatibility */
|
/* Not implemented as data class to ensure more controllable binary compatibility */
|
||||||
class Entry<T : Any>(val key: Key<T>, val value: T) : Serializable {
|
class Entry<T>(val key: Key<T>, val value: T) : Serializable {
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
if (this === other) return true
|
if (this === other) return true
|
||||||
if (other !is Entry<*>) return false
|
if (other !is Entry<*>) return false
|
||||||
@@ -152,22 +152,22 @@ interface Extras : Collection<Entry<out Any>> {
|
|||||||
|
|
||||||
val keys: Set<Key<*>>
|
val keys: Set<Key<*>>
|
||||||
val entries: Set<Entry<*>>
|
val entries: Set<Entry<*>>
|
||||||
operator fun <T : Any> get(key: Key<T>): T?
|
operator fun <T> get(key: Key<T>): T?
|
||||||
operator fun contains(key: Key<*>): Boolean
|
operator fun contains(key: Key<*>): Boolean
|
||||||
override fun iterator(): Iterator<Entry<out Any>>
|
override fun iterator(): Iterator<Entry<*>>
|
||||||
}
|
}
|
||||||
|
|
||||||
interface MutableExtras : Extras {
|
interface MutableExtras : Extras {
|
||||||
/**
|
/**
|
||||||
* @return The previous value or null if no previous value was set
|
* @return The previous value or null if no previous value was set
|
||||||
*/
|
*/
|
||||||
operator fun <T : Any> set(key: Key<T>, value: T): T?
|
operator fun <T> set(key: Key<T>, value: T): T?
|
||||||
|
|
||||||
fun <T : Any> put(entry: Entry<T>): T?
|
fun <T> put(entry: Entry<T>): T?
|
||||||
|
|
||||||
fun putAll(from: Iterable<Entry<*>>)
|
fun putAll(from: Iterable<Entry<*>>)
|
||||||
|
|
||||||
fun <T : Any> remove(key: Key<T>): T?
|
fun <T> remove(key: Key<T>): T?
|
||||||
|
|
||||||
fun clear()
|
fun clear()
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-10
@@ -11,7 +11,7 @@ import java.io.Serializable
|
|||||||
|
|
||||||
@Suppress("unchecked_cast")
|
@Suppress("unchecked_cast")
|
||||||
internal class MutableExtrasImpl(
|
internal class MutableExtrasImpl(
|
||||||
initialEntries: Iterable<Entry<*>> = emptyList()
|
initialEntries: Iterable<Entry<*>> = emptyList(),
|
||||||
) : MutableExtras, AbstractExtras(), Serializable {
|
) : MutableExtras, AbstractExtras(), Serializable {
|
||||||
|
|
||||||
private val extras: MutableMap<Key<*>, Entry<*>> =
|
private val extras: MutableMap<Key<*>, Entry<*>> =
|
||||||
@@ -28,11 +28,11 @@ internal class MutableExtrasImpl(
|
|||||||
|
|
||||||
override fun isEmpty(): Boolean = extras.isEmpty()
|
override fun isEmpty(): Boolean = extras.isEmpty()
|
||||||
|
|
||||||
override fun <T : Any> set(key: Key<T>, value: T): T? {
|
override fun <T> set(key: Key<T>, value: T): T? {
|
||||||
return put(Entry(key, value))
|
return put(Entry(key, value))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun <T : Any> put(entry: Entry<T>): T? {
|
override fun <T> put(entry: Entry<T>): T? {
|
||||||
return extras.put(entry.key, entry)?.let { it.value as T }
|
return extras.put(entry.key, entry)?.let { it.value as T }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -40,11 +40,11 @@ internal class MutableExtrasImpl(
|
|||||||
this.extras.putAll(from.associateBy { it.key })
|
this.extras.putAll(from.associateBy { it.key })
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun <T : Any> get(key: Key<T>): T? {
|
override fun <T> get(key: Key<T>): T? {
|
||||||
return extras[key]?.let { it.value as T }
|
return extras[key]?.let { it.value as T }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun <T : Any> remove(key: Key<T>): T? {
|
override fun <T> remove(key: Key<T>): T? {
|
||||||
return extras.remove(key)?.let { it.value as T }
|
return extras.remove(key)?.let { it.value as T }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,7 +59,7 @@ internal class MutableExtrasImpl(
|
|||||||
|
|
||||||
@Suppress("unchecked_cast")
|
@Suppress("unchecked_cast")
|
||||||
internal class ImmutableExtrasImpl private constructor(
|
internal class ImmutableExtrasImpl private constructor(
|
||||||
private val extras: Map<Key<*>, Entry<*>>
|
private val extras: Map<Key<*>, Entry<*>>,
|
||||||
) : AbstractExtras(), Serializable {
|
) : AbstractExtras(), Serializable {
|
||||||
constructor(extras: Iterable<Entry<*>>) : this(extras.associateBy { it.key })
|
constructor(extras: Iterable<Entry<*>>) : this(extras.associateBy { it.key })
|
||||||
|
|
||||||
@@ -73,7 +73,7 @@ internal class ImmutableExtrasImpl private constructor(
|
|||||||
|
|
||||||
override val entries: Set<Entry<*>> = extras.values.toSet()
|
override val entries: Set<Entry<*>> = extras.values.toSet()
|
||||||
|
|
||||||
override fun <T : Any> get(key: Key<T>): T? {
|
override fun <T> get(key: Key<T>): T? {
|
||||||
return extras[key]?.let { it.value as T }
|
return extras[key]?.let { it.value as T }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -107,7 +107,7 @@ abstract class AbstractExtras : Extras {
|
|||||||
override fun containsAll(elements: Collection<Entry<*>>): Boolean =
|
override fun containsAll(elements: Collection<Entry<*>>): Boolean =
|
||||||
entries.containsAll(elements)
|
entries.containsAll(elements)
|
||||||
|
|
||||||
override fun iterator(): Iterator<Entry<out Any>> = entries.iterator()
|
override fun iterator(): Iterator<Entry<*>> = entries.iterator()
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
if (other === this) return true
|
if (other === this) return true
|
||||||
@@ -135,11 +135,11 @@ internal object EmptyExtras : AbstractExtras(), Serializable {
|
|||||||
|
|
||||||
override fun isEmpty(): Boolean = true
|
override fun isEmpty(): Boolean = true
|
||||||
|
|
||||||
override fun <T : Any> get(key: Key<T>): T? = null
|
override fun <T> get(key: Key<T>): T? = null
|
||||||
|
|
||||||
override fun contains(key: Key<*>): Boolean = false
|
override fun contains(key: Key<*>): Boolean = false
|
||||||
|
|
||||||
override fun contains(element: Entry<out Any>): Boolean = false
|
override fun contains(element: Entry<*>): Boolean = false
|
||||||
|
|
||||||
@Suppress("unused") // Necessary for java.io.Serializable stability
|
@Suppress("unused") // Necessary for java.io.Serializable stability
|
||||||
private const val serialVersionUID = 0L
|
private const val serialVersionUID = 0L
|
||||||
|
|||||||
+6
-6
@@ -11,19 +11,19 @@ import kotlin.properties.ReadOnlyProperty
|
|||||||
import kotlin.properties.ReadWriteProperty
|
import kotlin.properties.ReadWriteProperty
|
||||||
import kotlin.reflect.KProperty
|
import kotlin.reflect.KProperty
|
||||||
|
|
||||||
interface ExtrasProperty<T : Any> {
|
interface ExtrasProperty<T> {
|
||||||
val key: Extras.Key<T>
|
val key: Extras.Key<T>
|
||||||
}
|
}
|
||||||
|
|
||||||
val <T : Any> Extras.Key<T>.readWriteProperty get() = extrasReadWriteProperty(this)
|
val <T : Any> Extras.Key<T>.readWriteProperty get() = extrasReadWriteProperty(this)
|
||||||
|
|
||||||
fun <Receiver : HasMutableExtras, T : Any> Extras.Key<T>.lazyProperty(factory: Receiver.() -> T) = extrasLazyProperty(this, factory)
|
fun <Receiver : HasMutableExtras, T> Extras.Key<T>.lazyProperty(factory: Receiver.() -> T) = extrasLazyProperty(this, factory)
|
||||||
|
|
||||||
fun <T : Any> extrasReadWriteProperty(key: Extras.Key<T>): ExtrasReadWriteProperty<T> = object : ExtrasReadWriteProperty<T> {
|
fun <T : Any> extrasReadWriteProperty(key: Extras.Key<T>): ExtrasReadWriteProperty<T> = object : ExtrasReadWriteProperty<T> {
|
||||||
override val key: Extras.Key<T> = key
|
override val key: Extras.Key<T> = key
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <Receiver : HasMutableExtras, T : Any> extrasLazyProperty(
|
fun <Receiver : HasMutableExtras, T> extrasLazyProperty(
|
||||||
key: Extras.Key<T>, factory: Receiver.() -> T,
|
key: Extras.Key<T>, factory: Receiver.() -> T,
|
||||||
): ExtrasLazyProperty<Receiver, T> =
|
): ExtrasLazyProperty<Receiver, T> =
|
||||||
object : ExtrasLazyProperty<Receiver, T> {
|
object : ExtrasLazyProperty<Receiver, T> {
|
||||||
@@ -36,7 +36,7 @@ inline fun <reified T : Any> extrasReadWriteProperty(name: String? = null) =
|
|||||||
extrasReadWriteProperty(extrasKeyOf<T>(name))
|
extrasReadWriteProperty(extrasKeyOf<T>(name))
|
||||||
|
|
||||||
|
|
||||||
inline fun <Receiver : HasMutableExtras, reified T : Any> extrasLazyProperty(name: String? = null, noinline factory: Receiver.() -> T) =
|
inline fun <Receiver : HasMutableExtras, reified T> extrasLazyProperty(name: String? = null, noinline factory: Receiver.() -> T) =
|
||||||
extrasLazyProperty(extrasKeyOf(name), factory)
|
extrasLazyProperty(extrasKeyOf(name), factory)
|
||||||
|
|
||||||
|
|
||||||
@@ -76,11 +76,11 @@ interface NotNullExtrasReadWriteProperty<T : Any> : ExtrasProperty<T>, ReadWrite
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ExtrasLazyProperty<Receiver : HasMutableExtras, T : Any> : ExtrasProperty<T>, ReadWriteProperty<Receiver, T> {
|
interface ExtrasLazyProperty<Receiver : HasMutableExtras, T> : ExtrasProperty<T>, ReadWriteProperty<Receiver, T> {
|
||||||
val factory: Receiver.() -> T
|
val factory: Receiver.() -> T
|
||||||
|
|
||||||
override fun getValue(thisRef: Receiver, property: KProperty<*>): T {
|
override fun getValue(thisRef: Receiver, property: KProperty<*>): T {
|
||||||
return thisRef.extras.getOrPut(key) { thisRef.factory() }
|
return thisRef.extras.getOrPutNullable(key) { thisRef.factory() }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setValue(thisRef: Receiver, property: KProperty<*>, value: T) {
|
override fun setValue(thisRef: Receiver, property: KProperty<*>, value: T) {
|
||||||
|
|||||||
+10
-3
@@ -26,7 +26,7 @@ import kotlin.reflect.typeOf
|
|||||||
* extrasKeyOf<String>("a") != extrasKeyOf<Int>("a")
|
* extrasKeyOf<String>("a") != extrasKeyOf<Int>("a")
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
inline fun <reified T : Any> extrasKeyOf(name: String? = null): Extras.Key<T> =
|
inline fun <reified T> extrasKeyOf(name: String? = null): Extras.Key<T> =
|
||||||
Extras.Key(extrasTypeOf(), name)
|
Extras.Key(extrasTypeOf(), name)
|
||||||
|
|
||||||
fun emptyExtras(): Extras = EmptyExtras
|
fun emptyExtras(): Extras = EmptyExtras
|
||||||
@@ -48,7 +48,7 @@ fun Iterable<Extras.Entry<*>>.toExtras(): Extras = ImmutableExtrasImpl(this)
|
|||||||
|
|
||||||
fun Iterable<Extras.Entry<*>>.toMutableExtras(): MutableExtras = MutableExtrasImpl(this)
|
fun Iterable<Extras.Entry<*>>.toMutableExtras(): MutableExtras = MutableExtrasImpl(this)
|
||||||
|
|
||||||
infix fun <T : Any> Extras.Key<T>.withValue(value: T): Extras.Entry<T> = Extras.Entry(this, value)
|
infix fun <T> Extras.Key<T>.withValue(value: T): Extras.Entry<T> = Extras.Entry(this, value)
|
||||||
|
|
||||||
operator fun Extras.plus(entry: Extras.Entry<*>): Extras = ImmutableExtrasImpl(this.entries + entry)
|
operator fun Extras.plus(entry: Extras.Entry<*>): Extras = ImmutableExtrasImpl(this.entries + entry)
|
||||||
|
|
||||||
@@ -56,4 +56,11 @@ operator fun Extras.plus(entries: Iterable<Extras.Entry<*>>): Extras = Immutable
|
|||||||
|
|
||||||
inline fun <T : Any> MutableExtras.getOrPut(key: Extras.Key<T>, defaultValue: () -> T): T {
|
inline fun <T : Any> MutableExtras.getOrPut(key: Extras.Key<T>, defaultValue: () -> T): T {
|
||||||
return this[key] ?: defaultValue().also { this[key] = it }
|
return this[key] ?: defaultValue().also { this[key] = it }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline fun <T> MutableExtras.getOrPutNullable(key: Extras.Key<T>, defaultValue: () -> T): T {
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
if (key in this) return this[key] as T
|
||||||
|
return defaultValue().also { this[key] = it }
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
+37
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.tooling.core
|
package org.jetbrains.kotlin.tooling.core
|
||||||
|
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger
|
||||||
import kotlin.test.*
|
import kotlin.test.*
|
||||||
|
|
||||||
@Suppress("DEPRECATION")
|
@Suppress("DEPRECATION")
|
||||||
@@ -18,6 +19,7 @@ class ExtrasPropertyTest {
|
|||||||
|
|
||||||
private val keyA = extrasKeyOf<Int>("a")
|
private val keyA = extrasKeyOf<Int>("a")
|
||||||
private val keyB = extrasKeyOf<Int>("b")
|
private val keyB = extrasKeyOf<Int>("b")
|
||||||
|
private val keyANullable = extrasKeyOf<Int?>("a")
|
||||||
|
|
||||||
private val Subject.readA: Int? by keyA.readProperty
|
private val Subject.readA: Int? by keyA.readProperty
|
||||||
private val Subject.readB: Int? by keyB.readProperty
|
private val Subject.readB: Int? by keyB.readProperty
|
||||||
@@ -171,4 +173,39 @@ class ExtrasPropertyTest {
|
|||||||
assertEquals("OK", subject2.lazyNullableString)
|
assertEquals("OK", subject2.lazyNullableString)
|
||||||
assertEquals(listOf(subject1, subject2), lazyNullableStringInvocations)
|
assertEquals(listOf(subject1, subject2), lazyNullableStringInvocations)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `test - lazyProperty - with nullable key`() {
|
||||||
|
val subject = Subject()
|
||||||
|
val invocationCounter = AtomicInteger(0)
|
||||||
|
|
||||||
|
with(object {
|
||||||
|
val Subject.lazyProperty by keyANullable.lazyProperty {
|
||||||
|
assertEquals(0, invocationCounter.getAndIncrement())
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}) {
|
||||||
|
assertNull(subject.lazyProperty)
|
||||||
|
assertNull(subject.lazyProperty)
|
||||||
|
assertEquals(1, invocationCounter.get())
|
||||||
|
|
||||||
|
invocationCounter.set(0)
|
||||||
|
assertEquals(null, Subject().lazyProperty)
|
||||||
|
assertEquals(1, invocationCounter.get())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `test - lazyProperty - with nullable key - set key to null manually`() {
|
||||||
|
with(object {
|
||||||
|
val Subject.lazyProperty by keyANullable.lazyProperty {
|
||||||
|
fail("Unexpected call to factory function")
|
||||||
|
}
|
||||||
|
}) {
|
||||||
|
val subject = Subject()
|
||||||
|
subject.extras[keyANullable] = null
|
||||||
|
assertNull(subject.lazyProperty)
|
||||||
|
assertTrue(keyANullable in subject.extras)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+52
-10
@@ -24,22 +24,22 @@ class ExtrasTest {
|
|||||||
assertNull(extras[extrasKeyOf<String>("a")])
|
assertNull(extras[extrasKeyOf<String>("a")])
|
||||||
assertNull(extras[extrasKeyOf<String>("b")])
|
assertNull(extras[extrasKeyOf<String>("b")])
|
||||||
|
|
||||||
extras[extrasKeyOf()] = "22222"
|
extras[extrasKeyOf<String>()] = "22222"
|
||||||
assertEquals("22222", extras[extrasKeyOf()])
|
assertEquals("22222", extras[extrasKeyOf<String>()])
|
||||||
assertNull(extras[extrasKeyOf("a")])
|
assertNull(extras[extrasKeyOf<String>("a")])
|
||||||
assertNull(extras[extrasKeyOf("b")])
|
assertNull(extras[extrasKeyOf<String>("b")])
|
||||||
|
|
||||||
extras[extrasKeyOf("a")] = "value a"
|
extras[extrasKeyOf("a")] = "value a"
|
||||||
assertEquals("22222", extras[extrasKeyOf()])
|
assertEquals("22222", extras[extrasKeyOf<String>()])
|
||||||
assertEquals("value a", extras[extrasKeyOf("a")])
|
assertEquals("value a", extras[extrasKeyOf<String>("a")])
|
||||||
assertNull(extras[extrasKeyOf("b")])
|
assertNull(extras[extrasKeyOf("b")])
|
||||||
|
|
||||||
extras[extrasKeyOf("b")] = "value b"
|
extras[extrasKeyOf("b")] = "value b"
|
||||||
assertEquals("22222", extras[extrasKeyOf()])
|
assertEquals("22222", extras[extrasKeyOf<String>()])
|
||||||
assertEquals("value a", extras[extrasKeyOf("a")])
|
assertEquals("value a", extras[extrasKeyOf<String>("a")])
|
||||||
assertEquals("value b", extras[extrasKeyOf("b")])
|
assertEquals("value b", extras[extrasKeyOf<String>("b")])
|
||||||
|
|
||||||
assertNull(extras[extrasKeyOf("c")])
|
assertNull(extras[extrasKeyOf<String>("c")])
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -286,4 +286,46 @@ class ExtrasTest {
|
|||||||
extras
|
extras
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `test - extras - nullable key`() {
|
||||||
|
val empty = extrasOf()
|
||||||
|
assertNull(empty[extrasKeyOf<String>()])
|
||||||
|
assertNull(empty[extrasKeyOf<String?>()])
|
||||||
|
|
||||||
|
val nonEmpty = extrasOf(
|
||||||
|
extrasKeyOf<String>() withValue "!",
|
||||||
|
extrasKeyOf<String?>() withValue "?"
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals("!", nonEmpty[extrasKeyOf<String>()])
|
||||||
|
assertEquals("?", nonEmpty[extrasKeyOf<String?>()])
|
||||||
|
|
||||||
|
val containsNull = extrasOf(
|
||||||
|
extrasKeyOf<String>() withValue "!",
|
||||||
|
extrasKeyOf<String?>() withValue null
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals("!", containsNull[extrasKeyOf<String>()])
|
||||||
|
assertNull(containsNull[extrasKeyOf<String?>()])
|
||||||
|
assertTrue(extrasKeyOf<String?>() in containsNull)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `test - mutable extras - nullable key`() {
|
||||||
|
val extras = mutableExtrasOf()
|
||||||
|
assertNull(extras[extrasKeyOf<String>()])
|
||||||
|
assertNull(extras[extrasKeyOf<String?>()])
|
||||||
|
|
||||||
|
extras[extrasKeyOf<String>()] = "!"
|
||||||
|
extras[extrasKeyOf<String?>()] = "?"
|
||||||
|
|
||||||
|
assertEquals("!", extras[extrasKeyOf<String>()])
|
||||||
|
assertEquals("?", extras[extrasKeyOf<String?>()])
|
||||||
|
|
||||||
|
extras[extrasKeyOf<String?>()] = null
|
||||||
|
assertEquals("!", extras[extrasKeyOf<String>()])
|
||||||
|
assertNull(extras[extrasKeyOf<String?>()])
|
||||||
|
assertTrue(extrasKeyOf<String?>() in extras)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user