JVM_IR. Support type annotations
This commit is contained in:
@@ -40,6 +40,7 @@ import org.jetbrains.kotlin.types.FlexibleType;
|
||||
import org.jetbrains.kotlin.types.FlexibleTypesKt;
|
||||
import org.jetbrains.kotlin.types.KotlinType;
|
||||
import org.jetbrains.kotlin.types.TypeUtils;
|
||||
import org.jetbrains.kotlin.types.checker.SimpleClassicTypeSystemContext;
|
||||
import org.jetbrains.org.objectweb.asm.*;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
@@ -675,9 +676,9 @@ public abstract class AnnotationCodegen {
|
||||
return;
|
||||
}
|
||||
|
||||
Iterable<TypePathInfo> infos =
|
||||
new TypeAnnotationCollector().collectTypeAnnotations(type, TypeReference.METHOD_FORMAL_PARAMETER);
|
||||
for (TypePathInfo info : infos) {
|
||||
Iterable<TypePathInfo<AnnotationDescriptor>> infos =
|
||||
new PsiTypeAnnotationCollector().collectTypeAnnotations(type);
|
||||
for (TypePathInfo<AnnotationDescriptor> info : infos) {
|
||||
for (AnnotationDescriptor annotationDescriptor : info.getAnnotations()) {
|
||||
genAnnotation(annotationDescriptor, info.getPath(), true);
|
||||
}
|
||||
|
||||
@@ -5,26 +5,29 @@
|
||||
|
||||
package org.jetbrains.kotlin.codegen
|
||||
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
|
||||
import org.jetbrains.kotlin.load.kotlin.FileBasedKotlinClass
|
||||
import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinarySourceElement
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.annotationClass
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedClassDescriptor
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeSystemCommonBackendContext
|
||||
import org.jetbrains.kotlin.types.checker.SimpleClassicTypeSystemContext
|
||||
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
|
||||
import org.jetbrains.kotlin.types.model.TypeVariance
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import org.jetbrains.org.objectweb.asm.TypePath
|
||||
|
||||
|
||||
class TypePathInfo(
|
||||
class TypePathInfo<T>(
|
||||
val path: TypePath?,
|
||||
val annotations: List<AnnotationDescriptor>
|
||||
val annotations: List<T>
|
||||
)
|
||||
|
||||
private class State(val type: Int, val path: MutableList<String>) {
|
||||
private class State<T>(val path: MutableList<String>) {
|
||||
|
||||
val results = arrayListOf<TypePathInfo>()
|
||||
val results = arrayListOf<TypePathInfo<T>>()
|
||||
|
||||
|
||||
fun addStep(step: String) {
|
||||
@@ -35,56 +38,69 @@ private class State(val type: Int, val path: MutableList<String>) {
|
||||
path.removeAt(path.lastIndex)
|
||||
}
|
||||
|
||||
fun rememberAnnotations(annotations: List<AnnotationDescriptor>) {
|
||||
fun rememberAnnotations(annotations: List<T>) {
|
||||
results.add(TypePathInfo(TypePath.fromString(path.joinToString("")), annotations))
|
||||
}
|
||||
}
|
||||
|
||||
class TypeAnnotationCollector {
|
||||
class PsiTypeAnnotationCollector : TypeAnnotationCollector<AnnotationDescriptor>(SimpleClassicTypeSystemContext) {
|
||||
|
||||
private lateinit var state: State
|
||||
override fun KotlinTypeMarker.extractAnnotations(): List<AnnotationDescriptor> {
|
||||
require(this is KotlinType)
|
||||
return annotations.filter {
|
||||
//We only generate annotations which have the TYPE_USE Java target.
|
||||
// Those are type annotations which were compiled with JVM target bytecode version 1.8 or greater
|
||||
isCompiledToJvm8OrHigher(it.annotationClass)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun collectTypeAnnotations(kotlinType: KotlinType, annotationType: Int): ArrayList<TypePathInfo> {
|
||||
state = State(annotationType, arrayListOf())
|
||||
kotlinType.collectTypeAnnotations()
|
||||
abstract class TypeAnnotationCollector<T>(val context: TypeSystemCommonBackendContext) {
|
||||
|
||||
private lateinit var state: State<T>
|
||||
|
||||
fun collectTypeAnnotations(kotlinType: KotlinTypeMarker): ArrayList<TypePathInfo<T>> {
|
||||
state = State(arrayListOf())
|
||||
kotlinType.gatherTypeAnnotations()
|
||||
return state.results
|
||||
}
|
||||
|
||||
private fun KotlinType.collectTypeAnnotations() {
|
||||
if (isFlexible()) {
|
||||
return upperIfFlexible().collectTypeAnnotations()
|
||||
} else if ((this.constructor.declarationDescriptor as? ClassDescriptor)?.isInner == true) {
|
||||
//skip inner classes for now it's not clear should type annotations on outer be supported or not
|
||||
return
|
||||
}
|
||||
private fun KotlinTypeMarker.gatherTypeAnnotations() {
|
||||
with(context) {
|
||||
if (isFlexible()) {
|
||||
return upperBoundIfFlexible().gatherTypeAnnotations()
|
||||
} else if (typeConstructor().isInnerClass()) {
|
||||
//skip inner classes for now it's not clear should type annotations on outer be supported or not
|
||||
return
|
||||
}
|
||||
|
||||
typeAnnotations.takeIf { it.isNotEmpty() }?.let { state.rememberAnnotations(it) }
|
||||
extractAnnotations().takeIf { it.isNotEmpty() }?.let { state.rememberAnnotations(it) }
|
||||
|
||||
arguments.forEachIndexed { index, type ->
|
||||
//skip in/out variance for now it's not clear should type annotations on wildcard bound be supported or not
|
||||
if (type.projectionKind == Variance.INVARIANT) {
|
||||
when {
|
||||
KotlinBuiltIns.isArray(this) -> type.type.process("[")
|
||||
else -> type.type.process("$index;")
|
||||
for (index in 0 until argumentsCount()) {
|
||||
val type = getArgument(index)
|
||||
//skip in/out variance for now it's not clear should type annotations on wildcard bound be supported or not
|
||||
if (type.getVariance() == TypeVariance.INV) {
|
||||
when {
|
||||
this@gatherTypeAnnotations.isArrayOrNullableArray() -> type.getType().process("[")
|
||||
else -> type.getType().process("$index;")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun KotlinType.process(step: String) {
|
||||
fun KotlinTypeMarker.process(step: String) {
|
||||
state.addStep(step)
|
||||
this.collectTypeAnnotations()
|
||||
this.gatherTypeAnnotations()
|
||||
state.removeStep(step)
|
||||
}
|
||||
|
||||
|
||||
private val KotlinType.typeAnnotations
|
||||
get() = annotations.filter {
|
||||
//We only generate annotations which have the TYPE_USE Java target.
|
||||
// Those are type annotations which were compiled with JVM target bytecode version 1.8 or greater
|
||||
(it.annotationClass as? DeserializedClassDescriptor)?.let { classDescriptor ->
|
||||
((classDescriptor.source as? KotlinJvmBinarySourceElement)?.binaryClass as? FileBasedKotlinClass)?.classVersion ?: 0 >= Opcodes.V1_8
|
||||
} ?: true
|
||||
}
|
||||
abstract fun KotlinTypeMarker.extractAnnotations(): List<T>
|
||||
|
||||
fun isCompiledToJvm8OrHigher(descriptor: ClassDescriptor?): Boolean =
|
||||
(descriptor as? DeserializedClassDescriptor)?.let { classDescriptor ->
|
||||
((classDescriptor.source as? KotlinJvmBinarySourceElement)?.binaryClass as? FileBasedKotlinClass)?.classVersion ?: 0 >= Opcodes.V1_8
|
||||
} ?: true
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user