diff --git a/Readme.md b/Readme.md index a2a52b0..f0a20bf 100644 --- a/Readme.md +++ b/Readme.md @@ -4,7 +4,7 @@ [![jCenter](https://img.shields.io/badge/Apache-2.0-green.svg )](https://github.com/Foso/KotlinReactNativeMpp/blob/master/LICENSE) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](http://makeapullrequest.com) -[![jCenter](https://img.shields.io/badge/Kotlin-1.9.10-green.svg +[![jCenter](https://img.shields.io/badge/Kotlin-2.0.0-green.svg )](https://github.com/Foso/Sheasy/blob/master/LICENSE) diff --git a/compiler-plugin/build.gradle.kts b/compiler-plugin/build.gradle.kts index 69d5a44..6cf4e39 100644 --- a/compiler-plugin/build.gradle.kts +++ b/compiler-plugin/build.gradle.kts @@ -2,8 +2,8 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompilationTask import org.jetbrains.kotlin.gradle.tasks.KotlinCompile plugins { - kotlin("jvm") version("1.9.23") - kotlin("kapt") version("1.9.23") + kotlin("jvm") version("2.0.0") + kotlin("kapt") version("2.0.0") id("com.vanniktech.maven.publish") version("0.23.1") `maven-publish` signing @@ -31,10 +31,10 @@ val autoService = "1.1.1" dependencies { compileOnly("com.google.auto.service:auto-service:$autoService") kapt("com.google.auto.service:auto-service:$autoService") - compileOnly("org.jetbrains.kotlin:kotlin-compiler-embeddable:1.9.23") - testImplementation("dev.zacsweers.kctfork:core:0.2.1") + compileOnly("org.jetbrains.kotlin:kotlin-compiler-embeddable:2.0.0") + testImplementation("dev.zacsweers.kctfork:core:0.4.1") testImplementation("junit:junit:4.13.2") - testImplementation("com.google.truth:truth:1.1.5") + testImplementation("com.google.truth:truth:1.4.2") testImplementation(kotlin("reflect")) } diff --git a/compiler-plugin/src/main/java/de/jensklingenberg/CommonComponentRegistrar.kt b/compiler-plugin/src/main/java/de/jensklingenberg/CommonComponentRegistrar.kt index eae51a3..8731151 100644 --- a/compiler-plugin/src/main/java/de/jensklingenberg/CommonComponentRegistrar.kt +++ b/compiler-plugin/src/main/java/de/jensklingenberg/CommonComponentRegistrar.kt @@ -1,6 +1,8 @@ package de.jensklingenberg import com.google.auto.service.AutoService +import de.jensklingenberg.transform.ExampleIrGenerationExtension +import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys import org.jetbrains.kotlin.cli.common.config.kotlinSourceRoots import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity @@ -26,5 +28,10 @@ class CommonComponentRegistrar : CompilerPluginRegistrar() { "*** Hello from ***" + it.path ) } + + val logging = true + IrGenerationExtension.registerExtension( + ExampleIrGenerationExtension(DebugLogger(logging, messageCollector)) + ) } } diff --git a/compiler-plugin/src/main/java/de/jensklingenberg/DebugLogger.kt b/compiler-plugin/src/main/java/de/jensklingenberg/DebugLogger.kt new file mode 100644 index 0000000..ec3d478 --- /dev/null +++ b/compiler-plugin/src/main/java/de/jensklingenberg/DebugLogger.kt @@ -0,0 +1,12 @@ +package de.jensklingenberg + +import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity +import org.jetbrains.kotlin.cli.common.messages.MessageCollector + +internal data class DebugLogger(val debug: Boolean, val messageCollector: MessageCollector) { + fun log(message: String) { + if (debug) { + messageCollector.report(CompilerMessageSeverity.INFO, message) + } + } +} \ No newline at end of file diff --git a/compiler-plugin/src/main/java/de/jensklingenberg/transform/CreateFuncTransformer.kt b/compiler-plugin/src/main/java/de/jensklingenberg/transform/CreateFuncTransformer.kt new file mode 100644 index 0000000..92e6851 --- /dev/null +++ b/compiler-plugin/src/main/java/de/jensklingenberg/transform/CreateFuncTransformer.kt @@ -0,0 +1,105 @@ +package de.jensklingenberg.transform + +import de.jensklingenberg.DebugLogger +import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext +import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext +import org.jetbrains.kotlin.ir.expressions.IrCall +import org.jetbrains.kotlin.ir.expressions.IrExpression +import org.jetbrains.kotlin.ir.expressions.impl.IrConstructorCallImpl +import org.jetbrains.kotlin.ir.types.classFqName +import org.jetbrains.kotlin.ir.types.defaultType +import org.jetbrains.kotlin.ir.types.impl.originalKotlinType +import org.jetbrains.kotlin.ir.util.constructors +import org.jetbrains.kotlin.name.ClassId +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.name.Name + +/** + * Transform create() to create(_TestApiIProvider()) + */ +internal class CreateFuncTransformer( + private val pluginContext: IrPluginContext, + private val debugLogger: DebugLogger +) : IrElementTransformerVoidWithContext() { + + companion object { + + fun ERROR_IMPL_NOT_FOUND(implName: String) = + "${implName} not found" + + private const val EXAMPLE_PACKAGE = "sample" + private const val EXAMPLE_CREATE = "create" + + } + + override fun visitExpression(expression: IrExpression): IrExpression { + + //Find exampleKtorfit.create() + (expression as? IrCall)?.let { irCall -> + if (irCall.typeArgumentsCount > 0) { + + if (!expression.symbol.owner.symbol.toString().contains(EXAMPLE_PACKAGE)) { + return expression + } + if (expression.symbol.owner.name.asString() != EXAMPLE_CREATE) { + return expression + } + + if (expression.getValueArgument(0) != null) { + return expression + } + + //Get T from create() + val argumentType = irCall.getTypeArgument(0) ?: return expression + val classFqName = argumentType.classFqName + + //if (!argumentType.isInterface()) throw IllegalStateException(ERROR_TYPE_ARGUMENT_NOT_INTERFACE(argumentType.originalKotlinType.toString())) + + if (classFqName == null) { + throw IllegalStateException(ERROR_IMPL_NOT_FOUND(argumentType.originalKotlinType.toString())) + } + + val packageName = classFqName.packageName + val className = classFqName.shortName().toString() + val providerClassName = "_$className" + "Provider" + + //Find the class _TestApiProvider + val implClassSymbol = pluginContext.referenceClass( + ClassId( + FqName(packageName), + Name.identifier(providerClassName) + ) + ) ?: throw IllegalStateException(ERROR_IMPL_NOT_FOUND(providerClassName)) + + val newConstructor = implClassSymbol.constructors.first() + + //Create the constructor call for _ExampleApiImpl() + val newCall = IrConstructorCallImpl( + 0, + 0, + type = implClassSymbol.defaultType, + symbol = newConstructor, + 0, + 0, + 0, + null + ) + + //Set _ExampleApiImpl() as argument for create() + irCall.putValueArgument(0, newCall) + debugLogger.log( + "Transformed " + argumentType.originalKotlinType.toString() + " to _$className" + "Impl" + ) + return super.visitExpression(irCall) + } + } + return super.visitExpression(expression) + } + +} + + +private val FqName?.packageName: String + get() { + return this.toString().substringBeforeLast(".") + } diff --git a/compiler-plugin/src/main/java/de/jensklingenberg/transform/ElementTransformer.kt b/compiler-plugin/src/main/java/de/jensklingenberg/transform/ElementTransformer.kt new file mode 100644 index 0000000..6a3f3e7 --- /dev/null +++ b/compiler-plugin/src/main/java/de/jensklingenberg/transform/ElementTransformer.kt @@ -0,0 +1,42 @@ +package de.jensklingenberg.transform + +import de.jensklingenberg.DebugLogger +import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext +import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext +import org.jetbrains.kotlin.ir.IrStatement +import org.jetbrains.kotlin.ir.declarations.* +import org.jetbrains.kotlin.ir.expressions.IrCall +import org.jetbrains.kotlin.ir.expressions.IrExpression +import org.jetbrains.kotlin.ir.expressions.IrFunctionExpression + +internal class ElementTransformer( + private val pluginContext: IrPluginContext, + private val debugLogger: DebugLogger +) : IrElementTransformerVoidWithContext() { + + override fun visitValueParameterNew(declaration: IrValueParameter): IrStatement { + declaration.transform(CreateFuncTransformer(pluginContext,debugLogger), null) + return super.visitValueParameterNew(declaration) + } + + override fun visitPropertyNew(declaration: IrProperty): IrStatement { + declaration.transform(CreateFuncTransformer(pluginContext, debugLogger), null) + return super.visitPropertyNew(declaration) + } + + override fun visitCall(expression: IrCall): IrExpression { + expression.transform(CreateFuncTransformer(pluginContext, debugLogger), null) + return super.visitCall(expression) + } + + override fun visitVariable(declaration: IrVariable): IrStatement { + declaration.transform(CreateFuncTransformer(pluginContext, debugLogger), null) + return super.visitVariable(declaration) + } + + + override fun visitFunctionExpression(expression: IrFunctionExpression): IrExpression { + expression.transform(CreateFuncTransformer(pluginContext, debugLogger), null) + return super.visitFunctionExpression(expression) + } +} \ No newline at end of file diff --git a/compiler-plugin/src/main/java/de/jensklingenberg/transform/ExampleIrGenerationExtension.kt b/compiler-plugin/src/main/java/de/jensklingenberg/transform/ExampleIrGenerationExtension.kt new file mode 100644 index 0000000..710135f --- /dev/null +++ b/compiler-plugin/src/main/java/de/jensklingenberg/transform/ExampleIrGenerationExtension.kt @@ -0,0 +1,12 @@ +package de.jensklingenberg.transform + +import de.jensklingenberg.DebugLogger +import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension +import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext +import org.jetbrains.kotlin.ir.declarations.IrModuleFragment + +internal class ExampleIrGenerationExtension(private val debugLogger: DebugLogger) : IrGenerationExtension { + override fun generate(moduleFragment: IrModuleFragment, pluginContext: IrPluginContext) { + moduleFragment.transform(ElementTransformer(pluginContext,debugLogger), null) + } +} \ No newline at end of file diff --git a/gradle-plugin/build.gradle.kts b/gradle-plugin/build.gradle.kts index 3b342b8..e8fce68 100644 --- a/gradle-plugin/build.gradle.kts +++ b/gradle-plugin/build.gradle.kts @@ -1,6 +1,6 @@ plugins { - kotlin("jvm") version("1.9.10") - kotlin("kapt") version("1.9.10") + kotlin("jvm") version("2.0.0") + kotlin("kapt") version("2.0.0") id("java-gradle-plugin") `maven-publish` } @@ -19,7 +19,7 @@ allprojects { } } dependencies { - implementation("org.jetbrains.kotlin:kotlin-gradle-plugin-api:1.9.21") + implementation("org.jetbrains.kotlin:kotlin-gradle-plugin-api:2.0.0") } gradlePlugin { diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f0be209..e7f9cf4 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,2 +1,2 @@ [versions] -kotlin = "1.9.10" \ No newline at end of file +kotlin = "2.0.0" \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 978e634..4cf24ea 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip diff --git a/lib/src/commonMain/kotlin/sample/Sample.kt b/lib/src/commonMain/kotlin/sample/Sample.kt index 8cd23de..4cfa5b6 100644 --- a/lib/src/commonMain/kotlin/sample/Sample.kt +++ b/lib/src/commonMain/kotlin/sample/Sample.kt @@ -8,4 +8,18 @@ expect object Platform { val name: String } -fun hello(): String = "Hello from ${Platform.name}" \ No newline at end of file +fun hello(): String = "Hello from ${Platform.name}" + +class _MyTestProvider : MyTest{ + override fun print(){ + println("Hello from _MyTestProvider") + } +} + +interface MyTest{ + fun print() +} + +fun create(myTestProvider: MyTest? = null): MyTest { + return myTestProvider!! +} \ No newline at end of file diff --git a/lib/src/jvmMain/kotlin/sample/SampleJvm.kt b/lib/src/jvmMain/kotlin/sample/SampleJvm.kt index 2771286..9221341 100644 --- a/lib/src/jvmMain/kotlin/sample/SampleJvm.kt +++ b/lib/src/jvmMain/kotlin/sample/SampleJvm.kt @@ -9,5 +9,9 @@ actual object Platform { } fun main() { - + /** + * The compiler plugin will replace this with create(_MyTestProvider) + */ + val myTest = create() + myTest.print() } \ No newline at end of file