Skip to content

Commit dc8ef63

Browse files
authored
Merge pull request #9 from stslex/dev
Custom actions support
2 parents 34161ce + ce9af36 commit dc8ef63

File tree

13 files changed

+174
-39
lines changed

13 files changed

+174
-39
lines changed

README.md

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,44 @@
22

33
> Check annotated functions arguments. If they don't change - return last result.
44
> Functions could be logged.
5+
> Support extra custom action on function processing
6+
7+
import compiler plugin:
58

6-
import compiler plugin:
79
```kotlin
810
dependencies {
9-
implementation("io.github.stslex:compiler-plugin:0.0.1")
10-
kotlinCompilerPluginClasspath("io.github.stslex:compiler-plugin:0.0.1")
11+
implementation("io.github.stslex:compiler-plugin:$version")
12+
kotlinCompilerPluginClasspath("io.github.stslex:compiler-plugin:$version")
1113
}
1214
```
1315

14-
in code:
16+
in code (all annotation properties are optional):
17+
1518
```kotlin
19+
1620
import io.github.stslex.compiler_plugin.DistinctUntilChangeFun
1721

18-
@DistinctUntilChangeFun
19-
fun setUserName(username: String){
20-
// function logic
22+
@DistinctUntilChangeFun(
23+
logging = true,
24+
singletonAllow = false,
25+
name = "set_user_second_name",
26+
action = TestLogger::class
27+
)
28+
fun setUserName(username: String) {
29+
// function logic
2130
}
2231
```
32+
33+
for custom actions:
34+
35+
```kotlin
36+
class TestLogger : Action {
37+
38+
override fun invoke(
39+
name: String,
40+
isProcess: Boolean
41+
) {
42+
println("test action $name procession: $isProcess")
43+
}
44+
}
45+
```

app/src/main/kotlin/com/stslex/compiler_app/MainActivity.kt

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,13 +54,18 @@ class MainActivity : ComponentActivity() {
5454
printUsernameWithSingletonDistinct(user.name)
5555
}
5656

57+
5758
@DistinctUntilChangeFun(true)
5859
private fun setName(name: String) {
5960
logger.log(Level.INFO, "setName: $name")
6061
findViewById<TextView>(R.id.usernameFieldTextView).text = name
6162
}
6263

