diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinGradlePluginExtensionPointInternal.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinGradlePluginExtensionPointInternal.kt index 06a9c16209e..de856f10467 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinGradlePluginExtensionPointInternal.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinGradlePluginExtensionPointInternal.kt @@ -6,7 +6,7 @@ package org.jetbrains.kotlin.gradle.plugin import org.gradle.api.Project -import org.jetbrains.kotlin.gradle.utils.storedProjectProperty +import org.jetbrains.kotlin.gradle.utils.projectStoredProperty import org.jetbrains.kotlin.tooling.core.UnsafeApi /** @@ -25,7 +25,7 @@ internal fun KotlinGradlePluginExtensionPoint(): KotlinGradlePluginExtension @UnsafeApi("Visible for tests only") internal class KotlinGradlePluginExtensionPointInternal : KotlinGradlePluginExtensionPoint { - private val Project.registeredExtensions by storedProjectProperty> { mutableListOf() } + private val Project.registeredExtensions by projectStoredProperty> { mutableListOf() } override fun get(project: Project): List { return project.registeredExtensions.toList() diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/resolvableMetadataConfiguration.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/resolvableMetadataConfiguration.kt index 683a7fbca92..308696b4cca 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/resolvableMetadataConfiguration.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/resolvableMetadataConfiguration.kt @@ -35,7 +35,7 @@ internal val InternalKotlinSourceSet.resolvableMetadataConfigurationName: String * These dependencies are set up to resolve Kotlin Metadata (without transformation) and will resolve * consistently across the whole project. */ -internal val InternalKotlinSourceSet.resolvableMetadataConfiguration: Configuration by storedExtrasProperty { +internal val InternalKotlinSourceSet.resolvableMetadataConfiguration: Configuration by extrasStoredProperty { assert(resolvableMetadataConfigurationName !in project.configurations.names) val configuration = project.configurations.maybeCreate(resolvableMetadataConfigurationName) configuration.markResolvable() diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/utils/storedProperty.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/utils/storedProperty.kt index 75d61c81e21..0ddfbfbb504 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/utils/storedProperty.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/utils/storedProperty.kt @@ -12,7 +12,6 @@ import org.jetbrains.kotlin.tooling.core.extrasKeyOf import org.jetbrains.kotlin.tooling.core.getOrPut import java.util.* import kotlin.properties.ReadOnlyProperty -import kotlin.properties.ReadWriteProperty import kotlin.reflect.KProperty /** @@ -21,7 +20,7 @@ import kotlin.reflect.KProperty * ```kotlin * class Foo(val projectName: String) * - * val Project.myFoo by storedProjectProperty { + * val Project.myFoo by projectStoredProperty { * Foo(project.name) * } * ``` @@ -52,15 +51,15 @@ import kotlin.reflect.KProperty * *not* the type, or any String based key * */ -internal fun storedProjectProperty(initializer: Project.() -> T): ReadOnlyProperty = StoredLazyProperty( +internal fun projectStoredProperty(initializer: Project.() -> T): ReadOnlyProperty = StoredLazyProperty( storage = { storedPropertyStorage }, initializer = initializer ) /** - * Same as [storedProjectProperty], but will allow storing the property on any object implementing [HasMutableExtras] + * Same as [projectStoredProperty], but will allow storing the property on any object implementing [HasMutableExtras] */ -internal fun storedExtrasProperty(initializer: R.() -> T): ReadOnlyProperty = StoredLazyProperty( +internal fun extrasStoredProperty(initializer: R.() -> T): ReadOnlyProperty = StoredLazyProperty( storage = { storedPropertyStorage }, initializer = initializer ) @@ -105,7 +104,8 @@ private class StoredPropertyStorage { private val values = WeakHashMap, Any?>() fun getOrPut(key: StoredLazyProperty<*, T>, create: () -> T): T { @Suppress("UNCHECKED_CAST") - return values.getOrPut(key) { create() } as T + return if (key in values) values[key] as T + else values.getOrPut(key, create) as T } @Suppress("UNCHECKED_CAST") diff --git a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/StoredPropertyTest.kt b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/StoredPropertyTest.kt index d3c8313a056..6b8128f03f1 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/StoredPropertyTest.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/StoredPropertyTest.kt @@ -9,34 +9,43 @@ package org.jetbrains.kotlin.gradle.unitTests import org.gradle.api.Project import org.jetbrains.kotlin.gradle.util.buildProject -import org.jetbrains.kotlin.gradle.utils.storedExtrasProperty -import org.jetbrains.kotlin.gradle.utils.storedProjectProperty +import org.jetbrains.kotlin.gradle.utils.extrasStoredProperty +import org.jetbrains.kotlin.gradle.utils.projectStoredProperty import org.jetbrains.kotlin.tooling.core.HasMutableExtras import org.jetbrains.kotlin.tooling.core.MutableExtras import org.jetbrains.kotlin.tooling.core.mutableExtrasOf import java.util.concurrent.atomic.AtomicInteger import kotlin.test.Test import kotlin.test.assertEquals +import kotlin.test.assertNull import kotlin.test.assertSame class StoredPropertyTest { private data class Value(val id: Any) - private val Project.projectNameProperty by storedProjectProperty { Value(project.name) } + private val Project.projectNameProperty by projectStoredProperty { Value(project.name) } private val atomic = AtomicInteger(0) - private val Project.counterProperty by storedProjectProperty { Value(atomic.getAndIncrement()) } + private val Project.counterProperty by projectStoredProperty { Value(atomic.getAndIncrement()) } + + private var myState: Any? = null + private val Project.myStateCapturingProperty by projectStoredProperty { myState } private class Scope(val id: Any) { - val Project.myProperty by storedProjectProperty { Value(id) } + val Project.myProperty by projectStoredProperty { Value(id) } } private class TestEntity(val id: Any) : HasMutableExtras { override val extras: MutableExtras = mutableExtrasOf() } - private val TestEntity.myProperty by storedExtrasProperty { Value(id) } + private val TestEntity.myProperty by extrasStoredProperty { Value(id) } + + + private val TestEntity.myStateCaptureProperty: Any? by extrasStoredProperty { + myState + } @Test fun `test - projectNameProperty`() { @@ -86,4 +95,29 @@ class StoredPropertyTest { assertSame(entityA.myProperty, entityA.myProperty) assertSame(entityB.myProperty, entityB.myProperty) } + + @Test + fun `test - nullable extras property`() { + val entity = TestEntity("a") + myState = null + assertNull(entity.myStateCaptureProperty) + + myState = "Should not be captured anymore" + assertNull(entity.myStateCaptureProperty) + + val anotherEntity = TestEntity("b") + myState = "foo" + assertEquals("foo", anotherEntity.myStateCaptureProperty) + } + + @Test + fun `test - nullable project property`() { + val project = buildProject() + assertNull(project.myStateCapturingProperty) + + myState = "foo" + assertNull(project.myStateCapturingProperty) + + assertEquals("foo", buildProject().myStateCapturingProperty) + } }