From 6e43dc4569e7525fe5adb02aef3e8927afa31227 Mon Sep 17 00:00:00 2001 From: Alejandro Serrano Date: Wed, 12 Jan 2022 12:04:27 +0100 Subject: [PATCH] [Optics] Show error for generic classes in KSP plug-in --- .../arrow-optics-ksp-plugin/build.gradle.kts | 46 +++++++++---------- .../arrow/optics/plugin/OpticsProcessor.kt | 14 ++++-- .../arrow/optics/plugin/internals/errors.kt | 18 ++++++-- .../kotlin/arrow/optics/plugin/LensTests.kt | 31 +++++++++++++ 4 files changed, 79 insertions(+), 30 deletions(-) diff --git a/arrow-libs/optics/arrow-optics-ksp-plugin/build.gradle.kts b/arrow-libs/optics/arrow-optics-ksp-plugin/build.gradle.kts index 3afe1f3580b..df4b079b417 100644 --- a/arrow-libs/optics/arrow-optics-ksp-plugin/build.gradle.kts +++ b/arrow-libs/optics/arrow-optics-ksp-plugin/build.gradle.kts @@ -1,5 +1,5 @@ plugins { - id(libs.plugins.kotlin.jvm.get().pluginId) + id(libs.plugins.kotlin.multiplatform.get().pluginId) alias(libs.plugins.arrowGradleConfig.kotlin) alias(libs.plugins.arrowGradleConfig.publish) } @@ -11,27 +11,27 @@ kotlin { apply(from = property("TEST_COVERAGE")) apply(from = property("ANIMALSNIFFER_MPP")) -dependencies { - implementation(libs.ksp) - - testImplementation(libs.kotlin.stdlibJDK8) - testImplementation(libs.junitJupiter) - testImplementation(libs.junitJupiterEngine) - testImplementation(libs.assertj) - testImplementation(libs.classgraph) - testImplementation(libs.kotlinCompileTesting) { - exclude( - group = libs.classgraph.get().module.group, - module = libs.classgraph.get().module.name - ) - exclude( - group = libs.kotlin.stdlibJDK8.get().module.group, - module = libs.kotlin.stdlibJDK8.get().module.name - ) +kotlin { + sourceSets { + jvmMain { + dependencies { + implementation(libs.ksp) + } + } + jvmTest { + dependencies { + implementation(libs.kotlin.stdlibJDK8) + implementation(libs.junitJupiter) + implementation(libs.junitJupiterEngine) + implementation(libs.assertj) + implementation(libs.classgraph) + implementation(libs.kotlinCompileTesting) + implementation(libs.kotlinCompileTestingKsp) + runtimeOnly(projects.arrowOpticsKspPlugin) + runtimeOnly(projects.arrowAnnotations) + runtimeOnly(projects.arrowCore) + runtimeOnly(projects.arrowOptics) + } + } } - testImplementation(libs.kotlinCompileTestingKsp) - testRuntimeOnly(projects.arrowOpticsKspPlugin) - testRuntimeOnly(projects.arrowAnnotations) - testRuntimeOnly(projects.arrowCore) - testRuntimeOnly(projects.arrowOptics) } diff --git a/arrow-libs/optics/arrow-optics-ksp-plugin/src/jvmMain/kotlin/arrow/optics/plugin/OpticsProcessor.kt b/arrow-libs/optics/arrow-optics-ksp-plugin/src/jvmMain/kotlin/arrow/optics/plugin/OpticsProcessor.kt index 2573547efb6..63dac0b4695 100644 --- a/arrow-libs/optics/arrow-optics-ksp-plugin/src/jvmMain/kotlin/arrow/optics/plugin/OpticsProcessor.kt +++ b/arrow-libs/optics/arrow-optics-ksp-plugin/src/jvmMain/kotlin/arrow/optics/plugin/OpticsProcessor.kt @@ -7,6 +7,7 @@ import arrow.optics.plugin.internals.join import arrow.optics.plugin.internals.noCompanion import arrow.optics.plugin.internals.otherClassTypeErrorMessage import arrow.optics.plugin.internals.snippets +import arrow.optics.plugin.internals.typeParametersErrorMessage import com.google.devtools.ksp.processing.CodeGenerator import com.google.devtools.ksp.processing.Dependencies import com.google.devtools.ksp.processing.KSPLogger @@ -36,14 +37,21 @@ class OpticsProcessor(private val codegen: CodeGenerator, private val logger: KS return } + // check that it does not have type arguments + if (klass.typeParameters.isNotEmpty()) { + logger.error(klass.simpleName.asString().typeParametersErrorMessage, klass) + return + } + // check that the companion object exists - val companion = klass.companionObject - if (companion == null) { + if (klass.companionObject == null) { logger.error(klass.simpleName.asString().noCompanion, klass) return } - adt(klass, logger).snippets().groupBy(Snippet::fqName).values.map(List::join).forEach { + val adts = adt(klass, logger) + val snippets = adts.snippets() + snippets.groupBy(Snippet::fqName).values.map(List::join).forEach { val writer = codegen .createNewFile( diff --git a/arrow-libs/optics/arrow-optics-ksp-plugin/src/jvmMain/kotlin/arrow/optics/plugin/internals/errors.kt b/arrow-libs/optics/arrow-optics-ksp-plugin/src/jvmMain/kotlin/arrow/optics/plugin/internals/errors.kt index 67c282ba2ce..1c9b65fd979 100644 --- a/arrow-libs/optics/arrow-optics-ksp-plugin/src/jvmMain/kotlin/arrow/optics/plugin/internals/errors.kt +++ b/arrow-libs/optics/arrow-optics-ksp-plugin/src/jvmMain/kotlin/arrow/optics/plugin/internals/errors.kt @@ -5,8 +5,14 @@ val String.otherClassTypeErrorMessage """ |$this cannot be annotated with @optics | ^ - | - |Only data and sealed classes can be annotated with @optics annotation""".trimMargin() + |Only data and sealed classes can be annotated with @optics""".trimMargin() + +val String.typeParametersErrorMessage + get() = + """ + |$this cannot be annotated with @optics + | ^ + |Only classes with no type parameters can be annotated with @optics""".trimMargin() val String.lensErrorMessage get() = @@ -56,10 +62,14 @@ val String.dslErrorMessage get() = """ |Cannot generate DSL (arrow.optics.BoundSetter) for $this - | ^ + | ^ |arrow.optics.OpticsTarget.DSL is an invalid @optics argument for $this. |It is only valid for data classes and sealed classes. """.trimMargin() val String.noCompanion - get() = "@optics annotated class $this needs to declare companion object." + get() = + """ + |$this must declare a companion object + | ^ + |A companion object is required for the generated optics""".trimMargin() diff --git a/arrow-libs/optics/arrow-optics-ksp-plugin/src/jvmTest/kotlin/arrow/optics/plugin/LensTests.kt b/arrow-libs/optics/arrow-optics-ksp-plugin/src/jvmTest/kotlin/arrow/optics/plugin/LensTests.kt index aae6eb67c0c..fc44c0b60fd 100755 --- a/arrow-libs/optics/arrow-optics-ksp-plugin/src/jvmTest/kotlin/arrow/optics/plugin/LensTests.kt +++ b/arrow-libs/optics/arrow-optics-ksp-plugin/src/jvmTest/kotlin/arrow/optics/plugin/LensTests.kt @@ -1,5 +1,6 @@ package arrow.optics.plugin +import arrow.optics.plugin.internals.typeParametersErrorMessage import org.junit.jupiter.api.Test class LensTests { @@ -32,4 +33,34 @@ class LensTests { |val r = i != null """.evals("r" to true) } + + @Test + fun `Lenses which mentions imported elements`() { + """ + |$imports + |import kotlin.time.Duration + | + |@optics + |data class OpticsTest(val time: Duration) { + | companion object + |} + | + |val i: Lens = OpticsTest.time + |val r = i != null + """.evals("r" to true) + } + + @Test + fun `Lenses which mentions type arguments`() { + """ + |$imports + |@optics + |data class OpticsTest(val field: A) { + | companion object + |} + | + |val i: Lens = OpticsTest.time + |val r = i != null + """.failsWith { it.contains("OpticsTest".typeParametersErrorMessage) } + } }