Skip to content

Commit ffe99df

Browse files
committed
init kotlin compiler plugin
1 parent 9610b8e commit ffe99df

19 files changed

+405
-4
lines changed

app/build.gradle.kts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,23 @@ android {
2828
}
2929

3030
dependencies {
31-
coreLibraryDesugaring(libs.android.desugarJdkLibs)
31+
implementation(project(":compiler-plugin-lib"))
32+
kotlinCompilerPluginClasspath(project(":compiler-plugin-lib"))
3233

34+
coreLibraryDesugaring(libs.android.desugarJdkLibs)
3335
implementation(libs.androidx.activity)
3436
implementation(libs.androidx.lifecycle.viewModel)
3537
implementation(libs.androidx.lifecycle.runtime)
3638
implementation(libs.androidx.lifecycle.common)
3739
implementation(libs.androidx.constraintlayout)
3840
}
41+
42+
tasks.named("build") {
43+
dependsOn("pluginJar")
44+
}
45+
46+
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile>().configureEach {
47+
kotlinOptions {
48+
freeCompilerArgs += listOf("-Xplugin=${rootProject.projectDir}/compiler-plugin-lib/build/libs/compiler-plugin-lib.jar")
49+
}
50+
}

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import androidx.lifecycle.lifecycleScope
99
import com.stslex.compiler_app.UserToastUtil.sendToastOfUserChanges
1010
import com.stslex.compiler_app.app.R
1111
import com.stslex.compiler_app.model.UserModel
12+
import com.stslex.compiler_plugin_lib.DistinctUntilChangeFun
1213
import kotlinx.coroutines.flow.launchIn
1314
import kotlinx.coroutines.flow.onEach
1415
import java.util.logging.Level
@@ -52,11 +53,13 @@ class MainActivity : ComponentActivity() {
5253
setSecondName(user.secondName)
5354
}
5455

56+
@DistinctUntilChangeFun
5557
private fun setName(name: String) {
5658
logger.log(Level.INFO, "setName: $name")
5759
findViewById<TextView>(R.id.usernameFieldTextView).text = name
5860
}
5961

62+
@DistinctUntilChangeFun
6063
private fun setSecondName(name: String) {
6164
logger.log(Level.INFO, "setSecondName: $name")
6265
findViewById<TextView>(R.id.secondNameFieldTextView).text = name

build.gradle.kts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,17 @@ plugins {
22
alias(libs.plugins.application) apply false
33
alias(libs.plugins.kotlin) apply false
44
alias(libs.plugins.library) apply false
5+
alias(libs.plugins.jetbrains.kotlin.jvm) apply false
56
}
67

78
buildscript {
89
repositories {
910
google()
1011
mavenCentral()
12+
mavenLocal()
1113
}
1214
}
1315

1416
tasks.register(name = "type", type = Delete::class) {
1517
delete(rootProject.projectDir.resolve("build"))
16-
}
18+
}

compiler-plugin-lib/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/build
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
plugins {
2+
`java-library`
3+
alias(libs.plugins.jetbrains.kotlin.jvm)
4+
}
5+
6+
java {
7+
sourceCompatibility = JavaVersion.VERSION_21
8+
targetCompatibility = JavaVersion.VERSION_21
9+
}
10+
11+
kotlin {
12+
explicitApi()
13+
compilerOptions {
14+
jvmTarget = org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_21
15+
}
16+
}
17+
18+
dependencies {
19+
implementation(kotlin("stdlib"))
20+
compileOnly(libs.jetbrains.kotlin.compiler.embeddable)
21+
}
22+
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS")
2+
3+
@Suppress("UnstableApiUsage")
4+
dependencyResolutionManagement {
5+
repositories {
6+
google()
7+
mavenCentral()
8+
}
9+
versionCatalogs {
10+
create("libs") {
11+
from(files("../gradle/libs.versions.toml"))
12+
}
13+
}
14+
}
15+
16+
rootProject.name = "compiler-plugin-lib"
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package com.stslex.compiler_plugin_lib
2+
3+
import java.util.logging.Level
4+
import java.util.logging.Logger
5+
6+
internal object DistinctChangeCache {
7+
8+
private const val TAG = "KotlinCompilerDistinct"
9+
private val logger = Logger.getLogger(TAG)
10+
private val cache = mutableMapOf<String, Pair<List<Any?>, Any?>>()
11+
12+
@JvmStatic
13+
@Suppress("UNCHECKED_CAST")
14+
fun <R> invoke(key: String, args: List<Any?>, body: () -> R): R {
15+
val entry = cache[key]
16+
logger.log(Level.INFO, "memorize key: $key, entry: $entry, args: $args")
17+
18+
if (entry != null && entry.first == args) {
19+
return entry.second as R
20+
}
21+
22+
val result = body()
23+
cache[key] = args to result
24+
return result
25+
}
26+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package com.stslex.compiler_plugin_lib
2+
3+
@Target(AnnotationTarget.FUNCTION)
4+
@Retention(AnnotationRetention.BINARY)
5+
public annotation class DistinctUntilChangeFun
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package com.stslex.compiler_plugin_lib
2+
3+
import com.stslex.compiler_plugin_lib.extensions.DistinctChangeIrGenerationExtension
4+
import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension
5+
import org.jetbrains.kotlin.compiler.plugin.CompilerPluginRegistrar
6+
import org.jetbrains.kotlin.compiler.plugin.ExperimentalCompilerApi
7+
import org.jetbrains.kotlin.config.CompilerConfiguration
8+
9+
@OptIn(ExperimentalCompilerApi::class)
10+
internal class WorkshopCompilerPlugin(
11+
override val supportsK2: Boolean = true
12+
) : CompilerPluginRegistrar() {
13+
14+
override fun ExtensionStorage.registerExtensions(configuration: CompilerConfiguration) {
15+
IrGenerationExtension.registerExtension(DistinctChangeIrGenerationExtension())
16+
}
17+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package com.stslex.compiler_plugin_lib.extensions
2+
3+
import com.stslex.compiler_plugin_lib.transformers.IrFunctionTransformer
4+
import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension
5+
import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
6+
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
7+
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
8+
9+
internal class DistinctChangeIrGenerationExtension : IrGenerationExtension {
10+
11+
override fun generate(
12+
moduleFragment: IrModuleFragment,
13+
pluginContext: IrPluginContext
14+
) {
15+
moduleFragment.transformChildrenVoid(IrFunctionTransformer(pluginContext))
16+
}
17+
}

0 commit comments

Comments
 (0)