[FIR] Implement simple serializer like declaration generator
This generator is needed to test complex dependency between generated members and annotated classes in incremental compilation
This commit is contained in:
committed by
TeamCityServer
parent
8c11ea266a
commit
11b9a6eed2
+3
@@ -13,6 +13,9 @@ annotation class NestedClassAndMaterializeMember
|
||||
annotation class MyInterfaceSupertype
|
||||
annotation class CompanionWithFoo
|
||||
|
||||
annotation class MySerializable
|
||||
annotation class CoreSerializer
|
||||
|
||||
annotation class AllPublic(val visibility: Visibility)
|
||||
|
||||
@Target(AnnotationTarget.TYPE)
|
||||
|
||||
+1
@@ -22,5 +22,6 @@ class FirAllOpenComponentRegistrar : FirExtensionRegistrar() {
|
||||
+::ExternalClassGenerator
|
||||
+::AdditionalMembersGenerator
|
||||
+::CompanionGenerator
|
||||
+::MembersOfSerializerGenerator
|
||||
}
|
||||
}
|
||||
|
||||
+103
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.fir.plugin.generators
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.EffectiveVisibility
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.FirPluginKey
|
||||
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
|
||||
import org.jetbrains.kotlin.fir.declarations.builder.buildSimpleFunction
|
||||
import org.jetbrains.kotlin.fir.declarations.builder.buildValueParameter
|
||||
import org.jetbrains.kotlin.fir.declarations.impl.FirResolvedDeclarationStatusImpl
|
||||
import org.jetbrains.kotlin.fir.expressions.builder.buildBlock
|
||||
import org.jetbrains.kotlin.fir.extensions.FirDeclarationGenerationExtension
|
||||
import org.jetbrains.kotlin.fir.extensions.FirDeclarationPredicateRegistrar
|
||||
import org.jetbrains.kotlin.fir.extensions.predicate.has
|
||||
import org.jetbrains.kotlin.fir.extensions.predicateBasedProvider
|
||||
import org.jetbrains.kotlin.fir.moduleData
|
||||
import org.jetbrains.kotlin.fir.plugin.fqn
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirValueParameterSymbol
|
||||
import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
|
||||
import org.jetbrains.kotlin.name.CallableId
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
/*
|
||||
* For each class with @Serializable annotation generates method serializeClassName(x: ClassName)
|
||||
* in each class annotated with @CoreSerializer
|
||||
*/
|
||||
class MembersOfSerializerGenerator(session: FirSession) : FirDeclarationGenerationExtension(session) {
|
||||
companion object {
|
||||
private val SERIALIZABLE_PREDICATE = has("MySerializable".fqn())
|
||||
private val CORE_SERIALIZER_PREDICATE = has("CoreSerializer".fqn())
|
||||
|
||||
private val X_NAME = Name.identifier("x")
|
||||
}
|
||||
|
||||
private val predicateBasedProvider = session.predicateBasedProvider
|
||||
private val matchedSerializableClasses by lazy {
|
||||
predicateBasedProvider.getSymbolsByPredicate(SERIALIZABLE_PREDICATE).filterIsInstance<FirRegularClassSymbol>()
|
||||
}
|
||||
private val serializableClassIds by lazy {
|
||||
matchedSerializableClasses.map { it.classId }
|
||||
}
|
||||
|
||||
private val matchedCoreSerializerClasses by lazy {
|
||||
predicateBasedProvider.getSymbolsByPredicate(CORE_SERIALIZER_PREDICATE).filterIsInstance<FirRegularClassSymbol>()
|
||||
}
|
||||
|
||||
private val serializeMethodNames by lazy {
|
||||
serializableClassIds.associateBy { Name.identifier("serialize${it.shortClassName.identifier}") }
|
||||
}
|
||||
|
||||
override fun generateFunctions(callableId: CallableId, owner: FirClassSymbol<*>?): List<FirNamedFunctionSymbol> {
|
||||
val argumentClassId = serializeMethodNames[callableId.callableName] ?: return emptyList()
|
||||
val dispatchReceiverClassId = callableId.classId ?: return emptyList()
|
||||
val function = buildSimpleFunction {
|
||||
moduleData = session.moduleData
|
||||
resolvePhase = FirResolvePhase.BODY_RESOLVE
|
||||
origin = Key.origin
|
||||
status = FirResolvedDeclarationStatusImpl(Visibilities.Public, Modality.FINAL, EffectiveVisibility.Public)
|
||||
returnTypeRef = session.builtinTypes.unitType
|
||||
dispatchReceiverType = dispatchReceiverClassId.toSimpleConeType()
|
||||
valueParameters += buildValueParameter {
|
||||
moduleData = session.moduleData
|
||||
resolvePhase = FirResolvePhase.BODY_RESOLVE
|
||||
origin = Key.origin
|
||||
returnTypeRef = buildResolvedTypeRef {
|
||||
type = argumentClassId.toSimpleConeType()
|
||||
}
|
||||
name = X_NAME
|
||||
symbol = FirValueParameterSymbol(name)
|
||||
isCrossinline = false
|
||||
isNoinline = false
|
||||
isVararg = false
|
||||
}
|
||||
body = buildBlock {}
|
||||
.apply { replaceTypeRef(session.builtinTypes.unitType) }
|
||||
name = callableId.callableName
|
||||
symbol = FirNamedFunctionSymbol(callableId)
|
||||
}
|
||||
return listOf(function.symbol)
|
||||
}
|
||||
|
||||
override fun getCallableNamesForClass(classSymbol: FirClassSymbol<*>): Set<Name> {
|
||||
return when (classSymbol) {
|
||||
in matchedCoreSerializerClasses -> serializeMethodNames.keys
|
||||
else -> emptySet()
|
||||
}
|
||||
}
|
||||
|
||||
override fun FirDeclarationPredicateRegistrar.registerPredicates() {
|
||||
register(SERIALIZABLE_PREDICATE, CORE_SERIALIZER_PREDICATE)
|
||||
}
|
||||
|
||||
object Key : FirPluginKey()
|
||||
}
|
||||
+9
@@ -25,6 +25,7 @@ import org.jetbrains.kotlin.fir.symbols.impl.ConeClassLikeLookupTagImpl
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirConstructorSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
|
||||
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
|
||||
import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
|
||||
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
|
||||
import org.jetbrains.kotlin.name.CallableId
|
||||
@@ -89,3 +90,11 @@ fun FirDeclarationGenerationExtension.buildConstructor(classId: ClassId, isInner
|
||||
it.containingClassForStaticMemberAttr = lookupTag
|
||||
}
|
||||
}
|
||||
|
||||
fun ClassId.toSimpleConeType(): ConeClassLikeType {
|
||||
return ConeClassLikeTypeImpl(
|
||||
ConeClassLikeLookupTagImpl(this),
|
||||
emptyArray(),
|
||||
isNullable = false
|
||||
)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
FILE: serializer.kt
|
||||
@R|org/jetbrains/kotlin/fir/plugin/CoreSerializer|() public final object FirstSerializer : R|kotlin/Any| {
|
||||
private constructor(): R|FirstSerializer| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
public final fun serializeA(x: R|A|): R|kotlin/Unit| {
|
||||
}
|
||||
|
||||
public final fun serializeB(x: R|B|): R|kotlin/Unit| {
|
||||
}
|
||||
|
||||
public final fun serializeC(x: R|C|): R|kotlin/Unit| {
|
||||
}
|
||||
|
||||
public final fun serializeD(x: R|D|): R|kotlin/Unit| {
|
||||
}
|
||||
|
||||
}
|
||||
@R|org/jetbrains/kotlin/fir/plugin/CoreSerializer|() public final object SecondSerializer : R|kotlin/Any| {
|
||||
private constructor(): R|SecondSerializer| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
public final fun serializeA(x: R|A|): R|kotlin/Unit| {
|
||||
}
|
||||
|
||||
public final fun serializeB(x: R|B|): R|kotlin/Unit| {
|
||||
}
|
||||
|
||||
public final fun serializeC(x: R|C|): R|kotlin/Unit| {
|
||||
}
|
||||
|
||||
public final fun serializeD(x: R|D|): R|kotlin/Unit| {
|
||||
}
|
||||
|
||||
}
|
||||
@R|org/jetbrains/kotlin/fir/plugin/MySerializable|() public final class A : R|kotlin/Any| {
|
||||
public constructor(): R|A| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
}
|
||||
@R|org/jetbrains/kotlin/fir/plugin/MySerializable|() public final class B : R|kotlin/Any| {
|
||||
public constructor(): R|B| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
}
|
||||
@R|org/jetbrains/kotlin/fir/plugin/MySerializable|() public final class C : R|kotlin/Any| {
|
||||
public constructor(): R|C| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
}
|
||||
@R|org/jetbrains/kotlin/fir/plugin/MySerializable|() public final class D : R|kotlin/Any| {
|
||||
public constructor(): R|D| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
}
|
||||
public final fun testFirstSerializer(): R|kotlin/Unit| {
|
||||
Q|FirstSerializer|.R|/FirstSerializer.serializeA|(R|/A.A|())
|
||||
Q|FirstSerializer|.R|/FirstSerializer.serializeB|(R|/B.B|())
|
||||
Q|FirstSerializer|.R|/FirstSerializer.serializeC|(R|/C.C|())
|
||||
Q|FirstSerializer|.R|/FirstSerializer.serializeD|(R|/D.D|())
|
||||
}
|
||||
public final fun testSecondSerializer(): R|kotlin/Unit| {
|
||||
Q|SecondSerializer|.R|/SecondSerializer.serializeA|(R|/A.A|())
|
||||
Q|SecondSerializer|.R|/SecondSerializer.serializeB|(R|/B.B|())
|
||||
Q|SecondSerializer|.R|/SecondSerializer.serializeC|(R|/C.C|())
|
||||
Q|SecondSerializer|.R|/SecondSerializer.serializeD|(R|/D.D|())
|
||||
}
|
||||
public final fun box(): R|kotlin/String| {
|
||||
R|/testFirstSerializer|()
|
||||
R|/testSecondSerializer|()
|
||||
^box String(OK)
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
import org.jetbrains.kotlin.fir.plugin.CoreSerializer
|
||||
import org.jetbrains.kotlin.fir.plugin.MySerializable
|
||||
|
||||
@CoreSerializer
|
||||
object FirstSerializer
|
||||
|
||||
@CoreSerializer
|
||||
object SecondSerializer
|
||||
|
||||
@MySerializable
|
||||
class A
|
||||
|
||||
@MySerializable
|
||||
class B
|
||||
|
||||
@MySerializable
|
||||
class C
|
||||
|
||||
@MySerializable
|
||||
class D
|
||||
|
||||
fun testFirstSerializer() {
|
||||
FirstSerializer.serializeA(A())
|
||||
FirstSerializer.serializeB(B())
|
||||
FirstSerializer.serializeC(C())
|
||||
FirstSerializer.serializeD(D())
|
||||
}
|
||||
|
||||
fun testSecondSerializer() {
|
||||
SecondSerializer.serializeA(A())
|
||||
SecondSerializer.serializeB(B())
|
||||
SecondSerializer.serializeC(C())
|
||||
SecondSerializer.serializeD(D())
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
testFirstSerializer()
|
||||
testSecondSerializer()
|
||||
return "OK"
|
||||
}
|
||||
+6
@@ -49,6 +49,12 @@ public class FirPluginBlackBoxCodegenTestGenerated extends AbstractFirPluginBlac
|
||||
runTest("plugins/fir-plugin-prototype/testData/box/newSupertype.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("serializer.kt")
|
||||
public void testSerializer() throws Exception {
|
||||
runTest("plugins/fir-plugin-prototype/testData/box/serializer.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("topLevelCallables.kt")
|
||||
public void testTopLevelCallables() throws Exception {
|
||||
|
||||
Reference in New Issue
Block a user