Skip to content

Commit

Permalink
[atomicfu] Added a check that atomic properties are declared as final…
Browse files Browse the repository at this point in the history
… values.

Fixes: Kotlin/kotlinx-atomicfu#237

YT: KT-61550


Merge-request: KT-MR-11887
Merged-by: Maria Sokolova <maria.sokolova@jetbrains.com>
  • Loading branch information
mvicsokolova authored and Space Team committed Aug 30, 2023
1 parent 2dced30 commit bde094a
Showing 1 changed file with 18 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -156,18 +156,19 @@ abstract class AbstractAtomicfuTransformer(val pluginContext: IrPluginContext) {
val isTopLevel = parentContainer is IrFile || (parentContainer is IrClass && parentContainer.kind == ClassKind.OBJECT)
when {
atomicProperty.isAtomic() -> {
atomicProperty.checkIsFinal(isArray = false)
atomicProperty.checkVisibility(isArray = false)
if (isTopLevel) {
atomicProperty.checkVisibility()
parentContainer.addTransformedStaticAtomic(atomicProperty, index)
} else {
atomicProperty.checkVisibility()
(parentContainer as IrClass).addTransformedInClassAtomic(atomicProperty, index)
}.also {
declarationsToBeRemoved.add(atomicProperty)
}
}
atomicProperty.isAtomicArray() -> {
atomicProperty.checkVisibility()
atomicProperty.checkIsFinal(isArray = true)
atomicProperty.checkVisibility(isArray = true)
parentContainer.addTransformedAtomicArray(atomicProperty, index).also {
declarationsToBeRemoved.add(atomicProperty)
}
Expand Down Expand Up @@ -448,18 +449,28 @@ abstract class AbstractAtomicfuTransformer(val pluginContext: IrPluginContext) {
)
}

private fun IrProperty.checkVisibility() =
private fun IrProperty.checkIsFinal(isArray: Boolean) =
check(!isVar) {
"Please consider declaring [${this.atomicfuRender()}] from [${this.parent.render()}] as a private val or internal val.\n" +
if (!isArray) "If you need to declare a variable with accessors delegated to the atomic property value, you can use a delegated property declared within the same scope, e.g:\n" +
"```\n" +
"private val _a = atomic<T>(initial) \n" +
"public var a: T by _a \n" +
"```\n" else ""
}

private fun IrProperty.checkVisibility(isArray: Boolean) =
check((visibility == DescriptorVisibilities.PRIVATE || visibility == DescriptorVisibilities.INTERNAL) ||
(parent is IrClass &&
(parentAsClass.visibility == DescriptorVisibilities.PRIVATE || parentAsClass.visibility == DescriptorVisibilities.INTERNAL))) {
"To ensure that atomic properties are not accessed out of the current Kotlin module, it is necessary to declare atomic properties as private or internal.\n" +
"Please consider declaring [${this.atomicfuRender()}] from [${this.parent.render()}] as a private or internal property.\n" +
(if (parent is IrClass) "You may also make the containing class [${parentAsClass.render()}] private or internal.\n" else "") +
"Alternatively, if you need to expose the atomic property value to the public, you can use a delegated property declared within the same scope, e.g:\n" +
if (!isArray) "Alternatively, if you need to expose the atomic property value to the public, you can use a delegated property declared within the same scope, e.g:\n" +
"```\n" +
"private val _a = atomic<T>(initial) \n" +
"public var a: T by _a \n" +
"```\n"
"```\n" else ""
}

protected fun IrProperty.getMinVisibility(): DescriptorVisibility {
Expand Down Expand Up @@ -1141,5 +1152,5 @@ abstract class AbstractAtomicfuTransformer(val pluginContext: IrPluginContext) {
protected fun IrType.isObject() = classOrNull?.owner?.kind == ClassKind.OBJECT

protected fun IrProperty.atomicfuRender(): String =
"val " + name.asString() + ": " + backingField?.type?.render()
(if (isVar) "var" else "val") + " " + name.asString() + ": " + backingField?.type?.render()
}

0 comments on commit bde094a

Please sign in to comment.