Repository: JetBrains/kotlin
File: plugins/atomicfu/atomicfu-compiler/src/org.jetbrains.kotlinx.atomicfu.compiler/extensions/AtomicfuTransformer.kt (Kotlin)

Code before:
            }
            return null
        }
    }

    private inner class AtomicTransformer : IrElementTransformer<IrFunction?> {

        override fun visitProperty(declaration: IrProperty, data: IrFunction?): IrStatement {
            // Support transformation for delegated properties:
            if (declaration.isDelegated && declaration.backingField?.type?.isAtomicValueType() == true) {
                declaration.backingField?.let { delegateBackingField ->
                    delegateBackingField.initializer?.let {
                        val initializer = it.expression as IrCall
                        when {
                            initializer.isAtomicFieldGetter() -> {
                                // val _a = atomic(0)
                                // var a: Int by _a
                                // Accessors of the delegated property `a` are implemented via the generated property `a$delegate`,
                                // that is the copy of the original `_a`.
                                // They should be delegated to the value of the original field `_a` instead of `a$delegate`.

                                // fun <get-a>() = a$delegate.value -> _a.value
                                // fun <set-a>(value: Int) = { a$delegate.value = value } -> { _a.value = value }
                                val initializerName = initializer.symbol.owner.name.asString()
                                val originalFieldName = initializerName.getFieldName()
                                val originalProperty = (declaration.parent as IrDeclarationContainer).declarations.single {
                                    it is IrProperty && it.name.asString() == originalFieldName &&
                                            it.backingField != null && it.backingField!!.type == delegateBackingField.type
                                }
                                declaration.transform(DelegatePropertyTransformer((originalProperty as IrProperty).backingField!!), null)
                            }
                            initializer.isAtomicFactory() -> {
                                // var a by atomic(77) -> var a: Int = 77
                                it.expression = initializer.eraseAtomicFactory()
                                    ?: error("Atomic factory was expected but found ${initializer.render()}")
                                declaration.transform(DelegatePropertyTransformer(delegateBackingField), null)
                            }
                            else -> error("Unexpected initializer of the delegated property: $initializer")
                        }
                    }
                }
            }
            return super.visitProperty(declaration, data)
        }

        override fun visitFunction(declaration: IrFunction, data: IrFunction?): IrStatement {
            return super.visitFunction(declaration, declaration)
        }

        override fun visitBlockBody(body: IrBlockBody, data: IrFunction?): IrBody {
            // Erase messages added by the Trace object from the function body:

Review comment (suggestion):
What if
```kotlin
val a = atomic(42)
class B {
  val b: Int by a
}
```

Code after:
            }
            return null
        }
    }

    private inner class AtomicTransformer : IrElementTransformer<IrFunction?> {

        override fun visitProperty(declaration: IrProperty, data: IrFunction?): IrStatement {
            // Support transformation for delegated properties:
            if (declaration.isDelegated && declaration.backingField?.type?.isAtomicValueType() == true) {
                declaration.backingField?.let { delegateBackingField ->
                    delegateBackingField.initializer?.let {
                        val initializer = it.expression as IrCall
                        when {
                            initializer.isAtomicFieldGetter() -> {
                                // val _a = atomic(0)
                                // var a: Int by _a
                                // Accessors of the delegated property `a` are implemented via the generated property `a$delegate`,
                                // that is the copy of the original `_a`.
                                // They should be delegated to the value of the original field `_a` instead of `a$delegate`.

                                // fun <get-a>() = a$delegate.value -> _a.value
                                // fun <set-a>(value: Int) = { a$delegate.value = value } -> { _a.value = value }
                                val originalField = initializer.getBackingField()
                                declaration.transform(DelegatePropertyTransformer(originalField, initializer.dispatchReceiver, false), null)
                            }
                            initializer.isAtomicFactory() -> {
                                // var a by atomic(77) -> var a: Int = 77
                                it.expression = initializer.eraseAtomicFactory()
                                    ?: error("Atomic factory was expected but found ${initializer.render()}")
                                declaration.transform(DelegatePropertyTransformer(delegateBackingField, initializer.dispatchReceiver, true), null)
                            }
                            else -> error("Unexpected initializer of the delegated property: $initializer")
                        }
                    }
                }
            }
            return super.visitProperty(declaration, data)
        }

        override fun visitFunction(declaration: IrFunction, data: IrFunction?): IrStatement {
            return super.visitFunction(declaration, declaration)
        }

        override fun visitBlockBody(body: IrBlockBody, data: IrFunction?): IrBody {
            // Erase messages added by the Trace object from the function body:
            // val trace = Trace(size)
            // Messages may be added via trace invocation:
            // trace { "Doing something" }
            // or via multi-append of arguments:
            // trace.append(index, "CAS", value)