Serialize descriptors for local/anonymous classes on JVM

Reflection needs this information to work for local classes and anonymous
objects
This commit is contained in:
Alexander Udalov
2015-02-14 03:27:05 +03:00
parent 98b554d995
commit 6ce8d6bd2e
34 changed files with 567 additions and 127 deletions
@@ -45,6 +45,19 @@ public final class JvmAnnotationNames {
public static class KotlinClass {
public static final JvmClassName CLASS_NAME = JvmClassName.byInternalName("kotlin/jvm/internal/KotlinClass");
public static final ClassId KIND_CLASS_ID =
ClassId.topLevel(CLASS_NAME.getFqNameForClassNameWithoutDollars()).createNestedClassId(Name.identifier("Kind"));
public static final String KIND_INTERNAL_NAME = JvmClassName.byClassId(KIND_CLASS_ID).getInternalName();
/**
* This enum duplicates {@link kotlin.jvm.internal.KotlinClass.Kind}. Both places should be updated simultaneously.
*/
public enum Kind {
CLASS,
LOCAL_CLASS,
ANONYMOUS_OBJECT,
;
}
}
public static class KotlinSyntheticClass {
@@ -54,8 +67,7 @@ public final class JvmAnnotationNames {
public static final String KIND_INTERNAL_NAME = JvmClassName.byClassId(KIND_CLASS_ID).getInternalName();
/**
* This enum duplicates {@link kotlin.jvm.internal.KotlinSyntheticClass.Kind}, because this code can't depend on "runtime.jvm".
* Both places should be updated simultaneously
* This enum duplicates {@link kotlin.jvm.internal.KotlinSyntheticClass.Kind}. Both places should be updated simultaneously.
*/
public enum Kind {
PACKAGE_PART,
@@ -66,8 +78,6 @@ public final class JvmAnnotationNames {
CALLABLE_REFERENCE_WRAPPER,
LOCAL_FUNCTION,
ANONYMOUS_FUNCTION,
LOCAL_CLASS,
ANONYMOUS_OBJECT,
;
}
}
@@ -17,22 +17,29 @@
package org.jetbrains.kotlin.load.kotlin.header
import org.jetbrains.kotlin.load.java.JvmAnnotationNames.KotlinSyntheticClass
import org.jetbrains.kotlin.load.java.JvmAnnotationNames.KotlinClass
import org.jetbrains.kotlin.load.java.AbiVersionUtil
public class KotlinClassHeader(
public val kind: KotlinClassHeader.Kind,
public val version: Int,
public val annotationData: Array<String>?,
public val classKind: KotlinClass.Kind?,
public val syntheticClassKind: KotlinSyntheticClass.Kind?
) {
public val isCompatibleAbiVersion: Boolean get() = AbiVersionUtil.isAbiVersionCompatible(version);
{
assert(!isCompatibleAbiVersion || (annotationData == null) == (kind != Kind.CLASS && kind != Kind.PACKAGE_FACADE)) {
"Annotation data should be not null only for CLASS and PACKAGE_FACADE (kind=" + kind + ")"
}
assert(!isCompatibleAbiVersion || (syntheticClassKind == null) == (kind != Kind.SYNTHETIC_CLASS)) {
"Synthetic class kind should be present for SYNTHETIC_CLASS (kind=" + kind + ")"
if (isCompatibleAbiVersion) {
assert((annotationData == null) == (kind != Kind.CLASS && kind != Kind.PACKAGE_FACADE)) {
"Annotation data should be not null only for CLASS and PACKAGE_FACADE (kind=$kind)"
}
assert((syntheticClassKind == null) == (kind != Kind.SYNTHETIC_CLASS)) {
"Synthetic class kind should be present for SYNTHETIC_CLASS (kind=$kind)"
}
assert((classKind == null) == (kind != Kind.CLASS)) {
"Class kind should be present for CLASS (kind=$kind)"
}
}
}
@@ -41,6 +48,12 @@ public class KotlinClassHeader(
PACKAGE_FACADE
SYNTHETIC_CLASS
}
override fun toString() =
"$kind " +
(if (classKind != null) "$classKind " else "") +
(if (syntheticClassKind != null) "$syntheticClassKind " else "") +
"version=$version"
}
public fun KotlinClassHeader.isCompatibleClassKind(): Boolean = isCompatibleAbiVersion && kind == KotlinClassHeader.Kind.CLASS
@@ -59,6 +59,7 @@ public class ReadKotlinClassHeaderAnnotationVisitor implements AnnotationVisitor
private String[] annotationData = null;
private KotlinClassHeader.Kind headerKind = null;
private KotlinClass.Kind classKind = null;
private KotlinSyntheticClass.Kind syntheticClassKind = null;
@Nullable
@@ -68,7 +69,7 @@ public class ReadKotlinClassHeaderAnnotationVisitor implements AnnotationVisitor
}
if (!AbiVersionUtil.isAbiVersionCompatible(version)) {
return new KotlinClassHeader(headerKind, version, null, syntheticClassKind);
return new KotlinClassHeader(headerKind, version, null, classKind, syntheticClassKind);
}
if ((headerKind == CLASS || headerKind == PACKAGE_FACADE) && annotationData == null) {
@@ -77,7 +78,7 @@ public class ReadKotlinClassHeaderAnnotationVisitor implements AnnotationVisitor
return null;
}
return new KotlinClassHeader(headerKind, version, annotationData, syntheticClassKind);
return new KotlinClassHeader(headerKind, version, annotationData, classKind, syntheticClassKind);
}
@Nullable
@@ -135,11 +136,6 @@ public class ReadKotlinClassHeaderAnnotationVisitor implements AnnotationVisitor
}
}
@Override
public void visitEnum(@NotNull Name name, @NotNull ClassId enumClassId, @NotNull Name enumEntryName) {
unexpectedEnumArgument(name, enumClassId, enumEntryName);
}
@Override
@Nullable
public AnnotationArrayArgumentVisitor visitArray(@NotNull Name name) {
@@ -203,12 +199,26 @@ public class ReadKotlinClassHeaderAnnotationVisitor implements AnnotationVisitor
public ClassHeaderReader() {
super(KotlinClass.CLASS_NAME);
}
@Override
public void visitEnum(@NotNull Name name, @NotNull ClassId enumClassId, @NotNull Name enumEntryName) {
if (KotlinClass.KIND_CLASS_ID.equals(enumClassId) && KIND_FIELD_NAME.equals(name.asString())) {
classKind = valueOfOrNull(KotlinClass.Kind.class, enumEntryName.asString());
if (classKind != null) return;
}
unexpectedEnumArgument(name, enumClassId, enumEntryName);
}
}
private class PackageHeaderReader extends HeaderAnnotationArgumentVisitor {
public PackageHeaderReader() {
super(JvmClassName.byFqNameWithoutInnerClasses(KOTLIN_PACKAGE));
}
@Override
public void visitEnum(@NotNull Name name, @NotNull ClassId enumClassId, @NotNull Name enumEntryName) {
unexpectedEnumArgument(name, enumClassId, enumEntryName);
}
}
private class SyntheticClassHeaderReader extends HeaderAnnotationArgumentVisitor {
@@ -218,7 +228,7 @@ public class ReadKotlinClassHeaderAnnotationVisitor implements AnnotationVisitor
@Override
public void visitEnum(@NotNull Name name, @NotNull ClassId enumClassId, @NotNull Name enumEntryName) {
if (enumClassId.equals(KotlinSyntheticClass.KIND_CLASS_ID) && name.asString().equals(KIND_FIELD_NAME)) {
if (KotlinSyntheticClass.KIND_CLASS_ID.equals(enumClassId) && KIND_FIELD_NAME.equals(name.asString())) {
syntheticClassKind = valueOfOrNull(KotlinSyntheticClass.Kind.class, enumEntryName.asString());
if (syntheticClassKind != null) return;
}