Read Metadata annotation, support option to ignore old annotations
This commit is contained in:
+15
@@ -31,17 +31,32 @@ class KotlinClassHeader(
|
|||||||
) {
|
) {
|
||||||
// See kotlin.Metadata
|
// See kotlin.Metadata
|
||||||
enum class Kind(val id: Int) {
|
enum class Kind(val id: Int) {
|
||||||
|
UNKNOWN(0),
|
||||||
CLASS(1),
|
CLASS(1),
|
||||||
FILE_FACADE(2),
|
FILE_FACADE(2),
|
||||||
SYNTHETIC_CLASS(3),
|
SYNTHETIC_CLASS(3),
|
||||||
MULTIFILE_CLASS(4),
|
MULTIFILE_CLASS(4),
|
||||||
MULTIFILE_CLASS_PART(5);
|
MULTIFILE_CLASS_PART(5);
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val entryById = values().toMapBy(Kind::id)
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun getById(id: Int) = entryById[id] ?: UNKNOWN
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class SyntheticClassKind(val id: Int) {
|
enum class SyntheticClassKind(val id: Int) {
|
||||||
FUNCTION(1),
|
FUNCTION(1),
|
||||||
LOCAL_CLASS(2),
|
LOCAL_CLASS(2),
|
||||||
INTERFACE_DEFAULT_IMPLS(3);
|
INTERFACE_DEFAULT_IMPLS(3);
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val entryById = values().toMapBy(SyntheticClassKind::id)
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun getById(id: Int) = entryById[id]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun toString() = "$kind " + (if (isLocalClass) "(local) " else "") + "version=$metadataVersion"
|
override fun toString() = "$kind " + (if (isLocalClass) "(local) " else "") + "version=$metadataVersion"
|
||||||
|
|||||||
+121
-25
@@ -35,6 +35,8 @@ import static org.jetbrains.kotlin.load.kotlin.KotlinJvmBinaryClass.*;
|
|||||||
import static org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader.Kind.*;
|
import static org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader.Kind.*;
|
||||||
|
|
||||||
public class ReadKotlinClassHeaderAnnotationVisitor implements AnnotationVisitor {
|
public class ReadKotlinClassHeaderAnnotationVisitor implements AnnotationVisitor {
|
||||||
|
private static final boolean IGNORE_OLD_METADATA = "true".equals(System.getProperty("kotlin.ignore.old.metadata"));
|
||||||
|
|
||||||
private static final Map<ClassId, KotlinClassHeader.Kind> HEADER_KINDS = new HashMap<ClassId, KotlinClassHeader.Kind>();
|
private static final Map<ClassId, KotlinClassHeader.Kind> HEADER_KINDS = new HashMap<ClassId, KotlinClassHeader.Kind>();
|
||||||
|
|
||||||
static {
|
static {
|
||||||
@@ -51,6 +53,7 @@ public class ReadKotlinClassHeaderAnnotationVisitor implements AnnotationVisitor
|
|||||||
private String[] data = null;
|
private String[] data = null;
|
||||||
private String[] strings = null;
|
private String[] strings = null;
|
||||||
private KotlinClassHeader.Kind headerKind = null;
|
private KotlinClassHeader.Kind headerKind = null;
|
||||||
|
private KotlinClassHeader.SyntheticClassKind syntheticClassKind = null;
|
||||||
private boolean isInterfaceDefaultImpls = false;
|
private boolean isInterfaceDefaultImpls = false;
|
||||||
private boolean isLocalClass = false;
|
private boolean isLocalClass = false;
|
||||||
|
|
||||||
@@ -73,7 +76,11 @@ public class ReadKotlinClassHeaderAnnotationVisitor implements AnnotationVisitor
|
|||||||
headerKind,
|
headerKind,
|
||||||
metadataVersion != null ? metadataVersion : JvmMetadataVersion.INVALID_VERSION,
|
metadataVersion != null ? metadataVersion : JvmMetadataVersion.INVALID_VERSION,
|
||||||
bytecodeVersion != null ? bytecodeVersion : JvmBytecodeBinaryVersion.INVALID_VERSION,
|
bytecodeVersion != null ? bytecodeVersion : JvmBytecodeBinaryVersion.INVALID_VERSION,
|
||||||
data, strings, multifileClassName, isInterfaceDefaultImpls, isLocalClass
|
data,
|
||||||
|
strings,
|
||||||
|
multifileClassName,
|
||||||
|
isInterfaceDefaultImpls || syntheticClassKind == KotlinClassHeader.SyntheticClassKind.INTERFACE_DEFAULT_IMPLS,
|
||||||
|
isLocalClass || syntheticClassKind == KotlinClassHeader.SyntheticClassKind.LOCAL_CLASS
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,6 +94,12 @@ public class ReadKotlinClassHeaderAnnotationVisitor implements AnnotationVisitor
|
|||||||
@Override
|
@Override
|
||||||
public AnnotationArgumentVisitor visitAnnotation(@NotNull ClassId classId, @NotNull SourceElement source) {
|
public AnnotationArgumentVisitor visitAnnotation(@NotNull ClassId classId, @NotNull SourceElement source) {
|
||||||
FqName fqName = classId.asSingleFqName();
|
FqName fqName = classId.asSingleFqName();
|
||||||
|
if (fqName.equals(METADATA)) {
|
||||||
|
return new KotlinMetadataArgumentVisitor();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IGNORE_OLD_METADATA) return null;
|
||||||
|
|
||||||
if (KOTLIN_INTERFACE_DEFAULT_IMPLS.equals(fqName)) {
|
if (KOTLIN_INTERFACE_DEFAULT_IMPLS.equals(fqName)) {
|
||||||
isInterfaceDefaultImpls = true;
|
isInterfaceDefaultImpls = true;
|
||||||
return null;
|
return null;
|
||||||
@@ -114,6 +127,89 @@ public class ReadKotlinClassHeaderAnnotationVisitor implements AnnotationVisitor
|
|||||||
public void visitEnd() {
|
public void visitEnd() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class KotlinMetadataArgumentVisitor implements AnnotationArgumentVisitor {
|
||||||
|
@Override
|
||||||
|
public void visit(@Nullable Name name, @Nullable Object value) {
|
||||||
|
if (name == null) return;
|
||||||
|
|
||||||
|
String string = name.asString();
|
||||||
|
if (KIND_FIELD_NAME.equals(string)) {
|
||||||
|
if (value instanceof Integer) {
|
||||||
|
headerKind = KotlinClassHeader.Kind.getById((Integer) value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (METADATA_VERSION_FIELD_NAME.equals(string)) {
|
||||||
|
if (value instanceof int[]) {
|
||||||
|
metadataVersion = JvmMetadataVersion.create((int[]) value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (BYTECODE_VERSION_FIELD_NAME.equals(string)) {
|
||||||
|
if (value instanceof int[]) {
|
||||||
|
bytecodeVersion = JvmBytecodeBinaryVersion.create((int[]) value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (SYNTHETIC_CLASS_KIND_FIELD_NAME.equals(string)) {
|
||||||
|
if (value instanceof Integer) {
|
||||||
|
syntheticClassKind = KotlinClassHeader.SyntheticClassKind.getById((Integer) value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (METADATA_MULTIFILE_CLASS_NAME_FIELD_NAME.equals(string)) {
|
||||||
|
if (value instanceof String) {
|
||||||
|
multifileClassName = (String) value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Nullable
|
||||||
|
public AnnotationArrayArgumentVisitor visitArray(@NotNull Name name) {
|
||||||
|
String string = name.asString();
|
||||||
|
if (METADATA_DATA_FIELD_NAME.equals(string)) {
|
||||||
|
return dataArrayVisitor();
|
||||||
|
}
|
||||||
|
else if (METADATA_STRINGS_FIELD_NAME.equals(string)) {
|
||||||
|
return stringsArrayVisitor();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private AnnotationArrayArgumentVisitor dataArrayVisitor() {
|
||||||
|
return new CollectStringArrayAnnotationVisitor() {
|
||||||
|
@Override
|
||||||
|
protected void visitEnd(@NotNull String[] result) {
|
||||||
|
data = result;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private AnnotationArrayArgumentVisitor stringsArrayVisitor() {
|
||||||
|
return new CollectStringArrayAnnotationVisitor() {
|
||||||
|
@Override
|
||||||
|
protected void visitEnd(@NotNull String[] result) {
|
||||||
|
strings = result;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitEnum(@NotNull Name name, @NotNull ClassId enumClassId, @NotNull Name enumEntryName) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public AnnotationArgumentVisitor visitAnnotation(@NotNull Name name, @NotNull ClassId classId) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitEnd() {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private class HeaderAnnotationArgumentVisitor implements AnnotationArgumentVisitor {
|
private class HeaderAnnotationArgumentVisitor implements AnnotationArgumentVisitor {
|
||||||
@Override
|
@Override
|
||||||
public void visit(@Nullable Name name, @Nullable Object value) {
|
public void visit(@Nullable Name name, @Nullable Object value) {
|
||||||
@@ -183,32 +279,32 @@ public class ReadKotlinClassHeaderAnnotationVisitor implements AnnotationVisitor
|
|||||||
@Override
|
@Override
|
||||||
public void visitEnd() {
|
public void visitEnd() {
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private abstract class CollectStringArrayAnnotationVisitor implements AnnotationArrayArgumentVisitor {
|
private abstract static class CollectStringArrayAnnotationVisitor implements AnnotationArrayArgumentVisitor {
|
||||||
private final List<String> strings;
|
private final List<String> strings;
|
||||||
|
|
||||||
public CollectStringArrayAnnotationVisitor() {
|
public CollectStringArrayAnnotationVisitor() {
|
||||||
this.strings = new ArrayList<String>();
|
this.strings = new ArrayList<String>();
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(@Nullable Object value) {
|
|
||||||
if (value instanceof String) {
|
|
||||||
strings.add((String) value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visitEnum(@NotNull ClassId enumClassId, @NotNull Name enumEntryName) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visitEnd() {
|
|
||||||
//noinspection SSBasedInspection
|
|
||||||
visitEnd(strings.toArray(new String[strings.size()]));
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract void visitEnd(@NotNull String[] data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(@Nullable Object value) {
|
||||||
|
if (value instanceof String) {
|
||||||
|
strings.add((String) value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitEnum(@NotNull ClassId enumClassId, @NotNull Name enumEntryName) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitEnd() {
|
||||||
|
//noinspection SSBasedInspection
|
||||||
|
visitEnd(strings.toArray(new String[strings.size()]));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract void visitEnd(@NotNull String[] data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,9 +14,12 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@file:Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER") // kotlin.Metadata
|
||||||
|
|
||||||
package kotlin.reflect.jvm
|
package kotlin.reflect.jvm
|
||||||
|
|
||||||
import org.jetbrains.kotlin.load.kotlin.JvmNameResolver
|
import org.jetbrains.kotlin.load.kotlin.JvmNameResolver
|
||||||
|
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader
|
||||||
import org.jetbrains.kotlin.serialization.ProtoBuf
|
import org.jetbrains.kotlin.serialization.ProtoBuf
|
||||||
import org.jetbrains.kotlin.serialization.deserialization.DeserializationContext
|
import org.jetbrains.kotlin.serialization.deserialization.DeserializationContext
|
||||||
import org.jetbrains.kotlin.serialization.deserialization.MemberDeserializer
|
import org.jetbrains.kotlin.serialization.deserialization.MemberDeserializer
|
||||||
@@ -24,7 +27,6 @@ import org.jetbrains.kotlin.serialization.deserialization.TypeTable
|
|||||||
import org.jetbrains.kotlin.serialization.jvm.BitEncoding
|
import org.jetbrains.kotlin.serialization.jvm.BitEncoding
|
||||||
import org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf
|
import org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf
|
||||||
import org.jetbrains.kotlin.serialization.jvm.JvmProtoBufUtil
|
import org.jetbrains.kotlin.serialization.jvm.JvmProtoBufUtil
|
||||||
import kotlin.jvm.internal.KotlinFunction
|
|
||||||
import kotlin.reflect.KFunction
|
import kotlin.reflect.KFunction
|
||||||
import kotlin.reflect.jvm.internal.EmptyContainerForLocal
|
import kotlin.reflect.jvm.internal.EmptyContainerForLocal
|
||||||
import kotlin.reflect.jvm.internal.KFunctionImpl
|
import kotlin.reflect.jvm.internal.KFunctionImpl
|
||||||
@@ -36,11 +38,11 @@ import kotlin.reflect.jvm.internal.getOrCreateModule
|
|||||||
* Not all features are currently supported, in particular [KCallable.call] and [KCallable.callBy] will fail at the moment.
|
* Not all features are currently supported, in particular [KCallable.call] and [KCallable.callBy] will fail at the moment.
|
||||||
*/
|
*/
|
||||||
fun <R> Function<R>.reflect(): KFunction<R>? {
|
fun <R> Function<R>.reflect(): KFunction<R>? {
|
||||||
val callable = javaClass.getAnnotation(KotlinFunction::class.java) ?: return null
|
val annotation = javaClass.getAnnotation(Metadata::class.java) ?: return null
|
||||||
val input = BitEncoding.decodeBytes(callable.data).inputStream()
|
if (annotation.xi != KotlinClassHeader.SyntheticClassKind.FUNCTION.id) return null
|
||||||
|
val input = BitEncoding.decodeBytes(annotation.d1).inputStream()
|
||||||
val nameResolver = JvmNameResolver(
|
val nameResolver = JvmNameResolver(
|
||||||
JvmProtoBuf.StringTableTypes.parseDelimitedFrom(input, JvmProtoBufUtil.EXTENSION_REGISTRY),
|
JvmProtoBuf.StringTableTypes.parseDelimitedFrom(input, JvmProtoBufUtil.EXTENSION_REGISTRY), annotation.d2
|
||||||
callable.strings
|
|
||||||
)
|
)
|
||||||
val proto = ProtoBuf.Function.parseFrom(input, JvmProtoBufUtil.EXTENSION_REGISTRY)
|
val proto = ProtoBuf.Function.parseFrom(input, JvmProtoBufUtil.EXTENSION_REGISTRY)
|
||||||
val moduleData = javaClass.getOrCreateModule()
|
val moduleData = javaClass.getOrCreateModule()
|
||||||
|
|||||||
Reference in New Issue
Block a user