[Commonizer] Split CirTreeMerger into composable 'Mergers'
This commit is contained in:
committed by
Space
parent
2f49e8e0af
commit
096e715652
@@ -11,7 +11,6 @@ import org.jetbrains.kotlin.commonizer.ResultsConsumer.Status
|
||||
import org.jetbrains.kotlin.commonizer.core.CommonizationVisitor
|
||||
import org.jetbrains.kotlin.commonizer.mergedtree.*
|
||||
import org.jetbrains.kotlin.commonizer.mergedtree.CirNode.Companion.dimension
|
||||
import org.jetbrains.kotlin.commonizer.mergedtree.CirTreeMerger.CirTreeMergeResult
|
||||
import org.jetbrains.kotlin.commonizer.metadata.CirTreeSerializer
|
||||
import org.jetbrains.kotlin.library.SerializedMetadata
|
||||
import org.jetbrains.kotlin.storage.LockBasedStorageManager
|
||||
@@ -45,11 +44,10 @@ private fun mergeAndCommonize(storageManager: StorageManager, parameters: Common
|
||||
CirProvidedClassifiers.by(parameters.dependencyModulesProvider)
|
||||
)
|
||||
)
|
||||
val mergeResult = CirTreeMerger(storageManager, classifiers, parameters).build()
|
||||
val mergeResult = mergeCirTree(storageManager, classifiers, parameters)
|
||||
|
||||
// commonize:
|
||||
val mergedTree = mergeResult.root
|
||||
mergedTree.accept(CommonizationVisitor(classifiers, mergedTree), Unit)
|
||||
mergeResult.root.accept(CommonizationVisitor(classifiers, mergeResult.root), Unit)
|
||||
parameters.progressLogger?.invoke("Commonized declarations")
|
||||
|
||||
return mergeResult
|
||||
|
||||
+51
-347
@@ -5,22 +5,17 @@
|
||||
|
||||
package org.jetbrains.kotlin.commonizer.mergedtree
|
||||
|
||||
import com.intellij.util.containers.FactoryMap
|
||||
import kotlinx.metadata.*
|
||||
import kotlinx.metadata.klib.KlibModuleMetadata
|
||||
import kotlinx.metadata.klib.fqName
|
||||
import kotlinx.metadata.klib.klibEnumEntries
|
||||
import kotlinx.metadata.KmTypeParameter
|
||||
import org.jetbrains.kotlin.commonizer.CommonizerParameters
|
||||
import org.jetbrains.kotlin.commonizer.LeafCommonizerTarget
|
||||
import org.jetbrains.kotlin.commonizer.ModulesProvider.ModuleInfo
|
||||
import org.jetbrains.kotlin.commonizer.TargetProvider
|
||||
import org.jetbrains.kotlin.commonizer.cir.*
|
||||
import org.jetbrains.kotlin.commonizer.mergedtree.ClassesToProcess.ClassEntry
|
||||
import org.jetbrains.kotlin.commonizer.metadata.CirDeserializers
|
||||
import org.jetbrains.kotlin.commonizer.mergedtree.mergers.*
|
||||
import org.jetbrains.kotlin.commonizer.mergedtree.mergers.ClassesToProcess
|
||||
import org.jetbrains.kotlin.commonizer.mergedtree.mergers.ModuleMerger
|
||||
import org.jetbrains.kotlin.commonizer.mergedtree.mergers.PropertyMerger
|
||||
import org.jetbrains.kotlin.commonizer.mergedtree.mergers.RootMerger
|
||||
import org.jetbrains.kotlin.commonizer.mergedtree.mergers.TargetMerger
|
||||
import org.jetbrains.kotlin.commonizer.metadata.CirTypeResolver
|
||||
import org.jetbrains.kotlin.commonizer.metadata.utils.SerializedMetadataLibraryProvider
|
||||
import org.jetbrains.kotlin.commonizer.prettyName
|
||||
import org.jetbrains.kotlin.commonizer.utils.*
|
||||
import org.jetbrains.kotlin.storage.StorageManager
|
||||
|
||||
/**
|
||||
@@ -48,347 +43,56 @@ import org.jetbrains.kotlin.storage.StorageManager
|
||||
* targets (which is not supported yet), or a Native library where one fragment is produced via C-interop tool and the other one
|
||||
* is compiled from Kotlin/Native source code (not sure this should be supported at all).
|
||||
*/
|
||||
class CirTreeMerger(
|
||||
private val storageManager: StorageManager,
|
||||
private val classifiers: CirKnownClassifiers,
|
||||
private val parameters: CommonizerParameters
|
||||
|
||||
class CirTreeMergeResult(
|
||||
val root: CirRootNode,
|
||||
val missingModuleInfos: Map<LeafCommonizerTarget, Collection<ModuleInfo>>
|
||||
)
|
||||
|
||||
internal class CirTargetMergingContext(
|
||||
val storageManager: StorageManager,
|
||||
val classifiers: CirKnownClassifiers,
|
||||
val parameters: CommonizerParameters,
|
||||
val targetIndex: Int,
|
||||
val typeResolver: CirTypeResolver
|
||||
) {
|
||||
class CirTreeMergeResult(
|
||||
val root: CirRootNode,
|
||||
val missingModuleInfos: Map<LeafCommonizerTarget, Collection<ModuleInfo>>
|
||||
)
|
||||
val targets = parameters.targetProviders.size
|
||||
}
|
||||
|
||||
private class CirTreeMergingContext(
|
||||
val targetIndex: Int,
|
||||
val typeResolver: CirTypeResolver
|
||||
) {
|
||||
fun create(classEntry: ClassEntry): CirTreeMergingContext = when (classEntry) {
|
||||
is ClassEntry.RegularClassEntry -> create(classEntry.clazz.typeParameters)
|
||||
is ClassEntry.EnumEntry -> this
|
||||
}
|
||||
internal fun CirTargetMergingContext.create(classEntry: ClassesToProcess.ClassEntry): CirTargetMergingContext = when (classEntry) {
|
||||
is ClassesToProcess.ClassEntry.RegularClassEntry -> create(classEntry.clazz.typeParameters)
|
||||
is ClassesToProcess.ClassEntry.EnumEntry -> this
|
||||
}
|
||||
|
||||
fun create(typeParameters: List<KmTypeParameter>): CirTreeMergingContext {
|
||||
val newTypeResolver = typeResolver.create(typeParameters)
|
||||
return if (newTypeResolver !== typeResolver)
|
||||
CirTreeMergingContext(targetIndex, newTypeResolver)
|
||||
else
|
||||
this
|
||||
}
|
||||
}
|
||||
internal fun CirTargetMergingContext.create(typeParameters: List<KmTypeParameter>): CirTargetMergingContext {
|
||||
val newTypeResolver = typeResolver.create(typeParameters)
|
||||
return if (newTypeResolver !== typeResolver)
|
||||
CirTargetMergingContext(storageManager, classifiers, parameters, targetIndex, newTypeResolver)
|
||||
else
|
||||
this
|
||||
}
|
||||
|
||||
private val leafTargetsSize = parameters.targetProviders.size
|
||||
|
||||
fun build(): CirTreeMergeResult {
|
||||
val result = processRoot()
|
||||
System.gc()
|
||||
return result
|
||||
}
|
||||
|
||||
private fun processRoot(): CirTreeMergeResult {
|
||||
val rootNode: CirRootNode = buildRootNode(storageManager, leafTargetsSize)
|
||||
|
||||
val commonModuleNames = parameters.getCommonModuleNames()
|
||||
val missingModuleInfosByTargets = mutableMapOf<LeafCommonizerTarget, Collection<ModuleInfo>>()
|
||||
|
||||
parameters.targetProviders.forEachIndexed { targetIndex, targetProvider ->
|
||||
val allModuleInfos = targetProvider.modulesProvider.loadModuleInfos()
|
||||
|
||||
val (commonModuleInfos, missingModuleInfos) = allModuleInfos.partition { it.name in commonModuleNames }
|
||||
processTarget(targetIndex, rootNode, targetProvider, commonModuleInfos)
|
||||
|
||||
missingModuleInfosByTargets[targetProvider.target] = missingModuleInfos
|
||||
|
||||
parameters.progressLogger?.invoke("Loaded declarations for ${targetProvider.target.prettyName}")
|
||||
System.gc()
|
||||
}
|
||||
|
||||
return CirTreeMergeResult(
|
||||
root = rootNode,
|
||||
missingModuleInfos = missingModuleInfosByTargets
|
||||
)
|
||||
}
|
||||
|
||||
private fun processTarget(
|
||||
targetIndex: Int,
|
||||
rootNode: CirRootNode,
|
||||
targetProvider: TargetProvider,
|
||||
commonModuleInfos: Collection<ModuleInfo>
|
||||
) {
|
||||
rootNode.targetDeclarations[targetIndex] = CirRoot.create(targetProvider.target)
|
||||
|
||||
if (commonModuleInfos.isEmpty())
|
||||
return
|
||||
|
||||
val context = CirTreeMergingContext(
|
||||
targetIndex = targetIndex,
|
||||
// all classifiers "visible" for the target:
|
||||
typeResolver = CirTypeResolver.create(
|
||||
providedClassifiers = CirProvidedClassifiers.of(
|
||||
classifiers.commonDependencies,
|
||||
CirProvidedClassifiers.by(targetProvider.dependencyModulesProvider),
|
||||
CirProvidedClassifiers.by(targetProvider.modulesProvider)
|
||||
fun mergeCirTree(
|
||||
storageManager: StorageManager,
|
||||
classifiers: CirKnownClassifiers,
|
||||
parameters: CommonizerParameters
|
||||
): CirTreeMergeResult {
|
||||
val rootMerger = RootMerger(
|
||||
targetMerger = TargetMerger(
|
||||
moduleMerger = ModuleMerger(
|
||||
packageMerger = PackageMerger(
|
||||
propertyMerger = PropertyMerger,
|
||||
functionMerger = FunctionMerger,
|
||||
classMerger = ClassMerger(
|
||||
classConstructorMerger = ClassConstructorMerger,
|
||||
propertyMerger = PropertyMerger,
|
||||
functionMerger = FunctionMerger,
|
||||
),
|
||||
typeAliasMerger = TypeAliasMerger
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
commonModuleInfos.forEach { moduleInfo ->
|
||||
val metadata = targetProvider.modulesProvider.loadModuleMetadata(moduleInfo.name)
|
||||
val module = KlibModuleMetadata.read(SerializedMetadataLibraryProvider(metadata))
|
||||
processModule(context, rootNode, module)
|
||||
}
|
||||
}
|
||||
|
||||
private fun processModule(
|
||||
context: CirTreeMergingContext,
|
||||
rootNode: CirRootNode,
|
||||
module: KlibModuleMetadata
|
||||
) {
|
||||
val moduleName: CirName = CirName.create(module.name)
|
||||
val moduleNode: CirModuleNode = rootNode.modules.getOrPut(moduleName) {
|
||||
buildModuleNode(storageManager, leafTargetsSize)
|
||||
}
|
||||
moduleNode.targetDeclarations[context.targetIndex] = CirModule.create(moduleName)
|
||||
|
||||
val groupedFragments: Map<CirPackageName, Collection<KmModuleFragment>> = module.fragments.foldToMap { fragment ->
|
||||
fragment.fqName?.let(CirPackageName::create) ?: error("A fragment without FQ name in module $moduleName: $fragment")
|
||||
}
|
||||
|
||||
groupedFragments.forEach { (packageName, fragments) ->
|
||||
processFragments(context, moduleNode, fragments, packageName)
|
||||
}
|
||||
}
|
||||
|
||||
private fun processFragments(
|
||||
context: CirTreeMergingContext,
|
||||
moduleNode: CirModuleNode,
|
||||
fragments: Collection<KmModuleFragment>,
|
||||
packageName: CirPackageName
|
||||
) {
|
||||
val packageNode: CirPackageNode = moduleNode.packages.getOrPut(packageName) {
|
||||
buildPackageNode(storageManager, leafTargetsSize)
|
||||
}
|
||||
packageNode.targetDeclarations[context.targetIndex] = CirPackage.create(packageName)
|
||||
|
||||
val classesToProcess = ClassesToProcess()
|
||||
fragments.forEach { fragment ->
|
||||
classesToProcess.addClassesFromFragment(fragment)
|
||||
|
||||
fragment.pkg?.let { pkg ->
|
||||
pkg.properties.forEach { property ->
|
||||
val propertyContext = context.create(property.typeParameters)
|
||||
processProperty(propertyContext, packageNode, property)
|
||||
}
|
||||
pkg.functions.forEach { function ->
|
||||
val functionContext = context.create(function.typeParameters)
|
||||
processFunction(functionContext, packageNode, function)
|
||||
}
|
||||
pkg.typeAliases.forEach { typeAlias ->
|
||||
val typeAliasContext = context.create(typeAlias.typeParameters)
|
||||
processTypeAlias(typeAliasContext, packageNode, typeAlias)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
classesToProcess.forEachClassInScope(parentClassId = null) { classEntry ->
|
||||
val classContext = context.create(classEntry)
|
||||
processClass(classContext, packageNode, classEntry, classesToProcess)
|
||||
}
|
||||
}
|
||||
|
||||
private fun processProperty(
|
||||
context: CirTreeMergingContext,
|
||||
ownerNode: CirNodeWithMembers<*, *>,
|
||||
property: KmProperty
|
||||
) {
|
||||
if (property.isFakeOverride())
|
||||
return
|
||||
|
||||
val maybeClassOwnerNode: CirClassNode? = ownerNode as? CirClassNode
|
||||
|
||||
val approximationKey = PropertyApproximationKey(property, context.typeResolver)
|
||||
val propertyNode: CirPropertyNode = ownerNode.properties.getOrPut(approximationKey) {
|
||||
buildPropertyNode(storageManager, leafTargetsSize, classifiers, maybeClassOwnerNode?.commonDeclaration)
|
||||
}
|
||||
propertyNode.targetDeclarations[context.targetIndex] = CirDeserializers.property(
|
||||
name = approximationKey.name,
|
||||
source = property,
|
||||
containingClass = maybeClassOwnerNode?.targetDeclarations?.get(context.targetIndex),
|
||||
typeResolver = context.typeResolver
|
||||
)
|
||||
}
|
||||
|
||||
private fun processFunction(
|
||||
context: CirTreeMergingContext,
|
||||
ownerNode: CirNodeWithMembers<*, *>,
|
||||
function: KmFunction
|
||||
) {
|
||||
if (function.isFakeOverride()
|
||||
|| function.isKniBridgeFunction()
|
||||
|| function.isTopLevelDeprecatedFunction(isTopLevel = ownerNode !is CirClassNode)
|
||||
) {
|
||||
return
|
||||
}
|
||||
|
||||
val maybeClassOwnerNode: CirClassNode? = ownerNode as? CirClassNode
|
||||
|
||||
val approximationKey = FunctionApproximationKey(function, context.typeResolver)
|
||||
val functionNode: CirFunctionNode = ownerNode.functions.getOrPut(approximationKey) {
|
||||
buildFunctionNode(storageManager, leafTargetsSize, classifiers, maybeClassOwnerNode?.commonDeclaration)
|
||||
}
|
||||
functionNode.targetDeclarations[context.targetIndex] = CirDeserializers.function(
|
||||
name = approximationKey.name,
|
||||
source = function,
|
||||
containingClass = maybeClassOwnerNode?.targetDeclarations?.get(context.targetIndex),
|
||||
typeResolver = context.typeResolver
|
||||
)
|
||||
}
|
||||
|
||||
private fun processClass(
|
||||
context: CirTreeMergingContext,
|
||||
ownerNode: CirNodeWithMembers<*, *>,
|
||||
classEntry: ClassEntry,
|
||||
classesToProcess: ClassesToProcess
|
||||
) {
|
||||
val classId = classEntry.classId
|
||||
val className = classId.relativeNameSegments.last()
|
||||
|
||||
val maybeClassOwnerNode: CirClassNode? = ownerNode as? CirClassNode
|
||||
val classNode: CirClassNode = ownerNode.classes.getOrPut(className) {
|
||||
buildClassNode(storageManager, leafTargetsSize, classifiers, maybeClassOwnerNode?.commonDeclaration, classId)
|
||||
}
|
||||
|
||||
val clazz: KmClass?
|
||||
val isEnumEntry: Boolean
|
||||
|
||||
classNode.targetDeclarations[context.targetIndex] = when (classEntry) {
|
||||
is ClassEntry.RegularClassEntry -> {
|
||||
clazz = classEntry.clazz
|
||||
isEnumEntry = Flag.Class.IS_ENUM_ENTRY(clazz.flags)
|
||||
|
||||
CirDeserializers.clazz(className, clazz, context.typeResolver)
|
||||
}
|
||||
is ClassEntry.EnumEntry -> {
|
||||
clazz = null
|
||||
isEnumEntry = true
|
||||
|
||||
CirDeserializers.defaultEnumEntry(
|
||||
name = className,
|
||||
annotations = classEntry.annotations,
|
||||
enumClassId = classEntry.enumClassId,
|
||||
enumClass = classEntry.enumClass,
|
||||
typeResolver = context.typeResolver
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (!isEnumEntry) {
|
||||
clazz?.constructors?.forEach { constructor ->
|
||||
// TODO: nowhere to read constructor type parameters from
|
||||
//val constructorContext = context.create(constructor.typeParameters)
|
||||
|
||||
processClassConstructor(context, classNode, constructor)
|
||||
}
|
||||
}
|
||||
|
||||
clazz?.properties?.forEach { property ->
|
||||
val propertyContext = context.create(property.typeParameters)
|
||||
processProperty(propertyContext, classNode, property)
|
||||
}
|
||||
clazz?.functions?.forEach { function ->
|
||||
val functionContext = context.create(function.typeParameters)
|
||||
processFunction(functionContext, classNode, function)
|
||||
}
|
||||
|
||||
classesToProcess.forEachClassInScope(parentClassId = classId) { nestedClassEntry ->
|
||||
val nestedClassContext = context.create(nestedClassEntry)
|
||||
processClass(nestedClassContext, classNode, nestedClassEntry, classesToProcess)
|
||||
}
|
||||
}
|
||||
|
||||
private fun processClassConstructor(
|
||||
context: CirTreeMergingContext,
|
||||
classNode: CirClassNode,
|
||||
constructor: KmConstructor
|
||||
) {
|
||||
val approximationKey = ConstructorApproximationKey(constructor, context.typeResolver)
|
||||
val constructorNode: CirClassConstructorNode = classNode.constructors.getOrPut(approximationKey) {
|
||||
buildClassConstructorNode(storageManager, leafTargetsSize, classifiers, classNode.commonDeclaration)
|
||||
}
|
||||
constructorNode.targetDeclarations[context.targetIndex] = CirDeserializers.constructor(
|
||||
source = constructor,
|
||||
containingClass = classNode.targetDeclarations[context.targetIndex]!!,
|
||||
typeResolver = context.typeResolver
|
||||
)
|
||||
}
|
||||
|
||||
private fun processTypeAlias(
|
||||
context: CirTreeMergingContext,
|
||||
packageNode: CirPackageNode,
|
||||
typeAlias: KmTypeAlias
|
||||
) {
|
||||
val typeAliasName = CirName.create(typeAlias.name)
|
||||
val typeAliasId = CirEntityId.create(packageNode.packageName, typeAliasName)
|
||||
|
||||
val typeAliasNode: CirTypeAliasNode = packageNode.typeAliases.getOrPut(typeAliasName) {
|
||||
buildTypeAliasNode(storageManager, leafTargetsSize, classifiers, typeAliasId)
|
||||
}
|
||||
typeAliasNode.targetDeclarations[context.targetIndex] = CirDeserializers.typeAlias(
|
||||
name = typeAliasName,
|
||||
source = typeAlias,
|
||||
typeResolver = context.typeResolver
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private class ClassesToProcess {
|
||||
sealed class ClassEntry {
|
||||
abstract val classId: CirEntityId
|
||||
|
||||
data class RegularClassEntry(
|
||||
override val classId: CirEntityId,
|
||||
val clazz: KmClass
|
||||
) : ClassEntry()
|
||||
|
||||
data class EnumEntry(
|
||||
override val classId: CirEntityId,
|
||||
val annotations: List<KmAnnotation>,
|
||||
val enumClassId: CirEntityId,
|
||||
val enumClass: KmClass
|
||||
) : ClassEntry()
|
||||
}
|
||||
|
||||
// key = parent class ID (or NON_EXISTING_CLASSIFIER_ID for top-level classes)
|
||||
// value = classes under this parent class (MutableList to preserve order of classes)
|
||||
private val groupedByParentClassId = FactoryMap.create<CirEntityId, MutableList<ClassEntry>> { ArrayList() }
|
||||
|
||||
fun addClassesFromFragment(fragment: KmModuleFragment) {
|
||||
val klibEnumEntries = LinkedHashMap<CirEntityId, ClassEntry.EnumEntry>() // linked hash map to preserve order
|
||||
val regularClassIds = HashSet<CirEntityId>()
|
||||
|
||||
fragment.classes.forEach { clazz ->
|
||||
val classId: CirEntityId = CirEntityId.create(clazz.name)
|
||||
val parentClassId: CirEntityId = classId.getParentEntityId() ?: NON_EXISTING_CLASSIFIER_ID
|
||||
|
||||
if (Flag.Class.IS_ENUM_CLASS(clazz.flags)) {
|
||||
clazz.klibEnumEntries.forEach { entry ->
|
||||
val enumEntryId = classId.createNestedEntityId(CirName.create(entry.name))
|
||||
klibEnumEntries[enumEntryId] = ClassEntry.EnumEntry(enumEntryId, entry.annotations, classId, clazz)
|
||||
}
|
||||
}
|
||||
|
||||
groupedByParentClassId.getValue(parentClassId) += ClassEntry.RegularClassEntry(classId, clazz)
|
||||
regularClassIds += classId
|
||||
}
|
||||
|
||||
// add enum entries that are not stored in module as KmClass records
|
||||
klibEnumEntries.forEach { (enumEntryId, enumEntry) ->
|
||||
if (enumEntryId !in regularClassIds) {
|
||||
groupedByParentClassId.getValue(enumEntry.enumClassId) += enumEntry
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun forEachClassInScope(parentClassId: CirEntityId?, block: (ClassEntry) -> Unit) {
|
||||
groupedByParentClassId[parentClassId ?: NON_EXISTING_CLASSIFIER_ID]?.forEach { classEntry -> block(classEntry) }
|
||||
}
|
||||
return rootMerger.processRoot(storageManager, classifiers, parameters)
|
||||
}
|
||||
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* 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.commonizer.mergedtree.mergers
|
||||
|
||||
import kotlinx.metadata.KmConstructor
|
||||
import org.jetbrains.kotlin.commonizer.mergedtree.*
|
||||
import org.jetbrains.kotlin.commonizer.mergedtree.CirTargetMergingContext
|
||||
import org.jetbrains.kotlin.commonizer.mergedtree.buildClassConstructorNode
|
||||
import org.jetbrains.kotlin.commonizer.metadata.CirDeserializers
|
||||
|
||||
internal object ClassConstructorMerger {
|
||||
fun processClassConstructor(
|
||||
context: CirTargetMergingContext,
|
||||
classNode: CirClassNode,
|
||||
constructor: KmConstructor
|
||||
) = with(context) {
|
||||
val approximationKey = ConstructorApproximationKey(constructor, context.typeResolver)
|
||||
val constructorNode: CirClassConstructorNode = classNode.constructors.getOrPut(approximationKey) {
|
||||
buildClassConstructorNode(storageManager, targets, classifiers, classNode.commonDeclaration)
|
||||
}
|
||||
constructorNode.targetDeclarations[context.targetIndex] = CirDeserializers.constructor(
|
||||
source = constructor,
|
||||
containingClass = classNode.targetDeclarations[context.targetIndex]!!,
|
||||
typeResolver = context.typeResolver
|
||||
)
|
||||
}
|
||||
}
|
||||
+80
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* 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.commonizer.mergedtree.mergers
|
||||
|
||||
import kotlinx.metadata.Flag
|
||||
import kotlinx.metadata.KmClass
|
||||
import org.jetbrains.kotlin.commonizer.mergedtree.*
|
||||
import org.jetbrains.kotlin.commonizer.mergedtree.CirTargetMergingContext
|
||||
import org.jetbrains.kotlin.commonizer.mergedtree.buildClassNode
|
||||
import org.jetbrains.kotlin.commonizer.metadata.CirDeserializers
|
||||
|
||||
internal class ClassMerger(
|
||||
private val classConstructorMerger: ClassConstructorMerger?,
|
||||
private val propertyMerger: PropertyMerger?,
|
||||
private val functionMerger: FunctionMerger?
|
||||
) {
|
||||
fun processClass(
|
||||
context: CirTargetMergingContext,
|
||||
ownerNode: CirNodeWithMembers<*, *>,
|
||||
classEntry: ClassesToProcess.ClassEntry,
|
||||
classesToProcess: ClassesToProcess
|
||||
): Unit = with(context) {
|
||||
val classId = classEntry.classId
|
||||
val className = classId.relativeNameSegments.last()
|
||||
|
||||
val maybeClassOwnerNode: CirClassNode? = ownerNode as? CirClassNode
|
||||
val classNode: CirClassNode = ownerNode.classes.getOrPut(className) {
|
||||
buildClassNode(storageManager, targets, classifiers, maybeClassOwnerNode?.commonDeclaration, classId)
|
||||
}
|
||||
|
||||
val clazz: KmClass?
|
||||
val isEnumEntry: Boolean
|
||||
|
||||
classNode.targetDeclarations[context.targetIndex] = when (classEntry) {
|
||||
is ClassesToProcess.ClassEntry.RegularClassEntry -> {
|
||||
clazz = classEntry.clazz
|
||||
isEnumEntry = Flag.Class.IS_ENUM_ENTRY(clazz.flags)
|
||||
|
||||
CirDeserializers.clazz(className, clazz, context.typeResolver)
|
||||
}
|
||||
is ClassesToProcess.ClassEntry.EnumEntry -> {
|
||||
clazz = null
|
||||
isEnumEntry = true
|
||||
|
||||
CirDeserializers.defaultEnumEntry(
|
||||
name = className,
|
||||
annotations = classEntry.annotations,
|
||||
enumClassId = classEntry.enumClassId,
|
||||
enumClass = classEntry.enumClass,
|
||||
typeResolver = context.typeResolver
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (!isEnumEntry) {
|
||||
clazz?.constructors?.forEach { constructor ->
|
||||
// TODO: nowhere to read constructor type parameters from
|
||||
//val constructorContext = context.create(constructor.typeParameters)
|
||||
classConstructorMerger?.processClassConstructor(context, classNode, constructor)
|
||||
}
|
||||
}
|
||||
|
||||
clazz?.properties?.forEach { property ->
|
||||
val propertyContext = context.create(property.typeParameters)
|
||||
propertyMerger?.processProperty(propertyContext, classNode, property)
|
||||
}
|
||||
clazz?.functions?.forEach { function ->
|
||||
val functionContext = context.create(function.typeParameters)
|
||||
functionMerger?.processFunction(functionContext, classNode, function)
|
||||
}
|
||||
|
||||
classesToProcess.forEachClassInScope(parentClassId = classId) { nestedClassEntry ->
|
||||
val nestedClassContext = context.create(nestedClassEntry)
|
||||
processClass(nestedClassContext, classNode, nestedClassEntry, classesToProcess)
|
||||
}
|
||||
}
|
||||
}
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* 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.commonizer.mergedtree.mergers
|
||||
|
||||
import com.intellij.util.containers.FactoryMap
|
||||
import kotlinx.metadata.Flag
|
||||
import kotlinx.metadata.KmAnnotation
|
||||
import kotlinx.metadata.KmClass
|
||||
import kotlinx.metadata.KmModuleFragment
|
||||
import kotlinx.metadata.klib.klibEnumEntries
|
||||
import org.jetbrains.kotlin.commonizer.cir.CirEntityId
|
||||
import org.jetbrains.kotlin.commonizer.cir.CirName
|
||||
import org.jetbrains.kotlin.commonizer.utils.NON_EXISTING_CLASSIFIER_ID
|
||||
|
||||
internal class ClassesToProcess {
|
||||
sealed class ClassEntry {
|
||||
abstract val classId: CirEntityId
|
||||
|
||||
data class RegularClassEntry(
|
||||
override val classId: CirEntityId,
|
||||
val clazz: KmClass
|
||||
) : ClassEntry()
|
||||
|
||||
data class EnumEntry(
|
||||
override val classId: CirEntityId,
|
||||
val annotations: List<KmAnnotation>,
|
||||
val enumClassId: CirEntityId,
|
||||
val enumClass: KmClass
|
||||
) : ClassEntry()
|
||||
}
|
||||
|
||||
// key = parent class ID (or NON_EXISTING_CLASSIFIER_ID for top-level classes)
|
||||
// value = classes under this parent class (MutableList to preserve order of classes)
|
||||
private val groupedByParentClassId = FactoryMap.create<CirEntityId, MutableList<ClassEntry>> { ArrayList() }
|
||||
|
||||
fun addClassesFromFragment(fragment: KmModuleFragment) {
|
||||
val klibEnumEntries = LinkedHashMap<CirEntityId, ClassEntry.EnumEntry>() // linked hash map to preserve order
|
||||
val regularClassIds = HashSet<CirEntityId>()
|
||||
|
||||
fragment.classes.forEach { clazz ->
|
||||
val classId: CirEntityId = CirEntityId.create(clazz.name)
|
||||
val parentClassId: CirEntityId = classId.getParentEntityId() ?: NON_EXISTING_CLASSIFIER_ID
|
||||
|
||||
if (Flag.Class.IS_ENUM_CLASS(clazz.flags)) {
|
||||
clazz.klibEnumEntries.forEach { entry ->
|
||||
val enumEntryId = classId.createNestedEntityId(CirName.create(entry.name))
|
||||
klibEnumEntries[enumEntryId] = ClassEntry.EnumEntry(enumEntryId, entry.annotations, classId, clazz)
|
||||
}
|
||||
}
|
||||
|
||||
groupedByParentClassId.getValue(parentClassId) += ClassEntry.RegularClassEntry(classId, clazz)
|
||||
regularClassIds += classId
|
||||
}
|
||||
|
||||
// add enum entries that are not stored in module as KmClass records
|
||||
klibEnumEntries.forEach { (enumEntryId, enumEntry) ->
|
||||
if (enumEntryId !in regularClassIds) {
|
||||
groupedByParentClassId.getValue(enumEntry.enumClassId) += enumEntry
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun forEachClassInScope(parentClassId: CirEntityId?, block: (ClassEntry) -> Unit) {
|
||||
groupedByParentClassId[parentClassId ?: NON_EXISTING_CLASSIFIER_ID]?.forEach { classEntry -> block(classEntry) }
|
||||
}
|
||||
}
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* 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.commonizer.mergedtree.mergers
|
||||
|
||||
import kotlinx.metadata.KmFunction
|
||||
import org.jetbrains.kotlin.commonizer.mergedtree.*
|
||||
import org.jetbrains.kotlin.commonizer.mergedtree.CirTargetMergingContext
|
||||
import org.jetbrains.kotlin.commonizer.mergedtree.buildFunctionNode
|
||||
import org.jetbrains.kotlin.commonizer.metadata.CirDeserializers
|
||||
import org.jetbrains.kotlin.commonizer.utils.isFakeOverride
|
||||
import org.jetbrains.kotlin.commonizer.utils.isKniBridgeFunction
|
||||
import org.jetbrains.kotlin.commonizer.utils.isTopLevelDeprecatedFunction
|
||||
|
||||
internal object FunctionMerger {
|
||||
fun processFunction(
|
||||
context: CirTargetMergingContext,
|
||||
ownerNode: CirNodeWithMembers<*, *>,
|
||||
function: KmFunction
|
||||
) = with(context) {
|
||||
if (function.isFakeOverride()
|
||||
|| function.isKniBridgeFunction()
|
||||
|| function.isTopLevelDeprecatedFunction(isTopLevel = ownerNode !is CirClassNode)
|
||||
) {
|
||||
return
|
||||
}
|
||||
|
||||
val maybeClassOwnerNode: CirClassNode? = ownerNode as? CirClassNode
|
||||
|
||||
val approximationKey = FunctionApproximationKey(function, context.typeResolver)
|
||||
val functionNode: CirFunctionNode = ownerNode.functions.getOrPut(approximationKey) {
|
||||
buildFunctionNode(storageManager, targets, classifiers, maybeClassOwnerNode?.commonDeclaration)
|
||||
}
|
||||
functionNode.targetDeclarations[context.targetIndex] = CirDeserializers.function(
|
||||
name = approximationKey.name,
|
||||
source = function,
|
||||
containingClass = maybeClassOwnerNode?.targetDeclarations?.get(context.targetIndex),
|
||||
typeResolver = context.typeResolver
|
||||
)
|
||||
}
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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.commonizer.mergedtree.mergers
|
||||
|
||||
import kotlinx.metadata.KmModuleFragment
|
||||
import kotlinx.metadata.klib.KlibModuleMetadata
|
||||
import kotlinx.metadata.klib.fqName
|
||||
import org.jetbrains.kotlin.commonizer.cir.CirModule
|
||||
import org.jetbrains.kotlin.commonizer.cir.CirName
|
||||
import org.jetbrains.kotlin.commonizer.cir.CirPackageName
|
||||
import org.jetbrains.kotlin.commonizer.mergedtree.CirModuleNode
|
||||
import org.jetbrains.kotlin.commonizer.mergedtree.CirRootNode
|
||||
import org.jetbrains.kotlin.commonizer.mergedtree.CirTargetMergingContext
|
||||
import org.jetbrains.kotlin.commonizer.mergedtree.buildModuleNode
|
||||
import org.jetbrains.kotlin.commonizer.utils.foldToMap
|
||||
|
||||
internal class ModuleMerger(
|
||||
private val packageMerger: PackageMerger
|
||||
) {
|
||||
fun processModule(
|
||||
context: CirTargetMergingContext,
|
||||
rootNode: CirRootNode,
|
||||
module: KlibModuleMetadata
|
||||
): Unit = with(context) {
|
||||
val moduleName: CirName = CirName.create(module.name)
|
||||
val moduleNode: CirModuleNode = rootNode.modules.getOrPut(moduleName) {
|
||||
buildModuleNode(storageManager, targets)
|
||||
}
|
||||
moduleNode.targetDeclarations[context.targetIndex] = CirModule.create(moduleName)
|
||||
|
||||
val groupedFragments: Map<CirPackageName, Collection<KmModuleFragment>> = module.fragments.foldToMap { fragment ->
|
||||
fragment.fqName?.let(CirPackageName.Companion::create) ?: error("A fragment without FQ name in module $moduleName: $fragment")
|
||||
}
|
||||
|
||||
groupedFragments.forEach { (packageName, fragments) ->
|
||||
packageMerger.processFragments(context, moduleNode, fragments, packageName)
|
||||
}
|
||||
}
|
||||
}
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* 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.commonizer.mergedtree.mergers
|
||||
|
||||
import kotlinx.metadata.KmModuleFragment
|
||||
import kotlinx.metadata.KmTypeParameter
|
||||
import org.jetbrains.kotlin.commonizer.cir.CirPackage
|
||||
import org.jetbrains.kotlin.commonizer.cir.CirPackageName
|
||||
import org.jetbrains.kotlin.commonizer.mergedtree.*
|
||||
import org.jetbrains.kotlin.commonizer.mergedtree.CirTargetMergingContext
|
||||
import org.jetbrains.kotlin.commonizer.mergedtree.buildPackageNode
|
||||
|
||||
internal class PackageMerger(
|
||||
private val propertyMerger: PropertyMerger?,
|
||||
private val functionMerger: FunctionMerger?,
|
||||
private val classMerger: ClassMerger?,
|
||||
private val typeAliasMerger: TypeAliasMerger?
|
||||
) {
|
||||
fun processFragments(
|
||||
context: CirTargetMergingContext,
|
||||
moduleNode: CirModuleNode,
|
||||
fragments: Collection<KmModuleFragment>,
|
||||
packageName: CirPackageName
|
||||
): Unit = with(context) {
|
||||
val packageNode: CirPackageNode = moduleNode.packages.getOrPut(packageName) {
|
||||
buildPackageNode(storageManager, targets)
|
||||
}
|
||||
packageNode.targetDeclarations[context.targetIndex] = CirPackage.create(packageName)
|
||||
|
||||
val classesToProcess = ClassesToProcess()
|
||||
fragments.forEach { fragment ->
|
||||
classesToProcess.addClassesFromFragment(fragment)
|
||||
|
||||
fragment.pkg?.let { pkg ->
|
||||
pkg.properties.forEach { property ->
|
||||
val propertyContext = context.create(property.typeParameters)
|
||||
propertyMerger?.processProperty(propertyContext, packageNode, property)
|
||||
}
|
||||
pkg.functions.forEach { function ->
|
||||
val functionContext = context.create(function.typeParameters)
|
||||
functionMerger?.processFunction(functionContext, packageNode, function)
|
||||
}
|
||||
pkg.typeAliases.forEach { typeAlias ->
|
||||
val typeAliasContext = context.create(typeAlias.typeParameters)
|
||||
typeAliasMerger?.processTypeAlias(typeAliasContext, packageNode, typeAlias)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
classesToProcess.forEachClassInScope(parentClassId = null) { classEntry ->
|
||||
val classContext = context.create(classEntry)
|
||||
classMerger?.processClass(classContext, packageNode, classEntry, classesToProcess)
|
||||
}
|
||||
}
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* 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.commonizer.mergedtree.mergers
|
||||
|
||||
import kotlinx.metadata.KmProperty
|
||||
import org.jetbrains.kotlin.commonizer.mergedtree.*
|
||||
import org.jetbrains.kotlin.commonizer.mergedtree.CirTargetMergingContext
|
||||
import org.jetbrains.kotlin.commonizer.mergedtree.buildPropertyNode
|
||||
import org.jetbrains.kotlin.commonizer.metadata.CirDeserializers
|
||||
import org.jetbrains.kotlin.commonizer.utils.isFakeOverride
|
||||
|
||||
internal object PropertyMerger {
|
||||
fun processProperty(
|
||||
context: CirTargetMergingContext,
|
||||
ownerNode: CirNodeWithMembers<*, *>,
|
||||
property: KmProperty
|
||||
) = with(context) {
|
||||
if (property.isFakeOverride())
|
||||
return
|
||||
|
||||
val maybeClassOwnerNode: CirClassNode? = ownerNode as? CirClassNode
|
||||
|
||||
val approximationKey = PropertyApproximationKey(property, context.typeResolver)
|
||||
val propertyNode: CirPropertyNode = ownerNode.properties.getOrPut(approximationKey) {
|
||||
buildPropertyNode(storageManager, targets, classifiers, maybeClassOwnerNode?.commonDeclaration)
|
||||
}
|
||||
propertyNode.targetDeclarations[context.targetIndex] = CirDeserializers.property(
|
||||
name = approximationKey.name,
|
||||
source = property,
|
||||
containingClass = maybeClassOwnerNode?.targetDeclarations?.get(context.targetIndex),
|
||||
typeResolver = context.typeResolver
|
||||
)
|
||||
}
|
||||
}
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* 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.commonizer.mergedtree.mergers
|
||||
|
||||
import org.jetbrains.kotlin.commonizer.CommonizerParameters
|
||||
import org.jetbrains.kotlin.commonizer.LeafCommonizerTarget
|
||||
import org.jetbrains.kotlin.commonizer.ModulesProvider
|
||||
import org.jetbrains.kotlin.commonizer.mergedtree.*
|
||||
import org.jetbrains.kotlin.commonizer.mergedtree.buildRootNode
|
||||
import org.jetbrains.kotlin.commonizer.metadata.CirTypeResolver
|
||||
import org.jetbrains.kotlin.commonizer.prettyName
|
||||
import org.jetbrains.kotlin.storage.StorageManager
|
||||
|
||||
internal class RootMerger(
|
||||
private val targetMerger: TargetMerger
|
||||
) {
|
||||
fun processRoot(
|
||||
storageManager: StorageManager,
|
||||
classifiers: CirKnownClassifiers,
|
||||
parameters: CommonizerParameters
|
||||
): CirTreeMergeResult {
|
||||
val rootNode: CirRootNode = buildRootNode(storageManager, parameters.targetProviders.size)
|
||||
|
||||
val commonModuleNames = parameters.getCommonModuleNames()
|
||||
val missingModuleInfosByTargets = mutableMapOf<LeafCommonizerTarget, Collection<ModulesProvider.ModuleInfo>>()
|
||||
|
||||
parameters.targetProviders.forEachIndexed { targetIndex, targetProvider ->
|
||||
val allModuleInfos = targetProvider.modulesProvider.loadModuleInfos()
|
||||
|
||||
val (commonModuleInfos, missingModuleInfos) = allModuleInfos.partition { it.name in commonModuleNames }
|
||||
val typeResolver = CirTypeResolver.create(
|
||||
providedClassifiers = CirProvidedClassifiers.of(
|
||||
classifiers.commonDependencies,
|
||||
CirProvidedClassifiers.by(targetProvider.dependencyModulesProvider),
|
||||
CirProvidedClassifiers.by(targetProvider.modulesProvider)
|
||||
)
|
||||
)
|
||||
targetMerger.processTarget(
|
||||
CirTargetMergingContext(
|
||||
storageManager, classifiers, parameters, targetIndex, typeResolver
|
||||
), rootNode, targetProvider, commonModuleInfos
|
||||
)
|
||||
|
||||
missingModuleInfosByTargets[targetProvider.target] = missingModuleInfos
|
||||
|
||||
parameters.progressLogger?.invoke("Loaded declarations for ${targetProvider.target.prettyName}")
|
||||
System.gc()
|
||||
}
|
||||
|
||||
return CirTreeMergeResult(
|
||||
root = rootNode,
|
||||
missingModuleInfos = missingModuleInfosByTargets
|
||||
)
|
||||
}
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* 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.commonizer.mergedtree.mergers
|
||||
|
||||
import kotlinx.metadata.klib.KlibModuleMetadata
|
||||
import org.jetbrains.kotlin.commonizer.ModulesProvider
|
||||
import org.jetbrains.kotlin.commonizer.TargetProvider
|
||||
import org.jetbrains.kotlin.commonizer.cir.CirRoot
|
||||
import org.jetbrains.kotlin.commonizer.mergedtree.CirRootNode
|
||||
import org.jetbrains.kotlin.commonizer.mergedtree.CirTargetMergingContext
|
||||
import org.jetbrains.kotlin.commonizer.metadata.utils.SerializedMetadataLibraryProvider
|
||||
|
||||
internal class TargetMerger(
|
||||
private val moduleMerger: ModuleMerger
|
||||
) {
|
||||
fun processTarget(
|
||||
context: CirTargetMergingContext,
|
||||
rootNode: CirRootNode,
|
||||
targetProvider: TargetProvider,
|
||||
commonModuleInfos: Collection<ModulesProvider.ModuleInfo>
|
||||
): Unit = with(context) {
|
||||
rootNode.targetDeclarations[targetIndex] = CirRoot.create(targetProvider.target)
|
||||
|
||||
if (commonModuleInfos.isEmpty()) {
|
||||
return
|
||||
}
|
||||
|
||||
commonModuleInfos.forEach { moduleInfo ->
|
||||
val metadata = targetProvider.modulesProvider.loadModuleMetadata(moduleInfo.name)
|
||||
val module = KlibModuleMetadata.read(SerializedMetadataLibraryProvider(metadata))
|
||||
moduleMerger.processModule(context, rootNode, module)
|
||||
}
|
||||
}
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* 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.commonizer.mergedtree.mergers
|
||||
|
||||
import kotlinx.metadata.KmTypeAlias
|
||||
import org.jetbrains.kotlin.commonizer.cir.CirEntityId
|
||||
import org.jetbrains.kotlin.commonizer.cir.CirName
|
||||
import org.jetbrains.kotlin.commonizer.mergedtree.CirPackageNode
|
||||
import org.jetbrains.kotlin.commonizer.mergedtree.CirTargetMergingContext
|
||||
import org.jetbrains.kotlin.commonizer.mergedtree.CirTypeAliasNode
|
||||
import org.jetbrains.kotlin.commonizer.mergedtree.buildTypeAliasNode
|
||||
import org.jetbrains.kotlin.commonizer.metadata.CirDeserializers
|
||||
|
||||
internal object TypeAliasMerger {
|
||||
fun processTypeAlias(
|
||||
context: CirTargetMergingContext,
|
||||
packageNode: CirPackageNode,
|
||||
typeAlias: KmTypeAlias
|
||||
) = with(context) {
|
||||
val typeAliasName = CirName.create(typeAlias.name)
|
||||
val typeAliasId = CirEntityId.create(packageNode.packageName, typeAliasName)
|
||||
|
||||
val typeAliasNode: CirTypeAliasNode = packageNode.typeAliases.getOrPut(typeAliasName) {
|
||||
buildTypeAliasNode(storageManager, targets, classifiers, typeAliasId)
|
||||
}
|
||||
typeAliasNode.targetDeclarations[context.targetIndex] = CirDeserializers.typeAlias(
|
||||
name = typeAliasName,
|
||||
source = typeAlias,
|
||||
typeResolver = context.typeResolver
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user