63-
@DistinctUntilChangeFun(true)
64+
@DistinctUntilChangeFun(
65+
name = "set_user_second_name",
66+
logging = true,
67+
action = TestLogger::class
68+
)
6469
private fun setSecondName(name: String) {
6570
logger.log(Level.INFO, "setSecondName: $name")
6671
findViewById<TextView>(R.id.secondNameFieldTextView).text = name
@@ -74,3 +79,5 @@ class MainActivity : ComponentActivity() {
7479
private fun printUsernameWithSingletonDistinct(name: String) {
7580
println("printUsernameWithSingletonDistinct: $name")
7681
}
82+
83+
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package com.stslex.compiler_app
2+
3+
import io.github.stslex.compiler_plugin.utils.Action
4+
5+
class TestLogger : Action {
6+
7+
override fun invoke(
8+
name: String,
9+
isProcess: Boolean
10+
) {
11+
println("test action $name procession: $isProcess")
12+
}
13+
}
Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
package io.github.stslex.compiler_plugin
22

3+
import io.github.stslex.compiler_plugin.model.DistinctChangeConfig
34
import io.github.stslex.compiler_plugin.utils.RuntimeLogger
5+
import org.jetbrains.kotlin.utils.addToStdlib.runIf
46

57
internal class DistinctChangeCache(
68
private val config: DistinctChangeConfig
79
) {
810

911
private val cache = mutableMapOf<String, Pair<List<Any?>, Any?>>()
10-
private val logger = RuntimeLogger.tag("DistinctChangeLogger")
12+
private val logger = runIf(config.logging) { RuntimeLogger.tag("DistinctChangeLogger") }
1113

1214
@Suppress("UNCHECKED_CAST")
1315
internal operator fun <R> invoke(
@@ -17,19 +19,21 @@ internal class DistinctChangeCache(
1719
): R {
1820
val entry = cache[key]
1921

20-
if (config.logging) {
21-
logger.i("key: $key, config:$config, entry: $entry, args: $args")
22-
}
22+
logger?.i("name: ${config.name} key: $key, config:$config, entry: $entry, args: $args")
23+
24+
config.action(
25+
name = config.name,
26+
isProcess = entry != null && entry.first == args
27+
)
2328

2429
if (entry != null && entry.first == args) {
25-
if (config.logging) {
26-
logger.i("$key not change")
27-
}
30+
logger?.i("${config.name} with key $key not change")
2831
return entry.second as R
2932
}
3033

3134
val result = body()
3235
cache[key] = args to result
36+
3337
return result
3438
}
3539
}

compiler-plugin/src/main/kotlin/io/github/stslex/compiler_plugin/DistinctChangeConfig.kt

Lines changed: 0 additions & 5 deletions
This file was deleted.
Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,30 @@
11
package io.github.stslex.compiler_plugin
22

3+
import io.github.stslex.compiler_plugin.utils.Action
4+
import io.github.stslex.compiler_plugin.utils.DefaultAction
5+
import kotlin.reflect.KClass
6+
37
/**
48
* @param logging enable logs for Kotlin Compiler Runtime work (useful for debug - don't use in production)
59
* @param singletonAllow if enable - generates distinction for function without classes (so it's singleton)
10+
* @param name set name for function in compiler logs and put in into action, else take function name
11+
* @param action any action to process when function enter - it invokes with state of processing function body info and [name].
12+
* @suppress [action] shouldn't have properties in it's constructor
613
* */
714
@Target(AnnotationTarget.FUNCTION)
815
@Retention(AnnotationRetention.BINARY)
916
public annotation class DistinctUntilChangeFun(
1017
val logging: Boolean = LOGGING_DEFAULT,
11-
val singletonAllow: Boolean = false
18+
val singletonAllow: Boolean = SINGLETON_ALLOW,
19+
val name: String = "",
20+
val action: KClass<out Action> = DefaultAction::class
1221
) {
1322

1423
public companion object {
1524

1625
internal const val LOGGING_DEFAULT = false
1726

27+
internal const val SINGLETON_ALLOW = false
28+
1829
}
1930
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package io.github.stslex.compiler_plugin.model
2+
3+
import io.github.stslex.compiler_plugin.utils.Action
4+
5+
internal data class DistinctChangeConfig(
6+
val logging: Boolean,
7+
val action: Action,
8+
val name: String
9+
)

compiler-plugin/src/main/kotlin/io/github/stslex/compiler_plugin/transformers/IrFunctionTransformer.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package io.github.stslex.compiler_plugin.transformers
22

33
import buildArgsListExpression
4+
import io.github.stslex.compiler_plugin.DistinctUntilChangeFun.Companion.SINGLETON_ALLOW
45
import io.github.stslex.compiler_plugin.utils.CompileLogger.Companion.toCompilerLogger
56
import io.github.stslex.compiler_plugin.utils.buildLambdaForBody
67
import io.github.stslex.compiler_plugin.utils.buildSaveInCacheCall
@@ -29,10 +30,9 @@ internal class IrFunctionTransformer(
2930
val qualifierArgs = pluginContext.readQualifier(declaration, logger)
3031
?: return super.visitSimpleFunction(declaration)
3132

32-
if (
33-
declaration.getQualifierValue("singletonAllow").not() &&
34-
declaration.parentClassOrNull == null
35-
) {
33+
val isSingletonAllow = declaration.getQualifierValue("singletonAllow", SINGLETON_ALLOW)
34+
35+
if (isSingletonAllow.not() && declaration.parentClassOrNull == null) {
3636
error("singleton is not allowed for ${declaration.name} in ${declaration.fileParentOrNull}")
3737
}
3838

compiler-plugin/src/main/kotlin/io/github/stslex/compiler_plugin/utils/CompilerExtensions.kt

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import org.jetbrains.kotlin.ir.util.file
3434
import org.jetbrains.kotlin.ir.util.kotlinFqName
3535
import org.jetbrains.kotlin.ir.util.parentClassOrNull
3636
import org.jetbrains.kotlin.ir.util.patchDeclarationParents
37+
import org.jetbrains.kotlin.name.CallableId
3738
import org.jetbrains.kotlin.name.ClassId
3839
import org.jetbrains.kotlin.name.FqName
3940
import org.jetbrains.kotlin.name.Name
@@ -46,10 +47,18 @@ internal fun IrPluginContext.createIrBuilder(
4647
symbol = declaration.symbol
4748
)
4849

49-
internal inline fun <reified T : Any> KClass<T>.toClassId(): ClassId = ClassId(
50-
FqName(java.`package`.name),
51-
Name.identifier(java.simpleName)
52-
)
50+
internal val <T : Any> KClass<T>.classId: ClassId
51+
get() = ClassId(fqName, name)
52+
53+
internal val <T : Any> KClass<T>.callableId: CallableId
54+
get() = CallableId(fqName, name)
55+
56+
57+
internal val <T : Any> KClass<T>.fqName: FqName
58+
get() = FqName(java.`package`.name)
59+
60+
internal val <T : Any> KClass<T>.name: Name
61+
get() = Name.identifier(java.simpleName)
5362

5463
internal fun IrPluginContext.buildLambdaForBody(
5564
originalBody: IrBody,
@@ -111,7 +120,7 @@ internal fun IrPluginContext.buildSaveInCacheCall(
111120
): IrExpression {
112121
logger.i("buildSaveInCacheCall for ${function.name}, args: ${argsListExpr.dump()}")
113122

114-
val distinctChangeClassSymbol = referenceClass(DistinctChangeCache::class.toClassId())
123+
val distinctChangeClassSymbol = referenceClass(DistinctChangeCache::class.classId)
115124
?: error("Cannot find DistinctChangeCache")
116125

117126
val invokeFunSymbol = distinctChangeClassSymbol.owner.declarations
@@ -177,7 +186,7 @@ internal fun IrPluginContext.generateFields(
177186

178187
val fieldSymbol = IrFieldSymbolImpl()
179188

180-
val distinctChangeClass = referenceClass(DistinctChangeCache::class.toClassId())
189+
val distinctChangeClass = referenceClass(DistinctChangeCache::class.classId)
181190
?: error("couldn't find DistinctChangeCache")
182191

183192
val backingField = irFactory.createField(
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package io.github.stslex.compiler_plugin.utils
2+
3+
/**
4+
* Use for any action in runtime plugin
5+
* @suppress shouldn't have properties in it's constructor - cause compiling crush
6+
**/
7+
public fun interface Action {
8+
9+
/**
10+
* @param name setted at [io.github.stslex.compiler_plugin.DistinctUntilChangeFun] property name
11+
* @param isProcess show that function block will process
12+
**/
13+
public operator fun invoke(
14+
name: String,
15+
isProcess: Boolean
16+
)
17+
18+
}

0 commit comments

Comments
 (0)