Created
February 2, 2020 22:09
-
-
Save LordRaydenMK/e7f6eddffb4d71de3c6b2534ff240619 to your computer and use it in GitHub Desktop.
Kotlin compiler plugin built with arrow-meta. Generates equals, hashCode and toString for classes annotated with @valueclass
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@Retention(AnnotationRetention.BINARY) | |
@Target(AnnotationTarget.CLASS) | |
annotation class ValueClass |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package io.arrowkt.example | |
import arrow.meta.Meta | |
import arrow.meta.Plugin | |
import arrow.meta.invoke | |
import arrow.meta.phases.analysis.ElementScope | |
import arrow.meta.quotes.Transform | |
import arrow.meta.quotes.classDeclaration | |
import arrow.meta.quotes.classorobject.ClassDeclaration | |
import arrow.meta.quotes.nameddeclaration.stub.typeparameterlistowner.NamedFunction | |
import org.jetbrains.kotlin.psi.KtClass | |
val Meta.valueClass: Plugin | |
get() = | |
"valueClass" { | |
meta( | |
classDeclaration(::isValueClass) { c: KtClass -> | |
Transform.replace( | |
replacing = c, | |
newDeclaration = | |
"""| | |
|$kind $name $`(params)` { | |
| | |
| ${overrideHashCode(this)} | |
| | |
| ${overrideEquals(this)} | |
| | |
| ${overrideToString(this)} | |
|}""".`class` | |
) | |
} | |
) | |
} | |
private fun isValueClass(ktClass: KtClass): Boolean = | |
!ktClass.isData() && | |
ktClass.annotationEntries.any { it.text.matches(Regex("@(arrow\\.)?ValueClass")) } && | |
ktClass.primaryConstructorParameters.isNotEmpty() && | |
ktClass.primaryConstructorParameters.all { !it.isMutable } && | |
ktClass.typeParameters.isEmpty() | |
private fun ElementScope.overrideHashCode(classScope: ClassDeclaration): NamedFunction { | |
val hashCodeArs = classScope.`(params)`.value.joinToString { it.name!! } | |
val hashCode = "java.util.Objects.hash($hashCodeArs)" | |
return """override fun hashCode(): Int = $hashCode""".function | |
} | |
private fun ElementScope.overrideEquals(classScope: ClassDeclaration): NamedFunction { | |
val fieldEquality = classScope.`(params)` | |
.value.joinToString( | |
separator = "&&" | |
) { "java.util.Objects.equals(this.${it.name}, other.${it.name})" } | |
return """| | |
|override fun equals(other: Any?): Boolean { | |
|if (this === other) return true | |
|if (javaClass != other?.javaClass) return false | |
|other as ${classScope.name} | |
|return $fieldEquality | |
|}""".trimMargin().function | |
} | |
private fun ElementScope.overrideToString(classScope: ClassDeclaration): NamedFunction { | |
val fields = classScope.`(params)`.value.joinToString { "${it.name} = '$${it.name}'" } | |
return """override fun toString(): String = "${classScope.name}($fields)"""".function | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment