Skip to content

Instantly share code, notes, and snippets.

View Morfly's full-sized avatar

Pavlo Stavytskyi Morfly

View GitHub Profile
interface KSVisitor<D, R> {
fun visitNode(node: KSNode, data: D): R
fun visitClassDeclaration(classDeclaration: KSClassDeclaration, data: D): R
fun visitPropertyDeclaration(property: KSPropertyDeclaration, data: D): R
// ~20 more functions
}
class FunctionProcessor(...) : SymbolProcessor {
...
inner class Visitor(private val file: OutputStream) : KSVisitorVoid() {
override fun visitClassDeclaration(classDeclaration: KSClassDeclaration, data: Unit) {
}
override fun visitPropertyDeclaration(property: KSPropertyDeclaration, data: Unit) {
}
package com.morfly
@Function(name = "myAmazingFunction")
interface MyAmazingFunction
fun main() {
println("Hello World!")
}
interface KSNode {
...
fun <D, R> accept(visitor: KSVisitor<D, R>, data: D): R
}
class KSPropertyDeclarationImpl(...) : KSPropertyDeclaration, ... {
...
override fun <D, R> accept(visitor: KSVisitor<D, R>, data: D): R {
return visitor.visitPropertyDeclaration(this, data)
}
}
...
kotlin {
sourceSets {
main {
kotlin.srcDirs(file("$buildDir/generated/ksp/main/kotlin"))
}
}
}
override fun visitClassDeclaration(classDeclaration: KSClassDeclaration, data: Unit) {
if (classDeclaration.classKind != ClassKind.INTERFACE) {
logger.error("Only interface can be annotated with @Function", classDeclaration)
return
}
// Getting the @Function annotation object.
val annotation: KSAnnotation = classDeclaration.annotations.first {
it.shortName.asString() == "Function"
}
override fun visitClassDeclaration(classDeclaration: KSClassDeclaration, data: Unit) {
...
// Getting the list of member properties of the annotated interface.
val properties: Sequence<KSPropertyDeclaration> = classDeclaration.getAllProperties()
.filter { it.validate() }
// Generating function signature.
file += "\n"
if (properties.iterator().hasNext()) {
override fun visitPropertyDeclaration(property: KSPropertyDeclaration, data: Unit) {
// Generating argument name.
val argumentName = property.simpleName.asString()
file += " $argumentName: "
// Generating argument type.
val resolvedType: KSType = property.type.resolve()
file += resolvedType.declaration.qualifiedName?.asString() ?: run {
logger.error("Invalid property type", property)
return
fun visitPropertyDeclaration(...) { ... }
private fun visitTypeArguments(typeArguments: List<KSTypeArgument>) {
if (typeArguments.isNotEmpty()) {
file += "<"
typeArguments.forEachIndexed { i, arg ->
visitTypeArgument(arg, data = Unit)
if (i < typeArguments.lastIndex) file += ", "
}
file += ">"