K2: report DUPLICATE_CLASS_NAMES error in JVM backend
It was already reported in the K2+PSI mode, but not LT because BuilderFactoryForDuplicateClassNameDiagnostics relied on PSI, and did not do anything if PSI was missing. No tests were added because it fixes the already existing test `compiler/testData/cli/jvm/fileClassClashMultipleFiles` after the project is migrated to 2.0. #KT-59586
This commit is contained in:
committed by
Space Team
parent
84bf411cc3
commit
2823fff63d
+11
-12
@@ -18,34 +18,33 @@ package org.jetbrains.kotlin.codegen.state
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.codegen.ClassBuilderFactory
|
import org.jetbrains.kotlin.codegen.ClassBuilderFactory
|
||||||
import org.jetbrains.kotlin.codegen.ClassNameCollectionClassBuilderFactory
|
import org.jetbrains.kotlin.codegen.ClassNameCollectionClassBuilderFactory
|
||||||
import org.jetbrains.kotlin.diagnostics.DiagnosticSink
|
|
||||||
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
||||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm
|
|
||||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
|
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
|
||||||
import java.util.concurrent.ConcurrentHashMap
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
|
|
||||||
|
|
||||||
class BuilderFactoryForDuplicateClassNameDiagnostics(
|
class BuilderFactoryForDuplicateClassNameDiagnostics(
|
||||||
builderFactory: ClassBuilderFactory,
|
builderFactory: ClassBuilderFactory,
|
||||||
private val diagnostics: DiagnosticSink
|
private val state: GenerationState,
|
||||||
) : ClassNameCollectionClassBuilderFactory(builderFactory) {
|
) : ClassNameCollectionClassBuilderFactory(builderFactory) {
|
||||||
|
|
||||||
private val className = ConcurrentHashMap<String, JvmDeclarationOrigin>()
|
private val className = ConcurrentHashMap<String, JvmDeclarationOrigin>()
|
||||||
|
|
||||||
override fun handleClashingNames(internalName: String, origin: JvmDeclarationOrigin) {
|
override fun handleClashingNames(internalName: String, origin: JvmDeclarationOrigin) {
|
||||||
val another = className.getOrPut(internalName, { origin })
|
val another = className.getOrPut(internalName) { origin }
|
||||||
//workaround for inlined anonymous objects
|
// Allow clashing classes if they are originated from the same source element. For example, this happens during inlining anonymous
|
||||||
if (origin.element != another.element) {
|
// objects. In JVM IR, this also happens for anonymous classes in default arguments of tailrec functions, because default arguments
|
||||||
|
// are deep-copied (see JvmTailrecLowering).
|
||||||
|
if (origin.originalSourceElement != another.originalSourceElement) {
|
||||||
reportError(internalName, origin, another)
|
reportError(internalName, origin, another)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun reportError(internalName: String, vararg another: JvmDeclarationOrigin) {
|
private fun reportError(internalName: String, vararg another: JvmDeclarationOrigin) {
|
||||||
val fromString = another.mapNotNull { it.descriptor }.
|
val duplicateClasses =
|
||||||
joinToString { DescriptorRenderer.ONLY_NAMES_WITH_SHORT_TYPES.render(it) }
|
another.mapNotNull { it.descriptor }.joinToString { DescriptorRenderer.ONLY_NAMES_WITH_SHORT_TYPES.render(it) }
|
||||||
|
|
||||||
another.mapNotNull { it.element }.forEach {
|
for (origin in another) {
|
||||||
diagnostics.report(ErrorsJvm.DUPLICATE_CLASS_NAMES.on(it, internalName, fromString))
|
state.reportDuplicateClassNameError(origin, internalName, duplicateClasses)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -46,6 +46,7 @@ import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics
|
|||||||
import org.jetbrains.kotlin.resolve.diagnostics.OnDemandSuppressCache
|
import org.jetbrains.kotlin.resolve.diagnostics.OnDemandSuppressCache
|
||||||
import org.jetbrains.kotlin.resolve.jvm.JvmClassName
|
import org.jetbrains.kotlin.resolve.jvm.JvmClassName
|
||||||
import org.jetbrains.kotlin.resolve.jvm.JvmCompilerDeserializationConfiguration
|
import org.jetbrains.kotlin.resolve.jvm.JvmCompilerDeserializationConfiguration
|
||||||
|
import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm
|
||||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
|
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
|
||||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKind.*
|
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKind.*
|
||||||
import org.jetbrains.kotlin.serialization.deserialization.DeserializationConfiguration
|
import org.jetbrains.kotlin.serialization.deserialization.DeserializationConfiguration
|
||||||
@@ -291,6 +292,12 @@ class GenerationState private constructor(
|
|||||||
|
|
||||||
var multiFieldValueClassUnboxInfo: (ClassDescriptor) -> MultiFieldValueClassUnboxInfo? = { null }
|
var multiFieldValueClassUnboxInfo: (ClassDescriptor) -> MultiFieldValueClassUnboxInfo? = { null }
|
||||||
|
|
||||||
|
var reportDuplicateClassNameError: (JvmDeclarationOrigin, String, String) -> Unit = { origin, internalName, duplicateClasses ->
|
||||||
|
origin.element?.let {
|
||||||
|
diagnostics.report(ErrorsJvm.DUPLICATE_CLASS_NAMES.on(it, internalName, duplicateClasses))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val typeApproximator: TypeApproximator? =
|
val typeApproximator: TypeApproximator? =
|
||||||
if (languageVersionSettings.supportsFeature(LanguageFeature.NewInference))
|
if (languageVersionSettings.supportsFeature(LanguageFeature.NewInference))
|
||||||
TypeApproximator(module.builtIns, languageVersionSettings)
|
TypeApproximator(module.builtIns, languageVersionSettings)
|
||||||
@@ -308,7 +315,7 @@ class GenerationState private constructor(
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
// In IR backend, we have more precise information about classes and methods we are going to generate,
|
// In IR backend, we have more precise information about classes and methods we are going to generate,
|
||||||
// and report signature conflict errors in JvmSignatureClashTracker.
|
// and report signature conflict errors in JvmSignatureClashDetector.
|
||||||
if (isIrBackend)
|
if (isIrBackend)
|
||||||
it
|
it
|
||||||
else
|
else
|
||||||
@@ -318,7 +325,7 @@ class GenerationState private constructor(
|
|||||||
shouldGenerate = { origin -> !shouldOnlyCollectSignatures(origin) },
|
shouldGenerate = { origin -> !shouldOnlyCollectSignatures(origin) },
|
||||||
).apply { duplicateSignatureFactory = this }
|
).apply { duplicateSignatureFactory = this }
|
||||||
},
|
},
|
||||||
{ BuilderFactoryForDuplicateClassNameDiagnostics(it, diagnostics) },
|
{ BuilderFactoryForDuplicateClassNameDiagnostics(it, this) },
|
||||||
{
|
{
|
||||||
configuration.get(JVMConfigurationKeys.DECLARATIONS_JSON_PATH)
|
configuration.get(JVMConfigurationKeys.DECLARATIONS_JSON_PATH)
|
||||||
?.let { destination -> SignatureDumpingBuilderFactory(it, File(destination)) } ?: it
|
?.let { destination -> SignatureDumpingBuilderFactory(it, File(destination)) } ?: it
|
||||||
|
|||||||
+4
@@ -39,6 +39,8 @@ object JvmBackendErrors {
|
|||||||
|
|
||||||
val NOT_ALL_MULTIFILE_CLASS_PARTS_ARE_JVM_SYNTHETIC by error0<PsiElement>()
|
val NOT_ALL_MULTIFILE_CLASS_PARTS_ARE_JVM_SYNTHETIC by error0<PsiElement>()
|
||||||
|
|
||||||
|
val DUPLICATE_CLASS_NAMES by error2<PsiElement, String, String>()
|
||||||
|
|
||||||
init {
|
init {
|
||||||
RootDiagnosticRendererFactory.registerFactory(KtDefaultJvmErrorMessages)
|
RootDiagnosticRendererFactory.registerFactory(KtDefaultJvmErrorMessages)
|
||||||
}
|
}
|
||||||
@@ -78,5 +80,7 @@ object KtDefaultJvmErrorMessages : BaseDiagnosticRendererFactory() {
|
|||||||
JvmBackendErrors.NOT_ALL_MULTIFILE_CLASS_PARTS_ARE_JVM_SYNTHETIC,
|
JvmBackendErrors.NOT_ALL_MULTIFILE_CLASS_PARTS_ARE_JVM_SYNTHETIC,
|
||||||
"All of multi-file class parts should be annotated with @JvmSynthetic if at least one of them is"
|
"All of multi-file class parts should be annotated with @JvmSynthetic if at least one of them is"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
map.put(JvmBackendErrors.DUPLICATE_CLASS_NAMES, "Duplicate JVM class name ''{0}'' generated from: {1}", STRING, STRING)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+5
@@ -25,6 +25,11 @@ open class JvmDeclarationOrigin(
|
|||||||
val descriptor: DeclarationDescriptor?,
|
val descriptor: DeclarationDescriptor?,
|
||||||
val parametersForJvmOverload: List<KtParameter?>? = null
|
val parametersForJvmOverload: List<KtParameter?>? = null
|
||||||
) {
|
) {
|
||||||
|
// This property is used to get the original element in the sources, from which this declaration was generated.
|
||||||
|
// In the old JVM backend, it is just the PSI element. In JVM IR, it is the original IR element (before any deep copy).
|
||||||
|
open val originalSourceElement: Any?
|
||||||
|
get() = element
|
||||||
|
|
||||||
override fun toString(): String =
|
override fun toString(): String =
|
||||||
if (this == NO_ORIGIN) "NO_ORIGIN" else "origin=$originKind element=${element?.javaClass?.simpleName} descriptor=$descriptor"
|
if (this == NO_ORIGIN) "NO_ORIGIN" else "origin=$originKind element=${element?.javaClass?.simpleName} descriptor=$descriptor"
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import org.jetbrains.kotlin.backend.jvm.MemoizedMultiFieldValueClassReplacements
|
|||||||
import org.jetbrains.kotlin.backend.jvm.MemoizedMultiFieldValueClassReplacements.RemappedParameter.RegularMapping
|
import org.jetbrains.kotlin.backend.jvm.MemoizedMultiFieldValueClassReplacements.RemappedParameter.RegularMapping
|
||||||
import org.jetbrains.kotlin.backend.jvm.caches.BridgeLoweringCache
|
import org.jetbrains.kotlin.backend.jvm.caches.BridgeLoweringCache
|
||||||
import org.jetbrains.kotlin.backend.jvm.caches.CollectionStubComputer
|
import org.jetbrains.kotlin.backend.jvm.caches.CollectionStubComputer
|
||||||
|
import org.jetbrains.kotlin.backend.jvm.extensions.JvmIrDeclarationOrigin
|
||||||
import org.jetbrains.kotlin.backend.jvm.mapping.IrTypeMapper
|
import org.jetbrains.kotlin.backend.jvm.mapping.IrTypeMapper
|
||||||
import org.jetbrains.kotlin.backend.jvm.mapping.MethodSignatureMapper
|
import org.jetbrains.kotlin.backend.jvm.mapping.MethodSignatureMapper
|
||||||
import org.jetbrains.kotlin.codegen.inline.SMAP
|
import org.jetbrains.kotlin.codegen.inline.SMAP
|
||||||
@@ -40,6 +41,7 @@ import org.jetbrains.kotlin.ir.types.defaultType
|
|||||||
import org.jetbrains.kotlin.ir.util.*
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.resolve.jvm.JvmClassName
|
import org.jetbrains.kotlin.resolve.jvm.JvmClassName
|
||||||
|
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmBackendErrors
|
||||||
import org.jetbrains.org.objectweb.asm.Type
|
import org.jetbrains.org.objectweb.asm.Type
|
||||||
import java.util.concurrent.ConcurrentHashMap
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
|
|
||||||
@@ -205,6 +207,13 @@ class JvmBackendContext(
|
|||||||
node.leaves.map { Triple(defaultTypeMapper.mapType(it.type), it.fullMethodName.asString(), it.fullFieldName.asString()) }
|
node.leaves.map { Triple(defaultTypeMapper.mapType(it.type), it.fullMethodName.asString(), it.fullFieldName.asString()) }
|
||||||
GenerationState.MultiFieldValueClassUnboxInfo(leavesInfo)
|
GenerationState.MultiFieldValueClassUnboxInfo(leavesInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
state.reportDuplicateClassNameError = { origin, internalName, duplicateClasses ->
|
||||||
|
val declaration = (origin as JvmIrDeclarationOrigin).declaration
|
||||||
|
if (declaration != null) {
|
||||||
|
ktDiagnosticReporter.at(declaration).report(JvmBackendErrors.DUPLICATE_CLASS_NAMES, internalName, duplicateClasses)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun referenceClass(descriptor: ClassDescriptor): IrClassSymbol =
|
fun referenceClass(descriptor: ClassDescriptor): IrClassSymbol =
|
||||||
|
|||||||
+4
-1
@@ -20,7 +20,10 @@ class JvmIrDeclarationOrigin(
|
|||||||
originKind: JvmDeclarationOriginKind,
|
originKind: JvmDeclarationOriginKind,
|
||||||
element: PsiElement?,
|
element: PsiElement?,
|
||||||
val declaration: IrDeclaration?,
|
val declaration: IrDeclaration?,
|
||||||
) : JvmDeclarationOrigin(originKind, element, declaration?.toIrBasedDescriptor(), null)
|
) : JvmDeclarationOrigin(originKind, element, declaration?.toIrBasedDescriptor(), null) {
|
||||||
|
override val originalSourceElement: Any?
|
||||||
|
get() = (declaration as? IrAttributeContainer)?.attributeOwnerId
|
||||||
|
}
|
||||||
|
|
||||||
val IrDeclaration.descriptorOrigin: JvmIrDeclarationOrigin
|
val IrDeclaration.descriptorOrigin: JvmIrDeclarationOrigin
|
||||||
get() {
|
get() {
|
||||||
|
|||||||
Reference in New Issue
Block a user