[klib] Implement diagnostics for clashing KLIB signatures
Now, we detect clashing signatures during serialization to KLIB and
report a compiler error if two or more declarations have the same
`IdSignature`
For example, for the following code:
```kotlin
@Deprecated("", level = DeprecationLevel.HIDDEN)
fun foo(): String = ""
fun foo(): Int = 0
```
the compiler will produce this diagnostic:
```
e: main.kt:1:1 Platform declaration clash: The following declarations
have the same KLIB signature (/foo|foo(){}[0]):
fun foo(): String defined in root package
fun foo(): Int defined in root package
e: main.kt:4:1 Platform declaration clash: The following declarations
have the same KLIB signature (/foo|foo(){}[0]):
fun foo(): String defined in root package
fun foo(): Int defined in root package
```
Note that we report this diagnostic during serialization and not earlier
(e.g., in fir2ir) for more robustness, so ensure that we check
exactly the signatures that will be written to a KLIB.
If we later introduce some annotation for customizing a declaration's
signature (e.g., for preserving binary compatibility), this
diagnostic will continue to work as expected.
^KT-63670 Fixed
This commit is contained in:
committed by
Space Team
parent
e0cb145c6b
commit
eda30ff704
+24
@@ -9,6 +9,7 @@ import com.intellij.openapi.util.text.StringUtil
|
|||||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.types.Variance
|
import org.jetbrains.kotlin.types.Variance
|
||||||
|
import org.jetbrains.kotlin.utils.addToStdlib.joinToWithBuffer
|
||||||
import java.io.PrintWriter
|
import java.io.PrintWriter
|
||||||
import java.io.StringWriter
|
import java.io.StringWriter
|
||||||
|
|
||||||
@@ -63,4 +64,27 @@ object CommonRenderers {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun <Declaration, Data> renderConflictingSignatureData(
|
||||||
|
signatureKind: String,
|
||||||
|
sortUsing: Comparator<Declaration>,
|
||||||
|
declarationRenderer: DiagnosticParameterRenderer<Declaration>,
|
||||||
|
renderSignature: StringBuilder.(Data) -> Unit,
|
||||||
|
declarations: (Data) -> Collection<Declaration>,
|
||||||
|
) = Renderer<Data> { data ->
|
||||||
|
val sortedDeclarations = declarations(data).sortedWith(sortUsing)
|
||||||
|
val renderingContext = RenderingContext.Impl(sortedDeclarations)
|
||||||
|
buildString {
|
||||||
|
append("The following declarations have the same ")
|
||||||
|
append(signatureKind)
|
||||||
|
append(" signature (")
|
||||||
|
renderSignature(data)
|
||||||
|
appendLine("):")
|
||||||
|
sortedDeclarations.joinToWithBuffer(this, separator = "\n") { descriptor ->
|
||||||
|
append(" ")
|
||||||
|
append(declarationRenderer.render(descriptor, renderingContext))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+14
-13
@@ -11,12 +11,14 @@ import org.jetbrains.kotlin.diagnostics.SourceElementPositioningStrategies.DECLA
|
|||||||
import org.jetbrains.kotlin.diagnostics.error0
|
import org.jetbrains.kotlin.diagnostics.error0
|
||||||
import org.jetbrains.kotlin.diagnostics.error1
|
import org.jetbrains.kotlin.diagnostics.error1
|
||||||
import org.jetbrains.kotlin.diagnostics.error2
|
import org.jetbrains.kotlin.diagnostics.error2
|
||||||
import org.jetbrains.kotlin.diagnostics.rendering.*
|
import org.jetbrains.kotlin.diagnostics.rendering.BaseDiagnosticRendererFactory
|
||||||
|
import org.jetbrains.kotlin.diagnostics.rendering.CommonRenderers
|
||||||
import org.jetbrains.kotlin.diagnostics.rendering.CommonRenderers.NAME
|
import org.jetbrains.kotlin.diagnostics.rendering.CommonRenderers.NAME
|
||||||
import org.jetbrains.kotlin.diagnostics.rendering.CommonRenderers.STRING
|
import org.jetbrains.kotlin.diagnostics.rendering.CommonRenderers.STRING
|
||||||
|
import org.jetbrains.kotlin.diagnostics.rendering.Renderers
|
||||||
|
import org.jetbrains.kotlin.diagnostics.rendering.RootDiagnosticRendererFactory
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.resolve.MemberComparator
|
import org.jetbrains.kotlin.resolve.MemberComparator
|
||||||
import org.jetbrains.kotlin.utils.join
|
|
||||||
|
|
||||||
object JvmBackendErrors {
|
object JvmBackendErrors {
|
||||||
val CONFLICTING_JVM_DECLARATIONS by error1<PsiElement, ConflictingJvmDeclarationsData>(DECLARATION_SIGNATURE_OR_DEFAULT)
|
val CONFLICTING_JVM_DECLARATIONS by error1<PsiElement, ConflictingJvmDeclarationsData>(DECLARATION_SIGNATURE_OR_DEFAULT)
|
||||||
@@ -48,17 +50,16 @@ object JvmBackendErrors {
|
|||||||
object KtDefaultJvmErrorMessages : BaseDiagnosticRendererFactory() {
|
object KtDefaultJvmErrorMessages : BaseDiagnosticRendererFactory() {
|
||||||
|
|
||||||
@JvmField
|
@JvmField
|
||||||
val CONFLICTING_JVM_DECLARATIONS_DATA = Renderer<ConflictingJvmDeclarationsData> {
|
val CONFLICTING_JVM_DECLARATIONS_DATA = CommonRenderers.renderConflictingSignatureData(
|
||||||
val renderedDescriptors = it.signatureDescriptors.sortedWith(MemberComparator.INSTANCE)
|
signatureKind = "JVM",
|
||||||
val renderingContext = RenderingContext.Impl(renderedDescriptors)
|
sortUsing = MemberComparator.INSTANCE,
|
||||||
"""
|
declarationRenderer = Renderers.WITHOUT_MODIFIERS,
|
||||||
The following declarations have the same JVM signature (${it.signature.name}${it.signature.desc}):
|
renderSignature = {
|
||||||
|
append(it.signature.name)
|
||||||
""".trimIndent() +
|
append(it.signature.desc)
|
||||||
join(renderedDescriptors.map { descriptor ->
|
},
|
||||||
" " + Renderers.WITHOUT_MODIFIERS.render(descriptor, renderingContext)
|
declarations = ConflictingJvmDeclarationsData::signatureDescriptors,
|
||||||
}, "\n")
|
)
|
||||||
}
|
|
||||||
|
|
||||||
override val MAP = KtDiagnosticFactoryToRendererMap("KT").also { map ->
|
override val MAP = KtDiagnosticFactoryToRendererMap("KT").also { map ->
|
||||||
map.put(JvmBackendErrors.CONFLICTING_JVM_DECLARATIONS, "Platform declaration clash: {0}", CONFLICTING_JVM_DECLARATIONS_DATA)
|
map.put(JvmBackendErrors.CONFLICTING_JVM_DECLARATIONS, "Platform declaration clash: {0}", CONFLICTING_JVM_DECLARATIONS_DATA)
|
||||||
|
|||||||
@@ -31,13 +31,14 @@ import org.jetbrains.kotlin.diagnostics.rendering.TabledDescriptorRenderer.newTe
|
|||||||
import org.jetbrains.kotlin.name.FqNameUnsafe
|
import org.jetbrains.kotlin.name.FqNameUnsafe
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.platform.isCommon
|
import org.jetbrains.kotlin.platform.isCommon
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.KtClass
|
||||||
import org.jetbrains.kotlin.renderer.AnnotationArgumentsRenderingPolicy
|
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||||
|
import org.jetbrains.kotlin.psi.KtNamedDeclaration
|
||||||
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
||||||
import org.jetbrains.kotlin.renderer.DescriptorRenderer.Companion.DEBUG_TEXT
|
import org.jetbrains.kotlin.renderer.DescriptorRenderer.Companion.DEBUG_TEXT
|
||||||
import org.jetbrains.kotlin.renderer.DescriptorRendererModifier
|
|
||||||
import org.jetbrains.kotlin.renderer.PropertyAccessorRenderingPolicy
|
import org.jetbrains.kotlin.renderer.PropertyAccessorRenderingPolicy
|
||||||
import org.jetbrains.kotlin.resolve.*
|
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||||
|
import org.jetbrains.kotlin.resolve.MemberComparator
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.*
|
import org.jetbrains.kotlin.resolve.calls.inference.*
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.TypeBounds.Bound
|
import org.jetbrains.kotlin.resolve.calls.inference.TypeBounds.Bound
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.TypeBounds.BoundKind.LOWER_BOUND
|
import org.jetbrains.kotlin.resolve.calls.inference.TypeBounds.BoundKind.LOWER_BOUND
|
||||||
@@ -52,6 +53,7 @@ import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
|
|||||||
import org.jetbrains.kotlin.utils.IDEAPlatforms
|
import org.jetbrains.kotlin.utils.IDEAPlatforms
|
||||||
import org.jetbrains.kotlin.utils.IDEAPluginsCompatibilityAPI
|
import org.jetbrains.kotlin.utils.IDEAPluginsCompatibilityAPI
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
|
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
|
||||||
|
import org.jetbrains.kotlin.utils.addToStdlib.joinToWithBuffer
|
||||||
|
|
||||||
object Renderers {
|
object Renderers {
|
||||||
|
|
||||||
@@ -706,9 +708,7 @@ object Renderers {
|
|||||||
@JvmField
|
@JvmField
|
||||||
val COMPACT_WITHOUT_SUPERTYPES = DescriptorRenderer.COMPACT_WITHOUT_SUPERTYPES.asRenderer()
|
val COMPACT_WITHOUT_SUPERTYPES = DescriptorRenderer.COMPACT_WITHOUT_SUPERTYPES.asRenderer()
|
||||||
@JvmField
|
@JvmField
|
||||||
val WITHOUT_MODIFIERS = DescriptorRenderer.withOptions {
|
val WITHOUT_MODIFIERS = DescriptorRenderer.WITHOUT_MODIFIERS.asRenderer()
|
||||||
modifiers = emptySet()
|
|
||||||
}.asRenderer()
|
|
||||||
@JvmField
|
@JvmField
|
||||||
val SHORT_NAMES_IN_TYPES = DescriptorRenderer.SHORT_NAMES_IN_TYPES.asRenderer()
|
val SHORT_NAMES_IN_TYPES = DescriptorRenderer.SHORT_NAMES_IN_TYPES.asRenderer()
|
||||||
@JvmField
|
@JvmField
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ dependencies {
|
|||||||
api(project(":kotlin-util-klib-metadata"))
|
api(project(":kotlin-util-klib-metadata"))
|
||||||
api(project(":compiler:util"))
|
api(project(":compiler:util"))
|
||||||
implementation(project(":compiler:psi"))
|
implementation(project(":compiler:psi"))
|
||||||
|
implementation(project(":compiler:frontend.common-psi"))
|
||||||
compileOnly(commonDependency("org.jetbrains.kotlin:kotlin-reflect")) { isTransitive = false }
|
compileOnly(commonDependency("org.jetbrains.kotlin:kotlin-reflect")) { isTransitive = false }
|
||||||
compileOnly(commonDependency("org.jetbrains.intellij.deps.fastutil:intellij-deps-fastutil"))
|
compileOnly(commonDependency("org.jetbrains.intellij.deps.fastutil:intellij-deps-fastutil"))
|
||||||
|
|
||||||
|
|||||||
+11
@@ -0,0 +1,11 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2023 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.backend.common.diagnostics
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
||||||
|
import org.jetbrains.kotlin.ir.util.IdSignature
|
||||||
|
|
||||||
|
internal data class ConflictingKlibSignaturesData(val signature: IdSignature, val declarations: Collection<IrDeclaration>)
|
||||||
+29
@@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2023 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.backend.common.diagnostics
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.ir.IrDiagnosticReporter
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
||||||
|
import org.jetbrains.kotlin.ir.linkage.SignatureClashDetector
|
||||||
|
import org.jetbrains.kotlin.ir.util.IdSignature
|
||||||
|
import org.jetbrains.kotlin.ir.util.file
|
||||||
|
import org.jetbrains.kotlin.ir.util.parentClassOrNull
|
||||||
|
|
||||||
|
class IdSignatureClashDetector : SignatureClashDetector<IdSignature, IrDeclaration>() {
|
||||||
|
override fun reportSignatureConflict(
|
||||||
|
signature: IdSignature,
|
||||||
|
declarations: Collection<IrDeclaration>,
|
||||||
|
diagnosticReporter: IrDiagnosticReporter
|
||||||
|
) {
|
||||||
|
reportSignatureClashTo(
|
||||||
|
diagnosticReporter,
|
||||||
|
SerializationErrors.CONFLICTING_KLIB_SIGNATURES_ERROR,
|
||||||
|
declarations,
|
||||||
|
ConflictingKlibSignaturesData(signature, declarations),
|
||||||
|
reportOnIfSynthetic = { it.parentClassOrNull ?: it.file },
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
+52
@@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2023 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.backend.common.diagnostics
|
||||||
|
|
||||||
|
import com.intellij.psi.PsiElement
|
||||||
|
import org.jetbrains.kotlin.backend.common.diagnostics.SerializationDiagnosticRenderers.CONFLICTING_KLIB_SIGNATURES_DATA
|
||||||
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||||
|
import org.jetbrains.kotlin.diagnostics.KtDiagnosticFactoryToRendererMap
|
||||||
|
import org.jetbrains.kotlin.diagnostics.error1
|
||||||
|
import org.jetbrains.kotlin.diagnostics.rendering.BaseDiagnosticRendererFactory
|
||||||
|
import org.jetbrains.kotlin.diagnostics.rendering.CommonRenderers
|
||||||
|
import org.jetbrains.kotlin.diagnostics.rendering.Renderer
|
||||||
|
import org.jetbrains.kotlin.diagnostics.rendering.RootDiagnosticRendererFactory
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
||||||
|
import org.jetbrains.kotlin.ir.descriptors.toIrBasedDescriptor
|
||||||
|
import org.jetbrains.kotlin.ir.util.render
|
||||||
|
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
||||||
|
import org.jetbrains.kotlin.resolve.MemberComparator
|
||||||
|
|
||||||
|
internal object SerializationErrors {
|
||||||
|
val CONFLICTING_KLIB_SIGNATURES_ERROR by error1<PsiElement, ConflictingKlibSignaturesData>()
|
||||||
|
|
||||||
|
init {
|
||||||
|
RootDiagnosticRendererFactory.registerFactory(KtDefaultSerializationErrorMessages)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal object KtDefaultSerializationErrorMessages : BaseDiagnosticRendererFactory() {
|
||||||
|
override val MAP = KtDiagnosticFactoryToRendererMap("KT").also { map ->
|
||||||
|
map.put(
|
||||||
|
SerializationErrors.CONFLICTING_KLIB_SIGNATURES_ERROR,
|
||||||
|
"Platform declaration clash: {0}",
|
||||||
|
CONFLICTING_KLIB_SIGNATURES_DATA,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal object SerializationDiagnosticRenderers {
|
||||||
|
val CONFLICTING_KLIB_SIGNATURES_DATA =
|
||||||
|
CommonRenderers.renderConflictingSignatureData<DeclarationDescriptor, ConflictingKlibSignaturesData>(
|
||||||
|
signatureKind = "KLIB",
|
||||||
|
sortUsing = MemberComparator.INSTANCE,
|
||||||
|
declarationRenderer = Renderer {
|
||||||
|
DescriptorRenderer.WITHOUT_MODIFIERS.render(it)
|
||||||
|
},
|
||||||
|
renderSignature = { append(it.signature.render()) },
|
||||||
|
declarations = { it.declarations.map(IrDeclaration::toIrBasedDescriptor) },
|
||||||
|
)
|
||||||
|
}
|
||||||
+7
-19
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.backend.common.serialization
|
package org.jetbrains.kotlin.backend.common.serialization
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.backend.common.diagnostics.IdSignatureClashDetector
|
||||||
import org.jetbrains.kotlin.backend.common.serialization.signature.IdSignatureFactory
|
import org.jetbrains.kotlin.backend.common.serialization.signature.IdSignatureFactory
|
||||||
import org.jetbrains.kotlin.backend.common.serialization.signature.PublicIdSignatureComputer
|
import org.jetbrains.kotlin.backend.common.serialization.signature.PublicIdSignatureComputer
|
||||||
import org.jetbrains.kotlin.ir.IrBuiltIns
|
import org.jetbrains.kotlin.ir.IrBuiltIns
|
||||||
@@ -15,37 +16,24 @@ import org.jetbrains.kotlin.ir.util.IdSignature
|
|||||||
import org.jetbrains.kotlin.ir.util.KotlinMangler
|
import org.jetbrains.kotlin.ir.util.KotlinMangler
|
||||||
import org.jetbrains.kotlin.ir.util.render
|
import org.jetbrains.kotlin.ir.util.render
|
||||||
|
|
||||||
|
abstract class GlobalDeclarationTable(private val mangler: KotlinMangler.IrMangler) {
|
||||||
interface IdSignatureClashTracker {
|
|
||||||
fun commit(declaration: IrDeclaration, signature: IdSignature)
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
val DEFAULT_TRACKER = object : IdSignatureClashTracker {
|
|
||||||
override fun commit(declaration: IrDeclaration, signature: IdSignature) {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract class GlobalDeclarationTable(
|
|
||||||
private val mangler: KotlinMangler.IrMangler,
|
|
||||||
private val clashTracker: IdSignatureClashTracker
|
|
||||||
) {
|
|
||||||
val publicIdSignatureComputer = PublicIdSignatureComputer(mangler)
|
val publicIdSignatureComputer = PublicIdSignatureComputer(mangler)
|
||||||
|
internal val clashDetector = IdSignatureClashDetector()
|
||||||
|
|
||||||
protected val table = hashMapOf<IrDeclaration, IdSignature>()
|
protected val table = hashMapOf<IrDeclaration, IdSignature>()
|
||||||
|
|
||||||
constructor(mangler: KotlinMangler.IrMangler) : this(mangler, IdSignatureClashTracker.DEFAULT_TRACKER)
|
|
||||||
|
|
||||||
protected fun loadKnownBuiltins(builtIns: IrBuiltIns) {
|
protected fun loadKnownBuiltins(builtIns: IrBuiltIns) {
|
||||||
builtIns.knownBuiltins.forEach {
|
builtIns.knownBuiltins.forEach {
|
||||||
val symbol = (it as IrSymbolOwner).symbol
|
val symbol = (it as IrSymbolOwner).symbol
|
||||||
table[it] = symbol.signature!!.also { id -> clashTracker.commit(it, id) }
|
table[it] = symbol.signature!!.also { id -> clashDetector.trackDeclaration(it, id) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun computeSignatureByDeclaration(declaration: IrDeclaration, compatibleMode: Boolean): IdSignature {
|
open fun computeSignatureByDeclaration(declaration: IrDeclaration, compatibleMode: Boolean): IdSignature {
|
||||||
return table.getOrPut(declaration) {
|
return table.getOrPut(declaration) {
|
||||||
publicIdSignatureComputer.composePublicIdSignature(declaration, compatibleMode).also { clashTracker.commit(declaration, it) }
|
publicIdSignatureComputer.composePublicIdSignature(declaration, compatibleMode).also {
|
||||||
|
clashDetector.trackDeclaration(declaration, it)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+16
-2
@@ -6,14 +6,23 @@
|
|||||||
package org.jetbrains.kotlin.backend.common.serialization
|
package org.jetbrains.kotlin.backend.common.serialization
|
||||||
|
|
||||||
import org.jetbrains.kotlin.builtins.FunctionInterfacePackageFragment
|
import org.jetbrains.kotlin.builtins.FunctionInterfacePackageFragment
|
||||||
|
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
|
||||||
|
import org.jetbrains.kotlin.ir.IrDiagnosticReporter
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
||||||
import org.jetbrains.kotlin.ir.util.IrMessageLogger
|
import org.jetbrains.kotlin.ir.util.IrMessageLogger
|
||||||
import org.jetbrains.kotlin.library.SerializedIrFile
|
import org.jetbrains.kotlin.library.SerializedIrFile
|
||||||
import org.jetbrains.kotlin.library.SerializedIrModule
|
import org.jetbrains.kotlin.library.SerializedIrModule
|
||||||
|
|
||||||
abstract class IrModuleSerializer<F : IrFileSerializer>(protected val messageLogger: IrMessageLogger, protected val compatibilityMode: CompatibilityMode, protected val normalizeAbsolutePaths: Boolean, protected val sourceBaseDirs: Collection<String>) {
|
abstract class IrModuleSerializer<Serializer : IrFileSerializer>(
|
||||||
abstract fun createSerializerForFile(file: IrFile): F
|
protected val diagnosticReporter: IrDiagnosticReporter,
|
||||||
|
protected val messageLogger: IrMessageLogger,
|
||||||
|
protected val compatibilityMode: CompatibilityMode,
|
||||||
|
protected val normalizeAbsolutePaths: Boolean,
|
||||||
|
protected val sourceBaseDirs: Collection<String>,
|
||||||
|
private val shouldCheckSignaturesOnUniqueness: Boolean,
|
||||||
|
) {
|
||||||
|
abstract fun createSerializerForFile(file: IrFile): Serializer
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allows to skip [file] during serialization.
|
* Allows to skip [file] during serialization.
|
||||||
@@ -23,6 +32,8 @@ abstract class IrModuleSerializer<F : IrFileSerializer>(protected val messageLog
|
|||||||
protected open fun backendSpecificFileFilter(file: IrFile): Boolean =
|
protected open fun backendSpecificFileFilter(file: IrFile): Boolean =
|
||||||
true
|
true
|
||||||
|
|
||||||
|
protected abstract val globalDeclarationTable: GlobalDeclarationTable
|
||||||
|
|
||||||
private fun serializeIrFile(file: IrFile): SerializedIrFile {
|
private fun serializeIrFile(file: IrFile): SerializedIrFile {
|
||||||
val fileSerializer = createSerializerForFile(file)
|
val fileSerializer = createSerializerForFile(file)
|
||||||
return fileSerializer.serializeIrFile(file)
|
return fileSerializer.serializeIrFile(file)
|
||||||
@@ -33,6 +44,9 @@ abstract class IrModuleSerializer<F : IrFileSerializer>(protected val messageLog
|
|||||||
.filter { it.packageFragmentDescriptor !is FunctionInterfacePackageFragment }
|
.filter { it.packageFragmentDescriptor !is FunctionInterfacePackageFragment }
|
||||||
.filter(this::backendSpecificFileFilter)
|
.filter(this::backendSpecificFileFilter)
|
||||||
.map(this::serializeIrFile)
|
.map(this::serializeIrFile)
|
||||||
|
if (shouldCheckSignaturesOnUniqueness) {
|
||||||
|
globalDeclarationTable.clashDetector.reportErrorsTo(diagnosticReporter)
|
||||||
|
}
|
||||||
return SerializedIrModule(serializedFiles)
|
return SerializedIrModule(serializedFiles)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -631,7 +631,7 @@ fun serializeModuleIntoKlib(
|
|||||||
val compatibilityMode = CompatibilityMode(abiVersion)
|
val compatibilityMode = CompatibilityMode(abiVersion)
|
||||||
val sourceBaseDirs = configuration[CommonConfigurationKeys.KLIB_RELATIVE_PATH_BASES] ?: emptyList()
|
val sourceBaseDirs = configuration[CommonConfigurationKeys.KLIB_RELATIVE_PATH_BASES] ?: emptyList()
|
||||||
val absolutePathNormalization = configuration[CommonConfigurationKeys.KLIB_NORMALIZE_ABSOLUTE_PATH] ?: false
|
val absolutePathNormalization = configuration[CommonConfigurationKeys.KLIB_NORMALIZE_ABSOLUTE_PATH] ?: false
|
||||||
val signatureClashChecks = configuration[CommonConfigurationKeys.PRODUCE_KLIB_SIGNATURES_CLASH_CHECKS] ?: false
|
val signatureClashChecks = configuration[CommonConfigurationKeys.PRODUCE_KLIB_SIGNATURES_CLASH_CHECKS] ?: true
|
||||||
|
|
||||||
val moduleExportedNames = moduleFragment.collectExportedNames()
|
val moduleExportedNames = moduleFragment.collectExportedNames()
|
||||||
|
|
||||||
@@ -643,6 +643,7 @@ fun serializeModuleIntoKlib(
|
|||||||
|
|
||||||
val serializedIr =
|
val serializedIr =
|
||||||
JsIrModuleSerializer(
|
JsIrModuleSerializer(
|
||||||
|
irDiagnosticReporter,
|
||||||
messageLogger,
|
messageLogger,
|
||||||
moduleFragment.irBuiltins,
|
moduleFragment.irBuiltins,
|
||||||
compatibilityMode,
|
compatibilityMode,
|
||||||
@@ -650,8 +651,7 @@ fun serializeModuleIntoKlib(
|
|||||||
sourceBaseDirs = sourceBaseDirs,
|
sourceBaseDirs = sourceBaseDirs,
|
||||||
configuration.languageVersionSettings,
|
configuration.languageVersionSettings,
|
||||||
signatureClashChecks,
|
signatureClashChecks,
|
||||||
jsIrFileMetadataFactory = { JsIrFileMetadata(moduleExportedNames[it]?.values?.toSmartList() ?: emptyList()) }
|
) { JsIrFileMetadata(moduleExportedNames[it]?.values?.toSmartList() ?: emptyList()) }.serializedIrModule(moduleFragment)
|
||||||
).serializedIrModule(moduleFragment)
|
|
||||||
|
|
||||||
val moduleDescriptor = moduleFragment.descriptor
|
val moduleDescriptor = moduleFragment.descriptor
|
||||||
|
|
||||||
|
|||||||
+1
-28
@@ -6,36 +6,9 @@
|
|||||||
package org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir
|
package org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir
|
||||||
|
|
||||||
import org.jetbrains.kotlin.backend.common.serialization.GlobalDeclarationTable
|
import org.jetbrains.kotlin.backend.common.serialization.GlobalDeclarationTable
|
||||||
import org.jetbrains.kotlin.backend.common.serialization.IdSignatureClashTracker
|
|
||||||
import org.jetbrains.kotlin.ir.IrBuiltIns
|
import org.jetbrains.kotlin.ir.IrBuiltIns
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrTypeParameter
|
|
||||||
import org.jetbrains.kotlin.ir.util.IdSignature
|
|
||||||
import org.jetbrains.kotlin.ir.util.render
|
|
||||||
|
|
||||||
class JsUniqIdClashTracker() : IdSignatureClashTracker {
|
class JsGlobalDeclarationTable(builtIns: IrBuiltIns) : GlobalDeclarationTable(JsManglerIr) {
|
||||||
private val committedIdSignatures = mutableMapOf<IdSignature, IrDeclaration>()
|
|
||||||
|
|
||||||
override fun commit(declaration: IrDeclaration, signature: IdSignature) {
|
|
||||||
if (!signature.isPubliclyVisible) return // don't track local ids
|
|
||||||
|
|
||||||
if (signature in committedIdSignatures) {
|
|
||||||
val clashedDeclaration = committedIdSignatures[signature]!!
|
|
||||||
val parent = declaration.parent
|
|
||||||
val clashedParent = clashedDeclaration.parent
|
|
||||||
if (declaration !is IrTypeParameter || parent !is IrSimpleFunction || clashedParent !is IrSimpleFunction || parent.correspondingPropertySymbol !== clashedParent.correspondingPropertySymbol) {
|
|
||||||
// TODO: handle clashes properly
|
|
||||||
error("IdSignature clash: $signature; Existed declaration ${clashedDeclaration.render()} clashed with new ${declaration.render()}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
committedIdSignatures[signature] = declaration
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class JsGlobalDeclarationTable(builtIns: IrBuiltIns, tracker: IdSignatureClashTracker = JsUniqIdClashTracker()) :
|
|
||||||
GlobalDeclarationTable(JsManglerIr, tracker) {
|
|
||||||
init {
|
init {
|
||||||
loadKnownBuiltins(builtIns)
|
loadKnownBuiltins(builtIns)
|
||||||
}
|
}
|
||||||
|
|||||||
+13
-7
@@ -7,14 +7,16 @@ package org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.backend.common.serialization.CompatibilityMode
|
import org.jetbrains.kotlin.backend.common.serialization.CompatibilityMode
|
||||||
import org.jetbrains.kotlin.backend.common.serialization.DeclarationTable
|
import org.jetbrains.kotlin.backend.common.serialization.DeclarationTable
|
||||||
import org.jetbrains.kotlin.backend.common.serialization.IdSignatureClashTracker
|
|
||||||
import org.jetbrains.kotlin.backend.common.serialization.IrModuleSerializer
|
import org.jetbrains.kotlin.backend.common.serialization.IrModuleSerializer
|
||||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||||
|
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
|
||||||
import org.jetbrains.kotlin.ir.IrBuiltIns
|
import org.jetbrains.kotlin.ir.IrBuiltIns
|
||||||
|
import org.jetbrains.kotlin.ir.IrDiagnosticReporter
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||||
import org.jetbrains.kotlin.ir.util.IrMessageLogger
|
import org.jetbrains.kotlin.ir.util.IrMessageLogger
|
||||||
|
|
||||||
class JsIrModuleSerializer(
|
class JsIrModuleSerializer(
|
||||||
|
diagnosticReporter: IrDiagnosticReporter,
|
||||||
messageLogger: IrMessageLogger,
|
messageLogger: IrMessageLogger,
|
||||||
irBuiltIns: IrBuiltIns,
|
irBuiltIns: IrBuiltIns,
|
||||||
compatibilityMode: CompatibilityMode,
|
compatibilityMode: CompatibilityMode,
|
||||||
@@ -22,13 +24,17 @@ class JsIrModuleSerializer(
|
|||||||
sourceBaseDirs: Collection<String>,
|
sourceBaseDirs: Collection<String>,
|
||||||
private val languageVersionSettings: LanguageVersionSettings,
|
private val languageVersionSettings: LanguageVersionSettings,
|
||||||
shouldCheckSignaturesOnUniqueness: Boolean = true,
|
shouldCheckSignaturesOnUniqueness: Boolean = true,
|
||||||
private val jsIrFileMetadataFactory: JsIrFileMetadataFactory = JsIrFileEmptyMetadataFactory
|
private val jsIrFileMetadataFactory: JsIrFileMetadataFactory = JsIrFileEmptyMetadataFactory,
|
||||||
) : IrModuleSerializer<JsIrFileSerializer>(messageLogger, compatibilityMode, normalizeAbsolutePaths, sourceBaseDirs) {
|
) : IrModuleSerializer<JsIrFileSerializer>(
|
||||||
|
diagnosticReporter,
|
||||||
|
messageLogger,
|
||||||
|
compatibilityMode,
|
||||||
|
normalizeAbsolutePaths,
|
||||||
|
sourceBaseDirs,
|
||||||
|
shouldCheckSignaturesOnUniqueness,
|
||||||
|
) {
|
||||||
|
|
||||||
private val globalDeclarationTable = JsGlobalDeclarationTable(
|
override val globalDeclarationTable = JsGlobalDeclarationTable(irBuiltIns)
|
||||||
irBuiltIns,
|
|
||||||
if (shouldCheckSignaturesOnUniqueness) JsUniqIdClashTracker() else IdSignatureClashTracker.DEFAULT_TRACKER
|
|
||||||
)
|
|
||||||
|
|
||||||
override fun createSerializerForFile(file: IrFile): JsIrFileSerializer =
|
override fun createSerializerForFile(file: IrFile): JsIrFileSerializer =
|
||||||
JsIrFileSerializer(
|
JsIrFileSerializer(
|
||||||
|
|||||||
+13
-2
@@ -8,12 +8,15 @@ package org.jetbrains.kotlin.backend.konan.serialization
|
|||||||
import org.jetbrains.kotlin.backend.common.serialization.CompatibilityMode
|
import org.jetbrains.kotlin.backend.common.serialization.CompatibilityMode
|
||||||
import org.jetbrains.kotlin.backend.common.serialization.IrModuleSerializer
|
import org.jetbrains.kotlin.backend.common.serialization.IrModuleSerializer
|
||||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||||
|
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
|
||||||
import org.jetbrains.kotlin.ir.IrBuiltIns
|
import org.jetbrains.kotlin.ir.IrBuiltIns
|
||||||
|
import org.jetbrains.kotlin.ir.IrDiagnosticReporter
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||||
import org.jetbrains.kotlin.ir.util.IrMessageLogger
|
import org.jetbrains.kotlin.ir.util.IrMessageLogger
|
||||||
import org.jetbrains.kotlin.name.NativeStandardInteropNames
|
import org.jetbrains.kotlin.name.NativeStandardInteropNames
|
||||||
|
|
||||||
class KonanIrModuleSerializer(
|
class KonanIrModuleSerializer(
|
||||||
|
diagnosticReporter: IrDiagnosticReporter,
|
||||||
messageLogger: IrMessageLogger,
|
messageLogger: IrMessageLogger,
|
||||||
irBuiltIns: IrBuiltIns,
|
irBuiltIns: IrBuiltIns,
|
||||||
compatibilityMode: CompatibilityMode,
|
compatibilityMode: CompatibilityMode,
|
||||||
@@ -22,9 +25,17 @@ class KonanIrModuleSerializer(
|
|||||||
private val languageVersionSettings: LanguageVersionSettings,
|
private val languageVersionSettings: LanguageVersionSettings,
|
||||||
private val bodiesOnlyForInlines: Boolean = false,
|
private val bodiesOnlyForInlines: Boolean = false,
|
||||||
private val skipPrivateApi: Boolean = false,
|
private val skipPrivateApi: Boolean = false,
|
||||||
) : IrModuleSerializer<KonanIrFileSerializer>(messageLogger, compatibilityMode, normalizeAbsolutePaths, sourceBaseDirs) {
|
shouldCheckSignaturesOnUniqueness: Boolean = true,
|
||||||
|
) : IrModuleSerializer<KonanIrFileSerializer>(
|
||||||
|
diagnosticReporter,
|
||||||
|
messageLogger,
|
||||||
|
compatibilityMode,
|
||||||
|
normalizeAbsolutePaths,
|
||||||
|
sourceBaseDirs,
|
||||||
|
shouldCheckSignaturesOnUniqueness,
|
||||||
|
) {
|
||||||
|
|
||||||
private val globalDeclarationTable = KonanGlobalDeclarationTable(irBuiltIns)
|
override val globalDeclarationTable = KonanGlobalDeclarationTable(irBuiltIns)
|
||||||
|
|
||||||
// We skip files with IR for C structs and enums because they should be
|
// We skip files with IR for C structs and enums because they should be
|
||||||
// generated anew.
|
// generated anew.
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
/foo.kt:7:1: error: Platform declaration clash: The following declarations have the same KLIB signature (com.example.klib.serialization.diagnostics/foo|foo(){}[0]):
|
||||||
|
fun foo(): kotlin.Long defined in com.example.klib.serialization.diagnostics
|
||||||
|
fun foo(): kotlin.String defined in com.example.klib.serialization.diagnostics
|
||||||
|
fun foo(): kotlin.Int defined in com.example.klib.serialization.diagnostics
|
||||||
|
|
||||||
|
/main.kt:13:1: error: Platform declaration clash: The following declarations have the same KLIB signature (com.example.klib.serialization.diagnostics/foo|foo(){}[0]):
|
||||||
|
fun foo(): kotlin.Long defined in com.example.klib.serialization.diagnostics
|
||||||
|
fun foo(): kotlin.String defined in com.example.klib.serialization.diagnostics
|
||||||
|
fun foo(): kotlin.Int defined in com.example.klib.serialization.diagnostics
|
||||||
|
|
||||||
|
/main.kt:16:1: error: Platform declaration clash: The following declarations have the same KLIB signature (com.example.klib.serialization.diagnostics/foo|foo(){}[0]):
|
||||||
|
fun foo(): kotlin.Long defined in com.example.klib.serialization.diagnostics
|
||||||
|
fun foo(): kotlin.String defined in com.example.klib.serialization.diagnostics
|
||||||
|
fun foo(): kotlin.Int defined in com.example.klib.serialization.diagnostics
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
// FIR_IDENTICAL
|
||||||
|
// RENDER_ALL_DIAGNOSTICS_FULL_TEXT
|
||||||
|
|
||||||
|
// FILE: foo.kt
|
||||||
|
package com.example.klib.serialization.diagnostics
|
||||||
|
|
||||||
|
<!CONFLICTING_KLIB_SIGNATURES_ERROR!>@Deprecated("", level = DeprecationLevel.HIDDEN)
|
||||||
|
fun foo(): Long = 0L<!>
|
||||||
|
|
||||||
|
// FILE: main.kt
|
||||||
|
package com.example.klib.serialization.diagnostics
|
||||||
|
|
||||||
|
<!CONFLICTING_KLIB_SIGNATURES_ERROR!>@Deprecated("", level = DeprecationLevel.HIDDEN)
|
||||||
|
fun foo(): String = ""<!>
|
||||||
|
|
||||||
|
<!CONFLICTING_KLIB_SIGNATURES_ERROR!>fun foo(): Int = 0<!>
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
foo()
|
||||||
|
}
|
||||||
+19
-7
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.klib
|
|||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
import junit.framework.TestCase
|
import junit.framework.TestCase
|
||||||
|
import org.jetbrains.kotlin.KtDiagnosticReporterWithImplicitIrBasedContext
|
||||||
import org.jetbrains.kotlin.backend.common.CommonKLibResolver
|
import org.jetbrains.kotlin.backend.common.CommonKLibResolver
|
||||||
import org.jetbrains.kotlin.ir.util.isExpect
|
import org.jetbrains.kotlin.ir.util.isExpect
|
||||||
import org.jetbrains.kotlin.backend.common.linkage.issues.checkNoUnboundSymbols
|
import org.jetbrains.kotlin.backend.common.linkage.issues.checkNoUnboundSymbols
|
||||||
@@ -24,6 +25,8 @@ import org.jetbrains.kotlin.config.*
|
|||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
|
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
|
||||||
|
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
|
||||||
|
import org.jetbrains.kotlin.diagnostics.DiagnosticReporterFactory
|
||||||
import org.jetbrains.kotlin.incremental.components.LookupTracker
|
import org.jetbrains.kotlin.incremental.components.LookupTracker
|
||||||
import org.jetbrains.kotlin.ir.AbstractIrGeneratorTestCase
|
import org.jetbrains.kotlin.ir.AbstractIrGeneratorTestCase
|
||||||
import org.jetbrains.kotlin.ir.IrElement
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
@@ -139,16 +142,25 @@ abstract class AbstractKlibIrTextTestCase : CodegenTestCase() {
|
|||||||
return serializePackageFragment(moduleDescriptor, memberScope, ktFile.packageFqName)
|
return serializePackageFragment(moduleDescriptor, memberScope, ktFile.packageFqName)
|
||||||
}
|
}
|
||||||
|
|
||||||
protected fun serializeModule(irModuleFragment: IrModuleFragment, bindingContext: BindingContext, stdlib: KotlinLibrary, containsErrorCode: Boolean): String {
|
private fun serializeModule(
|
||||||
|
irModuleFragment: IrModuleFragment,
|
||||||
|
bindingContext: BindingContext,
|
||||||
|
stdlib: KotlinLibrary,
|
||||||
|
containsErrorCode: Boolean,
|
||||||
|
): String {
|
||||||
val ktFiles = myFiles.psiFiles
|
val ktFiles = myFiles.psiFiles
|
||||||
val serializedIr = JsIrModuleSerializer(
|
val serializedIr = JsIrModuleSerializer(
|
||||||
IrMessageLogger.None,
|
KtDiagnosticReporterWithImplicitIrBasedContext(
|
||||||
irModuleFragment.irBuiltins,
|
DiagnosticReporterFactory.createPendingReporter(),
|
||||||
CompatibilityMode.CURRENT,
|
|
||||||
false,
|
|
||||||
emptyList(),
|
|
||||||
myEnvironment.configuration.languageVersionSettings,
|
myEnvironment.configuration.languageVersionSettings,
|
||||||
).serializedIrModule(irModuleFragment)
|
),
|
||||||
|
IrMessageLogger.None,
|
||||||
|
irModuleFragment.irBuiltins,
|
||||||
|
CompatibilityMode.CURRENT,
|
||||||
|
false,
|
||||||
|
emptyList(),
|
||||||
|
myEnvironment.configuration.languageVersionSettings,
|
||||||
|
).serializedIrModule(irModuleFragment)
|
||||||
|
|
||||||
val moduleDescriptor = irModuleFragment.descriptor
|
val moduleDescriptor = irModuleFragment.descriptor
|
||||||
val metadataSerializer = klibMetadataIncrementalSerializer(myEnvironment.configuration, myEnvironment.project, containsErrorCode)
|
val metadataSerializer = klibMetadataIncrementalSerializer(myEnvironment.configuration, myEnvironment.project, containsErrorCode)
|
||||||
|
|||||||
@@ -103,6 +103,11 @@ abstract class DescriptorRenderer {
|
|||||||
return DescriptorRendererImpl(options)
|
return DescriptorRendererImpl(options)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@JvmField
|
||||||
|
val WITHOUT_MODIFIERS: DescriptorRenderer = withOptions {
|
||||||
|
modifiers = emptySet()
|
||||||
|
}
|
||||||
|
|
||||||
@JvmField
|
@JvmField
|
||||||
val COMPACT_WITH_MODIFIERS: DescriptorRenderer = withOptions {
|
val COMPACT_WITH_MODIFIERS: DescriptorRenderer = withOptions {
|
||||||
withDefinedIn = false
|
withDefinedIn = false
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import com.intellij.openapi.vfs.StandardFileSystems
|
|||||||
import com.intellij.openapi.vfs.VfsUtilCore
|
import com.intellij.openapi.vfs.VfsUtilCore
|
||||||
import com.intellij.openapi.vfs.VirtualFileManager
|
import com.intellij.openapi.vfs.VirtualFileManager
|
||||||
import com.intellij.psi.PsiManager
|
import com.intellij.psi.PsiManager
|
||||||
|
import org.jetbrains.kotlin.KtDiagnosticReporterWithImplicitIrBasedContext
|
||||||
import org.jetbrains.kotlin.KtPsiSourceFile
|
import org.jetbrains.kotlin.KtPsiSourceFile
|
||||||
import org.jetbrains.kotlin.analyzer.AnalysisResult
|
import org.jetbrains.kotlin.analyzer.AnalysisResult
|
||||||
import org.jetbrains.kotlin.backend.common.linkage.issues.checkNoUnboundSymbols
|
import org.jetbrains.kotlin.backend.common.linkage.issues.checkNoUnboundSymbols
|
||||||
@@ -37,7 +38,6 @@ import org.jetbrains.kotlin.ir.backend.js.*
|
|||||||
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsIrLinker
|
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsIrLinker
|
||||||
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsIrModuleSerializer
|
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsIrModuleSerializer
|
||||||
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsManglerDesc
|
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsManglerDesc
|
||||||
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.collectExportedNames
|
|
||||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.IrModuleToJsTransformer
|
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.IrModuleToJsTransformer
|
||||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.TranslationMode
|
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.TranslationMode
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
||||||
@@ -529,7 +529,11 @@ class GenerateIrRuntime {
|
|||||||
|
|
||||||
|
|
||||||
private fun doSerializeIrModule(module: IrModuleFragment): SerializedIrModule {
|
private fun doSerializeIrModule(module: IrModuleFragment): SerializedIrModule {
|
||||||
val serializedIr = JsIrModuleSerializer(
|
return JsIrModuleSerializer(
|
||||||
|
KtDiagnosticReporterWithImplicitIrBasedContext(
|
||||||
|
DiagnosticReporterFactory.createPendingReporter(),
|
||||||
|
configuration.languageVersionSettings,
|
||||||
|
),
|
||||||
IrMessageLogger.None,
|
IrMessageLogger.None,
|
||||||
module.irBuiltins,
|
module.irBuiltins,
|
||||||
CompatibilityMode.CURRENT,
|
CompatibilityMode.CURRENT,
|
||||||
@@ -537,7 +541,6 @@ class GenerateIrRuntime {
|
|||||||
emptyList(),
|
emptyList(),
|
||||||
configuration.languageVersionSettings,
|
configuration.languageVersionSettings,
|
||||||
).serializedIrModule(module)
|
).serializedIrModule(module)
|
||||||
return serializedIr
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun doWriteIrModuleToStorage(serializedIrModule: SerializedIrModule, writer: KotlinLibraryOnlyIrWriter) {
|
private fun doWriteIrModuleToStorage(serializedIrModule: SerializedIrModule, writer: KotlinLibraryOnlyIrWriter) {
|
||||||
|
|||||||
@@ -211,6 +211,15 @@ fun main(args: Array<String>) {
|
|||||||
model("debug/localVariables")
|
model("debug/localVariables")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
testClass<AbstractFirPsiJsDiagnosticWithBackendTest>(suiteTestClassName = "FirPsiJsKlibDiagnosticsTestGenerated") {
|
||||||
|
model(
|
||||||
|
relativeRootPath = "diagnostics/klibSerializationTests",
|
||||||
|
pattern = "^([^_](.+))\\.kt$",
|
||||||
|
excludedPattern = excludedFirTestdataPattern,
|
||||||
|
targetBackend = TargetBackend.JS_IR
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
testClass<AbstractFirPsiJsDiagnosticTest>(suiteTestClassName = "FirPsiJsOldFrontendDiagnosticsTestGenerated") {
|
testClass<AbstractFirPsiJsDiagnosticTest>(suiteTestClassName = "FirPsiJsOldFrontendDiagnosticsTestGenerated") {
|
||||||
model(
|
model(
|
||||||
relativeRootPath = "diagnostics/testsWithJsStdLib",
|
relativeRootPath = "diagnostics/testsWithJsStdLib",
|
||||||
|
|||||||
+3
-1
@@ -164,5 +164,7 @@ fun <
|
|||||||
irHandlersStep()
|
irHandlersStep()
|
||||||
|
|
||||||
facadeStep(backendFacade)
|
facadeStep(backendFacade)
|
||||||
klibArtifactsHandlersStep()
|
klibArtifactsHandlersStep {
|
||||||
|
useHandlers(::JsBackendDiagnosticsHandler)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Generated
+33
@@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2024 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.js.test.fir;
|
||||||
|
|
||||||
|
import com.intellij.testFramework.TestDataPath;
|
||||||
|
import org.jetbrains.kotlin.test.util.KtTestUtil;
|
||||||
|
import org.jetbrains.kotlin.test.TargetBackend;
|
||||||
|
import org.jetbrains.kotlin.test.TestMetadata;
|
||||||
|
import org.junit.jupiter.api.Nested;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.GenerateJsTestsKt}. DO NOT MODIFY MANUALLY */
|
||||||
|
@SuppressWarnings("all")
|
||||||
|
@TestMetadata("compiler/testData/diagnostics/klibSerializationTests")
|
||||||
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
public class FirPsiJsKlibDiagnosticsTestGenerated extends AbstractFirPsiJsDiagnosticWithBackendTest {
|
||||||
|
@Test
|
||||||
|
public void testAllFilesPresentInKlibSerializationTests() throws Exception {
|
||||||
|
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/klibSerializationTests"), Pattern.compile("^([^_](.+))\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), TargetBackend.JS_IR, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("signatureClash.kt")
|
||||||
|
public void testSignatureClash() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/klibSerializationTests/signatureClash.kt");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -108,6 +108,7 @@ class K2Native : CLICompiler<K2NativeCompilerArguments>() {
|
|||||||
|
|
||||||
configuration.put(CommonConfigurationKeys.KLIB_NORMALIZE_ABSOLUTE_PATH, arguments.normalizeAbsolutePath)
|
configuration.put(CommonConfigurationKeys.KLIB_NORMALIZE_ABSOLUTE_PATH, arguments.normalizeAbsolutePath)
|
||||||
configuration.put(CLIConfigurationKeys.RENDER_DIAGNOSTIC_INTERNAL_NAME, arguments.renderInternalDiagnosticNames)
|
configuration.put(CLIConfigurationKeys.RENDER_DIAGNOSTIC_INTERNAL_NAME, arguments.renderInternalDiagnosticNames)
|
||||||
|
configuration.put(CommonConfigurationKeys.PRODUCE_KLIB_SIGNATURES_CLASH_CHECKS, arguments.enableSignatureClashChecks)
|
||||||
|
|
||||||
return environment
|
return environment
|
||||||
}
|
}
|
||||||
|
|||||||
+19
-2
@@ -1,5 +1,6 @@
|
|||||||
package org.jetbrains.kotlin.backend.konan
|
package org.jetbrains.kotlin.backend.konan
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.KtDiagnosticReporterWithImplicitIrBasedContext
|
||||||
import org.jetbrains.kotlin.KtSourceFile
|
import org.jetbrains.kotlin.KtSourceFile
|
||||||
import org.jetbrains.kotlin.backend.common.serialization.CompatibilityMode
|
import org.jetbrains.kotlin.backend.common.serialization.CompatibilityMode
|
||||||
import org.jetbrains.kotlin.backend.common.serialization.metadata.makeSerializedKlibMetadata
|
import org.jetbrains.kotlin.backend.common.serialization.metadata.makeSerializedKlibMetadata
|
||||||
@@ -10,9 +11,13 @@ import org.jetbrains.kotlin.backend.konan.driver.phases.FirOutput
|
|||||||
import org.jetbrains.kotlin.backend.konan.driver.phases.FirSerializerInput
|
import org.jetbrains.kotlin.backend.konan.driver.phases.FirSerializerInput
|
||||||
import org.jetbrains.kotlin.backend.konan.driver.phases.SerializerOutput
|
import org.jetbrains.kotlin.backend.konan.driver.phases.SerializerOutput
|
||||||
import org.jetbrains.kotlin.backend.konan.serialization.KonanIrModuleSerializer
|
import org.jetbrains.kotlin.backend.konan.serialization.KonanIrModuleSerializer
|
||||||
|
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
|
||||||
|
import org.jetbrains.kotlin.cli.common.fir.reportToMessageCollector
|
||||||
import org.jetbrains.kotlin.config.CommonConfigurationKeys
|
import org.jetbrains.kotlin.config.CommonConfigurationKeys
|
||||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||||
import org.jetbrains.kotlin.config.languageVersionSettings
|
import org.jetbrains.kotlin.config.languageVersionSettings
|
||||||
|
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
|
||||||
|
import org.jetbrains.kotlin.diagnostics.DiagnosticReporterFactory
|
||||||
import org.jetbrains.kotlin.fir.FirSession
|
import org.jetbrains.kotlin.fir.FirSession
|
||||||
import org.jetbrains.kotlin.fir.backend.ConstValueProviderImpl
|
import org.jetbrains.kotlin.fir.backend.ConstValueProviderImpl
|
||||||
import org.jetbrains.kotlin.fir.backend.extractFirDeclarations
|
import org.jetbrains.kotlin.fir.backend.extractFirDeclarations
|
||||||
@@ -65,8 +70,10 @@ internal fun PhaseContext.firSerializerBase(
|
|||||||
}
|
}
|
||||||
|
|
||||||
val actualizedFirDeclarations = fir2IrInput?.irActualizedResult?.actualizedExpectDeclarations?.extractFirDeclarations()
|
val actualizedFirDeclarations = fir2IrInput?.irActualizedResult?.actualizedExpectDeclarations?.extractFirDeclarations()
|
||||||
return serializeNativeModule(
|
val diagnosticReporter = DiagnosticReporterFactory.createPendingReporter()
|
||||||
|
val serializerOutput = serializeNativeModule(
|
||||||
configuration = configuration,
|
configuration = configuration,
|
||||||
|
diagnosticReporter = diagnosticReporter,
|
||||||
messageLogger = configuration.get(IrMessageLogger.IR_MESSAGE_LOGGER) ?: IrMessageLogger.None,
|
messageLogger = configuration.get(IrMessageLogger.IR_MESSAGE_LOGGER) ?: IrMessageLogger.None,
|
||||||
sourceFiles,
|
sourceFiles,
|
||||||
usedResolvedLibraries?.map { it.library as KonanLibrary },
|
usedResolvedLibraries?.map { it.library as KonanLibrary },
|
||||||
@@ -95,6 +102,12 @@ internal fun PhaseContext.firSerializerBase(
|
|||||||
produceHeaderKlib,
|
produceHeaderKlib,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
val renderDiagnosticNames = configuration.getBoolean(CLIConfigurationKeys.RENDER_DIAGNOSTIC_INTERNAL_NAME)
|
||||||
|
diagnosticReporter.reportToMessageCollector(messageCollector, renderDiagnosticNames)
|
||||||
|
if (diagnosticReporter.hasErrors) {
|
||||||
|
throw KonanCompilationException("Compilation failed: there were errors during module serialization")
|
||||||
|
}
|
||||||
|
return serializerOutput
|
||||||
}
|
}
|
||||||
|
|
||||||
class KotlinFileSerializedData(
|
class KotlinFileSerializedData(
|
||||||
@@ -109,6 +122,7 @@ class KotlinFileSerializedData(
|
|||||||
|
|
||||||
internal fun PhaseContext.serializeNativeModule(
|
internal fun PhaseContext.serializeNativeModule(
|
||||||
configuration: CompilerConfiguration,
|
configuration: CompilerConfiguration,
|
||||||
|
diagnosticReporter: DiagnosticReporter,
|
||||||
messageLogger: IrMessageLogger,
|
messageLogger: IrMessageLogger,
|
||||||
files: List<KtSourceFile>,
|
files: List<KtSourceFile>,
|
||||||
dependencies: List<KonanLibrary>?,
|
dependencies: List<KonanLibrary>?,
|
||||||
@@ -125,9 +139,11 @@ internal fun PhaseContext.serializeNativeModule(
|
|||||||
|
|
||||||
val sourceBaseDirs = configuration[CommonConfigurationKeys.KLIB_RELATIVE_PATH_BASES] ?: emptyList()
|
val sourceBaseDirs = configuration[CommonConfigurationKeys.KLIB_RELATIVE_PATH_BASES] ?: emptyList()
|
||||||
val absolutePathNormalization = configuration[CommonConfigurationKeys.KLIB_NORMALIZE_ABSOLUTE_PATH] ?: false
|
val absolutePathNormalization = configuration[CommonConfigurationKeys.KLIB_NORMALIZE_ABSOLUTE_PATH] ?: false
|
||||||
|
val signatureClashChecks = configuration[CommonConfigurationKeys.PRODUCE_KLIB_SIGNATURES_CLASH_CHECKS] ?: true
|
||||||
|
|
||||||
val serializedIr = moduleFragment?.let {
|
val serializedIr = moduleFragment?.let {
|
||||||
KonanIrModuleSerializer(
|
KonanIrModuleSerializer(
|
||||||
|
KtDiagnosticReporterWithImplicitIrBasedContext(diagnosticReporter, configuration.languageVersionSettings),
|
||||||
messageLogger,
|
messageLogger,
|
||||||
moduleFragment.irBuiltins,
|
moduleFragment.irBuiltins,
|
||||||
CompatibilityMode.CURRENT,
|
CompatibilityMode.CURRENT,
|
||||||
@@ -135,7 +151,8 @@ internal fun PhaseContext.serializeNativeModule(
|
|||||||
sourceBaseDirs = sourceBaseDirs,
|
sourceBaseDirs = sourceBaseDirs,
|
||||||
languageVersionSettings = configuration.languageVersionSettings,
|
languageVersionSettings = configuration.languageVersionSettings,
|
||||||
bodiesOnlyForInlines = bodiesOnlyForInlines,
|
bodiesOnlyForInlines = bodiesOnlyForInlines,
|
||||||
skipPrivateApi = skipPrivateApi
|
skipPrivateApi = skipPrivateApi,
|
||||||
|
shouldCheckSignaturesOnUniqueness = signatureClashChecks,
|
||||||
).serializedIrModule(moduleFragment)
|
).serializedIrModule(moduleFragment)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+8
-1
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.backend.konan.driver.phases
|
package org.jetbrains.kotlin.backend.konan.driver.phases
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.KtDiagnosticReporterWithImplicitIrBasedContext
|
||||||
import org.jetbrains.kotlin.backend.common.phaser.createSimpleNamedCompilerPhase
|
import org.jetbrains.kotlin.backend.common.phaser.createSimpleNamedCompilerPhase
|
||||||
import org.jetbrains.kotlin.backend.common.serialization.CompatibilityMode
|
import org.jetbrains.kotlin.backend.common.serialization.CompatibilityMode
|
||||||
import org.jetbrains.kotlin.backend.common.serialization.metadata.KlibMetadataMonolithicSerializer
|
import org.jetbrains.kotlin.backend.common.serialization.metadata.KlibMetadataMonolithicSerializer
|
||||||
@@ -14,6 +15,7 @@ import org.jetbrains.kotlin.backend.konan.serialization.KonanIrModuleSerializer
|
|||||||
import org.jetbrains.kotlin.config.CommonConfigurationKeys
|
import org.jetbrains.kotlin.config.CommonConfigurationKeys
|
||||||
import org.jetbrains.kotlin.config.languageVersionSettings
|
import org.jetbrains.kotlin.config.languageVersionSettings
|
||||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||||
|
import org.jetbrains.kotlin.diagnostics.DiagnosticReporterFactory
|
||||||
import org.jetbrains.kotlin.ir.util.IrMessageLogger
|
import org.jetbrains.kotlin.ir.util.IrMessageLogger
|
||||||
import org.jetbrains.kotlin.konan.library.KonanLibrary
|
import org.jetbrains.kotlin.konan.library.KonanLibrary
|
||||||
import org.jetbrains.kotlin.library.SerializedIrModule
|
import org.jetbrains.kotlin.library.SerializedIrModule
|
||||||
@@ -44,7 +46,12 @@ internal val SerializerPhase = createSimpleNamedCompilerPhase<PhaseContext, Seri
|
|||||||
val serializedIr = input.psiToIrOutput?.let {
|
val serializedIr = input.psiToIrOutput?.let {
|
||||||
val ir = it.irModule
|
val ir = it.irModule
|
||||||
KonanIrModuleSerializer(
|
KonanIrModuleSerializer(
|
||||||
messageLogger, ir.irBuiltins,
|
KtDiagnosticReporterWithImplicitIrBasedContext(
|
||||||
|
DiagnosticReporterFactory.createPendingReporter(),
|
||||||
|
config.languageVersionSettings
|
||||||
|
),
|
||||||
|
messageLogger,
|
||||||
|
ir.irBuiltins,
|
||||||
compatibilityMode = CompatibilityMode.CURRENT,
|
compatibilityMode = CompatibilityMode.CURRENT,
|
||||||
normalizeAbsolutePaths = normalizeAbsolutePaths,
|
normalizeAbsolutePaths = normalizeAbsolutePaths,
|
||||||
sourceBaseDirs = relativePathBase,
|
sourceBaseDirs = relativePathBase,
|
||||||
|
|||||||
+12
@@ -0,0 +1,12 @@
|
|||||||
|
package com.example.klib.serialization.diagnostics
|
||||||
|
|
||||||
|
class A {
|
||||||
|
@Deprecated("", level = DeprecationLevel.HIDDEN)
|
||||||
|
fun foo(): String = ""
|
||||||
|
|
||||||
|
fun foo(): Int = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
println(A().foo())
|
||||||
|
}
|
||||||
+11
@@ -0,0 +1,11 @@
|
|||||||
|
native/native.tests/testData/compilerOutput/SignatureClashDiagnostics/main.kt:4:5: error: platform declaration clash: The following declarations have the same KLIB signature (com.example.klib.serialization.diagnostics/A.foo|foo(){}[0]):
|
||||||
|
fun foo(): kotlin.String defined in com.example.klib.serialization.diagnostics.A
|
||||||
|
fun foo(): kotlin.Int defined in com.example.klib.serialization.diagnostics.A
|
||||||
|
@Deprecated("", level = DeprecationLevel.HIDDEN)
|
||||||
|
^
|
||||||
|
native/native.tests/testData/compilerOutput/SignatureClashDiagnostics/main.kt:7:5: error: platform declaration clash: The following declarations have the same KLIB signature (com.example.klib.serialization.diagnostics/A.foo|foo(){}[0]):
|
||||||
|
fun foo(): kotlin.String defined in com.example.klib.serialization.diagnostics.A
|
||||||
|
fun foo(): kotlin.Int defined in com.example.klib.serialization.diagnostics.A
|
||||||
|
fun foo(): Int = 0
|
||||||
|
^
|
||||||
|
COMPILATION_ERROR
|
||||||
+15
-3
@@ -109,7 +109,7 @@ abstract class CompilerOutputTestBase : AbstractNativeSimpleTest() {
|
|||||||
KotlinTestUtils.assertEqualsToFile(goldenData, compilationResult.toOutput())
|
KotlinTestUtils.assertEqualsToFile(goldenData, compilationResult.toOutput())
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun compileLibrary(
|
internal fun compileLibrary(
|
||||||
settings: Settings,
|
settings: Settings,
|
||||||
source: File,
|
source: File,
|
||||||
freeCompilerArgs: List<String> = emptyList(),
|
freeCompilerArgs: List<String> = emptyList(),
|
||||||
@@ -126,7 +126,7 @@ abstract class CompilerOutputTestBase : AbstractNativeSimpleTest() {
|
|||||||
return compilation.result
|
return compilation.result
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun TestCompilationResult<*>.toOutput(): String {
|
internal fun TestCompilationResult<*>.toOutput(): String {
|
||||||
check(this is TestCompilationResult.ImmediateResult<*>) { this }
|
check(this is TestCompilationResult.ImmediateResult<*>) { this }
|
||||||
val loggedData = this.loggedData
|
val loggedData = this.loggedData
|
||||||
check(loggedData is LoggedData.CompilationToolCall) { loggedData::class }
|
check(loggedData is LoggedData.CompilationToolCall) { loggedData::class }
|
||||||
@@ -152,4 +152,16 @@ class ClassicCompilerOutputTest : CompilerOutputTestBase()
|
|||||||
@Tag("frontend-fir")
|
@Tag("frontend-fir")
|
||||||
@TestDataPath("\$PROJECT_ROOT")
|
@TestDataPath("\$PROJECT_ROOT")
|
||||||
@EnforcedProperty(ClassLevelProperty.COMPILER_OUTPUT_INTERCEPTOR, "NONE")
|
@EnforcedProperty(ClassLevelProperty.COMPILER_OUTPUT_INTERCEPTOR, "NONE")
|
||||||
class FirCompilerOutputTest : CompilerOutputTestBase()
|
class FirCompilerOutputTest : CompilerOutputTestBase() {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testSignatureClashDiagnostics() {
|
||||||
|
// TODO: use the Compiler Core test infrastructure for testing these diagnostics (KT-64393)
|
||||||
|
val rootDir = File("native/native.tests/testData/compilerOutput/SignatureClashDiagnostics")
|
||||||
|
val settings = testRunSettings
|
||||||
|
val compilationResult = compileLibrary(settings, rootDir.resolve("main.kt"))
|
||||||
|
val goldenData = rootDir.resolve("output.txt")
|
||||||
|
|
||||||
|
KotlinTestUtils.assertEqualsToFile(goldenData, compilationResult.toOutput())
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user