Do not load Java @Repeatable for Kotlin-repeatable annotations

#KT-48131 Fixed
This commit is contained in:
Alexander Udalov
2021-08-06 14:32:17 +02:00
parent 89b3013294
commit f8af127a4e
11 changed files with 131 additions and 19 deletions
@@ -47,6 +47,7 @@ object JvmAbi {
const val IMPL_SUFFIX_FOR_INLINE_CLASS_MEMBERS = "-impl"
const val REPEATABLE_ANNOTATION_CONTAINER_NAME = "Container"
val REPEATABLE_ANNOTATION_CONTAINER_META_ANNOTATION = ClassId.fromString("kotlin/jvm/internal/RepeatableContainer")
/**
* @param baseName JVM name of the property getter since Kotlin 1.4, or Kotlin name of the property otherwise.
@@ -39,7 +39,7 @@ import java.util.*
abstract class AbstractBinaryClassAnnotationAndConstantLoader<A : Any, C : Any>(
storageManager: StorageManager,
private val kotlinClassFinder: KotlinClassFinder
protected val kotlinClassFinder: KotlinClassFinder
) : AnnotationAndConstantLoader<A, C> {
private val storage = storageManager.createMemoizedFunction<KotlinJvmBinaryClass, Storage<A, C>> { kotlinClass ->
loadAnnotationsAndInitializers(kotlinClass)
@@ -16,9 +16,12 @@
package org.jetbrains.kotlin.load.kotlin
import org.jetbrains.kotlin.SpecialJvmAnnotations
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptorImpl
import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.load.java.JvmAnnotationNames
import org.jetbrains.kotlin.load.java.components.DescriptorResolverUtils
import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinaryClass.AnnotationArrayArgumentVisitor
import org.jetbrains.kotlin.metadata.ProtoBuf
@@ -29,7 +32,6 @@ import org.jetbrains.kotlin.resolve.constants.*
import org.jetbrains.kotlin.serialization.deserialization.AnnotationDeserializer
import org.jetbrains.kotlin.storage.StorageManager
import org.jetbrains.kotlin.utils.compact
import java.util.*
class BinaryClassAnnotationAndConstantLoaderImpl(
private val module: ModuleDescriptor,
@@ -143,7 +145,13 @@ class BinaryClassAnnotationAndConstantLoaderImpl(
}
override fun visitEnd() {
result.add(AnnotationDescriptorImpl(annotationClass.defaultType, arguments, source))
val annotation = AnnotationDescriptorImpl(annotationClass.defaultType, arguments, source)
// Do not load the @java.lang.annotation.Repeatable annotation instance generated automatically by the compiler for
// Kotlin-repeatable annotation classes. Otherwise the reference to the implicit nested "Container" class cannot be
// resolved, since that class is only generated in the backend, and is not visible to the frontend.
if (!isRepeatableWithImplicitContainer(annotation)) {
result.add(annotation)
}
}
private fun createConstant(name: Name?, value: Any?): ConstantValue<*> {
@@ -156,4 +164,18 @@ class BinaryClassAnnotationAndConstantLoaderImpl(
private fun resolveClass(classId: ClassId): ClassDescriptor {
return module.findNonGenericClassAcrossDependencies(classId, notFoundClasses)
}
private fun isRepeatableWithImplicitContainer(annotation: AnnotationDescriptor): Boolean {
if (annotation.fqName != JvmAnnotationNames.REPEATABLE_ANNOTATION) return false
val containerKClassValue = annotation.allValueArguments[Name.identifier("value")] as? KClassValue ?: return false
val normalClass = containerKClassValue.value as? KClassValue.Value.NormalClass ?: return false
val classId = normalClass.classId
if (classId.outerClassId == null ||
classId.shortClassName.asString() != JvmAbi.REPEATABLE_ANNOTATION_CONTAINER_NAME
) return false
val klass = kotlinClassFinder.findKotlinClass(classId)
return klass != null && SpecialJvmAnnotations.isAnnotatedWithContainerMetaAnnotation(klass)
}
}
@@ -5,9 +5,11 @@
package org.jetbrains.kotlin
import org.jetbrains.kotlin.descriptors.SourceElement
import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.load.java.JvmAnnotationNames
import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinaryClass
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
object SpecialJvmAnnotations {
val SPECIAL_ANNOTATIONS: Set<ClassId> = listOf(
@@ -18,4 +20,22 @@ object SpecialJvmAnnotations {
JvmAnnotationNames.RETENTION_ANNOTATION,
JvmAnnotationNames.DOCUMENTED_ANNOTATION
).mapTo(mutableSetOf(), ClassId::topLevel)
val JAVA_LANG_ANNOTATION_REPEATABLE = ClassId.topLevel(JvmAnnotationNames.REPEATABLE_ANNOTATION)
fun isAnnotatedWithContainerMetaAnnotation(klass: KotlinJvmBinaryClass): Boolean {
var result = false
klass.loadClassAnnotations(object : KotlinJvmBinaryClass.AnnotationVisitor {
override fun visitAnnotation(classId: ClassId, source: SourceElement): KotlinJvmBinaryClass.AnnotationArgumentVisitor? {
if (classId == JvmAbi.REPEATABLE_ANNOTATION_CONTAINER_META_ANNOTATION) {
result = true
}
return null
}
override fun visitEnd() {
}
}, null)
return result
}
}