[Commonizer] Minor. Rename: 'dependee' -> 'dependency'
This commit is contained in:
+1
-1
@@ -17,7 +17,7 @@ class CommonizerParameters(
|
||||
val sharedTarget: SharedTarget get() = SharedTarget(_targetProviders.keys)
|
||||
|
||||
// common module dependencies (ex: Kotlin stdlib)
|
||||
var dependeeModulesProvider: ModulesProvider? = null
|
||||
var dependencyModulesProvider: ModulesProvider? = null
|
||||
set(value) {
|
||||
check(field == null)
|
||||
field = value
|
||||
|
||||
@@ -12,7 +12,7 @@ import java.io.File
|
||||
class TargetProvider(
|
||||
val target: LeafTarget,
|
||||
val modulesProvider: ModulesProvider,
|
||||
val dependeeModulesProvider: ModulesProvider?
|
||||
val dependencyModulesProvider: ModulesProvider?
|
||||
)
|
||||
|
||||
interface ModulesProvider {
|
||||
|
||||
+1
-1
@@ -126,7 +126,7 @@ internal class CommonizationVisitor(
|
||||
val supertypesMap: MutableMap<CirType, CommonizedGroup<CirType>> = linkedMapOf() // preserve supertype order
|
||||
for ((index, typeAlias) in targetDeclarations.withIndex()) {
|
||||
val expandedClassId = typeAlias!!.expandedType.classifierId
|
||||
if (classifiers.commonDependeeLibraries.hasClassifier(expandedClassId))
|
||||
if (classifiers.commonDependencies.hasClassifier(expandedClassId))
|
||||
return null // this case is not supported yet
|
||||
|
||||
val expandedClassNode = classifiers.commonized.classNode(expandedClassId) ?: return null
|
||||
|
||||
+7
-7
@@ -9,7 +9,7 @@ import org.jetbrains.kotlin.descriptors.DescriptorVisibility
|
||||
import org.jetbrains.kotlin.descriptors.commonizer.cir.*
|
||||
import org.jetbrains.kotlin.descriptors.commonizer.cir.factory.CirTypeFactory
|
||||
import org.jetbrains.kotlin.descriptors.commonizer.core.CommonizedTypeAliasAnswer.Companion.FAILURE_MISSING_IN_SOME_TARGET
|
||||
import org.jetbrains.kotlin.descriptors.commonizer.core.CommonizedTypeAliasAnswer.Companion.SUCCESS_FROM_DEPENDEE_LIBRARY
|
||||
import org.jetbrains.kotlin.descriptors.commonizer.core.CommonizedTypeAliasAnswer.Companion.SUCCESS_FROM_DEPENDENCY_LIBRARY
|
||||
import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.CirKnownClassifiers
|
||||
import org.jetbrains.kotlin.descriptors.commonizer.utils.isUnderKotlinNativeSyntheticPackages
|
||||
|
||||
@@ -192,8 +192,8 @@ private class FlexibleTypeCommonizer(classifiers: CirKnownClassifiers) : Abstrac
|
||||
}
|
||||
|
||||
private fun commonizeClass(classId: CirEntityId, classifiers: CirKnownClassifiers): Boolean {
|
||||
if (classifiers.commonDependeeLibraries.hasClassifier(classId)) {
|
||||
// The class is from common fragment of dependee library (ex: stdlib). Already commonized.
|
||||
if (classifiers.commonDependencies.hasClassifier(classId)) {
|
||||
// The class is from common fragment of dependency library (ex: stdlib). Already commonized.
|
||||
return true
|
||||
} else if (classId.packageName.isUnderKotlinNativeSyntheticPackages) {
|
||||
// C/Obj-C forward declarations are:
|
||||
@@ -219,9 +219,9 @@ private fun commonizeClass(classId: CirEntityId, classifiers: CirKnownClassifier
|
||||
}
|
||||
|
||||
private fun commonizeTypeAlias(typeAliasId: CirEntityId, classifiers: CirKnownClassifiers): CommonizedTypeAliasAnswer {
|
||||
if (classifiers.commonDependeeLibraries.hasClassifier(typeAliasId)) {
|
||||
// The type alias is from common fragment of dependee library (ex: stdlib). Already commonized.
|
||||
return SUCCESS_FROM_DEPENDEE_LIBRARY
|
||||
if (classifiers.commonDependencies.hasClassifier(typeAliasId)) {
|
||||
// The type alias is from common fragment of dependency library (ex: stdlib). Already commonized.
|
||||
return SUCCESS_FROM_DEPENDENCY_LIBRARY
|
||||
}
|
||||
|
||||
return when (val node = classifiers.commonized.typeAliasNode(typeAliasId)) {
|
||||
@@ -238,7 +238,7 @@ private fun commonizeTypeAlias(typeAliasId: CirEntityId, classifiers: CirKnownCl
|
||||
|
||||
private class CommonizedTypeAliasAnswer(val commonized: Boolean, val commonClassifier: CirClassifier?) {
|
||||
companion object {
|
||||
val SUCCESS_FROM_DEPENDEE_LIBRARY = CommonizedTypeAliasAnswer(true, null)
|
||||
val SUCCESS_FROM_DEPENDENCY_LIBRARY = CommonizedTypeAliasAnswer(true, null)
|
||||
val FAILURE_MISSING_IN_SOME_TARGET = CommonizedTypeAliasAnswer(false, null)
|
||||
|
||||
fun create(commonClassifier: CirClassifier?) =
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@ internal tailrec fun computeSuitableUnderlyingType(
|
||||
): CirClassOrTypeAliasType? {
|
||||
return when (underlyingType) {
|
||||
is CirClassType -> underlyingType.withCommonizedArguments(classifiers)
|
||||
is CirTypeAliasType -> if (classifiers.commonDependeeLibraries.hasClassifier(underlyingType.classifierId))
|
||||
is CirTypeAliasType -> if (classifiers.commonDependencies.hasClassifier(underlyingType.classifierId))
|
||||
underlyingType.withCommonizedArguments(classifiers)
|
||||
else
|
||||
computeSuitableUnderlyingType(classifiers, underlyingType.underlyingType)
|
||||
|
||||
@@ -41,10 +41,10 @@ private fun mergeAndCommonize(storageManager: StorageManager, parameters: Common
|
||||
val classifiers = CirKnownClassifiers(
|
||||
commonized = CirCommonizedClassifiers.default(),
|
||||
forwardDeclarations = CirForwardDeclarations.default(),
|
||||
dependeeLibraries = mapOf(
|
||||
// for now, supply only common dependee libraries (ex: Kotlin stdlib)
|
||||
dependencies = mapOf(
|
||||
// for now, supply only common dependency libraries (ex: Kotlin stdlib)
|
||||
parameters.sharedTarget to CirProvidedClassifiers.fromModules(storageManager) {
|
||||
parameters.dependeeModulesProvider?.loadModules(emptyList())?.values.orEmpty()
|
||||
parameters.dependencyModulesProvider?.loadModules(emptyList())?.values.orEmpty()
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
+2
-2
@@ -135,7 +135,7 @@ class NativeDistributionCommonizer(
|
||||
copyEndorsedLibs = copyEndorsedLibs,
|
||||
logProgress = ::logProgress
|
||||
)
|
||||
dependeeModulesProvider = NativeDistributionModulesProvider.forStandardLibrary(storageManager, allLibraries.stdlib)
|
||||
dependencyModulesProvider = NativeDistributionModulesProvider.forStandardLibrary(storageManager, allLibraries.stdlib)
|
||||
|
||||
allLibraries.librariesByTargets.forEach { (target, librariesToCommonize) ->
|
||||
if (librariesToCommonize.libraries.isEmpty()) return@forEach
|
||||
@@ -146,7 +146,7 @@ class NativeDistributionCommonizer(
|
||||
TargetProvider(
|
||||
target = target,
|
||||
modulesProvider = modulesProvider,
|
||||
dependeeModulesProvider = null // stdlib is already set as common dependency
|
||||
dependencyModulesProvider = null // stdlib is already set as common dependency
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
+8
-8
@@ -63,11 +63,11 @@ class CirTreeMerger(
|
||||
private fun processRoot(): CirTreeMergeResult {
|
||||
val rootNode: CirRootNode = buildRootNode(storageManager, size)
|
||||
|
||||
// remember any exported forward declarations from common fragments of dependee modules
|
||||
parameters.dependeeModulesProvider?.loadModuleInfos()?.forEach(::processCInteropModuleAttributes)
|
||||
// remember any exported forward declarations from common fragments of dependency modules
|
||||
parameters.dependencyModulesProvider?.loadModuleInfos()?.forEach(::processCInteropModuleAttributes)
|
||||
|
||||
// load common dependencies
|
||||
val dependeeModules = parameters.dependeeModulesProvider?.loadModules(emptyList())?.values.orEmpty()
|
||||
val dependencyModules = parameters.dependencyModulesProvider?.loadModules(emptyList())?.values.orEmpty()
|
||||
|
||||
val allModuleInfos: List<Map<String, ModuleInfo>> = parameters.targetProviders.map { targetProvider ->
|
||||
targetProvider.modulesProvider.loadModuleInfos().associateBy { it.name }
|
||||
@@ -76,7 +76,7 @@ class CirTreeMerger(
|
||||
|
||||
parameters.targetProviders.forEachIndexed { targetIndex, targetProvider ->
|
||||
val commonModuleInfos = allModuleInfos[targetIndex].filterKeys { it in commonModuleNames }
|
||||
processTarget(rootNode, targetIndex, targetProvider, commonModuleInfos, dependeeModules)
|
||||
processTarget(rootNode, targetIndex, targetProvider, commonModuleInfos, dependencyModules)
|
||||
parameters.progressLogger?.invoke("Loaded declarations for ${targetProvider.target.prettyName}")
|
||||
System.gc()
|
||||
}
|
||||
@@ -98,14 +98,14 @@ class CirTreeMerger(
|
||||
targetIndex: Int,
|
||||
targetProvider: TargetProvider,
|
||||
commonModuleInfos: Map<String, ModuleInfo>,
|
||||
dependeeModules: Collection<ModuleDescriptor>
|
||||
dependencyModules: Collection<ModuleDescriptor>
|
||||
) {
|
||||
rootNode.targetDeclarations[targetIndex] = CirRootFactory.create(targetProvider.target)
|
||||
|
||||
val targetDependeeModules = targetProvider.dependeeModulesProvider?.loadModules(dependeeModules)?.values.orEmpty()
|
||||
val allDependeeModules = targetDependeeModules + dependeeModules
|
||||
val targetDependencyModules = targetProvider.dependencyModulesProvider?.loadModules(dependencyModules)?.values.orEmpty()
|
||||
val allDependencyModules = targetDependencyModules + dependencyModules
|
||||
|
||||
val moduleDescriptors: Map<String, ModuleDescriptor> = targetProvider.modulesProvider.loadModules(allDependeeModules)
|
||||
val moduleDescriptors: Map<String, ModuleDescriptor> = targetProvider.modulesProvider.loadModules(allDependencyModules)
|
||||
|
||||
moduleDescriptors.forEach { (name, moduleDescriptor) ->
|
||||
val moduleInfo = commonModuleInfos[name] ?: return@forEach
|
||||
|
||||
+3
-3
@@ -21,11 +21,11 @@ import org.jetbrains.kotlin.storage.getValue
|
||||
class CirKnownClassifiers(
|
||||
val commonized: CirCommonizedClassifiers,
|
||||
val forwardDeclarations: CirForwardDeclarations,
|
||||
val dependeeLibraries: Map<CommonizerTarget, CirProvidedClassifiers>
|
||||
val dependencies: Map<CommonizerTarget, CirProvidedClassifiers>
|
||||
) {
|
||||
// a shortcut for fast access
|
||||
val commonDependeeLibraries: CirProvidedClassifiers =
|
||||
dependeeLibraries.filterKeys { it is SharedTarget }.values.singleOrNull() ?: CirProvidedClassifiers.EMPTY
|
||||
val commonDependencies: CirProvidedClassifiers =
|
||||
dependencies.filterKeys { it is SharedTarget }.values.singleOrNull() ?: CirProvidedClassifiers.EMPTY
|
||||
}
|
||||
|
||||
interface CirCommonizedClassifiers {
|
||||
|
||||
+27
-27
@@ -118,7 +118,7 @@ private data class SourceModuleRoot(
|
||||
private class SourceModuleRoots(
|
||||
val originalRoots: Map<LeafTarget, SourceModuleRoot>,
|
||||
val commonizedRoots: Map<CommonizerTarget, SourceModuleRoot>,
|
||||
val dependeeRoots: Map<CommonizerTarget, SourceModuleRoot>
|
||||
val dependencyRoots: Map<CommonizerTarget, SourceModuleRoot>
|
||||
) {
|
||||
val leafTargets: Set<LeafTarget> = originalRoots.keys
|
||||
val sharedTarget: SharedTarget
|
||||
@@ -135,7 +135,7 @@ private class SourceModuleRoots(
|
||||
|
||||
val allTargets = leafTargets + sharedTarget
|
||||
check(commonizedRoots.keys == allTargets)
|
||||
check(allTargets.containsAll(dependeeRoots.keys))
|
||||
check(allTargets.containsAll(dependencyRoots.keys))
|
||||
}
|
||||
|
||||
companion object {
|
||||
@@ -149,16 +149,16 @@ private class SourceModuleRoots(
|
||||
if (targetName == SHARED_TARGET_NAME) sharedTarget else leafTargets.first { it.name == targetName }
|
||||
|
||||
val commonizedRoots = listRoots(dataDir, COMMONIZED_ROOTS_DIR).mapKeys { getTarget(it.key) }
|
||||
val dependeeRoots = listRoots(dataDir, DEPENDEE_ROOTS_DIR).mapKeys { getTarget(it.key) }
|
||||
val dependencyRoots = listRoots(dataDir, DEPENDENCY_ROOTS_DIR).mapKeys { getTarget(it.key) }
|
||||
|
||||
SourceModuleRoots(originalRoots, commonizedRoots, dependeeRoots)
|
||||
SourceModuleRoots(originalRoots, commonizedRoots, dependencyRoots)
|
||||
} catch (e: Exception) {
|
||||
fail("Source module misconfiguration in $dataDir", cause = e)
|
||||
}
|
||||
|
||||
private const val ORIGINAL_ROOTS_DIR = "original"
|
||||
private const val COMMONIZED_ROOTS_DIR = "commonized"
|
||||
private const val DEPENDEE_ROOTS_DIR = "dependee"
|
||||
private const val DEPENDENCY_ROOTS_DIR = "dependency"
|
||||
|
||||
private fun listRoots(dataDir: File, rootsDirName: String): Map<String, SourceModuleRoot> =
|
||||
dataDir.resolve(rootsDirName).listFiles()?.toSet().orEmpty().map(SourceModuleRoot::load).associateBy { it.targetName }
|
||||
@@ -183,7 +183,7 @@ private class AnalyzedModuleDependencies(
|
||||
private class AnalyzedModules(
|
||||
val originalModules: Map<CommonizerTarget, ModuleDescriptor>,
|
||||
val commonizedModules: Map<CommonizerTarget, SerializedMetadata>,
|
||||
val dependeeModules: Map<CommonizerTarget, List<ModuleDescriptor>>
|
||||
val dependencyModules: Map<CommonizerTarget, List<ModuleDescriptor>>
|
||||
) {
|
||||
val leafTargets: Set<LeafTarget>
|
||||
val sharedTarget: SharedTarget
|
||||
@@ -200,13 +200,13 @@ private class AnalyzedModules(
|
||||
val allTargets = leafTargets + sharedTarget
|
||||
|
||||
check(commonizedModules.keys == allTargets)
|
||||
check(allTargets.containsAll(dependeeModules.keys))
|
||||
check(allTargets.containsAll(dependencyModules.keys))
|
||||
}
|
||||
|
||||
fun toCommonizerParameters(resultsConsumer: ResultsConsumer) =
|
||||
CommonizerParameters().also { parameters ->
|
||||
parameters.resultsConsumer = resultsConsumer
|
||||
parameters.dependeeModulesProvider = dependeeModules[sharedTarget]?.let(MockModulesProvider::create)
|
||||
parameters.dependencyModulesProvider = dependencyModules[sharedTarget]?.let(MockModulesProvider::create)
|
||||
|
||||
leafTargets.forEach { leafTarget ->
|
||||
val originalModule = originalModules.getValue(leafTarget)
|
||||
@@ -215,7 +215,7 @@ private class AnalyzedModules(
|
||||
TargetProvider(
|
||||
target = leafTarget,
|
||||
modulesProvider = MockModulesProvider.create(originalModule),
|
||||
dependeeModulesProvider = dependeeModules[leafTarget]?.let(MockModulesProvider::create)
|
||||
dependencyModulesProvider = dependencyModules[leafTarget]?.let(MockModulesProvider::create)
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -227,8 +227,8 @@ private class AnalyzedModules(
|
||||
parentDisposable: Disposable
|
||||
): AnalyzedModules = with(sourceModuleRoots) {
|
||||
// phase 1: provide the modules that are the dependencies for "original" and "commonized" modules
|
||||
val (dependeeModules: Map<CommonizerTarget, List<ModuleDescriptor>>, dependencies: AnalyzedModuleDependencies) =
|
||||
createDependeeModules(sharedTarget, dependeeRoots, parentDisposable)
|
||||
val (dependencyModules: Map<CommonizerTarget, List<ModuleDescriptor>>, dependencies: AnalyzedModuleDependencies) =
|
||||
createDependencyModules(sharedTarget, dependencyRoots, parentDisposable)
|
||||
|
||||
// phase 2: build "original" and "commonized" modules
|
||||
val originalModules: Map<CommonizerTarget, ModuleDescriptor> =
|
||||
@@ -238,27 +238,27 @@ private class AnalyzedModules(
|
||||
createModules(sharedTarget, commonizedRoots, dependencies, parentDisposable)
|
||||
.mapValues { (_, moduleDescriptor) -> MockModulesProvider.SERIALIZER.serializeModule(moduleDescriptor) }
|
||||
|
||||
return AnalyzedModules(originalModules, commonizedModules, dependeeModules)
|
||||
return AnalyzedModules(originalModules, commonizedModules, dependencyModules)
|
||||
}
|
||||
|
||||
private fun createDependeeModules(
|
||||
private fun createDependencyModules(
|
||||
sharedTarget: SharedTarget,
|
||||
dependeeRoots: Map<out CommonizerTarget, SourceModuleRoot>,
|
||||
dependencyRoots: Map<out CommonizerTarget, SourceModuleRoot>,
|
||||
parentDisposable: Disposable
|
||||
): Pair<Map<CommonizerTarget, List<ModuleDescriptor>>, AnalyzedModuleDependencies> {
|
||||
val customDependeeModules =
|
||||
createModules(sharedTarget, dependeeRoots, AnalyzedModuleDependencies.EMPTY, parentDisposable, isDependeeModule = true)
|
||||
val customDependencyModules =
|
||||
createModules(sharedTarget, dependencyRoots, AnalyzedModuleDependencies.EMPTY, parentDisposable, isDependencyModule = true)
|
||||
|
||||
val stdlibModule = DefaultBuiltIns.Instance.builtInsModule
|
||||
|
||||
val dependeeModules = (sharedTarget.targets + sharedTarget).associateWith { target ->
|
||||
val dependencyModules = (sharedTarget.targets + sharedTarget).associateWith { target ->
|
||||
// prepend stdlib for each target explicitly, so that the commonizer can see symbols from the stdlib
|
||||
listOfNotNull(stdlibModule, customDependeeModules[target])
|
||||
listOfNotNull(stdlibModule, customDependencyModules[target])
|
||||
}
|
||||
|
||||
return dependeeModules to AnalyzedModuleDependencies(
|
||||
regularDependencies = dependeeModules,
|
||||
expectByDependencies = dependeeModules.getValue(sharedTarget).filter { module -> module !== stdlibModule }
|
||||
return dependencyModules to AnalyzedModuleDependencies(
|
||||
regularDependencies = dependencyModules,
|
||||
expectByDependencies = dependencyModules.getValue(sharedTarget).filter { module -> module !== stdlibModule }
|
||||
)
|
||||
}
|
||||
|
||||
@@ -267,7 +267,7 @@ private class AnalyzedModules(
|
||||
moduleRoots: Map<out CommonizerTarget, SourceModuleRoot>,
|
||||
dependencies: AnalyzedModuleDependencies,
|
||||
parentDisposable: Disposable,
|
||||
isDependeeModule: Boolean = false
|
||||
isDependencyModule: Boolean = false
|
||||
): Map<CommonizerTarget, ModuleDescriptor> {
|
||||
val result = mutableMapOf<CommonizerTarget, ModuleDescriptor>()
|
||||
|
||||
@@ -275,7 +275,7 @@ private class AnalyzedModules(
|
||||
|
||||
// first, process the common module
|
||||
moduleRoots[sharedTarget]?.let { moduleRoot ->
|
||||
val commonModule = createModule(sharedTarget, sharedTarget, moduleRoot, dependencies, parentDisposable, isDependeeModule)
|
||||
val commonModule = createModule(sharedTarget, sharedTarget, moduleRoot, dependencies, parentDisposable, isDependencyModule)
|
||||
result[sharedTarget] = commonModule
|
||||
dependenciesForOthers = dependencies.withExpectByDependency(commonModule)
|
||||
}
|
||||
@@ -283,7 +283,7 @@ private class AnalyzedModules(
|
||||
// then, all platform modules
|
||||
moduleRoots.filterKeys { it != sharedTarget }.forEach { (leafTarget, moduleRoot) ->
|
||||
result[leafTarget] =
|
||||
createModule(sharedTarget, leafTarget, moduleRoot, dependenciesForOthers, parentDisposable, isDependeeModule)
|
||||
createModule(sharedTarget, leafTarget, moduleRoot, dependenciesForOthers, parentDisposable, isDependencyModule)
|
||||
}
|
||||
|
||||
return result
|
||||
@@ -295,10 +295,10 @@ private class AnalyzedModules(
|
||||
moduleRoot: SourceModuleRoot,
|
||||
dependencies: AnalyzedModuleDependencies,
|
||||
parentDisposable: Disposable,
|
||||
isDependeeModule: Boolean
|
||||
isDependencyModule: Boolean
|
||||
): ModuleDescriptor {
|
||||
val moduleName: String = moduleRoot.location.parentFile.parentFile.name.let {
|
||||
if (isDependeeModule) "dependee-$it" else it
|
||||
if (isDependencyModule) "dependency-$it" else it
|
||||
}
|
||||
check(Name.isValidIdentifier(moduleName))
|
||||
|
||||
@@ -329,7 +329,7 @@ private class AnalyzedModules(
|
||||
environment.createPackagePartProvider(content.moduleContentScope)
|
||||
}.moduleDescriptor
|
||||
|
||||
if (!isDependeeModule)
|
||||
if (!isDependencyModule)
|
||||
module.accept(PatchingTestDescriptorVisitor, Unit)
|
||||
|
||||
return module
|
||||
|
||||
+1
-1
@@ -71,7 +71,7 @@ class CommonizerFacadeTest {
|
||||
TargetProvider(
|
||||
target = LeafTarget(targetName),
|
||||
modulesProvider = MockModulesProvider.create(moduleNames),
|
||||
dependeeModulesProvider = null
|
||||
dependencyModulesProvider = null
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
+1
-1
@@ -35,7 +35,7 @@ class TypeCommonizerTest : AbstractCommonizerTest<CirType, CirType>() {
|
||||
classifiers = CirKnownClassifiers(
|
||||
commonized = CirCommonizedClassifiers.default(),
|
||||
forwardDeclarations = CirForwardDeclarations.default(),
|
||||
dependeeLibraries = mapOf(
|
||||
dependencies = mapOf(
|
||||
FAKE_SHARED_TARGET to object : CirProvidedClassifiers {
|
||||
override fun hasClassifier(classifierId: CirEntityId): Boolean = classifierId.packageName.isUnderStandardKotlinPackages
|
||||
}
|
||||
|
||||
@@ -150,7 +150,7 @@ internal val MOCK_CLASSIFIERS = CirKnownClassifiers(
|
||||
override fun isExportedForwardDeclaration(classId: CirEntityId) = false
|
||||
override fun addExportedForwardDeclaration(classId: CirEntityId) = error("This method should not be called")
|
||||
},
|
||||
dependeeLibraries = emptyMap()
|
||||
dependencies = emptyMap()
|
||||
)
|
||||
|
||||
internal class MockModulesProvider private constructor(
|
||||
|
||||
Reference in New Issue
Block a user