FIR: support class annotations in JVM deserialized

This commit is contained in:
Mikhail Glukhikh
2019-04-22 15:31:50 +03:00
parent a9db64989b
commit 48cd9e3251
27 changed files with 196 additions and 41 deletions
@@ -286,7 +286,7 @@ private fun <T> List<T>.createArrayOfCall(session: FirSession, @Suppress("UNUSED
}
}
private fun Any?.createConstant(session: FirSession): FirExpression {
internal fun Any?.createConstant(session: FirSession): FirExpression {
return when (this) {
is Byte -> FirConstExpressionImpl(session, null, IrConstKind.Byte, this)
is Short -> FirConstExpressionImpl(session, null, IrConstKind.Short, this)
@@ -6,30 +6,39 @@
package org.jetbrains.kotlin.fir.java.deserialization
import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.descriptors.SourceElement
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
import org.jetbrains.kotlin.fir.declarations.FirEnumEntry
import org.jetbrains.kotlin.fir.declarations.FirNamedDeclaration
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.declarations.impl.FirEnumEntryImpl
import org.jetbrains.kotlin.fir.deserialization.FirDeserializationContext
import org.jetbrains.kotlin.fir.deserialization.deserializeClassToSymbol
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.impl.*
import org.jetbrains.kotlin.fir.java.createConstant
import org.jetbrains.kotlin.fir.java.topLevelName
import org.jetbrains.kotlin.fir.references.FirErrorNamedReference
import org.jetbrains.kotlin.fir.references.FirResolvedCallableReferenceImpl
import org.jetbrains.kotlin.fir.resolve.*
import org.jetbrains.kotlin.fir.resolve.transformers.firUnsafe
import org.jetbrains.kotlin.fir.scopes.FirScope
import org.jetbrains.kotlin.fir.scopes.impl.FirClassDeclaredMemberScope
import org.jetbrains.kotlin.fir.symbols.ConeCallableSymbol
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeSymbol
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
import org.jetbrains.kotlin.fir.service
import org.jetbrains.kotlin.fir.symbols.*
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeAliasSymbol
import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
import org.jetbrains.kotlin.fir.types.impl.FirErrorTypeRefImpl
import org.jetbrains.kotlin.fir.types.impl.FirResolvedTypeRefImpl
import org.jetbrains.kotlin.load.java.JavaClassFinder
import org.jetbrains.kotlin.load.java.structure.JavaClass
import org.jetbrains.kotlin.load.kotlin.KotlinClassFinder
import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinaryClass
import org.jetbrains.kotlin.load.kotlin.PackagePartProvider
import org.jetbrains.kotlin.load.kotlin.findKotlinClass
import org.jetbrains.kotlin.load.kotlin.*
import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinaryClass.AnnotationArrayArgumentVisitor
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader
import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmNameResolver
@@ -37,6 +46,7 @@ import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmProtoBufUtil
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.constants.ClassLiteralValue
import org.jetbrains.kotlin.resolve.jvm.JvmClassName
import org.jetbrains.kotlin.serialization.deserialization.getName
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
@@ -129,6 +139,140 @@ class KotlinDeserializedJvmSymbolsProvider(
return JvmProtoBufUtil.readClassDataFrom(data, strings)
}
private fun ConeClassifierSymbol?.toDefaultResolvedTypeRef(classId: ClassId): FirResolvedTypeRef {
return this?.let {
FirResolvedTypeRefImpl(
session, null, it.constructType(emptyList(), isNullable = false),
isMarkedNullable = false, annotations = emptyList()
)
} ?: FirErrorTypeRefImpl(session, null, "Symbol not found for $classId")
}
private fun loadAnnotation(
annotationClassId: ClassId, result: MutableList<FirAnnotationCall>
): KotlinJvmBinaryClass.AnnotationArgumentVisitor? {
val lookupTag = ConeClassLikeLookupTagImpl(annotationClassId)
val symbol = lookupTag.toSymbol(session)
return object : KotlinJvmBinaryClass.AnnotationArgumentVisitor {
private val argumentMap = mutableMapOf<Name, FirExpression>()
override fun visit(name: Name?, value: Any?) {
if (name != null) {
argumentMap[name] = createConstant(value)
}
}
private fun ClassLiteralValue.toFirClassReferenceExpression(): FirClassReferenceExpression {
val literalLookupTag = ConeClassLikeLookupTagImpl(classId)
val literalSymbol = literalLookupTag.toSymbol(this@KotlinDeserializedJvmSymbolsProvider.session)
return FirClassReferenceExpressionImpl(
this@KotlinDeserializedJvmSymbolsProvider.session, null,
literalSymbol.toDefaultResolvedTypeRef(classId)
)
}
private fun ClassId.toEnumEntryReferenceExpression(name: Name): FirExpression {
return FirFunctionCallImpl(session, null).apply {
val entryClassId = createNestedClassId(name)
val entryLookupTag = ConeClassLikeLookupTagImpl(entryClassId)
val entryClassSymbol = entryLookupTag.toSymbol(this@KotlinDeserializedJvmSymbolsProvider.session)
val entryCallableSymbol =
this@KotlinDeserializedJvmSymbolsProvider.session.service<FirSymbolProvider>().getClassDeclaredCallableSymbols(
this@toEnumEntryReferenceExpression, name
).firstOrNull()
this.calleeReference = when {
entryClassSymbol != null && (entryClassSymbol as? FirClassSymbol)?.fir is FirEnumEntry -> {
FirResolvedCallableReferenceImpl(
this@KotlinDeserializedJvmSymbolsProvider.session, null, name, entryClassSymbol
)
}
entryCallableSymbol != null -> {
FirResolvedCallableReferenceImpl(
this@KotlinDeserializedJvmSymbolsProvider.session, null, name, entryCallableSymbol
)
}
else -> {
FirErrorNamedReference(
this@KotlinDeserializedJvmSymbolsProvider.session, null,
errorReason = "Strange deserialized enum value: ${this@toEnumEntryReferenceExpression}.$name"
)
}
}
}
}
override fun visitClassLiteral(name: Name, value: ClassLiteralValue) {
argumentMap[name] = FirGetClassCallImpl(session, null).apply {
arguments += value.toFirClassReferenceExpression()
}
}
override fun visitEnum(name: Name, enumClassId: ClassId, enumEntryName: Name) {
argumentMap[name] = enumClassId.toEnumEntryReferenceExpression(enumEntryName)
}
override fun visitArray(name: Name): AnnotationArrayArgumentVisitor? {
return object : AnnotationArrayArgumentVisitor {
private val elements = mutableListOf<FirExpression>()
override fun visit(value: Any?) {
elements.add(createConstant(value))
}
override fun visitEnum(enumClassId: ClassId, enumEntryName: Name) {
elements.add(enumClassId.toEnumEntryReferenceExpression(enumEntryName))
}
override fun visitClassLiteral(value: ClassLiteralValue) {
elements.add(value.toFirClassReferenceExpression())
}
override fun visitEnd() {
argumentMap[name] = FirArrayOfCallImpl(session, null).apply {
arguments += elements
}
}
}
}
override fun visitAnnotation(name: Name, classId: ClassId): KotlinJvmBinaryClass.AnnotationArgumentVisitor? {
val list = mutableListOf<FirAnnotationCall>()
val visitor = loadAnnotation(classId, list)!!
return object : KotlinJvmBinaryClass.AnnotationArgumentVisitor by visitor {
override fun visitEnd() {
visitor.visitEnd()
argumentMap[name] = list.single()
}
}
}
override fun visitEnd() {
result += FirAnnotationCallImpl(session, null, null, symbol.toDefaultResolvedTypeRef(annotationClassId)).apply {
for ((name, expression) in argumentMap) {
arguments += FirNamedArgumentExpressionImpl(
this@KotlinDeserializedJvmSymbolsProvider.session, null, name, expression
)
}
}
}
private fun createConstant(value: Any?): FirExpression {
return value.createConstant(session)
}
}
}
private fun loadAnnotationIfNotSpecial(
annotationClassId: ClassId, result: MutableList<FirAnnotationCall>
): KotlinJvmBinaryClass.AnnotationArgumentVisitor? {
if (annotationClassId in AbstractBinaryClassAnnotationAndConstantLoader.SPECIAL_ANNOTATIONS) return null
return loadAnnotation(annotationClassId, result)
}
private fun findAndDeserializeClass(
classId: ClassId,
parentContext: FirDeserializationContext? = null
@@ -158,6 +302,17 @@ class KotlinDeserializedJvmSymbolsProvider(
classId, classProto, symbol, nameResolver, session, parentContext,
this::findAndDeserializeClass
)
val annotations = mutableListOf<FirAnnotationCall>()
kotlinJvmBinaryClass.loadClassAnnotations(object : KotlinJvmBinaryClass.AnnotationVisitor {
override fun visitAnnotation(classId: ClassId, source: SourceElement): KotlinJvmBinaryClass.AnnotationArgumentVisitor? {
return loadAnnotationIfNotSpecial(classId, annotations)
}
override fun visitEnd() {
}
}, null)
(symbol.fir as FirAbstractAnnotatedElement).annotations += annotations
symbol
}
}
@@ -1,4 +1,4 @@
public final class AnnotationInAnnotationArguments : R|kotlin/Any| {
@R|test/OptionGroups|(o1 = @R|test/StringOptions|(option = <implicitArrayOf>(String(abc), String(d), String(ef))) , o2 = @R|test/EnumOption|(option = R|test/E.ENTRY|()) ) public final class AnnotationInAnnotationArguments : R|kotlin/Any| {
public constructor(): R|test/AnnotationInAnnotationArguments|
}
@@ -15,7 +15,7 @@ public final annotation class Anno : R|kotlin/Annotation| {
}
public final class Klass : R|kotlin/Any| {
@R|test/Anno|(klass = <getClass>(<getClass>(R|kotlin/String|)), klasses = <implicitArrayOf>(<getClass>(R|kotlin/Int|), <getClass>(R|kotlin/String|), <getClass>(R|kotlin/Float|)), sarKlass = <getClass>(<getClass>(R|kotlin/String|)), d2arKlass = <getClass>(<getClass>(R|kotlin/DoubleArray|))) public final class Klass : R|kotlin/Any| {
public constructor(): R|test/Klass|
}
@@ -27,7 +27,7 @@ public final annotation class Anno : R|kotlin/Annotation| {
}
public final class Klass : R|kotlin/Any| {
@R|test/Anno|(bytes = ERROR_EXPR(Unknown value in JavaLiteralAnnotationArgument: [B@1ab59349), shorts = ERROR_EXPR(Unknown value in JavaLiteralAnnotationArgument: [S@3a9e0124), ints = ERROR_EXPR(Unknown value in JavaLiteralAnnotationArgument: [I@472931b8), longs = ERROR_EXPR(Unknown value in JavaLiteralAnnotationArgument: [J@44b10709), chars = ERROR_EXPR(Unknown value in JavaLiteralAnnotationArgument: [C@72a8fb0d), floats = ERROR_EXPR(Unknown value in JavaLiteralAnnotationArgument: [F@3875435d), doubles = ERROR_EXPR(Unknown value in JavaLiteralAnnotationArgument: [D@365f111a), booleans = ERROR_EXPR(Unknown value in JavaLiteralAnnotationArgument: [Z@7a1ac197)) public final class Klass : R|kotlin/Any| {
public constructor(): R|test/Klass|
}
@@ -1,4 +1,4 @@
public final annotation class TargetedAnnotation : R|kotlin/Annotation| {
@R|kotlin/annotation/Target|(allowedTargets = <implicitArrayOf>(R|kotlin/annotation/AnnotationTarget.CLASS|())) public final annotation class TargetedAnnotation : R|kotlin/Annotation| {
public constructor(): R|test/TargetedAnnotation|
}
@@ -23,7 +23,7 @@ public final class A : R|kotlin/Any| {
}
public final class C : R|kotlin/Any| {
@R|test/A.Companion.Anno1|() @R|test/A.Companion.B.Anno2|() public final class C : R|kotlin/Any| {
public constructor(): R|test/C|
}
@@ -9,7 +9,7 @@ public final class Class : R|kotlin/Any| {
public final companion object Companion : R|kotlin/Any| {
private constructor(): R|test/Class.Companion|
public final class Nested : R|kotlin/Any| {
@R|test/Anno|() public final class Nested : R|kotlin/Any| {
public constructor(): R|test/Class.Companion.Nested|
}
@@ -6,7 +6,7 @@ public final annotation class Anno : R|kotlin/Annotation| {
public final class Class : R|kotlin/Any| {
public constructor(): R|test/Class|
public final companion object Companion : R|kotlin/Any| {
@R|test/Anno|() public final companion object Companion : R|kotlin/Any| {
private constructor(): R|test/Class.Companion|
}
@@ -1,17 +1,17 @@
public final class Class : R|kotlin/Any| {
@R|kotlin/Deprecated|(message = String(Class)) public final class Class : R|kotlin/Any| {
public constructor(): R|test/Class|
public final companion object Companion : R|kotlin/Any| {
@R|kotlin/Deprecated|(message = String(companion object)) public final companion object Companion : R|kotlin/Any| {
private constructor(): R|test/Class.Companion|
}
public final inner class Inner : R|kotlin/Any| {
@R|kotlin/Deprecated|(message = String(Inner)) public final inner class Inner : R|kotlin/Any| {
public constructor(): R|test/Class.Inner|
}
public final class Nested : R|kotlin/Any| {
@R|kotlin/Deprecated|(message = String(Nested)) public final class Nested : R|kotlin/Any| {
public constructor(): R|test/Class.Nested|
}
@@ -3,7 +3,7 @@ public final annotation class $$$$$$ : R|kotlin/Annotation| {
}
public final class A : R|kotlin/Any| {
@R|test/$$$$$$|() public final class A : R|kotlin/Any| {
public constructor(): R|test/A|
}
@@ -13,7 +13,7 @@ public final annotation class Anno$tation : R|kotlin/Annotation| {
}
public final class Cla$s : R|kotlin/Any| {
@R|test/Anno$tation|() public final class Cla$s : R|kotlin/Any| {
public constructor(): R|test/Cla$s|
}
@@ -6,20 +6,20 @@ public final annotation class Anno : R|kotlin/Annotation| {
}
public final class Class : R|kotlin/Any| {
@R|test/Anno|(t = R|java/lang/annotation/ElementType.METHOD|()) public final class Class : R|kotlin/Any| {
public constructor(): R|test/Class|
public final companion object Companion : R|kotlin/Any| {
@R|test/Anno|(t = R|java/lang/annotation/ElementType.ANNOTATION_TYPE|()) public final companion object Companion : R|kotlin/Any| {
private constructor(): R|test/Class.Companion|
}
public final inner class Inner : R|kotlin/Any| {
@R|test/Anno|(t = R|java/lang/annotation/ElementType.PARAMETER|()) public final inner class Inner : R|kotlin/Any| {
public constructor(): R|test/Class.Inner|
}
public final class Nested : R|kotlin/Any| {
@R|test/Anno|(t = R|java/lang/annotation/ElementType.TYPE|()) public final class Nested : R|kotlin/Any| {
public constructor(): R|test/Class.Nested|
}
@@ -13,7 +13,7 @@ public final annotation class A3 : R|kotlin/Annotation| {
}
public final class Class : R|kotlin/Any| {
@R|test/A1|() @R|test/A2|() @R|test/A3|() public final class Class : R|kotlin/Any| {
public constructor(): R|test/Class|
}
@@ -8,7 +8,7 @@ public final class A : R|kotlin/Any| {
}
public final class B : R|kotlin/Any| {
@R|test/A.Anno|() public final class B : R|kotlin/Any| {
public final fun f(): R|kotlin/Unit|
public constructor(): R|test/B|
@@ -6,12 +6,12 @@ public final annotation class Anno : R|kotlin/Annotation| {
public final class Class : R|kotlin/Any| {
public constructor(): R|test/Class|
public final inner class Inner : R|kotlin/Any| {
@R|test/Anno|() public final inner class Inner : R|kotlin/Any| {
public constructor(): R|test/Class.Inner|
}
public final class Nested : R|kotlin/Any| {
@R|test/Anno|() public final class Nested : R|kotlin/Any| {
public constructor(): R|test/Class.Nested|
}
@@ -1,4 +1,4 @@
public final annotation class Anno : R|kotlin/Annotation| {
@R|kotlin/annotation/Retention|(value = R|kotlin/annotation/AnnotationRetention.RUNTIME|()) public final annotation class Anno : R|kotlin/Annotation| {
public constructor(): R|test/Anno|
}
@@ -3,7 +3,7 @@ public final annotation class Anno : R|kotlin/Annotation| {
}
public final class X : R|kotlin/Any| {
@R|test/Anno|() public final class X : R|kotlin/Any| {
public constructor(): R|test/X|
}
@@ -22,7 +22,7 @@ public final annotation class CharAnno : R|kotlin/Annotation| {
}
public final class Class : R|kotlin/Any| {
@R|test/IntAnno|(value = Int(42)) @R|test/ShortAnno|(value = Short(42)) @R|test/ByteAnno|(value = Byte(42)) @R|test/LongAnno|(value = Long(42)) @R|test/CharAnno|(value = Char(A)) @R|test/BooleanAnno|(value = Boolean(false)) @R|test/FloatAnno|(value = Float(3.14)) @R|test/DoubleAnno|(value = Double(3.14)) public final class Class : R|kotlin/Any| {
public constructor(): R|test/Class|
}
@@ -12,7 +12,7 @@ public final annotation class Anno : R|kotlin/Annotation| {
}
public final class Class : R|kotlin/Any| {
@R|test/Anno|(int = Int(42), string = String(OK), double = Double(3.14)) public final class Class : R|kotlin/Any| {
public constructor(): R|test/Class|
}
@@ -1,6 +1,6 @@
public final fun typeAnnotation(): R|kotlin/Unit|
public final annotation class A : R|kotlin/Annotation| {
@R|kotlin/annotation/Target|(allowedTargets = <implicitArrayOf>(R|kotlin/annotation/AnnotationTarget.TYPE_PARAMETER|(), R|kotlin/annotation/AnnotationTarget.TYPEALIAS|(), R|kotlin/annotation/AnnotationTarget.TYPE|())) @R|kotlin/annotation/Retention|(value = R|kotlin/annotation/AnnotationRetention.SOURCE|()) public final annotation class A : R|kotlin/Annotation| {
public constructor(): R|test/A|
}
@@ -1,4 +1,4 @@
public final annotation class Ann : R|kotlin/Annotation| {
@R|kotlin/annotation/Target|(allowedTargets = <implicitArrayOf>(R|kotlin/annotation/AnnotationTarget.TYPE|())) public final annotation class Ann : R|kotlin/Annotation| {
public final val x: R|kotlin/String|
public get(): R|kotlin/String|
@@ -1,6 +1,6 @@
public final fun foo(bar: R|kotlin/collections/Map<kotlin/String, kotlin/collections/List<kotlin/Int>>|): R|kotlin/Unit|
public final annotation class A : R|kotlin/Annotation| {
@R|kotlin/annotation/Target|(allowedTargets = <implicitArrayOf>(R|kotlin/annotation/AnnotationTarget.TYPE|())) public final annotation class A : R|kotlin/Annotation| {
public constructor(): R|test/A|
}
@@ -1,4 +1,4 @@
public final annotation class A : R|kotlin/Annotation| {
@R|kotlin/annotation/Target|(allowedTargets = <implicitArrayOf>(R|kotlin/annotation/AnnotationTarget.TYPE_PARAMETER|())) public final annotation class A : R|kotlin/Annotation| {
public constructor(): R|test/A|
}
@@ -1,4 +1,4 @@
public final annotation class A : R|kotlin/Annotation| {
@R|kotlin/annotation/Target|(allowedTargets = <implicitArrayOf>(R|kotlin/annotation/AnnotationTarget.TYPE_PARAMETER|())) public final annotation class A : R|kotlin/Annotation| {
public final val x: R|kotlin/String|
public get(): R|kotlin/String|
@@ -12,7 +12,7 @@ public final class A : R|kotlin/Any| {
}
public final annotation class Ann : R|kotlin/Annotation| {
@R|kotlin/annotation/Target|(allowedTargets = <implicitArrayOf>(R|kotlin/annotation/AnnotationTarget.VALUE_PARAMETER|())) public final annotation class Ann : R|kotlin/Annotation| {
public constructor(): R|test/Ann|
}
@@ -1,4 +1,4 @@
public final annotation class Ann : R|kotlin/Annotation| {
@R|kotlin/annotation/Target|(allowedTargets = <implicitArrayOf>(R|kotlin/annotation/AnnotationTarget.TYPEALIAS|())) public final annotation class Ann : R|kotlin/Annotation| {
public final val value: R|kotlin/String|
public get(): R|kotlin/String|
@@ -410,7 +410,7 @@ abstract class AbstractBinaryClassAnnotationAndConstantLoader<A : Any, C : Any>(
val propertyConstants: Map<MemberSignature, C>
)
private companion object {
companion object {
val SPECIAL_ANNOTATIONS = listOf(
JvmAnnotationNames.METADATA_FQ_NAME,
JvmAnnotationNames.JETBRAINS_NOT_NULL_ANNOTATION,