diff options
author | Linnea Gräf <nea@nea.moe> | 2024-05-07 20:26:04 +0200 |
---|---|---|
committer | Linnea Gräf <nea@nea.moe> | 2024-05-07 20:26:04 +0200 |
commit | 8f3cc34740fcfe1572d23c8f1c1db1a309217b84 (patch) | |
tree | 1a4d7922b8ec1785e0c1f52fcdf85f3e33f16859 /symbols/src/main/kotlin | |
parent | 0cb976ce078b9b0217c9a8e5763638764d89a31e (diff) | |
download | Firmament-8f3cc34740fcfe1572d23c8f1c1db1a309217b84.tar.gz Firmament-8f3cc34740fcfe1572d23c8f1c1db1a309217b84.tar.bz2 Firmament-8f3cc34740fcfe1572d23c8f1c1db1a309217b84.zip |
Add @Subscribe annotation
[no changelog]
Diffstat (limited to 'symbols/src/main/kotlin')
-rw-r--r-- | symbols/src/main/kotlin/Subscribe.kt | 12 | ||||
-rw-r--r-- | symbols/src/main/kotlin/process/SubscribeAnnotationProcessor.kt | 116 |
2 files changed, 128 insertions, 0 deletions
diff --git a/symbols/src/main/kotlin/Subscribe.kt b/symbols/src/main/kotlin/Subscribe.kt new file mode 100644 index 0000000..e7a7bf4 --- /dev/null +++ b/symbols/src/main/kotlin/Subscribe.kt @@ -0,0 +1,12 @@ +/* + * SPDX-FileCopyrightText: 2024 Linnea Gräf <nea@nea.moe> + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +package moe.nea.firmament.annotations + +@Target(AnnotationTarget.FUNCTION) +@Retention(AnnotationRetention.SOURCE) +annotation class Subscribe + diff --git a/symbols/src/main/kotlin/process/SubscribeAnnotationProcessor.kt b/symbols/src/main/kotlin/process/SubscribeAnnotationProcessor.kt new file mode 100644 index 0000000..be817ce --- /dev/null +++ b/symbols/src/main/kotlin/process/SubscribeAnnotationProcessor.kt @@ -0,0 +1,116 @@ +/* + * SPDX-FileCopyrightText: 2024 Linnea Gräf <nea@nea.moe> + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +package moe.nea.firmament.annotations.process + +import com.google.auto.service.AutoService +import com.google.devtools.ksp.processing.CodeGenerator +import com.google.devtools.ksp.processing.Dependencies +import com.google.devtools.ksp.processing.KSPLogger +import com.google.devtools.ksp.processing.Resolver +import com.google.devtools.ksp.processing.SymbolProcessor +import com.google.devtools.ksp.processing.SymbolProcessorEnvironment +import com.google.devtools.ksp.processing.SymbolProcessorProvider +import com.google.devtools.ksp.symbol.ClassKind +import com.google.devtools.ksp.symbol.KSAnnotated +import com.google.devtools.ksp.symbol.KSClassDeclaration +import com.google.devtools.ksp.symbol.KSFunctionDeclaration +import com.google.devtools.ksp.symbol.KSType +import com.google.devtools.ksp.symbol.Nullability +import com.google.devtools.ksp.validate +import java.text.SimpleDateFormat +import java.util.Date +import moe.nea.firmament.annotations.Subscribe + +class SubscribeAnnotationProcessor( + val logger: KSPLogger, + val codeGenerator: CodeGenerator, +) : SymbolProcessor { + override fun finish() { + val dependencies = Dependencies( + aggregating = true, + *subscriptions.mapTo(mutableSetOf()) { it.parent.containingFile!! }.toTypedArray()) + val subscriptionsFile = + codeGenerator + .createNewFile(dependencies, "moe.nea.firmament.annotations.generated", "AllSubscriptions") + .bufferedWriter() + subscriptionsFile.apply { + appendLine("// This file is @generated by SubscribeAnnotationProcessor at ${SimpleDateFormat("yyyy-MM-dd HH:mm:ss z").format( + Date())}") + appendLine("// Do not edit") + appendLine("package moe.nea.firmament.annotations.generated") + appendLine() + appendLine("import moe.nea.firmament.events.subscription.*") + appendLine() + appendLine("object AllSubscriptions {") + appendLine(" fun provideSubscriptions(addSubscription: (Subscription<*>) -> Unit) {") + for (subscription in subscriptions) { + val owner = subscription.parent.qualifiedName!!.asString() + val method = subscription.child.simpleName.asString() + val type = subscription.type.declaration.qualifiedName!!.asString() + appendLine(" addSubscription(Subscription<$type>(") + appendLine(" ${owner},") + appendLine(" ${owner}::${method},") + appendLine(" ${type}))") + } + appendLine(" }") + appendLine("}") + } + subscriptionsFile.close() + } + + data class Subscription( + val parent: KSClassDeclaration, + val child: KSFunctionDeclaration, + val type: KSType, + ) + + val subscriptions = mutableListOf<Subscription>() + + fun processCandidates(list: List<KSAnnotated>) { + for (element in list) { + if (element !is KSFunctionDeclaration) { + logger.error("@Subscribe annotation on a not-function", element) + continue + } + if (element.isAbstract) { + logger.error("@Subscribe annotation on an abstract function", element) + continue + } + val parent = element.parentDeclaration + if (parent !is KSClassDeclaration || parent.isCompanionObject || parent.classKind != ClassKind.OBJECT) { + logger.error("@Subscribe on a non-object", element) + continue + } + val param = element.parameters.singleOrNull() + if (param == null) { + logger.error("@Subscribe annotated functions need to take exactly one parameter", element) + continue + } + val type = param.type.resolve() + if (type.nullability != Nullability.NOT_NULL) { + logger.error("@Subscribe annotated functions cannot take a nullable event", element) + continue + } + subscriptions.add(Subscription(parent, element, type)) + } + } + + override fun process(resolver: Resolver): List<KSAnnotated> { + val candidates = resolver.getSymbolsWithAnnotation(Subscribe::class.qualifiedName!!).toList() + val valid = candidates.filter { it.validate() } + val invalid = candidates.filter { !it.validate() } + processCandidates(valid) + return invalid + } +} + +@AutoService(SymbolProcessorProvider::class) +class SubscribeAnnotationProcessorProvider : SymbolProcessorProvider { + override fun create(environment: SymbolProcessorEnvironment): SymbolProcessor { + return SubscribeAnnotationProcessor(environment.logger, environment.codeGenerator) + } +} |