1
0
mirror of https://github.com/InsanusMokrassar/TelegramBotAPI.git synced 2025-09-03 07:09:23 +00:00

update classcasts

This commit is contained in:
2025-04-21 12:16:17 +06:00
parent 92cd2a3def
commit c610f4eab2
19 changed files with 1484 additions and 454 deletions

View File

@@ -9,5 +9,6 @@ repositories {
dependencies {
implementation libs.kotlin.poet
implementation libs.ksp
implementation libs.microutils.ksp.generator
implementation project(":tgbotapi.core")
}

View File

@@ -1,9 +1,13 @@
package dev.inmo.tgbotapi.ksp.processor
import com.google.devtools.ksp.KspExperimental
import com.google.devtools.ksp.getAnnotationsByType
import com.google.devtools.ksp.isAnnotationPresent
import com.google.devtools.ksp.symbol.*
import com.squareup.kotlinpoet.*
import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy
import com.squareup.kotlinpoet.ksp.*
import dev.inmo.tgbotapi.utils.internal.ClassCastsIncluded
private fun FileSpec.Builder.addTopLevelImport(className: ClassName) {
className.topLevelClassName().let {
@@ -27,6 +31,24 @@ private fun FileSpec.Builder.createTypeDefinition(ksClassDeclaration: KSClassDec
}
}
@OptIn(KspExperimental::class)
private fun KSClassDeclaration.buildPrefix(sourceDeclaration: KSClassDeclaration): String {
val ownName = if (isAnnotationPresent(ClassCastsIncluded.ExcludeSubName::class)) {
""
} else {
simpleName.asString()
}
when (val parentDeclaration = parentDeclaration) {
is KSClassDeclaration -> if (parentDeclaration === sourceDeclaration) {
return ownName
} else {
return "${parentDeclaration.buildPrefix(sourceDeclaration)}$ownName"
}
}
return ownName
}
@OptIn(KspExperimental::class)
fun FileSpec.Builder.fill(
sourceKSClassDeclaration: KSClassDeclaration,
subtypesMap: Map<KSClassDeclaration, Set<KSClassDeclaration>>,
@@ -40,8 +62,10 @@ fun FileSpec.Builder.fill(
val sourceClassName = sourceKSClassDeclaration.toClassName()
val targetClassClassName = targetClassDeclaration.toClassName()
val targetClassTypeDefinition = createTypeDefinition(targetClassDeclaration)
val simpleName = targetClassDeclaration.simpleName.asString()
val withFirstLowerCase = simpleName.replaceFirstChar { it.lowercase() }
// val simpleName = targetClassDeclaration.simpleName.asString()
// val additionalPrefix = targetClassDeclaration.buildPrefix()
val resultPrefix = targetClassDeclaration.buildPrefix(sourceKSClassDeclaration)
val withFirstLowerCase = resultPrefix.replaceFirstChar { it.lowercase() }
val castedOrNullName = "${withFirstLowerCase}OrNull"
addTopLevelImport(targetClassClassName)
@@ -68,7 +92,7 @@ fun FileSpec.Builder.fill(
}.build()
)
addFunction(
FunSpec.builder("if$simpleName").apply {
FunSpec.builder("if$resultPrefix").apply {
val genericType = TypeVariableName("T", null)
addTypeVariable(genericType)
receiver(sourceClassName)

View File

@@ -1,22 +1,21 @@
package dev.inmo.tgbotapi.ksp.processor
import com.google.devtools.ksp.KspExperimental
import com.google.devtools.ksp.getAllSuperTypes
import com.google.devtools.ksp.getAnnotationsByType
import com.google.devtools.ksp.isAnnotationPresent
import com.google.devtools.ksp.*
import com.google.devtools.ksp.processing.*
import com.google.devtools.ksp.symbol.KSAnnotated
import com.google.devtools.ksp.symbol.KSClassDeclaration
import com.google.devtools.ksp.symbol.*
import com.squareup.kotlinpoet.AnnotationSpec
import com.squareup.kotlinpoet.ClassName
import com.squareup.kotlinpoet.FileSpec
import com.squareup.kotlinpoet.asClassName
import com.squareup.kotlinpoet.ksp.toClassName
import com.squareup.kotlinpoet.ksp.writeTo
import dev.inmo.micro_ksp.generator.resolveSubclasses
import dev.inmo.tgbotapi.types.message.ChatEvents.abstracts.ChatEvent
import dev.inmo.tgbotapi.utils.RiskFeature
import dev.inmo.tgbotapi.utils.internal.ClassCastsExcluded
import dev.inmo.tgbotapi.utils.internal.ClassCastsIncluded
import java.io.File
import java.io.InputStream
import java.io.OutputStreamWriter
import java.io.StringWriter
class TelegramBotAPISymbolProcessor(
private val codeGenerator: CodeGenerator,
@@ -37,25 +36,38 @@ class TelegramBotAPISymbolProcessor(
val classesSubtypes = mutableMapOf<KSClassDeclaration, MutableSet<KSClassDeclaration>>()
resolver.getAllFiles().forEach {
it.declarations.forEach { potentialSubtype ->
if (
potentialSubtype is KSClassDeclaration
&& potentialSubtype.isAnnotationPresent(ClassCastsExcluded::class).not()
) {
val allSupertypes = potentialSubtype.getAllSuperTypes().map { it.declaration }
val declarationsToAnalyze = mutableSetOf<KSDeclaration>()
declarationsToAnalyze.addAll(it.declarations)
val analyzed = mutableSetOf<KSDeclaration>()
for (currentClass in classes) {
val regexes = classesRegexes[currentClass]
val simpleName = potentialSubtype.simpleName.getShortName()
when {
currentClass !in allSupertypes
|| regexes ?.first ?.matches(simpleName) == false
|| regexes ?.second ?.matches(simpleName) == true -> continue
else -> {
classesSubtypes.getOrPut(currentClass) { mutableSetOf() }.add(potentialSubtype)
while (declarationsToAnalyze.isNotEmpty()) {
val potentialSubtype = declarationsToAnalyze.first()
declarationsToAnalyze.remove(potentialSubtype)
if (analyzed.add(potentialSubtype)) {
if (
potentialSubtype is KSClassDeclaration
&& potentialSubtype.isAnnotationPresent(ClassCastsExcluded::class).not()
) {
val allSupertypes = potentialSubtype.getAllSuperTypes().map { it.declaration }
for (currentClass in classes) {
val regexes = classesRegexes[currentClass]
val simpleName = potentialSubtype.simpleName.getShortName()
when {
currentClass !in allSupertypes
|| regexes ?.first ?.matches(simpleName) == false
|| regexes ?.second ?.matches(simpleName) == true -> continue
else -> {
classesSubtypes.getOrPut(currentClass) { mutableSetOf() }.add(potentialSubtype)
}
}
}
}
when (potentialSubtype) {
is KSFile -> declarationsToAnalyze.addAll(potentialSubtype.declarations)
is KSClassDeclaration ->declarationsToAnalyze.addAll(potentialSubtype.declarations)
is KSFunctionDeclaration -> declarationsToAnalyze.addAll(potentialSubtype.declarations)
}
}
}
}
@@ -98,15 +110,21 @@ class TelegramBotAPISymbolProcessor(
)
}
}.build()
runCatching {
outputFolder ?.also {
File(it).apply {
delete()
runCatching { mkdirs() }
fileSpec.writeTo(this)
outputFolder ?.also {
File(it, outputFile).apply {
val text = StringWriter().use {
fileSpec.writeTo(it)
it.toString()
}
} ?: fileSpec.writeTo(codeGenerator, false)
}
if (exists() == false || readText() != text) {
delete()
runCatching { parentFile.mkdirs() }
createNewFile()
writeText(text)
}
}
} ?: fileSpec.writeTo(codeGenerator, false)
return emptyList()
}