Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ADD: Kudos function switch #12

Merged
merged 2 commits into from
Nov 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -19,25 +19,38 @@ package com.kanyun.kudos.json.reader
import android.util.JsonReader
import com.kanyun.kudos.json.reader.adapter.KudosJsonAdapter
import com.kanyun.kudos.json.reader.adapter.parseKudosObject
import java.io.BufferedReader
import java.io.InputStream
import java.lang.reflect.Type

object KudosAndroidJsonReader {
inline fun <reified T> fromJson(json: String): T {
return fromJson(json, T::class.java)
return fromJson(json.reader().buffered(), T::class.java)
}

fun <T> fromJson(json: String, clazz: Class<T>): T {
inline fun <reified T> fromJson(inputStream: InputStream): T {
return fromJson(inputStream.bufferedReader(), T::class.java)
}

fun <T> fromJson(bufferedReader: BufferedReader, clazz: Class<T>): T {
val adapter = clazz.getDeclaredConstructor().newInstance()
return if (adapter is KudosJsonAdapter<*>) {
val jsonReader = JsonReader(json.reader())
val jsonReader = JsonReader(bufferedReader)
adapter.fromJson(jsonReader) as T
} else {
throw IllegalArgumentException("class ${clazz.name} must implement KudosJsonAdapter")
}
}

fun <T> fromJson(json: String, type: Type): T {
val jsonReader = JsonReader(json.reader())
val jsonReader = JsonReader(json.reader().buffered())
return parseKudosObject(jsonReader, type) as T
}

fun <T> fromJson(inputStream: InputStream, type: Type): T {
val jsonReader = JsonReader(inputStream.bufferedReader())
return parseKudosObject(jsonReader, type) as T
}
}

const val KUDOS_ANDROID_JSON_READER: Int = 3
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,4 @@ package com.kanyun.kudos.annotations
*/
@Retention(AnnotationRetention.BINARY)
@Target(AnnotationTarget.CLASS, AnnotationTarget.TYPE)
annotation class Kudos
annotation class Kudos(vararg val value: Int)
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,11 @@ class KudosCompilerPluginRegistrar : CompilerPluginRegistrar() {
configuration.get(NoArgConfigurationKeys.PRESET)?.forEach { preset ->
NoArgPluginNames.SUPPORTED_PRESETS[preset]?.let { noArgAnnotations += it }
}

IrGenerationExtension.registerExtension(KudosIrGenerationExtension())
SyntheticResolveExtension.registerExtension(KudosSyntheticResolveExtension())
val kudosAnnotationValueMap = hashMapOf<String, List<Int>>()
IrGenerationExtension.registerExtension(KudosIrGenerationExtension(kudosAnnotationValueMap))
SyntheticResolveExtension.registerExtension(KudosSyntheticResolveExtension(kudosAnnotationValueMap))
StorageComponentContainerContributor.registerExtension(KudosComponentContainerContributor(noArgAnnotations))
FirExtensionRegistrarAdapter.registerExtension(KudosFirExtensionRegistrar(noArgAnnotations))
FirExtensionRegistrarAdapter.registerExtension(KudosFirExtensionRegistrar(noArgAnnotations, kudosAnnotationValueMap))
}

override val supportsK2: Boolean
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ import org.jetbrains.kotlin.ir.types.starProjectedType
import org.jetbrains.kotlin.ir.types.typeOrNull
import org.jetbrains.kotlin.ir.types.typeWith
import org.jetbrains.kotlin.ir.util.SYNTHETIC_OFFSET
import org.jetbrains.kotlin.ir.util.classId
import org.jetbrains.kotlin.ir.util.constructors
import org.jetbrains.kotlin.ir.util.copyTo
import org.jetbrains.kotlin.ir.util.defaultType
Expand All @@ -86,17 +87,20 @@ class KudosIrClassTransformer(
private val context: IrPluginContext,
private val irClass: IrClass,
private val noArgConstructors: MutableMap<IrClass, IrConstructor>,
private val kudosAnnotationValueMap: HashMap<String, List<Int>>,
) {

private val defaults = HashSet<String>()

fun transform() {
if (Options.gson()) {
if (Options.isGsonEnabled(kudosAnnotationValueMap, irClass.classId?.asString())) {
generateJsonAdapter()
}
generateNoArgConstructor()
val validatorFunction = generateValidator()
generateFromJson(validatorFunction)
if (Options.isAndroidJsonReaderEnabled(kudosAnnotationValueMap, irClass.classId?.asString())) {
generateFromJson(validatorFunction)
}
}

private fun generateJsonAdapter() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,11 @@ import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
import org.jetbrains.kotlin.ir.visitors.acceptVoid

class KudosIrGenerationExtension : IrGenerationExtension {
class KudosIrGenerationExtension(
private val kudosAnnotationValueMap: HashMap<String, List<Int>>,
) : IrGenerationExtension {

override fun generate(moduleFragment: IrModuleFragment, pluginContext: IrPluginContext) {
moduleFragment.acceptVoid(KudosIrTransformer(pluginContext))
moduleFragment.acceptVoid(KudosIrTransformer(pluginContext, kudosAnnotationValueMap))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
*/
class KudosIrTransformer(
private val context: IrPluginContext,
private val kudosAnnotationValueMap: HashMap<String, List<Int>>,
) : IrElementVisitorVoid {
private val noArgConstructors = mutableMapOf<IrClass, IrConstructor>()

Expand All @@ -41,6 +42,6 @@ class KudosIrTransformer(
if (declaration.kind != ClassKind.CLASS) return
if (!declaration.hasKudosAnnotation()) return

KudosIrClassTransformer(context, declaration, noArgConstructors).transform()
KudosIrClassTransformer(context, declaration, noArgConstructors, kudosAnnotationValueMap).transform()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ object KudosNames {
val ADAPTER_FACTORY_NAME = FqName("com.kanyun.kudos.gson.adapter.KudosReflectiveTypeAdapterFactory")

// ClassId
val KUDOS_ANNOTATION_CLASS_ID = ClassId(FqName("com.kanyun.kudos.annotations"), Name.identifier("Kudos"))
val KUDOS_VALIDATOR_CLASS_ID = ClassId(FqName("com.kanyun.kudos.validator"), Name.identifier("KudosValidator"))
val KUDOS_JSON_ADAPTER_CLASS_ID = ClassId(FqName("com.kanyun.kudos.json.reader.adapter"), Name.identifier("KudosJsonAdapter"))
val JSON_READER_CLASS_ID = ClassId.fromString("android/util/JsonReader")
Expand All @@ -50,6 +51,7 @@ object KudosNames {
val JSON_TOKEN_NULL_CALLABLE_ID = CallableId(FqName("android.util"), FqName("JsonToken"), Name.identifier("NULL"))

// Name.identifier
val KUDOS_VALUE_IDENTIFIER = Name.identifier("value")
val KUDOS_FROM_JSON_IDENTIFIER = Name.identifier("fromJson")
val JSON_READER_IDENTIFIER = Name.identifier("jsonReader")
val KUDOS_FIELD_STATUS_MAP_IDENTIFIER = Name.identifier("kudosFieldStatusMap")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ import com.kanyun.kudos.compiler.KudosNames.KUDOS_NAME
import com.kanyun.kudos.compiler.KudosNames.KUDOS_VALIDATOR
import com.kanyun.kudos.compiler.KudosNames.KUDOS_VALIDATOR_CLASS_ID
import com.kanyun.kudos.compiler.k1.symbol.FromJsonFunctionDescriptorImpl
import com.kanyun.kudos.compiler.options.Options
import com.kanyun.kudos.compiler.utils.safeAs
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor
Expand All @@ -35,6 +37,8 @@ import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
import org.jetbrains.kotlin.js.descriptorUtils.getKotlinTypeFqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.constants.IntValue
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.resolve.extensions.SyntheticResolveExtension
import org.jetbrains.kotlin.types.KotlinType
Expand All @@ -44,14 +48,24 @@ import org.jetbrains.kotlin.types.TypeAttributes
import org.jetbrains.kotlin.types.TypeProjectionImpl
import org.jetbrains.kotlin.types.typeUtil.supertypes

class KudosSyntheticResolveExtension : SyntheticResolveExtension {
class KudosSyntheticResolveExtension(
private val kudosAnnotationValueMap: HashMap<String, List<Int>>,
) : SyntheticResolveExtension {

override fun addSyntheticSupertypes(
thisDescriptor: ClassDescriptor,
supertypes: MutableList<KotlinType>,
) {
if (thisDescriptor.kind != ClassKind.CLASS) return
if (thisDescriptor.annotations.hasAnnotation(KUDOS_NAME)) {
val kudosAnnotation = thisDescriptor.annotations.findAnnotation(KUDOS_NAME)
val annotationValues = kudosAnnotation?.allValueArguments?.values?.firstOrNull()?.value?.safeAs<List<IntValue>>()?.map {
if (it.value !in Options.validAnnotationList) {
throw IllegalArgumentException("unknown annotation argument ${it.value}")
}
it.value
}
kudosAnnotationValueMap[thisDescriptor.classId?.asString() ?: ""] = annotationValues ?: emptyList()
val superTypeNames = supertypes.asSequence().flatMap {
listOf(it) + it.supertypes()
}.map {
Expand All @@ -68,21 +82,25 @@ class KudosSyntheticResolveExtension : SyntheticResolveExtension {
),
)
}
if (KUDOS_JSON_ADAPTER !in superTypeNames) {
val kudosJsonAdapter = thisDescriptor.module.findClassAcrossModuleDependencies(KUDOS_JSON_ADAPTER_CLASS_ID)!!
supertypes.add(
KotlinTypeFactory.simpleNotNullType(
TypeAttributes.Empty,
kudosJsonAdapter,
listOf(TypeProjectionImpl(thisDescriptor.defaultType)),
),
)
if (Options.isAndroidJsonReaderEnabled(kudosAnnotationValueMap, thisDescriptor.classId?.asString())) {
if (KUDOS_JSON_ADAPTER !in superTypeNames) {
val kudosJsonAdapter = thisDescriptor.module.findClassAcrossModuleDependencies(KUDOS_JSON_ADAPTER_CLASS_ID)!!
supertypes.add(
KotlinTypeFactory.simpleNotNullType(
TypeAttributes.Empty,
kudosJsonAdapter,
listOf(TypeProjectionImpl(thisDescriptor.defaultType)),
),
)
}
}
}
}

override fun getSyntheticFunctionNames(thisDescriptor: ClassDescriptor): List<Name> {
if (thisDescriptor.annotations.hasAnnotation(KUDOS_NAME)) {
if (Options.isAndroidJsonReaderEnabled(kudosAnnotationValueMap, thisDescriptor.classId?.asString()) &&
thisDescriptor.annotations.hasAnnotation(KUDOS_NAME)
) {
return listOf(KUDOS_FROM_JSON_IDENTIFIER)
}
return super.getSyntheticFunctionNames(thisDescriptor)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import com.kanyun.kudos.compiler.KudosNames.JSON_READER_CLASS_ID
import com.kanyun.kudos.compiler.KudosNames.JSON_READER_IDENTIFIER
import com.kanyun.kudos.compiler.KudosNames.KUDOS_FROM_JSON_IDENTIFIER
import com.kanyun.kudos.compiler.KudosNames.KUDOS_NAME
import com.kanyun.kudos.compiler.options.Options
import org.jetbrains.kotlin.GeneratedDeclarationKey
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.fir.FirSession
Expand Down Expand Up @@ -48,8 +49,10 @@ import org.jetbrains.kotlin.name.CallableId
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.utils.addToStdlib.runIf

class KudosFirDeclarationGenerator(session: FirSession) :
FirDeclarationGenerationExtension(session) {
class KudosFirDeclarationGenerator(
session: FirSession,
private val kudosAnnotationValueMap: HashMap<String, List<Int>>,
) : FirDeclarationGenerationExtension(session) {

companion object {
private val PREDICATE = LookupPredicate.create {
Expand All @@ -71,8 +74,10 @@ class KudosFirDeclarationGenerator(session: FirSession) :
}

override fun getCallableNamesForClass(classSymbol: FirClassSymbol<*>): Set<Name> {
if (classSymbol in matchedClasses) {
return kudosMethodsNames
if (Options.isAndroidJsonReaderEnabled(kudosAnnotationValueMap, classSymbol.classId.toString())) {
if (classSymbol in matchedClasses) {
return kudosMethodsNames
}
}
return super.getCallableNamesForClass(classSymbol)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,26 @@
package com.kanyun.kudos.compiler.k2

import org.jetbrains.kotlin.fir.analysis.extensions.FirAdditionalCheckersExtension
import org.jetbrains.kotlin.fir.extensions.FirDeclarationGenerationExtension
import org.jetbrains.kotlin.fir.extensions.FirExtensionRegistrar
import org.jetbrains.kotlin.fir.extensions.FirSupertypeGenerationExtension

/**
* Created by Benny Huo on 2023/8/21
*/
class KudosFirExtensionRegistrar(
private val noArgAnnotations: List<String>,
private val kudosAnnotationValueMap: HashMap<String, List<Int>>,
) : FirExtensionRegistrar() {
override fun ExtensionRegistrarContext.configurePlugin() {
+FirAdditionalCheckersExtension.Factory { session ->
KudosFirCheckers(session, noArgAnnotations)
}
+::KudosFirSupertypeGenerationExtension
+::KudosFirDeclarationGenerator
+FirSupertypeGenerationExtension.Factory { session ->
KudosFirSupertypeGenerationExtension(session, kudosAnnotationValueMap)
}
+FirDeclarationGenerationExtension.Factory { session ->
KudosFirDeclarationGenerator(session, kudosAnnotationValueMap)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,29 @@

package com.kanyun.kudos.compiler.k2

import com.kanyun.kudos.compiler.KudosNames.KUDOS_ANNOTATION_CLASS_ID
import com.kanyun.kudos.compiler.KudosNames.KUDOS_JSON_ADAPTER_CLASS_ID
import com.kanyun.kudos.compiler.KudosNames.KUDOS_NAME
import com.kanyun.kudos.compiler.KudosNames.KUDOS_VALIDATOR_CLASS_ID
import com.kanyun.kudos.compiler.options.Options
import com.kanyun.kudos.compiler.utils.safeAs
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirClass
import org.jetbrains.kotlin.fir.declarations.FirClassLikeDeclaration
import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.declarations.FirTypeAlias
import org.jetbrains.kotlin.fir.declarations.getAnnotationByClassId
import org.jetbrains.kotlin.fir.declarations.utils.classId
import org.jetbrains.kotlin.fir.expressions.FirAnnotation
import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall
import org.jetbrains.kotlin.fir.expressions.FirPropertyAccessExpression
import org.jetbrains.kotlin.fir.expressions.arguments
import org.jetbrains.kotlin.fir.extensions.FirDeclarationPredicateRegistrar
import org.jetbrains.kotlin.fir.extensions.FirSupertypeGenerationExtension
import org.jetbrains.kotlin.fir.extensions.predicate.DeclarationPredicate
import org.jetbrains.kotlin.fir.extensions.predicateBasedProvider
import org.jetbrains.kotlin.fir.references.impl.FirSimpleNamedReference
import org.jetbrains.kotlin.fir.resolve.toSymbol
import org.jetbrains.kotlin.fir.scopes.impl.toConeType
import org.jetbrains.kotlin.fir.symbols.SymbolInternals
Expand All @@ -49,6 +58,7 @@ import org.jetbrains.kotlin.name.ClassId
*/
class KudosFirSupertypeGenerationExtension(
session: FirSession,
private val kudosAnnotationValueMap: HashMap<String, List<Int>>,
) : FirSupertypeGenerationExtension(session) {

private val hasKudos = DeclarationPredicate.create {
Expand All @@ -66,6 +76,9 @@ class KudosFirSupertypeGenerationExtension(
): List<FirResolvedTypeRef> {
var hasValidator = false
var hasJsonAdapter = false
val annotationValues = classLikeDeclaration.symbol.resolvedAnnotationsWithArguments.getAnnotationByClassId(KUDOS_ANNOTATION_CLASS_ID, session)
?.getIntArrayArgument()
kudosAnnotationValueMap[classLikeDeclaration.classId.toString()] = annotationValues ?: emptyList()
for (superTypeRef in resolvedSupertypes) {
val superType = superTypeRef.type
val superTypeClassIds = superType.allSuperTypeClassIds()
Expand All @@ -86,19 +99,21 @@ class KudosFirSupertypeGenerationExtension(
)
}
}
if (!hasJsonAdapter) {
val genericType = ConeClassLikeTypeImpl(
ConeClassLikeLookupTagImpl(classLikeDeclaration.classId),
classLikeDeclaration.typeParameters.map {
it.toConeType()
}.toTypedArray(),
false,
)
firTypeRefList += buildResolvedTypeRef {
type = KUDOS_JSON_ADAPTER_CLASS_ID.constructClassLikeType(
arrayOf(genericType),
isNullable = false,
if (Options.isAndroidJsonReaderEnabled(kudosAnnotationValueMap, classLikeDeclaration.classId.toString())) {
if (!hasJsonAdapter) {
val genericType = ConeClassLikeTypeImpl(
ConeClassLikeLookupTagImpl(classLikeDeclaration.classId),
classLikeDeclaration.typeParameters.map {
it.toConeType()
}.toTypedArray(),
false,
)
firTypeRefList += buildResolvedTypeRef {
type = KUDOS_JSON_ADAPTER_CLASS_ID.constructClassLikeType(
arrayOf(genericType),
isNullable = false,
)
}
}
}
return firTypeRefList
Expand Down Expand Up @@ -134,4 +149,27 @@ class KudosFirSupertypeGenerationExtension(
else -> null
}
}

private fun FirAnnotation.getIntArrayArgument(): List<Int>? {
if (this !is FirAnnotationCall) return null
return arguments.map {
when (val annotationValue = it.safeAs<FirPropertyAccessExpression>()?.calleeReference?.safeAs<FirSimpleNamedReference>()?.name?.asString()) {
"KUDOS_ANDROID_JSON_READER" -> {
Options.KUDOS_ANDROID_JSON_READER
}

"KUDOS_GSON" -> {
Options.KUDOS_GSON
}

"KUDOS_JACKSON" -> {
Options.KUDOS_JACKSON
}

else -> {
throw IllegalArgumentException("unknown annotation argument $annotationValue")
}
}
}
}
}
Loading