[Commonizer] Implement CirTree and CirTree deserializers and CirTree merging
This commit is contained in:
@@ -9,20 +9,20 @@ import org.jetbrains.kotlin.commonizer.konan.NativeManifestDataProvider
|
||||
import org.jetbrains.kotlin.commonizer.stats.StatsCollector
|
||||
|
||||
class CommonizerParameters(
|
||||
val targetProviders: List<TargetProvider>,
|
||||
val targetProviders: TargetDependent<TargetProvider>,
|
||||
val resultsConsumer: ResultsConsumer,
|
||||
val commonManifestProvider: NativeManifestDataProvider,
|
||||
val commonDependencyModulesProvider: ModulesProvider? = null,
|
||||
val statsCollector: StatsCollector? = null,
|
||||
val progressLogger: ((String) -> Unit)? = null
|
||||
) {
|
||||
internal val commonTarget: SharedCommonizerTarget = SharedCommonizerTarget(targetProviders.map { it.target }.toSet())
|
||||
internal val commonTarget: SharedCommonizerTarget = SharedCommonizerTarget(targetProviders.targets.toSet())
|
||||
|
||||
internal val manifestDataProvider: TargetDependent<NativeManifestDataProvider>
|
||||
get() = TargetDependent { target ->
|
||||
get() = TargetDependent(setOf(SharedCommonizerTarget(targetProviders.targets.toSet())) + targetProviders.targets) { target ->
|
||||
if (target == commonTarget) return@TargetDependent commonManifestProvider
|
||||
this.targetProviders.firstOrNull { it.target == target }?.manifestProvider?.let { return@TargetDependent it }
|
||||
null
|
||||
throw IllegalStateException("Illegal target $target")
|
||||
}
|
||||
|
||||
}
|
||||
@@ -30,7 +30,7 @@ class CommonizerParameters(
|
||||
fun CommonizerParameters.getCommonModuleNames(): Set<String> {
|
||||
if (targetProviders.size < 2) return emptySet() // too few targets
|
||||
|
||||
val allModuleNames: List<Set<String>> = targetProviders.map { targetProvider ->
|
||||
val allModuleNames: List<Set<String>> = targetProviders.toList().map { targetProvider ->
|
||||
targetProvider.modulesProvider.loadModuleInfos().mapTo(HashSet()) { it.name }
|
||||
}
|
||||
|
||||
|
||||
@@ -7,43 +7,95 @@
|
||||
|
||||
package org.jetbrains.kotlin.commonizer
|
||||
|
||||
sealed interface TargetDependent<T : Any> {
|
||||
fun getOrNull(target: CommonizerTarget): T?
|
||||
operator fun get(target: CommonizerTarget): T {
|
||||
return getOrNull(target) ?: throw NoSuchElementException("Missing element for target ${target.prettyName}")
|
||||
sealed interface TargetDependent<T> : Iterable<T> {
|
||||
val size: Int get() = targets.size
|
||||
val targets: List<CommonizerTarget>
|
||||
fun indexOf(target: CommonizerTarget): Int = targets.indexOf(target)
|
||||
|
||||
fun <R : Any> map(mapper: (target: CommonizerTarget, T) -> R): TargetDependent<R> {
|
||||
return TargetDependent(targets) { target ->
|
||||
mapper(target, get(target))
|
||||
}
|
||||
}
|
||||
|
||||
override fun iterator(): Iterator<T> {
|
||||
return iterator { for (key in targets) yield(this@TargetDependent[key]) }
|
||||
}
|
||||
|
||||
operator fun get(target: CommonizerTarget): T
|
||||
|
||||
fun getOrNull(target: CommonizerTarget): T? {
|
||||
return if (target in targets) get(target) else null
|
||||
}
|
||||
}
|
||||
|
||||
internal fun <T : Any> Map<CommonizerTarget, T>.toTargetDependent(): TargetDependent<T> {
|
||||
internal fun <T : Any> TargetDependent<T?>.filterNonNull(): TargetDependent<T> {
|
||||
val nonNullTargets = targets.filter { this[it] != null }
|
||||
return TargetDependent(nonNullTargets) { target -> this@filterNonNull[target] ?: throw NullPointerException() }
|
||||
}
|
||||
|
||||
internal fun <T> TargetDependent<T>.toMap(): Map<CommonizerTarget, T> {
|
||||
return mutableMapOf<CommonizerTarget, T>().apply {
|
||||
for (key in keys) {
|
||||
put(key, this@toMap[key])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal fun <T> Map<out CommonizerTarget, T>.toTargetDependent(): TargetDependent<T> {
|
||||
return TargetDependent(toMap())
|
||||
}
|
||||
|
||||
internal fun <T : Any> Map<CommonizerTarget, T>.asTargetDependent(): TargetDependent<T> {
|
||||
return TargetDependent(this)
|
||||
internal fun <T, R> TargetDependent<T>.mapValue(mapper: (T) -> R): TargetDependent<R> {
|
||||
return TargetDependent(targets) { target -> this@mapValue.get(target).let(mapper) }
|
||||
}
|
||||
|
||||
internal fun <T : Any, R : Any> TargetDependent<T>.map(mapper: (T) -> R): TargetDependent<R> {
|
||||
return TargetDependent { target -> this@map.getOrNull(target)?.let(mapper) }
|
||||
internal fun <T, R> TargetDependent<T>.mapTargets(mapper: (CommonizerTarget) -> R): TargetDependent<R> {
|
||||
return TargetDependent(targets) { target -> mapper(target) }
|
||||
}
|
||||
|
||||
internal fun <T : Any> TargetDependent(map: Map<CommonizerTarget, T>): TargetDependent<T> {
|
||||
|
||||
internal fun <T> TargetDependent(map: Map<CommonizerTarget, T>): TargetDependent<T> {
|
||||
return MapBasedTargetDependent(map)
|
||||
}
|
||||
|
||||
internal fun <T : Any> TargetDependent(factory: (target: CommonizerTarget) -> T?): TargetDependent<T> {
|
||||
return FactoryBasedTargetDependent(factory)
|
||||
internal fun <T> TargetDependent(keys: Iterable<CommonizerTarget>, factory: (target: CommonizerTarget) -> T): TargetDependent<T> {
|
||||
return FactoryBasedTargetDependent(keys.toList(), factory)
|
||||
}
|
||||
|
||||
private class MapBasedTargetDependent<T : Any>(private val map: Map<CommonizerTarget, T>) : TargetDependent<T> {
|
||||
override fun getOrNull(target: CommonizerTarget): T? = map[target]
|
||||
private class MapBasedTargetDependent<T>(private val map: Map<CommonizerTarget, T>) : TargetDependent<T> {
|
||||
override val targets: List<CommonizerTarget> = map.keys.toList()
|
||||
override fun get(target: CommonizerTarget): T = map.getValue(target)
|
||||
}
|
||||
|
||||
private class FactoryBasedTargetDependent<T : Any>(private val factory: (target: CommonizerTarget) -> T?) : TargetDependent<T> {
|
||||
private val values = mutableMapOf<CommonizerTarget, Any>()
|
||||
override fun getOrNull(target: CommonizerTarget): T? {
|
||||
@Suppress("unchecked_cast")
|
||||
return values.getOrPut(target) { factory(target) ?: Null }.takeIf { it != Null }?.run { this as T }
|
||||
/**
|
||||
* Not thread safe!
|
||||
*/
|
||||
private class FactoryBasedTargetDependent<T>(
|
||||
override val targets: List<CommonizerTarget>,
|
||||
private var factory: ((target: CommonizerTarget) -> T)?
|
||||
) : TargetDependent<T> {
|
||||
|
||||
private object Uninitialized
|
||||
|
||||
private val values: Array<Any?> = Array(targets.size) { Uninitialized }
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override fun get(target: CommonizerTarget): T {
|
||||
val indexOfTarget = indexOf(target)
|
||||
if (indexOfTarget < 0) throw NoSuchElementException("Missing target $target")
|
||||
val storedValue = values[indexOfTarget]
|
||||
if (storedValue == Uninitialized) {
|
||||
val producedValue = factory?.invoke(target)
|
||||
values[indexOfTarget] = producedValue
|
||||
|
||||
/* All values initialized. Factory can be released */
|
||||
if (values.none { it === Uninitialized }) {
|
||||
factory = null
|
||||
}
|
||||
return producedValue as T
|
||||
}
|
||||
|
||||
return storedValue as T
|
||||
}
|
||||
|
||||
private object Null
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.commonizer.cir
|
||||
|
||||
import org.jetbrains.kotlin.commonizer.mergedtree.PropertyApproximationKey
|
||||
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.descriptors.Visibility
|
||||
|
||||
@@ -12,6 +12,8 @@ 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.metadata.CirTreeSerializer
|
||||
import org.jetbrains.kotlin.commonizer.tree.deserializer.deserialize
|
||||
import org.jetbrains.kotlin.commonizer.tree.merger.mergeCirTree
|
||||
import org.jetbrains.kotlin.library.SerializedMetadata
|
||||
import org.jetbrains.kotlin.storage.LockBasedStorageManager
|
||||
import org.jetbrains.kotlin.storage.StorageManager
|
||||
@@ -24,18 +26,17 @@ fun runCommonization(parameters: CommonizerParameters) {
|
||||
|
||||
val storageManager = LockBasedStorageManager("Declarations commonization")
|
||||
|
||||
val mergeResult = mergeAndCommonize(storageManager, parameters)
|
||||
val mergedTree = mergeResult.root
|
||||
val mergedTree = mergeAndCommonize(storageManager, parameters)
|
||||
|
||||
// build resulting declarations:
|
||||
for (targetIndex in 0 until mergedTree.dimension) {
|
||||
serializeTarget(mergeResult, targetIndex, parameters)
|
||||
serializeTarget(mergedTree, targetIndex, parameters)
|
||||
}
|
||||
|
||||
parameters.resultsConsumer.allConsumed(Status.DONE)
|
||||
}
|
||||
|
||||
private fun mergeAndCommonize(storageManager: StorageManager, parameters: CommonizerParameters): CirTreeMergeResult {
|
||||
private fun mergeAndCommonize(storageManager: StorageManager, parameters: CommonizerParameters): CirRootNode {
|
||||
// build merged tree:
|
||||
val classifiers = CirKnownClassifiers(
|
||||
commonizedNodes = CirCommonizedClassifierNodes.default(),
|
||||
@@ -44,17 +45,18 @@ private fun mergeAndCommonize(storageManager: StorageManager, parameters: Common
|
||||
CirProvidedClassifiers.by(parameters.commonDependencyModulesProvider)
|
||||
)
|
||||
)
|
||||
val mergeResult = mergeCirTree(storageManager, classifiers, parameters)
|
||||
|
||||
// commonize:
|
||||
mergeResult.root.accept(CommonizationVisitor(classifiers, mergeResult.root), Unit)
|
||||
val targetTrees = parameters.targetProviders.mapValue { target -> deserialize(parameters, target) }
|
||||
parameters.progressLogger?.invoke("Deserialized targets")
|
||||
|
||||
val mergedTree = mergeCirTree(storageManager, classifiers, targetTrees)
|
||||
mergedTree.accept(CommonizationVisitor(classifiers, mergedTree), Unit)
|
||||
parameters.progressLogger?.invoke("Commonized declarations")
|
||||
|
||||
return mergeResult
|
||||
return mergedTree
|
||||
}
|
||||
|
||||
private fun serializeTarget(mergeResult: CirTreeMergeResult, targetIndex: Int, parameters: CommonizerParameters) {
|
||||
val mergedTree = mergeResult.root
|
||||
private fun serializeTarget(mergedTree: CirRootNode, targetIndex: Int, parameters: CommonizerParameters) {
|
||||
val target = mergedTree.getTarget(targetIndex)
|
||||
|
||||
CirTreeSerializer.serializeSingleTarget(mergedTree, targetIndex, parameters.statsCollector) { metadataModule ->
|
||||
@@ -66,10 +68,10 @@ private fun serializeTarget(mergeResult: CirTreeMergeResult, targetIndex: Int, p
|
||||
parameters.resultsConsumer.consume(target, ModuleResult.Commonized(libraryName, serializedMetadata, manifestData))
|
||||
}
|
||||
|
||||
if (target is LeafCommonizerTarget) {
|
||||
mergeResult.missingModuleInfos.getValue(target).forEach {
|
||||
parameters.resultsConsumer.consume(target, ModuleResult.Missing(it.originalLocation))
|
||||
}
|
||||
if (target in parameters.targetProviders.targets) {
|
||||
parameters.targetProviders[target].modulesProvider.loadModuleInfos()
|
||||
.filter { it.name !in parameters.getCommonModuleNames() }
|
||||
.forEach { missingModule -> parameters.resultsConsumer.consume(target, ModuleResult.Missing(missingModule.originalLocation)) }
|
||||
}
|
||||
|
||||
parameters.resultsConsumer.targetConsumed(target)
|
||||
|
||||
@@ -42,7 +42,8 @@ internal class LibraryCommonizer internal constructor(
|
||||
|
||||
private fun commonizeAndSaveResults(allLibraries: TargetDependent<NativeLibrariesToCommonize>) {
|
||||
val parameters = CommonizerParameters(
|
||||
targetProviders = commonTarget.targets.mapNotNull { target -> createTargetProvider(target, allLibraries[target]) },
|
||||
targetProviders = TargetDependent(commonTarget.targets) { target -> createTargetProvider(target, allLibraries[target]) }
|
||||
.filterNonNull(),
|
||||
resultsConsumer = resultsConsumer,
|
||||
commonManifestProvider = CommonNativeManifestDataProvider(commonTarget.targets.map { allLibraries[it] }),
|
||||
commonDependencyModulesProvider = DefaultModulesProvider.create(dependencies.getLibraries(commonTarget)),
|
||||
|
||||
+5
-1
@@ -63,7 +63,11 @@ internal class ClassesToProcess {
|
||||
}
|
||||
}
|
||||
|
||||
fun classesInScope(parentClassId: CirEntityId?): List<ClassEntry> {
|
||||
return groupedByParentClassId[parentClassId ?: NON_EXISTING_CLASSIFIER_ID].orEmpty()
|
||||
}
|
||||
|
||||
fun forEachClassInScope(parentClassId: CirEntityId?, block: (ClassEntry) -> Unit) {
|
||||
groupedByParentClassId[parentClassId ?: NON_EXISTING_CLASSIFIER_ID]?.forEach { classEntry -> block(classEntry) }
|
||||
classesInScope(parentClassId).forEach { classEntry -> block(classEntry) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import kotlinx.metadata.KmTypeParameter
|
||||
import org.jetbrains.kotlin.commonizer.cir.CirEntityId
|
||||
import org.jetbrains.kotlin.commonizer.mergedtree.CirProvided
|
||||
import org.jetbrains.kotlin.commonizer.mergedtree.CirProvidedClassifiers
|
||||
import org.jetbrains.kotlin.commonizer.mergedtree.mergers.ClassesToProcess
|
||||
|
||||
typealias TypeParameterId = Int
|
||||
typealias TypeParameterIndex = Int
|
||||
@@ -71,6 +72,13 @@ abstract class CirTypeResolver : CirTypeParameterResolver {
|
||||
Nested(this, mapping)
|
||||
}
|
||||
|
||||
internal fun create(classEntry: ClassesToProcess.ClassEntry): CirTypeResolver {
|
||||
return when (classEntry) {
|
||||
is ClassesToProcess.ClassEntry.RegularClassEntry -> create(classEntry.clazz.typeParameters)
|
||||
is ClassesToProcess.ClassEntry.EnumEntry -> this
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun create(providedClassifiers: CirProvidedClassifiers): CirTypeResolver = TopLevel(providedClassifiers)
|
||||
}
|
||||
|
||||
@@ -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.tree
|
||||
|
||||
import org.jetbrains.kotlin.commonizer.cir.*
|
||||
import org.jetbrains.kotlin.commonizer.mergedtree.ConstructorApproximationKey
|
||||
import org.jetbrains.kotlin.commonizer.mergedtree.FunctionApproximationKey
|
||||
import org.jetbrains.kotlin.commonizer.mergedtree.PropertyApproximationKey
|
||||
|
||||
data class CirTreeRoot(
|
||||
val modules: List<CirTreeModule>
|
||||
)
|
||||
|
||||
data class CirTreeModule(
|
||||
val module: CirModule,
|
||||
val packages: List<CirTreePackage>
|
||||
)
|
||||
|
||||
data class CirTreePackage(
|
||||
val pkg: CirPackage,
|
||||
val properties: List<CirTreeProperty>,
|
||||
val functions: List<CirTreeFunction>,
|
||||
val classes: List<CirTreeClass>,
|
||||
val typeAliases: List<CirTreeTypeAlias>
|
||||
)
|
||||
|
||||
data class CirTreeProperty(
|
||||
val approximationKey: PropertyApproximationKey,
|
||||
val property: CirProperty
|
||||
)
|
||||
|
||||
data class CirTreeFunction(
|
||||
val approximationKey: FunctionApproximationKey,
|
||||
val function: CirFunction
|
||||
)
|
||||
|
||||
data class CirTreeTypeAlias(
|
||||
val id: CirEntityId,
|
||||
val typeAlias: CirTypeAlias
|
||||
)
|
||||
|
||||
data class CirTreeClass(
|
||||
val id: CirEntityId,
|
||||
val clazz: CirClass,
|
||||
val properties: List<CirTreeProperty>,
|
||||
val functions: List<CirTreeFunction>,
|
||||
val constructors: List<CirTreeClassConstructor>,
|
||||
val classes: List<CirTreeClass>,
|
||||
)
|
||||
|
||||
class CirTreeClassConstructor(
|
||||
val approximationKey: ConstructorApproximationKey,
|
||||
val constructor: CirClassConstructor
|
||||
)
|
||||
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* 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.tree.deserializer
|
||||
|
||||
import kotlinx.metadata.Flag
|
||||
import kotlinx.metadata.KmClass
|
||||
import org.jetbrains.kotlin.commonizer.mergedtree.mergers.ClassesToProcess
|
||||
import org.jetbrains.kotlin.commonizer.metadata.CirDeserializers
|
||||
import org.jetbrains.kotlin.commonizer.metadata.CirTypeResolver
|
||||
import org.jetbrains.kotlin.commonizer.tree.CirTreeClass
|
||||
|
||||
internal class ClassCirTreeDeserializer(
|
||||
private val propertyDeserializer: PropertyCirTreeDeserializer,
|
||||
private val functionDeserializer: FunctionCirTreeDeserializer,
|
||||
private val constructorDeserializer: ClassConstructorCirTreeDeserializer,
|
||||
) {
|
||||
operator fun invoke(
|
||||
classEntry: ClassesToProcess.ClassEntry, classesToProcess: ClassesToProcess, typeResolver: CirTypeResolver
|
||||
): CirTreeClass {
|
||||
val classTypeResolver = typeResolver.create(classEntry)
|
||||
val classId = classEntry.classId
|
||||
val className = classId.relativeNameSegments.last()
|
||||
|
||||
val clazz: KmClass?
|
||||
val isEnumEntry: Boolean
|
||||
|
||||
val cirClass = when (classEntry) {
|
||||
is ClassesToProcess.ClassEntry.RegularClassEntry -> {
|
||||
clazz = classEntry.clazz
|
||||
isEnumEntry = Flag.Class.IS_ENUM_ENTRY(clazz.flags)
|
||||
CirDeserializers.clazz(className, clazz, classTypeResolver)
|
||||
}
|
||||
is ClassesToProcess.ClassEntry.EnumEntry -> {
|
||||
clazz = null
|
||||
isEnumEntry = true
|
||||
|
||||
CirDeserializers.defaultEnumEntry(
|
||||
name = className,
|
||||
annotations = classEntry.annotations,
|
||||
enumClassId = classEntry.enumClassId,
|
||||
enumClass = classEntry.enumClass,
|
||||
typeResolver = classTypeResolver
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
val constructors = clazz?.constructors
|
||||
?.takeIf { !isEnumEntry }
|
||||
?.map { constructor -> constructorDeserializer(constructor, cirClass, classTypeResolver) }
|
||||
.orEmpty()
|
||||
|
||||
val properties = clazz?.properties?.mapNotNull { property -> propertyDeserializer(property, cirClass, classTypeResolver) }
|
||||
|
||||
val functions = clazz?.functions?.mapNotNull { function -> functionDeserializer(function, cirClass, classTypeResolver) }
|
||||
|
||||
val classes = classesToProcess.classesInScope(classId).map { nestedClassEntry ->
|
||||
this(nestedClassEntry, classesToProcess, classTypeResolver)
|
||||
}
|
||||
|
||||
return CirTreeClass(
|
||||
id = classId,
|
||||
clazz = cirClass,
|
||||
properties = properties.orEmpty(),
|
||||
functions = functions.orEmpty(),
|
||||
constructors = constructors,
|
||||
classes = classes
|
||||
)
|
||||
}
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* 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.tree.deserializer
|
||||
|
||||
import kotlinx.metadata.KmConstructor
|
||||
import org.jetbrains.kotlin.commonizer.cir.CirContainingClass
|
||||
import org.jetbrains.kotlin.commonizer.mergedtree.ConstructorApproximationKey
|
||||
import org.jetbrains.kotlin.commonizer.metadata.CirDeserializers
|
||||
import org.jetbrains.kotlin.commonizer.metadata.CirTypeResolver
|
||||
import org.jetbrains.kotlin.commonizer.tree.CirTreeClassConstructor
|
||||
|
||||
internal object ClassConstructorCirTreeDeserializer {
|
||||
operator fun invoke(
|
||||
constructor: KmConstructor, containingClass: CirContainingClass, typeResolver: CirTypeResolver
|
||||
): CirTreeClassConstructor {
|
||||
return CirTreeClassConstructor(
|
||||
approximationKey = ConstructorApproximationKey(constructor, typeResolver),
|
||||
constructor = CirDeserializers.constructor(
|
||||
source = constructor,
|
||||
containingClass = containingClass,
|
||||
typeResolver = typeResolver
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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.tree.deserializer
|
||||
|
||||
import kotlinx.metadata.KmFunction
|
||||
import org.jetbrains.kotlin.commonizer.cir.CirClass
|
||||
import org.jetbrains.kotlin.commonizer.cir.CirContainingClass
|
||||
import org.jetbrains.kotlin.commonizer.mergedtree.FunctionApproximationKey
|
||||
import org.jetbrains.kotlin.commonizer.metadata.CirDeserializers
|
||||
import org.jetbrains.kotlin.commonizer.metadata.CirTypeResolver
|
||||
import org.jetbrains.kotlin.commonizer.tree.CirTreeFunction
|
||||
import org.jetbrains.kotlin.commonizer.utils.isFakeOverride
|
||||
import org.jetbrains.kotlin.commonizer.utils.isKniBridgeFunction
|
||||
import org.jetbrains.kotlin.commonizer.utils.isTopLevelDeprecatedFunction
|
||||
|
||||
object FunctionCirTreeDeserializer {
|
||||
operator fun invoke(function: KmFunction, containingClass: CirContainingClass?, typeResolver: CirTypeResolver): CirTreeFunction? {
|
||||
val functionTypeResolver = typeResolver.create(function.typeParameters)
|
||||
if (function.isFakeOverride()
|
||||
|| function.isKniBridgeFunction()
|
||||
|| function.isTopLevelDeprecatedFunction(isTopLevel = containingClass !is CirClass)
|
||||
) {
|
||||
return null
|
||||
}
|
||||
|
||||
val approximationKey = FunctionApproximationKey(function, functionTypeResolver)
|
||||
return CirTreeFunction(
|
||||
approximationKey = approximationKey,
|
||||
function = CirDeserializers.function(
|
||||
name = approximationKey.name,
|
||||
source = function,
|
||||
containingClass = containingClass,
|
||||
typeResolver = functionTypeResolver
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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.tree.deserializer
|
||||
|
||||
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.metadata.CirTypeResolver
|
||||
import org.jetbrains.kotlin.commonizer.metadata.utils.SerializedMetadataLibraryProvider
|
||||
import org.jetbrains.kotlin.commonizer.tree.CirTreeModule
|
||||
import org.jetbrains.kotlin.commonizer.utils.foldToMap
|
||||
import org.jetbrains.kotlin.library.SerializedMetadata
|
||||
|
||||
internal class ModuleCirTreeDeserializer(
|
||||
private val packageDeserializer: PackageCirTreeDeserializer
|
||||
) {
|
||||
operator fun invoke(metadata: SerializedMetadata, typeResolver: CirTypeResolver): CirTreeModule {
|
||||
val module = KlibModuleMetadata.read(SerializedMetadataLibraryProvider(metadata))
|
||||
|
||||
val fragmentsByPackage: Map<CirPackageName, Collection<KmModuleFragment>> = module.fragments.foldToMap { fragment ->
|
||||
fragment.fqName?.let(CirPackageName.Companion::create)
|
||||
?: error("A fragment without FQ name in module ${module.name}: $fragment")
|
||||
}
|
||||
|
||||
val packages = fragmentsByPackage.map { (packageName, fragments) ->
|
||||
packageDeserializer(packageName, fragments, typeResolver)
|
||||
}
|
||||
|
||||
return CirTreeModule(
|
||||
module = CirModule.create(CirName.create(module.name)),
|
||||
packages = packages
|
||||
)
|
||||
}
|
||||
}
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* 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.tree.deserializer
|
||||
|
||||
import kotlinx.metadata.KmModuleFragment
|
||||
import org.jetbrains.kotlin.commonizer.cir.CirPackage
|
||||
import org.jetbrains.kotlin.commonizer.cir.CirPackageName
|
||||
import org.jetbrains.kotlin.commonizer.mergedtree.mergers.ClassesToProcess
|
||||
import org.jetbrains.kotlin.commonizer.metadata.CirTypeResolver
|
||||
import org.jetbrains.kotlin.commonizer.tree.CirTreePackage
|
||||
|
||||
internal class PackageCirTreeDeserializer(
|
||||
private val propertyDeserializer: PropertyCirTreeDeserializer,
|
||||
private val functionDeserializer: FunctionCirTreeDeserializer,
|
||||
private val typeAliasDeserializer: TypeAliasCirTreeDeserializer,
|
||||
private val classDeserializer: ClassCirTreeDeserializer,
|
||||
) {
|
||||
operator fun invoke(
|
||||
packageName: CirPackageName,
|
||||
fragments: Collection<KmModuleFragment>,
|
||||
typeResolver: CirTypeResolver
|
||||
): CirTreePackage {
|
||||
val pkg = CirPackage.create(packageName)
|
||||
|
||||
val properties = fragments.asSequence().mapNotNull { it.pkg }
|
||||
.flatMap { it.properties }
|
||||
.mapNotNull { property -> propertyDeserializer(property, null, typeResolver) }
|
||||
.toList()
|
||||
|
||||
val functions = fragments.asSequence().mapNotNull { it.pkg }
|
||||
.flatMap { it.functions }
|
||||
.mapNotNull { function -> functionDeserializer(function, null, typeResolver) }
|
||||
.toList()
|
||||
|
||||
val typeAliases = fragments.asSequence().mapNotNull { it.pkg }
|
||||
.flatMap { it.typeAliases }
|
||||
.mapNotNull { typeAlias -> typeAliasDeserializer(typeAlias, pkg.packageName, typeResolver) }
|
||||
.toList()
|
||||
|
||||
val classes = ClassesToProcess()
|
||||
.apply { fragments.forEach { fragment -> addClassesFromFragment(fragment) } }
|
||||
.run { classesInScope(parentClassId = null).map { classEntry -> classDeserializer(classEntry, this, typeResolver) } }
|
||||
|
||||
return CirTreePackage(
|
||||
pkg = pkg,
|
||||
properties = properties,
|
||||
functions = functions,
|
||||
typeAliases = typeAliases,
|
||||
classes = classes
|
||||
)
|
||||
}
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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.tree.deserializer
|
||||
|
||||
import kotlinx.metadata.KmProperty
|
||||
import org.jetbrains.kotlin.commonizer.cir.CirContainingClass
|
||||
import org.jetbrains.kotlin.commonizer.mergedtree.PropertyApproximationKey
|
||||
import org.jetbrains.kotlin.commonizer.metadata.CirDeserializers
|
||||
import org.jetbrains.kotlin.commonizer.metadata.CirTypeResolver
|
||||
import org.jetbrains.kotlin.commonizer.tree.CirTreeProperty
|
||||
import org.jetbrains.kotlin.commonizer.utils.isFakeOverride
|
||||
|
||||
object PropertyCirTreeDeserializer {
|
||||
operator fun invoke(property: KmProperty, containingClass: CirContainingClass?, typeResolver: CirTypeResolver): CirTreeProperty? {
|
||||
if (property.isFakeOverride()) return null
|
||||
val propertyTypeResolver = typeResolver.create(property.typeParameters)
|
||||
val approximationKey = PropertyApproximationKey(property, propertyTypeResolver)
|
||||
return CirTreeProperty(
|
||||
approximationKey = PropertyApproximationKey(property, propertyTypeResolver),
|
||||
property = CirDeserializers.property(
|
||||
name = approximationKey.name,
|
||||
source = property,
|
||||
containingClass = containingClass,
|
||||
typeResolver = propertyTypeResolver
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
+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.tree.deserializer
|
||||
|
||||
import org.jetbrains.kotlin.commonizer.CommonizerParameters
|
||||
import org.jetbrains.kotlin.commonizer.TargetProvider
|
||||
import org.jetbrains.kotlin.commonizer.getCommonModuleNames
|
||||
import org.jetbrains.kotlin.commonizer.mergedtree.CirFictitiousFunctionClassifiers
|
||||
import org.jetbrains.kotlin.commonizer.mergedtree.CirProvidedClassifiers
|
||||
import org.jetbrains.kotlin.commonizer.metadata.CirTypeResolver
|
||||
import org.jetbrains.kotlin.commonizer.tree.CirTreeRoot
|
||||
|
||||
internal class RootCirTreeDeserializer(
|
||||
private val moduleDeserializer: ModuleCirTreeDeserializer
|
||||
) {
|
||||
operator fun invoke(parameters: CommonizerParameters, targetProvider: TargetProvider): CirTreeRoot {
|
||||
|
||||
val commonModuleInfos = targetProvider.modulesProvider.loadModuleInfos()
|
||||
.filter { moduleInfo -> moduleInfo.name in parameters.getCommonModuleNames() }
|
||||
|
||||
val typeResolver = CirTypeResolver.create(
|
||||
providedClassifiers = CirProvidedClassifiers.of(
|
||||
CirProvidedClassifiers.by(targetProvider.modulesProvider),
|
||||
CirProvidedClassifiers.by(targetProvider.dependencyModulesProvider),
|
||||
CirProvidedClassifiers.of(
|
||||
CirFictitiousFunctionClassifiers,
|
||||
CirProvidedClassifiers.by(parameters.commonDependencyModulesProvider)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
return CirTreeRoot(
|
||||
modules = commonModuleInfos.map { moduleInfo ->
|
||||
val metadata = targetProvider.modulesProvider.loadModuleMetadata(moduleInfo.name)
|
||||
moduleDeserializer(metadata, typeResolver)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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.tree.deserializer
|
||||
|
||||
import kotlinx.metadata.KmTypeAlias
|
||||
import org.jetbrains.kotlin.commonizer.cir.CirEntityId
|
||||
import org.jetbrains.kotlin.commonizer.cir.CirName
|
||||
import org.jetbrains.kotlin.commonizer.cir.CirPackageName
|
||||
import org.jetbrains.kotlin.commonizer.metadata.CirDeserializers
|
||||
import org.jetbrains.kotlin.commonizer.metadata.CirTypeResolver
|
||||
import org.jetbrains.kotlin.commonizer.tree.CirTreeTypeAlias
|
||||
|
||||
|
||||
internal object TypeAliasCirTreeDeserializer {
|
||||
operator fun invoke(typeAlias: KmTypeAlias, packageName: CirPackageName, typeResolver: CirTypeResolver): CirTreeTypeAlias {
|
||||
val typeAliasTypeResolver = typeResolver.create(typeAlias.typeParameters)
|
||||
val typeAliasName = CirName.create(typeAlias.name)
|
||||
return CirTreeTypeAlias(
|
||||
id = CirEntityId.create(packageName, typeAliasName),
|
||||
typeAlias = CirDeserializers.typeAlias(
|
||||
name = typeAliasName,
|
||||
source = typeAlias,
|
||||
typeResolver = typeAliasTypeResolver
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+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.tree.deserializer
|
||||
|
||||
import org.jetbrains.kotlin.commonizer.CommonizerParameters
|
||||
import org.jetbrains.kotlin.commonizer.TargetProvider
|
||||
import org.jetbrains.kotlin.commonizer.tree.CirTreeRoot
|
||||
|
||||
|
||||
private val defaultRootCirTreeDeserializer = RootCirTreeDeserializer(
|
||||
ModuleCirTreeDeserializer(
|
||||
packageDeserializer = PackageCirTreeDeserializer(
|
||||
propertyDeserializer = PropertyCirTreeDeserializer,
|
||||
functionDeserializer = FunctionCirTreeDeserializer,
|
||||
typeAliasDeserializer = TypeAliasCirTreeDeserializer,
|
||||
classDeserializer = ClassCirTreeDeserializer(
|
||||
propertyDeserializer = PropertyCirTreeDeserializer,
|
||||
functionDeserializer = FunctionCirTreeDeserializer,
|
||||
constructorDeserializer = ClassConstructorCirTreeDeserializer
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
internal fun deserialize(parameters: CommonizerParameters, target: TargetProvider): CirTreeRoot {
|
||||
return defaultRootCirTreeDeserializer(parameters, target)
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* 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.tree.merger
|
||||
|
||||
import org.jetbrains.kotlin.commonizer.TargetDependent
|
||||
import org.jetbrains.kotlin.commonizer.cir.CirRoot
|
||||
import org.jetbrains.kotlin.commonizer.mergedtree.*
|
||||
import org.jetbrains.kotlin.commonizer.tree.*
|
||||
import org.jetbrains.kotlin.storage.StorageManager
|
||||
|
||||
internal data class TargetBuildingContext(
|
||||
val storageManager: StorageManager, val classifiers: CirKnownClassifiers, val targets: Int, val targetIndex: Int
|
||||
)
|
||||
|
||||
internal fun mergeCirTree(
|
||||
storageManager: StorageManager, classifiers: CirKnownClassifiers, roots: TargetDependent<CirTreeRoot>
|
||||
): CirRootNode {
|
||||
val node = buildRootNode(storageManager, roots.size)
|
||||
roots.targets.withIndex().forEach { (targetIndex, target) ->
|
||||
node.targetDeclarations[targetIndex] = CirRoot.create(target)
|
||||
node.buildModules(TargetBuildingContext(storageManager, classifiers, roots.size, targetIndex), roots[target].modules)
|
||||
}
|
||||
return node
|
||||
}
|
||||
|
||||
internal fun CirRootNode.buildModules(context: TargetBuildingContext, modules: List<CirTreeModule>) {
|
||||
modules.forEach { module -> buildModule(context, module) }
|
||||
}
|
||||
|
||||
internal fun CirRootNode.buildModule(context: TargetBuildingContext, treeModule: CirTreeModule) {
|
||||
val moduleNode = modules.getOrPut(treeModule.module.name) {
|
||||
buildModuleNode(context.storageManager, context.targets)
|
||||
}
|
||||
moduleNode.targetDeclarations[context.targetIndex] = treeModule.module
|
||||
treeModule.packages.forEach { pkg -> moduleNode.buildPackage(context, pkg) }
|
||||
}
|
||||
|
||||
internal fun CirModuleNode.buildPackage(context: TargetBuildingContext, treePackage: CirTreePackage) {
|
||||
val packageNode = packages.getOrPut(treePackage.pkg.packageName) {
|
||||
buildPackageNode(context.storageManager, context.targets)
|
||||
}
|
||||
packageNode.targetDeclarations[context.targetIndex] = treePackage.pkg
|
||||
treePackage.functions.forEach { function -> packageNode.buildFunction(context, function) }
|
||||
treePackage.properties.forEach { property -> packageNode.buildProperty(context, property) }
|
||||
treePackage.typeAliases.forEach { typeAlias -> packageNode.buildTypeAlias(context, typeAlias) }
|
||||
treePackage.classes.forEach { clazz -> packageNode.buildClass(context, clazz) }
|
||||
}
|
||||
|
||||
internal fun CirNodeWithMembers<*, *>.buildClass(context: TargetBuildingContext, treeClass: CirTreeClass) {
|
||||
val classNode = classes.getOrPut(treeClass.clazz.name) {
|
||||
buildClassNode(context.storageManager, context.targets, context.classifiers, treeClass.id)
|
||||
}
|
||||
classNode.targetDeclarations[context.targetIndex] = treeClass.clazz
|
||||
treeClass.functions.forEach { function -> classNode.buildFunction(context, function) }
|
||||
treeClass.properties.forEach { property -> classNode.buildProperty(context, property) }
|
||||
treeClass.constructors.forEach { constructor -> classNode.buildConstructor(context, constructor) }
|
||||
treeClass.classes.forEach { clazz -> classNode.buildClass(context, clazz) }
|
||||
}
|
||||
|
||||
internal fun CirNodeWithMembers<*, *>.buildFunction(context: TargetBuildingContext, treeFunction: CirTreeFunction) {
|
||||
val functionNode = functions.getOrPut(treeFunction.approximationKey) {
|
||||
buildFunctionNode(context.storageManager, context.targets, context.classifiers)
|
||||
}
|
||||
functionNode.targetDeclarations[context.targetIndex] = treeFunction.function
|
||||
}
|
||||
|
||||
internal fun CirNodeWithMembers<*, *>.buildProperty(context: TargetBuildingContext, treeProperty: CirTreeProperty) {
|
||||
val propertyNode = properties.getOrPut(treeProperty.approximationKey) {
|
||||
buildPropertyNode(context.storageManager, context.targets, context.classifiers)
|
||||
}
|
||||
propertyNode.targetDeclarations[context.targetIndex] = treeProperty.property
|
||||
}
|
||||
|
||||
internal fun CirClassNode.buildConstructor(context: TargetBuildingContext, treeConstructor: CirTreeClassConstructor) {
|
||||
val constructorNode = constructors.getOrPut(treeConstructor.approximationKey) {
|
||||
buildClassConstructorNode(context.storageManager, context.targets, context.classifiers)
|
||||
}
|
||||
constructorNode.targetDeclarations[context.targetIndex] = treeConstructor.constructor
|
||||
}
|
||||
|
||||
internal fun CirPackageNode.buildTypeAlias(context: TargetBuildingContext, treeTypeAlias: CirTreeTypeAlias) {
|
||||
val typeAliasNode = typeAliases.getOrPut(treeTypeAlias.typeAlias.name) {
|
||||
buildTypeAliasNode(context.storageManager, context.targets, context.classifiers, treeTypeAlias.id)
|
||||
}
|
||||
typeAliasNode.targetDeclarations[context.targetIndex] = treeTypeAlias.typeAlias
|
||||
}
|
||||
|
||||
+5
-5
@@ -16,15 +16,15 @@ import org.jetbrains.kotlin.backend.common.serialization.metadata.impl.ExportedF
|
||||
import org.jetbrains.kotlin.builtins.DefaultBuiltIns
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
||||
import org.jetbrains.kotlin.config.CommonConfigurationKeys
|
||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
import org.jetbrains.kotlin.config.languageVersionSettings
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.commonizer.ResultsConsumer.ModuleResult
|
||||
import org.jetbrains.kotlin.commonizer.ResultsConsumer.Status
|
||||
import org.jetbrains.kotlin.commonizer.SourceModuleRoot.Companion.SHARED_TARGET_NAME
|
||||
import org.jetbrains.kotlin.commonizer.konan.NativeManifestDataProvider
|
||||
import org.jetbrains.kotlin.commonizer.utils.*
|
||||
import org.jetbrains.kotlin.config.CommonConfigurationKeys
|
||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
import org.jetbrains.kotlin.config.languageVersionSettings
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.impl.DeclarationDescriptorVisitorEmptyBodies
|
||||
import org.jetbrains.kotlin.descriptors.impl.FunctionDescriptorImpl
|
||||
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
|
||||
@@ -208,7 +208,7 @@ private class AnalyzedModules(
|
||||
resultsConsumer: ResultsConsumer,
|
||||
manifestDataProvider: NativeManifestDataProvider = MockNativeManifestDataProvider()
|
||||
) = CommonizerParameters(
|
||||
targetProviders = leafTargets.map { leafTarget ->
|
||||
targetProviders = TargetDependent(leafTargets) { leafTarget ->
|
||||
TargetProvider(
|
||||
target = leafTarget,
|
||||
modulesProvider = MockModulesProvider.create(originalModules.getValue(leafTarget)),
|
||||
|
||||
@@ -8,9 +8,9 @@ package org.jetbrains.kotlin.commonizer
|
||||
import org.jetbrains.kotlin.commonizer.ResultsConsumer.ModuleResult
|
||||
import org.jetbrains.kotlin.commonizer.ResultsConsumer.Status
|
||||
import org.jetbrains.kotlin.commonizer.konan.NativeManifestDataProvider
|
||||
import org.jetbrains.kotlin.commonizer.utils.MockResultsConsumer
|
||||
import org.jetbrains.kotlin.commonizer.utils.MockModulesProvider
|
||||
import org.jetbrains.kotlin.commonizer.utils.MockNativeManifestDataProvider
|
||||
import org.jetbrains.kotlin.commonizer.utils.MockResultsConsumer
|
||||
import org.junit.Test
|
||||
import kotlin.contracts.ExperimentalContracts
|
||||
import kotlin.test.assertEquals
|
||||
@@ -69,14 +69,15 @@ class CommonizerFacadeTest {
|
||||
resultsConsumer: ResultsConsumer,
|
||||
manifestDataProvider: NativeManifestDataProvider = MockNativeManifestDataProvider()
|
||||
) = CommonizerParameters(
|
||||
targetProviders = map { (targetName, moduleNames) ->
|
||||
TargetProvider(
|
||||
target = LeafCommonizerTarget(targetName),
|
||||
modulesProvider = MockModulesProvider.create(moduleNames),
|
||||
dependencyModulesProvider = null,
|
||||
manifestProvider = manifestDataProvider,
|
||||
)
|
||||
},
|
||||
targetProviders = mapKeys { (targetName, _) -> LeafCommonizerTarget(targetName) }.toTargetDependent()
|
||||
.map { target, moduleNames ->
|
||||
TargetProvider(
|
||||
target = target,
|
||||
modulesProvider = MockModulesProvider.create(moduleNames),
|
||||
dependencyModulesProvider = null,
|
||||
manifestProvider = manifestDataProvider,
|
||||
)
|
||||
},
|
||||
resultsConsumer = resultsConsumer,
|
||||
commonManifestProvider = manifestDataProvider
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user