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
@@ -9,28 +9,30 @@ import org.jetbrains.kotlin.SpecialJvmAnnotations
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.diagnostics.ConeSimpleDiagnostic
import org.jetbrains.kotlin.fir.diagnostics.DiagnosticKind
import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall
import org.jetbrains.kotlin.fir.expressions.FirClassReferenceExpression
import org.jetbrains.kotlin.fir.expressions.FirExpression
import org.jetbrains.kotlin.fir.expressions.buildUnaryArgumentList
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.expressions.builder.*
import org.jetbrains.kotlin.fir.java.createConstantOrError
import org.jetbrains.kotlin.fir.references.builder.buildErrorNamedReference
import org.jetbrains.kotlin.fir.references.builder.buildResolvedNamedReference
import org.jetbrains.kotlin.fir.references.impl.FirReferencePlaceholderForResolvedAnnotations
import org.jetbrains.kotlin.fir.resolve.symbolProvider
import org.jetbrains.kotlin.fir.resolve.providers.getClassDeclaredPropertySymbols
import org.jetbrains.kotlin.fir.resolve.symbolProvider
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag
import org.jetbrains.kotlin.fir.symbols.impl.ConeClassLikeLookupTagImpl
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
import org.jetbrains.kotlin.fir.types.coneType
import org.jetbrains.kotlin.fir.types.constructClassType
import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.load.kotlin.KotlinClassFinder
import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinaryClass
import org.jetbrains.kotlin.load.kotlin.findKotlinClass
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.constants.ClassLiteralValue
internal class AnnotationsLoader(private val session: FirSession) {
internal class AnnotationsLoader(private val session: FirSession, private val kotlinClassFinder: KotlinClassFinder) {
private fun loadAnnotation(
annotationClassId: ClassId, result: MutableList<FirAnnotationCall>,
): KotlinJvmBinaryClass.AnnotationArgumentVisitor {
@@ -141,6 +143,11 @@ internal class AnnotationsLoader(private val session: FirSession) {
}
override fun visitEnd() {
// 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(lookupTag, argumentMap)) return
result += buildAnnotationCall {
annotationTypeRef = lookupTag.toDefaultResolvedTypeRef()
argumentList = buildArgumentList {
@@ -162,6 +169,21 @@ internal class AnnotationsLoader(private val session: FirSession) {
}
}
private fun isRepeatableWithImplicitContainer(lookupTag: ConeClassLikeLookupTag, argumentMap: Map<Name, FirExpression>): Boolean {
if (lookupTag.classId != SpecialJvmAnnotations.JAVA_LANG_ANNOTATION_REPEATABLE) return false
val getClassCall = argumentMap[Name.identifier("value")] as? FirGetClassCall ?: return false
val classReference = getClassCall.argument as? FirClassReferenceExpression ?: return false
val containerType = classReference.classTypeRef.coneType as? ConeClassLikeType ?: return false
val classId = containerType.lookupTag.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)
}
internal fun loadAnnotationIfNotSpecial(
annotationClassId: ClassId, result: MutableList<FirAnnotationCall>,
): KotlinJvmBinaryClass.AnnotationArgumentVisitor? {
@@ -33,14 +33,14 @@ class JvmBinaryAnnotationDeserializer(
byteContent: ByteArray?
) : AbstractAnnotationDeserializer(session) {
private val annotationInfo by lazy(LazyThreadSafetyMode.PUBLICATION) {
session.loadMemberAnnotations(kotlinBinaryClass, byteContent)
session.loadMemberAnnotations(kotlinBinaryClass, byteContent, kotlinClassFinder)
}
private val annotationInfoForDefaultImpls by lazy(LazyThreadSafetyMode.PUBLICATION) {
val defaultImplsClassId = kotlinBinaryClass.classId.createNestedClassId(Name.identifier(JvmAbi.DEFAULT_IMPLS_CLASS_NAME))
val (defaultImplsClass, defaultImplsByteContent) = kotlinClassFinder.findKotlinClassOrContent(defaultImplsClassId) as? KotlinClassFinder.Result.KotlinClass
?: return@lazy null
session.loadMemberAnnotations(defaultImplsClass, defaultImplsByteContent)
session.loadMemberAnnotations(defaultImplsClass, defaultImplsByteContent, kotlinClassFinder)
}
override fun inheritAnnotationInfo(parent: AbstractAnnotationDeserializer) {
@@ -288,9 +288,13 @@ class JvmBinaryAnnotationDeserializer(
private data class MemberAnnotations(val memberAnnotations: MutableMap<MemberSignature, MutableList<FirAnnotationCall>>)
// TODO: better to be in KotlinDeserializedJvmSymbolsProvider?
private fun FirSession.loadMemberAnnotations(kotlinBinaryClass: KotlinJvmBinaryClass, byteContent: ByteArray?): MemberAnnotations {
private fun FirSession.loadMemberAnnotations(
kotlinBinaryClass: KotlinJvmBinaryClass,
byteContent: ByteArray?,
kotlinClassFinder: KotlinClassFinder,
): MemberAnnotations {
val memberAnnotations = hashMapOf<MemberSignature, MutableList<FirAnnotationCall>>()
val annotationsLoader = AnnotationsLoader(this)
val annotationsLoader = AnnotationsLoader(this, kotlinClassFinder)
kotlinBinaryClass.visitMembers(object : KotlinJvmBinaryClass.MemberVisitor {
override fun visitMethod(name: Name, desc: String): KotlinJvmBinaryClass.MethodAnnotationVisitor {
@@ -9,15 +9,17 @@ import com.intellij.openapi.progress.ProcessCanceledException
import org.jetbrains.kotlin.descriptors.SourceElement
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.ThreadSafeMutableState
import org.jetbrains.kotlin.fir.caches.*
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.caches.createCache
import org.jetbrains.kotlin.fir.caches.firCachesFactory
import org.jetbrains.kotlin.fir.caches.getValue
import org.jetbrains.kotlin.fir.declarations.getDeprecationInfos
import org.jetbrains.kotlin.fir.deserialization.*
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall
import org.jetbrains.kotlin.fir.java.JavaSymbolProvider
import org.jetbrains.kotlin.fir.java.topLevelName
import org.jetbrains.kotlin.fir.languageVersionSettings
import org.jetbrains.kotlin.fir.scopes.FirKotlinScopeProvider
import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
import org.jetbrains.kotlin.load.java.JavaClassFinder
import org.jetbrains.kotlin.load.kotlin.*
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader
@@ -44,7 +46,7 @@ class KotlinDeserializedJvmSymbolsProvider(
javaClassFinder: JavaClassFinder,
) : AbstractFirDeserializedSymbolsProvider(session, moduleDataProvider, kotlinScopeProvider) {
private val knownNameInPackageCache = KnownNameInPackageCache(session, javaClassFinder)
private val annotationsLoader = AnnotationsLoader(session)
private val annotationsLoader = AnnotationsLoader(session, kotlinClassFinder)
override fun computePackagePartsInfos(packageFqName: FqName): List<PackagePartsCacheData> {
return packagePartProvider.findPackageParts(packageFqName.asString()).mapNotNull { partName ->