[StubIr][Metadata] Preparations for class metadata support
ClassStubs are containers themselves. Thus we need to make metadata emitter recursive and: 1. Pass context from parent nodes to children. 2. Return result of translation from children back to parent.
This commit is contained in:
committed by
Sergey Bogolepov
parent
c42b588f12
commit
7e0a65e480
+83
-64
@@ -20,93 +20,112 @@ class StubIrMetadataEmitter(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun emitModuleFragments(): List<KmModuleFragment> =
|
private fun emitModuleFragments(): List<KmModuleFragment> =
|
||||||
ModuleMetadataEmitter(context.configuration.pkgName).let {
|
ModuleMetadataEmitter(context.configuration.pkgName, builderResult.stubs).emit().let(::listOf)
|
||||||
builderResult.stubs.accept(it, null)
|
|
||||||
listOf(it.writeModule())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Translates single [StubContainer] to [KmModuleFragment].
|
* Translates single [StubContainer] to [KmModuleFragment].
|
||||||
*/
|
*/
|
||||||
internal class ModuleMetadataEmitter(
|
internal class ModuleMetadataEmitter(
|
||||||
private val packageFqName: String
|
private val packageFqName: String,
|
||||||
) : StubIrVisitor<StubContainer?, Unit> {
|
private val module: SimpleStubContainer
|
||||||
|
) {
|
||||||
|
|
||||||
private val uniqIds = StubIrUniqIdProvider(ManglingContext.Module(packageFqName))
|
fun emit(): KmModuleFragment {
|
||||||
|
val uniqIdProvider = StubIrUniqIdProvider(ManglingContext.Module(packageFqName))
|
||||||
|
val context = VisitingContext(uniqIds = uniqIdProvider)
|
||||||
|
val elements = KmElements(visitor.visitSimpleStubContainer(module, context))
|
||||||
|
return writeModule(elements)
|
||||||
|
}
|
||||||
|
|
||||||
private val classes = mutableListOf<KmClass>()
|
private fun writeModule(elements: KmElements) = KmModuleFragment().also { km ->
|
||||||
private val properties = mutableListOf<KmProperty>()
|
|
||||||
private val typeAliases = mutableListOf<KmTypeAlias>()
|
|
||||||
private val functions = mutableListOf<KmFunction>()
|
|
||||||
|
|
||||||
fun writeModule(): KmModuleFragment = KmModuleFragment().also { km ->
|
|
||||||
km.fqName = packageFqName
|
km.fqName = packageFqName
|
||||||
km.classes += classes
|
km.classes += elements.classes.toList()
|
||||||
km.pkg = writePackage()
|
km.className += elements.classes.map(KmClass::name)
|
||||||
|
km.pkg = writePackage(elements)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun writePackage() = KmPackage().also { km ->
|
private fun writePackage(elements: KmElements) = KmPackage().also { km ->
|
||||||
km.fqName = packageFqName
|
km.fqName = packageFqName
|
||||||
km.typeAliases += typeAliases
|
km.typeAliases += elements.typeAliases.toList()
|
||||||
km.properties += properties
|
km.properties += elements.properties.toList()
|
||||||
km.functions += functions
|
km.functions += elements.functions.toList()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitClass(element: ClassStub, data: StubContainer?) {
|
/**
|
||||||
// TODO("not implemented")
|
* StubIr translation result. Since Km* classes don't have common hierarchy we need
|
||||||
|
* to use list of Any.
|
||||||
|
*/
|
||||||
|
private class KmElements(result: List<Any>) {
|
||||||
|
val classes: List<KmClass> = result.filterIsInstance<List<KmClass>>().flatten()
|
||||||
|
val properties: List<KmProperty> = result.filterIsInstance<KmProperty>()
|
||||||
|
val typeAliases: List<KmTypeAlias> = result.filterIsInstance<KmTypeAlias>()
|
||||||
|
val functions: List<KmFunction> = result.filterIsInstance<KmFunction>()
|
||||||
|
val constructors: List<KmConstructor> = result.filterIsInstance<KmConstructor>()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitTypealias(element: TypealiasStub, data: StubContainer?) {
|
/**
|
||||||
KmTypeAlias(element.flags, element.alias.topLevelName).apply {
|
* Used to pass data between parents and children when visiting StubIr elements.
|
||||||
uniqId = uniqIds.uniqIdForTypeAlias(element)
|
*/
|
||||||
underlyingType = element.aliasee.map(shouldExpandTypeAliases = false)
|
private data class VisitingContext(
|
||||||
expandedType = element.aliasee.map()
|
val container: StubContainer? = null,
|
||||||
}.let(typeAliases::add)
|
val uniqIds: StubIrUniqIdProvider
|
||||||
}
|
)
|
||||||
|
|
||||||
override fun visitFunction(element: FunctionStub, data: StubContainer?) {
|
private val visitor = object : StubIrVisitor<VisitingContext, Any> {
|
||||||
KmFunction(element.flags, element.name).apply {
|
|
||||||
element.annotations.mapTo(annotations, AnnotationStub::map)
|
|
||||||
returnType = element.returnType.map()
|
|
||||||
element.parameters.mapTo(valueParameters, FunctionParameterStub::map)
|
|
||||||
element.typeParameters.mapTo(typeParameters, TypeParameterStub::map)
|
|
||||||
uniqId = uniqIds.uniqIdForFunction(element)
|
|
||||||
}.let(functions::add)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitProperty(element: PropertyStub, data: StubContainer?) {
|
override fun visitClass(element: ClassStub, data: VisitingContext) {
|
||||||
KmProperty(element.flags, element.name, element.getterFlags, element.setterFlags).apply {
|
// TODO("not implemented")
|
||||||
element.annotations.mapTo(annotations, AnnotationStub::map)
|
}
|
||||||
uniqId = uniqIds.uniqIdForProperty(element)
|
|
||||||
returnType = element.type.map()
|
override fun visitTypealias(element: TypealiasStub, data: VisitingContext): KmTypeAlias =
|
||||||
if (element.kind is PropertyStub.Kind.Var) {
|
KmTypeAlias(element.flags, element.alias.topLevelName).also { km ->
|
||||||
val setter = element.kind.setter
|
km.uniqId = data.uniqIds.uniqIdForTypeAlias(element)
|
||||||
setter.annotations.mapTo(setterAnnotations, AnnotationStub::map)
|
km.underlyingType = element.aliasee.map(shouldExpandTypeAliases = false)
|
||||||
// TODO: Maybe it's better to explicitly add setter parameter in stub.
|
km.expandedType = element.aliasee.map()
|
||||||
setterParameter = FunctionParameterStub("value", element.type).map()
|
|
||||||
}
|
}
|
||||||
getterAnnotations += when (element.kind) {
|
|
||||||
is PropertyStub.Kind.Val -> element.kind.getter.annotations.map(AnnotationStub::map)
|
override fun visitFunction(element: FunctionStub, data: VisitingContext) =
|
||||||
is PropertyStub.Kind.Var -> element.kind.getter.annotations.map(AnnotationStub::map)
|
KmFunction(element.flags, element.name).also { km ->
|
||||||
is PropertyStub.Kind.Constant -> emptyList()
|
element.annotations.mapTo(km.annotations, AnnotationStub::map)
|
||||||
|
km.returnType = element.returnType.map()
|
||||||
|
element.parameters.mapTo(km.valueParameters, FunctionParameterStub::map)
|
||||||
|
element.typeParameters.mapTo(km.typeParameters, TypeParameterStub::map)
|
||||||
|
km.uniqId = data.uniqIds.uniqIdForFunction(element)
|
||||||
}
|
}
|
||||||
if (element.kind is PropertyStub.Kind.Constant) {
|
|
||||||
compileTimeValue = element.kind.constant.map()
|
override fun visitProperty(element: PropertyStub, data: VisitingContext) =
|
||||||
|
KmProperty(element.flags, element.name, element.getterFlags, element.setterFlags).also { km ->
|
||||||
|
element.annotations.mapTo(km.annotations, AnnotationStub::map)
|
||||||
|
km.uniqId = data.uniqIds.uniqIdForProperty(element)
|
||||||
|
km.returnType = element.type.map()
|
||||||
|
if (element.kind is PropertyStub.Kind.Var) {
|
||||||
|
val setter = element.kind.setter
|
||||||
|
setter.annotations.mapTo(km.setterAnnotations, AnnotationStub::map)
|
||||||
|
// TODO: Maybe it's better to explicitly add setter parameter in stub.
|
||||||
|
km.setterParameter = FunctionParameterStub("value", element.type).map()
|
||||||
|
}
|
||||||
|
km.getterAnnotations += when (element.kind) {
|
||||||
|
is PropertyStub.Kind.Val -> element.kind.getter.annotations.map(AnnotationStub::map)
|
||||||
|
is PropertyStub.Kind.Var -> element.kind.getter.annotations.map(AnnotationStub::map)
|
||||||
|
is PropertyStub.Kind.Constant -> emptyList()
|
||||||
|
}
|
||||||
|
if (element.kind is PropertyStub.Kind.Constant) {
|
||||||
|
km.compileTimeValue = element.kind.constant.mapToAnnotationArgument()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}.let(properties::add)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitConstructor(constructorStub: ConstructorStub, data: StubContainer?) {
|
override fun visitConstructor(constructorStub: ConstructorStub, data: VisitingContext) {
|
||||||
// TODO("not implemented")
|
// TODO("not implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitPropertyAccessor(propertyAccessor: PropertyAccessor, data: StubContainer?) {
|
override fun visitPropertyAccessor(propertyAccessor: PropertyAccessor, data: VisitingContext) {
|
||||||
// TODO("not implemented")
|
// TODO("not implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitSimpleStubContainer(simpleStubContainer: SimpleStubContainer, data: StubContainer?) {
|
override fun visitSimpleStubContainer(simpleStubContainer: SimpleStubContainer, data: VisitingContext): List<Any> =
|
||||||
simpleStubContainer.children.forEach { it.accept(this, simpleStubContainer) }
|
simpleStubContainer.children.map { it.accept(this, data) } +
|
||||||
|
simpleStubContainer.simpleContainers.flatMap { visitSimpleStubContainer(it, data) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -292,7 +311,7 @@ private fun TypeArgument.Variance.map(): KmVariance = when (this) {
|
|||||||
TypeArgument.Variance.OUT -> KmVariance.OUT
|
TypeArgument.Variance.OUT -> KmVariance.OUT
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun ConstantStub.map(): KmAnnotationArgument<*> = when (this) {
|
private fun ConstantStub.mapToAnnotationArgument(): KmAnnotationArgument<*> = when (this) {
|
||||||
is StringConstantStub -> KmAnnotationArgument.StringValue(value)
|
is StringConstantStub -> KmAnnotationArgument.StringValue(value)
|
||||||
is IntegralConstantStub -> when (size) {
|
is IntegralConstantStub -> when (size) {
|
||||||
1 -> if (isSigned) {
|
1 -> if (isSigned) {
|
||||||
|
|||||||
+3
-5
@@ -49,11 +49,9 @@ class StubIrToMetadataTests {
|
|||||||
fqName: String,
|
fqName: String,
|
||||||
functions: List<FunctionStub> = emptyList(),
|
functions: List<FunctionStub> = emptyList(),
|
||||||
properties: List<PropertyStub> = emptyList()
|
properties: List<PropertyStub> = emptyList()
|
||||||
) = ModuleMetadataEmitter(fqName).let {
|
) = SimpleStubContainer(functions = functions, properties = properties)
|
||||||
val stubs = SimpleStubContainer(functions = functions, properties = properties)
|
.let { ModuleMetadataEmitter(fqName, it).emit() }
|
||||||
stubs.accept(it, null)
|
.also(this::checkUniqIdPresence)
|
||||||
it.writeModule()
|
|
||||||
}.also(this::checkUniqIdPresence)
|
|
||||||
|
|
||||||
private fun checkUniqIdPresence(metadata: KmModuleFragment) {
|
private fun checkUniqIdPresence(metadata: KmModuleFragment) {
|
||||||
metadata.classes.forEach { assertNotNull(it.uniqId) }
|
metadata.classes.forEach { assertNotNull(it.uniqId) }
|
||||||
|
|||||||
Reference in New Issue
Block a user