Add @Subscribe annotation
[no changelog]
This commit is contained in:
19
symbols/build.gradle.kts
Normal file
19
symbols/build.gradle.kts
Normal file
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Linnea Gräf <nea@nea.moe>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
plugins {
|
||||
kotlin("jvm")
|
||||
id("com.google.devtools.ksp")
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
ksp("dev.zacsweers.autoservice:auto-service-ksp:1.1.0")
|
||||
implementation("com.google.auto.service:auto-service-annotations:1.1.1")
|
||||
implementation("com.google.devtools.ksp:symbol-processing-api:1.9.23-1.0.20")
|
||||
}
|
||||
12
symbols/src/main/kotlin/Subscribe.kt
Normal file
12
symbols/src/main/kotlin/Subscribe.kt
Normal file
@@ -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
|
||||
|
||||
116
symbols/src/main/kotlin/process/SubscribeAnnotationProcessor.kt
Normal file
116
symbols/src/main/kotlin/process/SubscribeAnnotationProcessor.kt
Normal file
@@ -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)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user