[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 MyInterfaceSupertype
|
||||||
annotation class CompanionWithFoo
|
annotation class CompanionWithFoo
|
||||||
|
|
||||||
|
annotation class MySerializable
|
||||||
|
annotation class CoreSerializer
|
||||||
|
|
||||||
annotation class AllPublic(val visibility: Visibility)
|
annotation class AllPublic(val visibility: Visibility)
|
||||||
|
|
||||||
@Target(AnnotationTarget.TYPE)
|
@Target(AnnotationTarget.TYPE)
|
||||||
|
|||||||
+1
@@ -22,5 +22,6 @@ class FirAllOpenComponentRegistrar : FirExtensionRegistrar() {
|
|||||||
+::ExternalClassGenerator
|
+::ExternalClassGenerator
|
||||||
+::AdditionalMembersGenerator
|
+::AdditionalMembersGenerator
|
||||||
+::CompanionGenerator
|
+::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.FirClassLikeSymbol
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirConstructorSymbol
|
import org.jetbrains.kotlin.fir.symbols.impl.FirConstructorSymbol
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
|
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.builder.buildResolvedTypeRef
|
||||||
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
|
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
|
||||||
import org.jetbrains.kotlin.name.CallableId
|
import org.jetbrains.kotlin.name.CallableId
|
||||||
@@ -89,3 +90,11 @@ fun FirDeclarationGenerationExtension.buildConstructor(classId: ClassId, isInner
|
|||||||
it.containingClassForStaticMemberAttr = lookupTag
|
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");
|
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
|
@Test
|
||||||
@TestMetadata("topLevelCallables.kt")
|
@TestMetadata("topLevelCallables.kt")
|
||||||
public void testTopLevelCallables() throws Exception {
|
public void testTopLevelCallables() throws Exception {
|
||||||
|
|||||||
Reference in New Issue
Block a user