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
+12
-13
@@ -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
|
||||
|
||||
+4
@@ -39,6 +39,8 @@ object JvmBackendErrors {
|
||||
|
||||
val NOT_ALL_MULTIFILE_CLASS_PARTS_ARE_JVM_SYNTHETIC by error0<PsiElement>()
|
||||
|
||||
val DUPLICATE_CLASS_NAMES by error2<PsiElement, String, String>()
|
||||
|
||||
init {
|
||||
RootDiagnosticRendererFactory.registerFactory(KtDefaultJvmErrorMessages)
|
||||
}
|
||||
@@ -78,5 +80,7 @@ object KtDefaultJvmErrorMessages : BaseDiagnosticRendererFactory() {
|
||||
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"
|
||||
)
|
||||
|
||||
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 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 =
|
||||
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.caches.BridgeLoweringCache
|
||||
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.MethodSignatureMapper
|
||||
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.name.FqName
|
||||
import org.jetbrains.kotlin.resolve.jvm.JvmClassName
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmBackendErrors
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
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()) }
|
||||
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 =
|
||||
|
||||
+4
-1
@@ -20,7 +20,10 @@ class JvmIrDeclarationOrigin(
|
||||
originKind: JvmDeclarationOriginKind,
|
||||
element: PsiElement?,
|
||||
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
|
||||
get() {
|
||||
|
||||
Reference in New Issue
Block a user