From a538d51c8d7e741f7147131d43aee0d857dff1d3 Mon Sep 17 00:00:00 2001 From: stslex Date: Mon, 17 Feb 2025 22:41:29 +0300 Subject: [PATCH 1/4] - add custom actions --- .../com/stslex/compiler_app/MainActivity.kt | 5 +- .../com/stslex/compiler_app/TestLogger.kt | 10 ++++ .../compiler_plugin/DistinctChangeCache.kt | 4 ++ .../compiler_plugin/DistinctChangeConfig.kt | 5 -- .../compiler_plugin/DistinctUntilChangeFun.kt | 9 +++- .../model/DistinctChangeConfig.kt | 8 ++++ .../transformers/IrFunctionTransformer.kt | 8 ++-- .../utils/CompilerExtensions.kt | 21 +++++--- .../compiler_plugin/utils/CompilerLogger.kt | 11 +++++ .../compiler_plugin/utils/DefaultAction.kt | 6 +++ .../utils/ReadQualifierUtil.kt | 48 +++++++++++++++---- 11 files changed, 110 insertions(+), 25 deletions(-) create mode 100644 app/src/main/kotlin/com/stslex/compiler_app/TestLogger.kt delete mode 100644 compiler-plugin/src/main/kotlin/io/github/stslex/compiler_plugin/DistinctChangeConfig.kt create mode 100644 compiler-plugin/src/main/kotlin/io/github/stslex/compiler_plugin/model/DistinctChangeConfig.kt create mode 100644 compiler-plugin/src/main/kotlin/io/github/stslex/compiler_plugin/utils/CompilerLogger.kt create mode 100644 compiler-plugin/src/main/kotlin/io/github/stslex/compiler_plugin/utils/DefaultAction.kt diff --git a/app/src/main/kotlin/com/stslex/compiler_app/MainActivity.kt b/app/src/main/kotlin/com/stslex/compiler_app/MainActivity.kt index aa3359d..bbb1a20 100644 --- a/app/src/main/kotlin/com/stslex/compiler_app/MainActivity.kt +++ b/app/src/main/kotlin/com/stslex/compiler_app/MainActivity.kt @@ -54,13 +54,14 @@ class MainActivity : ComponentActivity() { printUsernameWithSingletonDistinct(user.name) } + @DistinctUntilChangeFun(true) private fun setName(name: String) { logger.log(Level.INFO, "setName: $name") findViewById(R.id.usernameFieldTextView).text = name } - @DistinctUntilChangeFun(true) + @DistinctUntilChangeFun(true, action = TestLogger::class) private fun setSecondName(name: String) { logger.log(Level.INFO, "setSecondName: $name") findViewById(R.id.secondNameFieldTextView).text = name @@ -74,3 +75,5 @@ class MainActivity : ComponentActivity() { private fun printUsernameWithSingletonDistinct(name: String) { println("printUsernameWithSingletonDistinct: $name") } + + diff --git a/app/src/main/kotlin/com/stslex/compiler_app/TestLogger.kt b/app/src/main/kotlin/com/stslex/compiler_app/TestLogger.kt new file mode 100644 index 0000000..05e0ac9 --- /dev/null +++ b/app/src/main/kotlin/com/stslex/compiler_app/TestLogger.kt @@ -0,0 +1,10 @@ +package com.stslex.compiler_app + +import io.github.stslex.compiler_plugin.utils.Action + +class TestLogger : Action { + + override fun invoke(isProcess: Boolean) { + println("test logger procession: $isProcess") + } +} \ No newline at end of file diff --git a/compiler-plugin/src/main/kotlin/io/github/stslex/compiler_plugin/DistinctChangeCache.kt b/compiler-plugin/src/main/kotlin/io/github/stslex/compiler_plugin/DistinctChangeCache.kt index 0d2d1ab..655b5e5 100644 --- a/compiler-plugin/src/main/kotlin/io/github/stslex/compiler_plugin/DistinctChangeCache.kt +++ b/compiler-plugin/src/main/kotlin/io/github/stslex/compiler_plugin/DistinctChangeCache.kt @@ -1,5 +1,6 @@ package io.github.stslex.compiler_plugin +import io.github.stslex.compiler_plugin.model.DistinctChangeConfig import io.github.stslex.compiler_plugin.utils.RuntimeLogger internal class DistinctChangeCache( @@ -25,9 +26,12 @@ internal class DistinctChangeCache( if (config.logging) { logger.i("$key not change") } + config.action(isProcess = false) return entry.second as R } + config.action(isProcess = true) + val result = body() cache[key] = args to result return result diff --git a/compiler-plugin/src/main/kotlin/io/github/stslex/compiler_plugin/DistinctChangeConfig.kt b/compiler-plugin/src/main/kotlin/io/github/stslex/compiler_plugin/DistinctChangeConfig.kt deleted file mode 100644 index 49f0917..0000000 --- a/compiler-plugin/src/main/kotlin/io/github/stslex/compiler_plugin/DistinctChangeConfig.kt +++ /dev/null @@ -1,5 +0,0 @@ -package io.github.stslex.compiler_plugin - -internal data class DistinctChangeConfig( - val logging: Boolean -) \ No newline at end of file diff --git a/compiler-plugin/src/main/kotlin/io/github/stslex/compiler_plugin/DistinctUntilChangeFun.kt b/compiler-plugin/src/main/kotlin/io/github/stslex/compiler_plugin/DistinctUntilChangeFun.kt index 04997f6..31cfb16 100644 --- a/compiler-plugin/src/main/kotlin/io/github/stslex/compiler_plugin/DistinctUntilChangeFun.kt +++ b/compiler-plugin/src/main/kotlin/io/github/stslex/compiler_plugin/DistinctUntilChangeFun.kt @@ -1,5 +1,9 @@ package io.github.stslex.compiler_plugin +import io.github.stslex.compiler_plugin.utils.Action +import io.github.stslex.compiler_plugin.utils.DefaultAction +import kotlin.reflect.KClass + /** * @param logging enable logs for Kotlin Compiler Runtime work (useful for debug - don't use in production) * @param singletonAllow if enable - generates distinction for function without classes (so it's singleton) @@ -8,12 +12,15 @@ package io.github.stslex.compiler_plugin @Retention(AnnotationRetention.BINARY) public annotation class DistinctUntilChangeFun( val logging: Boolean = LOGGING_DEFAULT, - val singletonAllow: Boolean = false + val singletonAllow: Boolean = SINGLETON_ALLOW, + val action: KClass = DefaultAction::class ) { public companion object { internal const val LOGGING_DEFAULT = false + internal const val SINGLETON_ALLOW = false + } } \ No newline at end of file diff --git a/compiler-plugin/src/main/kotlin/io/github/stslex/compiler_plugin/model/DistinctChangeConfig.kt b/compiler-plugin/src/main/kotlin/io/github/stslex/compiler_plugin/model/DistinctChangeConfig.kt new file mode 100644 index 0000000..5788296 --- /dev/null +++ b/compiler-plugin/src/main/kotlin/io/github/stslex/compiler_plugin/model/DistinctChangeConfig.kt @@ -0,0 +1,8 @@ +package io.github.stslex.compiler_plugin.model + +import io.github.stslex.compiler_plugin.utils.Action + +internal data class DistinctChangeConfig( + val logging: Boolean, + val action: Action +) \ No newline at end of file diff --git a/compiler-plugin/src/main/kotlin/io/github/stslex/compiler_plugin/transformers/IrFunctionTransformer.kt b/compiler-plugin/src/main/kotlin/io/github/stslex/compiler_plugin/transformers/IrFunctionTransformer.kt index 1b23139..83d4b04 100644 --- a/compiler-plugin/src/main/kotlin/io/github/stslex/compiler_plugin/transformers/IrFunctionTransformer.kt +++ b/compiler-plugin/src/main/kotlin/io/github/stslex/compiler_plugin/transformers/IrFunctionTransformer.kt @@ -1,6 +1,7 @@ package io.github.stslex.compiler_plugin.transformers import buildArgsListExpression +import io.github.stslex.compiler_plugin.DistinctUntilChangeFun.Companion.SINGLETON_ALLOW import io.github.stslex.compiler_plugin.utils.CompileLogger.Companion.toCompilerLogger import io.github.stslex.compiler_plugin.utils.buildLambdaForBody import io.github.stslex.compiler_plugin.utils.buildSaveInCacheCall @@ -29,10 +30,9 @@ internal class IrFunctionTransformer( val qualifierArgs = pluginContext.readQualifier(declaration, logger) ?: return super.visitSimpleFunction(declaration) - if ( - declaration.getQualifierValue("singletonAllow").not() && - declaration.parentClassOrNull == null - ) { + val isSingletonAllow = declaration.getQualifierValue("singletonAllow", SINGLETON_ALLOW) + + if (isSingletonAllow.not() && declaration.parentClassOrNull == null) { error("singleton is not allowed for ${declaration.name} in ${declaration.fileParentOrNull}") } diff --git a/compiler-plugin/src/main/kotlin/io/github/stslex/compiler_plugin/utils/CompilerExtensions.kt b/compiler-plugin/src/main/kotlin/io/github/stslex/compiler_plugin/utils/CompilerExtensions.kt index ec5007b..20f1ad5 100644 --- a/compiler-plugin/src/main/kotlin/io/github/stslex/compiler_plugin/utils/CompilerExtensions.kt +++ b/compiler-plugin/src/main/kotlin/io/github/stslex/compiler_plugin/utils/CompilerExtensions.kt @@ -34,6 +34,7 @@ import org.jetbrains.kotlin.ir.util.file import org.jetbrains.kotlin.ir.util.kotlinFqName import org.jetbrains.kotlin.ir.util.parentClassOrNull import org.jetbrains.kotlin.ir.util.patchDeclarationParents +import org.jetbrains.kotlin.name.CallableId import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name @@ -46,10 +47,18 @@ internal fun IrPluginContext.createIrBuilder( symbol = declaration.symbol ) -internal inline fun KClass.toClassId(): ClassId = ClassId( - FqName(java.`package`.name), - Name.identifier(java.simpleName) -) +internal val KClass.classId: ClassId + get() = ClassId(fqName, name) + +internal val KClass.callableId: CallableId + get() = CallableId(fqName, name) + + +internal val KClass.fqName: FqName + get() = FqName(java.`package`.name) + +internal val KClass.name: Name + get() = Name.identifier(java.simpleName) internal fun IrPluginContext.buildLambdaForBody( originalBody: IrBody, @@ -111,7 +120,7 @@ internal fun IrPluginContext.buildSaveInCacheCall( ): IrExpression { logger.i("buildSaveInCacheCall for ${function.name}, args: ${argsListExpr.dump()}") - val distinctChangeClassSymbol = referenceClass(DistinctChangeCache::class.toClassId()) + val distinctChangeClassSymbol = referenceClass(DistinctChangeCache::class.classId) ?: error("Cannot find DistinctChangeCache") val invokeFunSymbol = distinctChangeClassSymbol.owner.declarations @@ -177,7 +186,7 @@ internal fun IrPluginContext.generateFields( val fieldSymbol = IrFieldSymbolImpl() - val distinctChangeClass = referenceClass(DistinctChangeCache::class.toClassId()) + val distinctChangeClass = referenceClass(DistinctChangeCache::class.classId) ?: error("couldn't find DistinctChangeCache") val backingField = irFactory.createField( diff --git a/compiler-plugin/src/main/kotlin/io/github/stslex/compiler_plugin/utils/CompilerLogger.kt b/compiler-plugin/src/main/kotlin/io/github/stslex/compiler_plugin/utils/CompilerLogger.kt new file mode 100644 index 0000000..d7113cb --- /dev/null +++ b/compiler-plugin/src/main/kotlin/io/github/stslex/compiler_plugin/utils/CompilerLogger.kt @@ -0,0 +1,11 @@ +package io.github.stslex.compiler_plugin.utils + +/**Use for any action in runtime plugin*/ +public fun interface Action { + + /** + * @param isProcess show that function block will process + **/ + public operator fun invoke(isProcess: Boolean) + +} diff --git a/compiler-plugin/src/main/kotlin/io/github/stslex/compiler_plugin/utils/DefaultAction.kt b/compiler-plugin/src/main/kotlin/io/github/stslex/compiler_plugin/utils/DefaultAction.kt new file mode 100644 index 0000000..7f3b1b2 --- /dev/null +++ b/compiler-plugin/src/main/kotlin/io/github/stslex/compiler_plugin/utils/DefaultAction.kt @@ -0,0 +1,6 @@ +package io.github.stslex.compiler_plugin.utils + +internal class DefaultAction : Action { + + override fun invoke(isProcess: Boolean) = Unit +} \ No newline at end of file diff --git a/compiler-plugin/src/main/kotlin/io/github/stslex/compiler_plugin/utils/ReadQualifierUtil.kt b/compiler-plugin/src/main/kotlin/io/github/stslex/compiler_plugin/utils/ReadQualifierUtil.kt index 6a8d186..1a17758 100644 --- a/compiler-plugin/src/main/kotlin/io/github/stslex/compiler_plugin/utils/ReadQualifierUtil.kt +++ b/compiler-plugin/src/main/kotlin/io/github/stslex/compiler_plugin/utils/ReadQualifierUtil.kt @@ -1,22 +1,28 @@ package io.github.stslex.compiler_plugin.utils -import io.github.stslex.compiler_plugin.DistinctChangeConfig import io.github.stslex.compiler_plugin.DistinctUntilChangeFun import io.github.stslex.compiler_plugin.DistinctUntilChangeFun.Companion.LOGGING_DEFAULT +import io.github.stslex.compiler_plugin.model.DistinctChangeConfig import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext +import org.jetbrains.kotlin.backend.common.lower.DeclarationIrBuilder import org.jetbrains.kotlin.ir.builders.irBoolean import org.jetbrains.kotlin.ir.builders.irCallConstructor import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction +import org.jetbrains.kotlin.ir.expressions.IrClassReference import org.jetbrains.kotlin.ir.expressions.IrConst import org.jetbrains.kotlin.ir.expressions.IrConstKind +import org.jetbrains.kotlin.ir.expressions.IrConstructorCall import org.jetbrains.kotlin.ir.expressions.IrExpression +import org.jetbrains.kotlin.ir.symbols.IrClassSymbol import org.jetbrains.kotlin.ir.symbols.UnsafeDuringIrConstructionAPI +import org.jetbrains.kotlin.ir.types.defaultType import org.jetbrains.kotlin.ir.util.constructors import org.jetbrains.kotlin.ir.util.getAnnotation import org.jetbrains.kotlin.ir.util.getValueArgument import org.jetbrains.kotlin.ir.util.patchDeclarationParents import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name +import kotlin.reflect.KClass @OptIn(UnsafeDuringIrConstructionAPI::class) internal fun IrPluginContext.readQualifier( @@ -30,10 +36,10 @@ internal fun IrPluginContext.readQualifier( val irBuilder = createIrBuilder(function) - val logging = annotation.getValueArgument(0) - ?: irBuilder.irBoolean(LOGGING_DEFAULT) + val loggingExpr = annotation.getValueArgument(0) ?: irBuilder.irBoolean(LOGGING_DEFAULT) + val actionInstanceExpr = getQualifierAction(annotation, irBuilder) - val constructorSymbol = referenceClass(DistinctChangeConfig::class.toClassId()) + val constructorSymbol = referenceClass(DistinctChangeConfig::class.classId) ?.constructors ?.firstOrNull() ?: error("CheckChangesConfig not found in IR") @@ -45,16 +51,42 @@ internal fun IrPluginContext.readQualifier( ) .also { it.patchDeclarationParents(function) } .apply { - putValueArgument(0, logging) + putValueArgument(0, loggingExpr) + putValueArgument(1, actionInstanceExpr) } } -internal fun IrSimpleFunction.getQualifierValue(name: String): Boolean = getAnnotation( +@OptIn(UnsafeDuringIrConstructionAPI::class) +private fun IrPluginContext.getQualifierAction( + annotation: IrConstructorCall, + irBuilder: DeclarationIrBuilder +): IrExpression { + val defaultActionClass = irBuiltIns + .findClass(DefaultAction::class.name, DefaultAction::class.fqName) + ?: error("readQualifier ${DefaultAction::class.java.simpleName} not found") + + val actionReference = annotation.getValueArgument(2) as? IrClassReference + + val actionClassSymbol = actionReference?.symbol as? IrClassSymbol ?: defaultActionClass + + val actionConstructorSymbol = actionClassSymbol.constructors.firstOrNull { + it.owner.valueParameters.isEmpty() + } ?: error("No no-arg constructor for action class: ${actionReference?.symbol?.defaultType}") + + return irBuilder.irCallConstructor(actionConstructorSymbol, emptyList()) +} + +public fun getJavaClassNonInline(kClass: KClass<*>): Class<*> = kClass.java + +internal inline fun IrSimpleFunction.getQualifierValue( + name: String, + defaultValue: T +): T = getAnnotation( FqName(DistinctUntilChangeFun::class.qualifiedName!!) ) ?.getValueArgument(Name.identifier(name)) - ?.parseValue() - ?: false + ?.parseValue() + ?: defaultValue private inline fun IrExpression.parseValue(): T = when (this) { is IrConst<*> -> when (kind) { From 0cd3ee152d269e420e9542dcd53076c309cebcfd Mon Sep 17 00:00:00 2001 From: stslex Date: Mon, 17 Feb 2025 22:52:05 +0300 Subject: [PATCH 2/4] - add name for custom actions --- .../com/stslex/compiler_app/MainActivity.kt | 6 +++++- .../kotlin/com/stslex/compiler_app/TestLogger.kt | 7 +++++-- .../compiler_plugin/DistinctChangeCache.kt | 16 +++++++++------- .../compiler_plugin/DistinctUntilChangeFun.kt | 4 ++++ .../model/DistinctChangeConfig.kt | 3 ++- .../compiler_plugin/utils/CompilerLogger.kt | 11 +++++++++-- .../compiler_plugin/utils/DefaultAction.kt | 5 ++++- .../compiler_plugin/utils/ReadQualifierUtil.kt | 9 +++++++-- gradle/libs.versions.toml | 2 +- 9 files changed, 46 insertions(+), 17 deletions(-) diff --git a/app/src/main/kotlin/com/stslex/compiler_app/MainActivity.kt b/app/src/main/kotlin/com/stslex/compiler_app/MainActivity.kt index bbb1a20..9d3c101 100644 --- a/app/src/main/kotlin/com/stslex/compiler_app/MainActivity.kt +++ b/app/src/main/kotlin/com/stslex/compiler_app/MainActivity.kt @@ -61,7 +61,11 @@ class MainActivity : ComponentActivity() { findViewById(R.id.usernameFieldTextView).text = name } - @DistinctUntilChangeFun(true, action = TestLogger::class) + @DistinctUntilChangeFun( + name = "set_user_second_name", + logging = true, + action = TestLogger::class + ) private fun setSecondName(name: String) { logger.log(Level.INFO, "setSecondName: $name") findViewById(R.id.secondNameFieldTextView).text = name diff --git a/app/src/main/kotlin/com/stslex/compiler_app/TestLogger.kt b/app/src/main/kotlin/com/stslex/compiler_app/TestLogger.kt index 05e0ac9..3179a2a 100644 --- a/app/src/main/kotlin/com/stslex/compiler_app/TestLogger.kt +++ b/app/src/main/kotlin/com/stslex/compiler_app/TestLogger.kt @@ -4,7 +4,10 @@ import io.github.stslex.compiler_plugin.utils.Action class TestLogger : Action { - override fun invoke(isProcess: Boolean) { - println("test logger procession: $isProcess") + override fun invoke( + name: String, + isProcess: Boolean + ) { + println("test action $name procession: $isProcess") } } \ No newline at end of file diff --git a/compiler-plugin/src/main/kotlin/io/github/stslex/compiler_plugin/DistinctChangeCache.kt b/compiler-plugin/src/main/kotlin/io/github/stslex/compiler_plugin/DistinctChangeCache.kt index 655b5e5..3778267 100644 --- a/compiler-plugin/src/main/kotlin/io/github/stslex/compiler_plugin/DistinctChangeCache.kt +++ b/compiler-plugin/src/main/kotlin/io/github/stslex/compiler_plugin/DistinctChangeCache.kt @@ -18,22 +18,24 @@ internal class DistinctChangeCache( ): R { val entry = cache[key] + // log enter to invoke processing if (config.logging) { - logger.i("key: $key, config:$config, entry: $entry, args: $args") + logger.i("name: ${config.name} key: $key, config:$config, entry: $entry, args: $args") } + config.action( + name = config.name, + isProcess = entry != null && entry.first == args + ) + if (entry != null && entry.first == args) { - if (config.logging) { - logger.i("$key not change") - } - config.action(isProcess = false) + if (config.logging) logger.i("${config.name} with key $key not change") return entry.second as R } - config.action(isProcess = true) - val result = body() cache[key] = args to result + return result } } \ No newline at end of file diff --git a/compiler-plugin/src/main/kotlin/io/github/stslex/compiler_plugin/DistinctUntilChangeFun.kt b/compiler-plugin/src/main/kotlin/io/github/stslex/compiler_plugin/DistinctUntilChangeFun.kt index 31cfb16..7cd5ef6 100644 --- a/compiler-plugin/src/main/kotlin/io/github/stslex/compiler_plugin/DistinctUntilChangeFun.kt +++ b/compiler-plugin/src/main/kotlin/io/github/stslex/compiler_plugin/DistinctUntilChangeFun.kt @@ -7,12 +7,16 @@ import kotlin.reflect.KClass /** * @param logging enable logs for Kotlin Compiler Runtime work (useful for debug - don't use in production) * @param singletonAllow if enable - generates distinction for function without classes (so it's singleton) + * @param name set name for function in compiler logs and put in into action, else take function name + * @param action any action to process when function enter - it invokes with state of processing function body info and [name]. + * @suppress [action] shouldn't have properties in it's constructor * */ @Target(AnnotationTarget.FUNCTION) @Retention(AnnotationRetention.BINARY) public annotation class DistinctUntilChangeFun( val logging: Boolean = LOGGING_DEFAULT, val singletonAllow: Boolean = SINGLETON_ALLOW, + val name: String = "", val action: KClass = DefaultAction::class ) { diff --git a/compiler-plugin/src/main/kotlin/io/github/stslex/compiler_plugin/model/DistinctChangeConfig.kt b/compiler-plugin/src/main/kotlin/io/github/stslex/compiler_plugin/model/DistinctChangeConfig.kt index 5788296..5a93806 100644 --- a/compiler-plugin/src/main/kotlin/io/github/stslex/compiler_plugin/model/DistinctChangeConfig.kt +++ b/compiler-plugin/src/main/kotlin/io/github/stslex/compiler_plugin/model/DistinctChangeConfig.kt @@ -4,5 +4,6 @@ import io.github.stslex.compiler_plugin.utils.Action internal data class DistinctChangeConfig( val logging: Boolean, - val action: Action + val action: Action, + val name: String ) \ No newline at end of file diff --git a/compiler-plugin/src/main/kotlin/io/github/stslex/compiler_plugin/utils/CompilerLogger.kt b/compiler-plugin/src/main/kotlin/io/github/stslex/compiler_plugin/utils/CompilerLogger.kt index d7113cb..12ad59b 100644 --- a/compiler-plugin/src/main/kotlin/io/github/stslex/compiler_plugin/utils/CompilerLogger.kt +++ b/compiler-plugin/src/main/kotlin/io/github/stslex/compiler_plugin/utils/CompilerLogger.kt @@ -1,11 +1,18 @@ package io.github.stslex.compiler_plugin.utils -/**Use for any action in runtime plugin*/ +/** + * Use for any action in runtime plugin + * @suppress shouldn't have properties in it's constructor - cause compiling crush + **/ public fun interface Action { /** + * @param name setted at [io.github.stslex.compiler_plugin.DistinctUntilChangeFun] property name * @param isProcess show that function block will process **/ - public operator fun invoke(isProcess: Boolean) + public operator fun invoke( + name: String, + isProcess: Boolean + ) } diff --git a/compiler-plugin/src/main/kotlin/io/github/stslex/compiler_plugin/utils/DefaultAction.kt b/compiler-plugin/src/main/kotlin/io/github/stslex/compiler_plugin/utils/DefaultAction.kt index 7f3b1b2..c01b2f3 100644 --- a/compiler-plugin/src/main/kotlin/io/github/stslex/compiler_plugin/utils/DefaultAction.kt +++ b/compiler-plugin/src/main/kotlin/io/github/stslex/compiler_plugin/utils/DefaultAction.kt @@ -2,5 +2,8 @@ package io.github.stslex.compiler_plugin.utils internal class DefaultAction : Action { - override fun invoke(isProcess: Boolean) = Unit + override fun invoke( + name: String, + isProcess: Boolean + ) = Unit } \ No newline at end of file diff --git a/compiler-plugin/src/main/kotlin/io/github/stslex/compiler_plugin/utils/ReadQualifierUtil.kt b/compiler-plugin/src/main/kotlin/io/github/stslex/compiler_plugin/utils/ReadQualifierUtil.kt index 1a17758..1257ce3 100644 --- a/compiler-plugin/src/main/kotlin/io/github/stslex/compiler_plugin/utils/ReadQualifierUtil.kt +++ b/compiler-plugin/src/main/kotlin/io/github/stslex/compiler_plugin/utils/ReadQualifierUtil.kt @@ -7,6 +7,7 @@ import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext import org.jetbrains.kotlin.backend.common.lower.DeclarationIrBuilder import org.jetbrains.kotlin.ir.builders.irBoolean import org.jetbrains.kotlin.ir.builders.irCallConstructor +import org.jetbrains.kotlin.ir.builders.irString import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction import org.jetbrains.kotlin.ir.expressions.IrClassReference import org.jetbrains.kotlin.ir.expressions.IrConst @@ -36,7 +37,10 @@ internal fun IrPluginContext.readQualifier( val irBuilder = createIrBuilder(function) - val loggingExpr = annotation.getValueArgument(0) ?: irBuilder.irBoolean(LOGGING_DEFAULT) + val loggingExpr = annotation.getValueArgument(0) + ?: irBuilder.irBoolean(LOGGING_DEFAULT) + val actionName = annotation.getValueArgument(2) + ?: irBuilder.irString(function.name.identifier) val actionInstanceExpr = getQualifierAction(annotation, irBuilder) val constructorSymbol = referenceClass(DistinctChangeConfig::class.classId) @@ -53,6 +57,7 @@ internal fun IrPluginContext.readQualifier( .apply { putValueArgument(0, loggingExpr) putValueArgument(1, actionInstanceExpr) + putValueArgument(2, actionName) } } @@ -65,7 +70,7 @@ private fun IrPluginContext.getQualifierAction( .findClass(DefaultAction::class.name, DefaultAction::class.fqName) ?: error("readQualifier ${DefaultAction::class.java.simpleName} not found") - val actionReference = annotation.getValueArgument(2) as? IrClassReference + val actionReference = annotation.getValueArgument(3) as? IrClassReference val actionClassSymbol = actionReference?.symbol as? IrClassSymbol ?: defaultActionClass diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 13c03c7..5f507f1 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -14,7 +14,7 @@ activity = "1.10.0" constraintLayout = "2.2.0" jetbrainsKotlinJvm = "2.0.20" -stslexCompilerPlugin = "0.0.3" +stslexCompilerPlugin = "0.0.4" [libraries] android-desugarJdkLibs = { module = "com.android.tools:desugar_jdk_libs", version.ref = "androidDesugarJdkLibs" } From afed0be7d7b32abfac11c7d1d4d1f3955ecf1f91 Mon Sep 17 00:00:00 2001 From: stslex Date: Mon, 17 Feb 2025 22:55:55 +0300 Subject: [PATCH 3/4] logger small refactor --- .../stslex/compiler_plugin/DistinctChangeCache.kt | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/compiler-plugin/src/main/kotlin/io/github/stslex/compiler_plugin/DistinctChangeCache.kt b/compiler-plugin/src/main/kotlin/io/github/stslex/compiler_plugin/DistinctChangeCache.kt index 3778267..28ffa38 100644 --- a/compiler-plugin/src/main/kotlin/io/github/stslex/compiler_plugin/DistinctChangeCache.kt +++ b/compiler-plugin/src/main/kotlin/io/github/stslex/compiler_plugin/DistinctChangeCache.kt @@ -2,13 +2,14 @@ package io.github.stslex.compiler_plugin import io.github.stslex.compiler_plugin.model.DistinctChangeConfig import io.github.stslex.compiler_plugin.utils.RuntimeLogger +import org.jetbrains.kotlin.utils.addToStdlib.runIf internal class DistinctChangeCache( private val config: DistinctChangeConfig ) { private val cache = mutableMapOf, Any?>>() - private val logger = RuntimeLogger.tag("DistinctChangeLogger") + private val logger = runIf(config.logging) { RuntimeLogger.tag("DistinctChangeLogger") } @Suppress("UNCHECKED_CAST") internal operator fun invoke( @@ -18,10 +19,7 @@ internal class DistinctChangeCache( ): R { val entry = cache[key] - // log enter to invoke processing - if (config.logging) { - logger.i("name: ${config.name} key: $key, config:$config, entry: $entry, args: $args") - } + logger?.i("name: ${config.name} key: $key, config:$config, entry: $entry, args: $args") config.action( name = config.name, @@ -29,7 +27,7 @@ internal class DistinctChangeCache( ) if (entry != null && entry.first == args) { - if (config.logging) logger.i("${config.name} with key $key not change") + logger?.i("${config.name} with key $key not change") return entry.second as R } From ce9af363646c858d9aa1ad1ac4308d7d1228502c Mon Sep 17 00:00:00 2001 From: stslex Date: Mon, 17 Feb 2025 22:59:47 +0300 Subject: [PATCH 4/4] update README.md --- README.md | 37 ++++++++++++++++++++++++++++++------- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index dca5044..78578fb 100644 --- a/README.md +++ b/README.md @@ -2,21 +2,44 @@ > Check annotated functions arguments. If they don't change - return last result. > Functions could be logged. +> Support extra custom action on function processing + +import compiler plugin: -import compiler plugin: ```kotlin dependencies { - implementation("io.github.stslex:compiler-plugin:0.0.1") - kotlinCompilerPluginClasspath("io.github.stslex:compiler-plugin:0.0.1") + implementation("io.github.stslex:compiler-plugin:$version") + kotlinCompilerPluginClasspath("io.github.stslex:compiler-plugin:$version") } ``` -in code: +in code (all annotation properties are optional): + ```kotlin + import io.github.stslex.compiler_plugin.DistinctUntilChangeFun -@DistinctUntilChangeFun -fun setUserName(username: String){ - // function logic +@DistinctUntilChangeFun( + logging = true, + singletonAllow = false, + name = "set_user_second_name", + action = TestLogger::class +) +fun setUserName(username: String) { + // function logic } ``` + +for custom actions: + +```kotlin +class TestLogger : Action { + + override fun invoke( + name: String, + isProcess: Boolean + ) { + println("test action $name procession: $isProcess") + } +} +``` \ No newline at end of file