Coverage Summary for Class: IrNewClassUtilKt (com.kotlinorm.compiler.plugin.utils)
Class |
Class, %
|
Method, %
|
Branch, %
|
Line, %
|
Instruction, %
|
IrNewClassUtilKt |
100%
(1/1)
|
100%
(25/25)
|
66.7%
(16/24)
|
98.6%
(139/141)
|
98.3%
(872/887)
|
/**
* Copyright 2022-2025 kronos-orm
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.kotlinorm.compiler.plugin.utils
import com.kotlinorm.compiler.helpers.IrTryBuilder.Companion.irTry
import com.kotlinorm.compiler.helpers.dispatchReceiver
import com.kotlinorm.compiler.helpers.filterByFqName
import com.kotlinorm.compiler.helpers.invoke
import com.kotlinorm.compiler.helpers.irListOf
import com.kotlinorm.compiler.helpers.irMutableMapOf
import com.kotlinorm.compiler.helpers.mapGetterSymbol
import com.kotlinorm.compiler.helpers.referenceClass
import com.kotlinorm.compiler.helpers.referenceFunctions
import com.kotlinorm.compiler.helpers.toKClass
import com.kotlinorm.compiler.helpers.valueArguments
import com.kotlinorm.compiler.helpers.valueParameters
import com.kotlinorm.compiler.plugin.utils.kTableForCondition.ignore
import com.kotlinorm.compiler.plugin.utils.kTableForCondition.ignoreAnnotationValue
import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
import org.jetbrains.kotlin.ir.builders.IrBuilderWithScope
import org.jetbrains.kotlin.ir.builders.irBlock
import org.jetbrains.kotlin.ir.builders.irBlockBody
import org.jetbrains.kotlin.ir.builders.irBoolean
import org.jetbrains.kotlin.ir.builders.irBranch
import org.jetbrains.kotlin.ir.builders.irElseBranch
import org.jetbrains.kotlin.ir.builders.irEquals
import org.jetbrains.kotlin.ir.builders.irGet
import org.jetbrains.kotlin.ir.builders.irGetField
import org.jetbrains.kotlin.ir.builders.irNull
import org.jetbrains.kotlin.ir.builders.irReturn
import org.jetbrains.kotlin.ir.builders.irSetField
import org.jetbrains.kotlin.ir.builders.irString
import org.jetbrains.kotlin.ir.builders.irWhen
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.IrProperty
import org.jetbrains.kotlin.ir.expressions.IrBlockBody
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.symbols.UnsafeDuringIrConstructionAPI
import org.jetbrains.kotlin.ir.types.classOrFail
import org.jetbrains.kotlin.ir.types.defaultType
import org.jetbrains.kotlin.ir.types.getClass
import org.jetbrains.kotlin.ir.util.constructors
import org.jetbrains.kotlin.ir.util.defaultType
import org.jetbrains.kotlin.ir.util.hasAnnotation
import org.jetbrains.kotlin.ir.util.isGetter
import org.jetbrains.kotlin.ir.util.isSetter
import org.jetbrains.kotlin.ir.util.kotlinFqName
import org.jetbrains.kotlin.ir.util.properties
import org.jetbrains.kotlin.name.FqName
import kotlin.contracts.ExperimentalContracts
context(_: IrPluginContext)
val KronosSymbol
get() = referenceClass("com.kotlinorm.Kronos")!!
context(_: IrPluginContext)
private val getSafeValueSymbol
get() = referenceFunctions("com.kotlinorm.utils", "getSafeValue").first()
context(_: IrPluginContext)
private val KTableIndexSymbol
get() = referenceClass("com.kotlinorm.beans.dsl.KTableIndex")!!
context(_: IrPluginContext)
val KPojoFqName
get() = FqName("com.kotlinorm.interfaces.KPojo")
context(_: IrPluginContext)
val KPojoSymbol
get() = referenceClass("com.kotlinorm.interfaces.KPojo")!!
@OptIn(UnsafeDuringIrConstructionAPI::class)
context(context: IrPluginContext, builder: IrBuilderWithScope)
fun createPropertyGetter(
declaration: IrClass,
irFunction: IrFunction
): IrBlockBody {
val dispatcher = builder.irGet(irFunction.dispatchReceiverParameter!!)
return builder.irBlockBody {
+irReturn(
irWhen(
context.irBuiltIns.anyNType,
declaration.properties.map {
irBranch(
irEquals(
irString(it.name.asString()),
irGet(irFunction.parameters.valueParameters[0])
),
dispatcher.getValue(it)
)
}.toList() + irElseBranch(
irNull()
)
)
)
}
}
@OptIn(UnsafeDuringIrConstructionAPI::class)
context(context: IrPluginContext, builder: IrBuilderWithScope)
fun createPropertySetter(
declaration: IrClass,
irFunction: IrFunction
): IrBlockBody {
val dispatcher = builder.irGet(irFunction.dispatchReceiverParameter!!)
return builder.irBlockBody {
+irWhen(
context.irBuiltIns.unitType,
declaration.properties.map {
irBranch(
irEquals(
irString(it.name.asString()),
irGet(irFunction.parameters.valueParameters[0])
),
irBlock {
+(dispatcher.setValue(
it,
irGet(irFunction.parameters.valueParameters[1])
) ?: irNull())
}
)
}.toList() + irElseBranch(
irNull()
)
)
}
}
/**
* Creates a new IrBlockBody that represents a function that returns the KClass of the given
*
* @param declaration The IrClass to be converted to a KClass.
* @return the `IrBlockBody` that represents the function.
*/
@OptIn(UnsafeDuringIrConstructionAPI::class)
context(_: IrPluginContext, builder: IrBuilderWithScope)
fun createKClassFunction(
declaration: IrClass
) = builder.irBlockBody { +irReturn(declaration.symbol.toKClass()) }
/**
* Creates a new IrBlockBody that represents a function that converts an instance of an IrClass
* to a mutable map. The function takes in an IrClass and an IrFunction as parameters.
*
* @param declaration The IrClass to be converted to a map.
* @param irFunction The IrFunction that contains the instance of the IrClass.
* @return the `IrBlockBody` that represents the function.
*/
@OptIn(UnsafeDuringIrConstructionAPI::class)
context(context: IrPluginContext, builder: IrBuilderWithScope)
fun createToMapFunction(
declaration: IrClass,
irFunction: IrFunction
) = builder.irBlockBody {
val dispatcher = irGet(irFunction.dispatchReceiverParameter!!)
+irReturn(
irMutableMapOf(
context.irBuiltIns.stringType,
context.irBuiltIns.anyNType,
declaration.properties.filter {
return@filter !it.ignoreAnnotationValue().ignore("to_map") && !it.isSetter
}.associate {
irString(it.name.asString()) to dispatcher.getValue(it)
}
)
)
}
/**
* Creates an IrBlockBody that sets the properties of an IrClass instance using values from a map.
*
* @param declaration the IrClass instance whose properties will be set
* @param irFunction the IrFunction that contains the map parameter
* @return an `IrBlockBody` that sets the properties of the IrClass instance using values from the map
*/
@OptIn(UnsafeDuringIrConstructionAPI::class)
context(_: IrPluginContext, builder: IrBuilderWithScope)
fun createFromMapValueFunction(declaration: IrClass, irFunction: IrFunction): IrBlockBody {
val map = irFunction.parameters.valueParameters.first()
return builder.irBlockBody {
val dispatcher = irGet(irFunction.dispatchReceiverParameter!!)
+declaration.properties.toList().mapNotNull { property ->
if (property.isDelegated || property.isGetter ||
property.ignoreAnnotationValue().ignore("from_map")
) {
return@mapNotNull null
}
dispatcher.setValue(
property, mapGetterSymbol(
irGet(map),
irString(property.name.asString())
)
)
}
+irReturn(
irGet(irFunction.dispatchReceiverParameter!!)
)
}
}
/**
* Creates a safe from map value function.
*
* @param declaration The IrClass declaration.
* @param irFunction The IrFunction to create the safe from map value function for.
* @return an `IrBlockBody` containing the generated code.
*/
@OptIn(UnsafeDuringIrConstructionAPI::class, ExperimentalContracts::class)
context(context: IrPluginContext, builder: IrBuilderWithScope)
fun createSafeFromMapValueFunction(declaration: IrClass, irFunction: IrFunction): IrBlockBody {
val map = irFunction.parameters.valueParameters.first()
return builder.irBlockBody {
val dispatcher = irGet(irFunction.parameters.dispatchReceiver!!)
+irBlock {
declaration.properties.toList().mapNotNull { property ->
if (property.isDelegated || property.isGetter ||
property.ignoreAnnotationValue().ignore("from_map")
) {
return@mapNotNull null
}
dispatcher.setValue(
property, getSafeValueSymbol(
irGet(irFunction.parameters.dispatchReceiver!!),
property.backingField!!.type.classOrFail.toKClass(),
irListOf(
context.irBuiltIns.stringType,
property.backingField!!.type.getClass()!!.superTypes.map { type ->
irString(type.getClass()!!.kotlinFqName.asString())
}
),
irGet(map),
irString(property.name.asString()),
irBoolean(property.hasAnnotation(SerializeAnnotationsFqName))
)
)?.let {
+irTry(it, context.irBuiltIns.unitType).catch().build()
}
}
}
+irReturn(dispatcher)
}
}
/**
* Creates an IrBlockBody that contains an IrReturn statement with the result of calling the
* getTableName function with the given IrClass declaration as an argument.
*
* @param declaration the IrClass declaration to generate the table name for
* @return an `IrBlockBody` containing an IrReturn statement with the generated table name
*/
context(_: IrPluginContext, builder: IrBuilderWithScope)
fun createKronosTableName(declaration: IrClass) = builder.irBlockBody {
+irReturn(
getTableName(declaration)
)
}
context(_: IrPluginContext, builder: IrBuilderWithScope)
fun createKronosComment(declaration: IrClass) = builder.irBlockBody {
+irReturn(
declaration.getKDocString()
)
}
@OptIn(UnsafeDuringIrConstructionAPI::class)
context(_: IrPluginContext, builder: IrBuilderWithScope)
fun createKronosTableIndex(declaration: IrClass) = builder.irBlockBody {
val indexesAnnotations = declaration.annotations.filterByFqName(TableIndexAnnotationsFqName)
+irReturn(
irListOf(
KTableIndexSymbol.defaultType,
indexesAnnotations.map {
KTableIndexSymbol.constructors.first()(
*it.valueArguments.toTypedArray()
)
}
)
)
}
/**
* Creates a safe from map value function for the given declaration and irFunction.
*
* @param declaration The IrClass declaration.
* @return an `IrBlockBody` containing the generated code.
*/
@OptIn(UnsafeDuringIrConstructionAPI::class)
context(_: IrPluginContext, builder: IrBuilderWithScope)
fun createGetFieldsFunction(declaration: IrClass) = builder.irBlockBody {
+irReturn(
irListOf(
fieldSymbol.owner.defaultType,
declaration.properties.map {
getColumnName(it)
}.toList()
)
)
}
/**
* Creates an IrBlockBody that contains an IrReturn statement with the result of calling the
* getValidStrategy function with the given IrClass declaration, globalCreateTimeSymbol, and
* CreateTimeFqName as arguments.
*
* @param declaration The IrClass declaration to generate the IrBlockBody for.
* @return an `IrBlockBody` containing the generated code.
*/
context(_: IrPluginContext, builder: IrBuilderWithScope)
fun createKronosCreateTime(declaration: IrClass) = builder.irBlockBody {
+irReturn(
getValidStrategy(declaration, createTimeStrategySymbol, CreateTimeFqName)
)
}
/**
* Creates an IrBlockBody that contains an IrReturn statement with the result of calling the
* getValidStrategy function with the given IrClass declaration, globalUpdateTimeSymbol, and
* UpdateTimeFqName as arguments.
*
* @param declaration The IrClass declaration to generate the IrBlockBody for.
* @return an `IrBlockBody` containing the generated code.
*/
context(_: IrPluginContext, builder: IrBuilderWithScope)
fun createKronosUpdateTime(declaration: IrClass) = builder.irBlockBody {
+irReturn(
getValidStrategy(declaration, updateTimeStrategySymbol, UpdateTimeFqName)
)
}
/**
* Creates a function that returns a block body containing an irCall to createFieldListSymbol
* with the properties of the given IrClass as arguments.
*
* @param declaration the IrClass whose properties will be used as arguments for createFieldListSymbol
* @return an `IrBlockBody` containing an irCall to createFieldListSymbol
*/
context(_: IrPluginContext, builder: IrBuilderWithScope)
fun createKronosLogicDelete(declaration: IrClass) = builder.irBlockBody {
+irReturn(
getValidStrategy(declaration, logicDeleteStrategySymbol, LogicDeleteFqName)
)
}
context(_: IrPluginContext, builder: IrBuilderWithScope)
fun createKronosOptimisticLock(declaration: IrClass) = builder.irBlockBody {
+irReturn(
getValidStrategy(declaration, optimisticLockStrategySymbol, OptimisticLockFqName)
)
}
context(builder: IrBuilderWithScope)
fun IrExpression.getValue(property: IrProperty): IrExpression {
return if (property.getter != null) {
property.getter!!.symbol(this@getValue)
} else {
builder.irGetField(
this@getValue, property.backingField!!
)
}
}
context(builder: IrBuilderWithScope)
fun IrExpression.setValue(property: IrProperty, value: IrExpression): IrExpression? {
with(builder) {
if (property.isDelegated) return null
return if (property.setter != null) {
property.setter!!.symbol(this@setValue, value)
} else {
irSetField(
this@setValue, property.backingField!!, value
)
}
}
}