aboutsummaryrefslogtreecommitdiff
path: root/annotations
diff options
context:
space:
mode:
authorRoman / Linnea Gräf <roman.graef@gmail.com>2023-01-25 19:43:51 +0100
committerGitHub <noreply@github.com>2023-01-25 19:43:51 +0100
commitf1a5ba28e92da4f46b39da27277b1c8b7a6ec4bb (patch)
treef8ad2c2ab2f859446345e189e62007b3e28b44c0 /annotations
parentf1ce88fb8e98b41a10ba374d32cb312b949ba8ef (diff)
downloadNotEnoughUpdates-f1a5ba28e92da4f46b39da27277b1c8b7a6ec4bb.tar.gz
NotEnoughUpdates-f1a5ba28e92da4f46b39da27277b1c8b7a6ec4bb.tar.bz2
NotEnoughUpdates-f1a5ba28e92da4f46b39da27277b1c8b7a6ec4bb.zip
Annotation registering (and also some comptime performance) (#554)
Diffstat (limited to 'annotations')
-rw-r--r--annotations/build.gradle.kts44
-rw-r--r--annotations/src/main/kotlin/io/github/moulberry/notenoughupdates/autosubscribe/NEUAutoSubscribe.kt24
-rw-r--r--annotations/src/main/kotlin/io/github/moulberry/notenoughupdates/autosubscribe/NEUAutoSymbolProcessor.kt165
-rw-r--r--annotations/src/main/kotlin/io/github/moulberry/notenoughupdates/autosubscribe/NEUAutoSymbolProcessorProvider.kt30
-rw-r--r--annotations/src/main/kotlin/io/github/moulberry/notenoughupdates/autosubscribe/NEUEventSubscriber.kt34
-rw-r--r--annotations/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider20
6 files changed, 317 insertions, 0 deletions
diff --git a/annotations/build.gradle.kts b/annotations/build.gradle.kts
new file mode 100644
index 00000000..c9e13173
--- /dev/null
+++ b/annotations/build.gradle.kts
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2023 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+plugins {
+ kotlin("jvm")
+ java
+}
+
+repositories {
+ mavenCentral()
+}
+
+tasks.withType<JavaCompile> {
+ if (JavaVersion.current().isJava9Compatible) {
+ options.release.set(8)
+ }
+}
+
+dependencies {
+ implementation(kotlin("stdlib-jdk8"))
+ implementation("com.google.devtools.ksp:symbol-processing-api:1.8.0-1.0.8")
+ implementation("com.squareup:kotlinpoet:1.12.0")
+ implementation("com.squareup:kotlinpoet-ksp:1.12.0")
+}
+
+
+
+
diff --git a/annotations/src/main/kotlin/io/github/moulberry/notenoughupdates/autosubscribe/NEUAutoSubscribe.kt b/annotations/src/main/kotlin/io/github/moulberry/notenoughupdates/autosubscribe/NEUAutoSubscribe.kt
new file mode 100644
index 00000000..1ba6be99
--- /dev/null
+++ b/annotations/src/main/kotlin/io/github/moulberry/notenoughupdates/autosubscribe/NEUAutoSubscribe.kt
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2023 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.autosubscribe
+
+@Retention(AnnotationRetention.SOURCE)
+@Target(AnnotationTarget.CLASS)
+annotation class NEUAutoSubscribe
diff --git a/annotations/src/main/kotlin/io/github/moulberry/notenoughupdates/autosubscribe/NEUAutoSymbolProcessor.kt b/annotations/src/main/kotlin/io/github/moulberry/notenoughupdates/autosubscribe/NEUAutoSymbolProcessor.kt
new file mode 100644
index 00000000..157749d0
--- /dev/null
+++ b/annotations/src/main/kotlin/io/github/moulberry/notenoughupdates/autosubscribe/NEUAutoSymbolProcessor.kt
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2023 Linnea Gräf
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.autosubscribe
+
+import com.google.devtools.ksp.getDeclaredFunctions
+import com.google.devtools.ksp.getDeclaredProperties
+import com.google.devtools.ksp.processing.CodeGenerator
+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.symbol.ClassKind
+import com.google.devtools.ksp.symbol.KSAnnotated
+import com.google.devtools.ksp.symbol.KSClassDeclaration
+import com.google.devtools.ksp.symbol.Modifier
+import com.google.devtools.ksp.validate
+import com.squareup.kotlinpoet.FileSpec
+import com.squareup.kotlinpoet.FunSpec
+import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy
+import com.squareup.kotlinpoet.TypeSpec
+import com.squareup.kotlinpoet.asTypeName
+import com.squareup.kotlinpoet.ksp.toClassName
+import com.squareup.kotlinpoet.ksp.writeTo
+import java.util.function.Consumer
+import java.util.function.Supplier
+
+internal class NEUAutoSymbolProcessor(val codeGenerator: CodeGenerator, val logger: KSPLogger) : SymbolProcessor {
+ fun collectSubscribers(elements: List<KSAnnotated>): List<NEUEventSubscriber> = buildList {
+ for (element in elements) {
+ if (element !is KSClassDeclaration) {
+ logger.error("@NEUAutoSubscribe is only valid on class or object declarations", element)
+ continue
+ }
+ if (element.typeParameters.isNotEmpty()) {
+ logger.error("@NEUAutoSubscribe is not valid on generic classes", element)
+ continue
+ }
+ val name = element.qualifiedName
+ if (name == null) {
+ logger.error("@NEUAutoSubscribe could not find name", element)
+ continue
+ }
+ when (element.classKind) {
+ ClassKind.CLASS -> {
+ val instanceGetter = element.getDeclaredFunctions().find {
+ it.simpleName.asString() == "getInstance"
+ }
+ val instanceVariable = element.getDeclaredProperties().find {
+ it.simpleName.asString() == "INSTANCE"
+ }
+ if (instanceGetter != null) {
+ val returnType = instanceGetter.returnType
+ if (returnType == null || !element.asStarProjectedType().isAssignableFrom(returnType.resolve())) {
+ logger.error(
+ "getInstance() does not have the expected return type ${element.asStarProjectedType()}",
+ instanceGetter
+ )
+ continue
+ }
+ add(NEUEventSubscriber(InvocationKind.GET_INSTANCE, element))
+ } else if (instanceVariable != null) {
+ val variableType = instanceVariable.type
+ if (!element.asStarProjectedType().isAssignableFrom(variableType.resolve())) {
+ logger.error(
+ "INSTANCE does not have expected type ${element.asStarProjectedType()}",
+ instanceVariable
+ )
+ continue
+ }
+ add(NEUEventSubscriber(InvocationKind.ACCESS_INSTANCE, element))
+ } else {
+ add(NEUEventSubscriber(InvocationKind.DEFAULT_CONSTRUCTOR, element))
+ }
+ }
+
+ ClassKind.OBJECT -> {
+ add(NEUEventSubscriber(InvocationKind.OBJECT_INSTANCE, element))
+ }
+
+ else -> {
+ logger.error(
+ "@NEUAutoSubscribe is only valid on classes and objects, not on ${element.classKind}",
+ element
+ )
+ continue
+ }
+ }
+ }
+
+ }
+
+ val subscribers = mutableListOf<NEUEventSubscriber>()
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val candidates = resolver.getSymbolsWithAnnotation(NEUAutoSubscribe::class.qualifiedName!!).toList()
+ val valid = candidates.filter { it.validate() }
+ val invalid = candidates.filter { !it.validate() }
+
+ subscribers.addAll(collectSubscribers(valid))
+ return invalid
+ }
+
+ override fun finish() {
+ if (subscribers.isEmpty()) return
+ val deps = subscribers.mapNotNull { it.declaration.containingFile }
+ logger.info("Dependencies: $deps")
+ FileSpec.builder("io.github.moulberry.notenoughupdates.autosubscribe", "AutoLoad")
+ .addFileComment("@generated by ${NEUAutoSymbolProcessor::class.simpleName}")
+ .addType(
+ TypeSpec.objectBuilder("AutoLoad")
+ .addFunction(
+ FunSpec.builder("provide")
+ .addParameter(
+ "consumer",
+ Consumer::class.asTypeName()
+ .parameterizedBy(Supplier::class.parameterizedBy(Any::class))
+ )
+ .apply {
+ subscribers.sortedBy { it.declaration.simpleName.asString() }.forEach { (invocationKind, declaration) ->
+ when (invocationKind) {
+ InvocationKind.GET_INSTANCE -> addStatement(
+ "consumer.accept { %T.getInstance() }",
+ declaration.toClassName()
+ )
+
+ InvocationKind.OBJECT_INSTANCE -> addStatement(
+ "consumer.accept { %T }",
+ declaration.toClassName()
+ )
+
+ InvocationKind.DEFAULT_CONSTRUCTOR -> addStatement(
+ "consumer.accept { %T() }",
+ declaration.toClassName()
+ )
+
+ InvocationKind.ACCESS_INSTANCE -> addStatement(
+ "consumer.accept { %T.INSTANCE }",
+ declaration.toClassName()
+ )
+ }
+ }
+ }
+ .build()
+ )
+ .build()
+ )
+ .build()
+ .writeTo(codeGenerator, aggregating = true, originatingKSFiles = deps)
+ }
+}
diff --git a/annotations/src/main/kotlin/io/github/moulberry/notenoughupdates/autosubscribe/NEUAutoSymbolProcessorProvider.kt b/annotations/src/main/kotlin/io/github/moulberry/notenoughupdates/autosubscribe/NEUAutoSymbolProcessorProvider.kt
new file mode 100644
index 00000000..ef0edd88
--- /dev/null
+++ b/annotations/src/main/kotlin/io/github/moulberry/notenoughupdates/autosubscribe/NEUAutoSymbolProcessorProvider.kt
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2023 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.autosubscribe
+
+import com.google.devtools.ksp.processing.SymbolProcessor
+import com.google.devtools.ksp.processing.SymbolProcessorEnvironment
+import com.google.devtools.ksp.processing.SymbolProcessorProvider
+
+class NEUAutoSymbolProcessorProvider : SymbolProcessorProvider {
+ override fun create(environment: SymbolProcessorEnvironment): SymbolProcessor {
+ return NEUAutoSymbolProcessor(environment.codeGenerator, environment.logger)
+ }
+}
diff --git a/annotations/src/main/kotlin/io/github/moulberry/notenoughupdates/autosubscribe/NEUEventSubscriber.kt b/annotations/src/main/kotlin/io/github/moulberry/notenoughupdates/autosubscribe/NEUEventSubscriber.kt
new file mode 100644
index 00000000..d17b6004
--- /dev/null
+++ b/annotations/src/main/kotlin/io/github/moulberry/notenoughupdates/autosubscribe/NEUEventSubscriber.kt
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2023 Linnea Gräf
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.autosubscribe
+
+import com.google.devtools.ksp.symbol.KSClassDeclaration
+
+internal data class NEUEventSubscriber(
+ val invocationKind: InvocationKind,
+ val declaration: KSClassDeclaration,
+)
+
+internal enum class InvocationKind {
+ GET_INSTANCE,
+ OBJECT_INSTANCE,
+ DEFAULT_CONSTRUCTOR,
+ ACCESS_INSTANCE,
+}
diff --git a/annotations/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider b/annotations/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider
new file mode 100644
index 00000000..eaad70ce
--- /dev/null
+++ b/annotations/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider
@@ -0,0 +1,20 @@
+#
+# Copyright (C) 2023 NotEnoughUpdates contributors
+#
+# This file is part of NotEnoughUpdates.
+#
+# NotEnoughUpdates is free software: you can redistribute it
+# and/or modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation, either
+# version 3 of the License, or (at your option) any later version.
+#
+# NotEnoughUpdates is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+#
+
+io.github.moulberry.notenoughupdates.autosubscribe.NEUAutoSymbolProcessorProvider