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:
Alexander Udalov
2023-07-25 17:41:01 +02:00
committed by Space Team
parent 84bf411cc3
commit 2823fff63d
6 changed files with 43 additions and 16 deletions
@@ -18,34 +18,33 @@ package org.jetbrains.kotlin.codegen.state
import org.jetbrains.kotlin.codegen.ClassBuilderFactory
import org.jetbrains.kotlin.codegen.ClassNameCollectionClassBuilderFactory
import org.jetbrains.kotlin.diagnostics.DiagnosticSink
import org.jetbrains.kotlin.renderer.DescriptorRenderer
import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
import java.util.concurrent.ConcurrentHashMap
class BuilderFactoryForDuplicateClassNameDiagnostics(
builderFactory: ClassBuilderFactory,
private val diagnostics: DiagnosticSink
builderFactory: ClassBuilderFactory,
private val state: GenerationState,
) : ClassNameCollectionClassBuilderFactory(builderFactory) {
private val className = ConcurrentHashMap<String, JvmDeclarationOrigin>()
override fun handleClashingNames(internalName: String, origin: JvmDeclarationOrigin) {
val another = className.getOrPut(internalName, { origin })
//workaround for inlined anonymous objects
if (origin.element != another.element) {
val another = className.getOrPut(internalName) { origin }
// Allow clashing classes if they are originated from the same source element. For example, this happens during inlining anonymous
// 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)
}
}
private fun reportError(internalName: String, vararg another: JvmDeclarationOrigin) {
val fromString = another.mapNotNull { it.descriptor }.
joinToString { DescriptorRenderer.ONLY_NAMES_WITH_SHORT_TYPES.render(it) }
val duplicateClasses =
another.mapNotNull { it.descriptor }.joinToString { DescriptorRenderer.ONLY_NAMES_WITH_SHORT_TYPES.render(it) }
another.mapNotNull { it.element }.forEach {
diagnostics.report(ErrorsJvm.DUPLICATE_CLASS_NAMES.on(it, internalName, fromString))
for (origin in another) {
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.jvm.JvmClassName
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.JvmDeclarationOriginKind.*
import org.jetbrains.kotlin.serialization.deserialization.DeserializationConfiguration
@@ -291,6 +292,12 @@ class GenerationState private constructor(
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? =
if (languageVersionSettings.supportsFeature(LanguageFeature.NewInference))
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,
// and report signature conflict errors in JvmSignatureClashTracker.
// and report signature conflict errors in JvmSignatureClashDetector.
if (isIrBackend)
it
else
@@ -318,7 +325,7 @@ class GenerationState private constructor(
shouldGenerate = { origin -> !shouldOnlyCollectSignatures(origin) },
).apply { duplicateSignatureFactory = this }
},
{ BuilderFactoryForDuplicateClassNameDiagnostics(it, diagnostics) },
{ BuilderFactoryForDuplicateClassNameDiagnostics(it, this) },
{
configuration.get(JVMConfigurationKeys.DECLARATIONS_JSON_PATH)
?.let { destination -> SignatureDumpingBuilderFactory(it, File(destination)) } ?: it