From 3087c6f584792a21128e2bd696d5469f3354a144 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Thu, 26 Sep 2013 16:21:12 +0400 Subject: [PATCH] ReadDataFromAnnotationVisitor doesn't depend on ASM anymore --- .../kotlin/VirtualFileKotlinClass.java | 22 ++-- .../AnnotationDescriptorDeserializer.java | 15 ++- .../resolve/kotlin/KotlinJvmBinaryClass.java | 7 +- .../kotlin/header/KotlinClassFileHeader.java | 17 +-- .../header/ReadDataFromAnnotationVisitor.java | 119 ++++++++++++------ 5 files changed, 116 insertions(+), 64 deletions(-) diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/kotlin/VirtualFileKotlinClass.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/kotlin/VirtualFileKotlinClass.java index 0de5fc752a0..64f3d6499c5 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/kotlin/VirtualFileKotlinClass.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/kotlin/VirtualFileKotlinClass.java @@ -87,17 +87,23 @@ public class VirtualFileKotlinClass implements KotlinJvmBinaryClass { } @Nullable - private static org.jetbrains.asm4.AnnotationVisitor convertAnnotationVisitor( - @NotNull AnnotationVisitor visitor, - @NotNull String desc - ) { - final AnnotationArgumentVisitor v = visitor.visitAnnotation(classNameFromAsmDesc(desc)); - if (v == null) return null; + private static org.jetbrains.asm4.AnnotationVisitor convertAnnotationVisitor(@NotNull AnnotationVisitor visitor, @NotNull String desc) { + AnnotationArgumentVisitor v = visitor.visitAnnotation(classNameFromAsmDesc(desc)); + return v == null ? null : convertAnnotationVisitor(v); + } + @NotNull + private static org.jetbrains.asm4.AnnotationVisitor convertAnnotationVisitor(@NotNull final AnnotationArgumentVisitor v) { return new org.jetbrains.asm4.AnnotationVisitor(ASM4) { @Override public void visit(String name, Object value) { - v.visit(Name.identifier(name), value); + v.visit(name == null ? null : Name.identifier(name), value); + } + + @Override + public org.jetbrains.asm4.AnnotationVisitor visitArray(String name) { + AnnotationArgumentVisitor av = v.visitArray(Name.guess(name)); + return av == null ? null : convertAnnotationVisitor(av); } @Override @@ -147,7 +153,7 @@ public class VirtualFileKotlinClass implements KotlinJvmBinaryClass { @Override public void visitEnd() { - super.visitEnd(); + v.visitEnd(); } }; } diff --git a/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/kotlin/AnnotationDescriptorDeserializer.java b/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/kotlin/AnnotationDescriptorDeserializer.java index 8ba6bb3dd1c..f95fc88c09d 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/kotlin/AnnotationDescriptorDeserializer.java +++ b/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/kotlin/AnnotationDescriptorDeserializer.java @@ -157,9 +157,11 @@ public class AnnotationDescriptorDeserializer implements AnnotationDeserializer return new KotlinJvmBinaryClass.AnnotationArgumentVisitor() { @Override - public void visit(@NotNull Name name, @Nullable Object value) { - CompileTimeConstant argument = JavaAnnotationArgumentResolver.resolveCompileTimeConstantValue(value, null); - setArgumentValueByName(name, argument != null ? argument : ErrorValue.create("Unsupported annotation argument: " + name)); + public void visit(@Nullable Name name, @Nullable Object value) { + if (name != null) { + CompileTimeConstant argument = JavaAnnotationArgumentResolver.resolveCompileTimeConstantValue(value, null); + setArgumentValueByName(name, argument != null ? argument : ErrorValue.create("Unsupported annotation argument: " + name)); + } } @Override @@ -167,6 +169,13 @@ public class AnnotationDescriptorDeserializer implements AnnotationDeserializer setArgumentValueByName(name, enumEntryValue(enumClassName, enumEntryName)); } + @Nullable + @Override + public KotlinJvmBinaryClass.AnnotationArgumentVisitor visitArray(@NotNull Name name) { + // TODO: support arrays + return null; + } + @NotNull private CompileTimeConstant enumEntryValue(@NotNull JvmClassName enumClassName, @NotNull Name name) { ClassDescriptor enumClass = javaClassResolver.resolveClass(enumClassName.getFqName(), IGNORE_KOTLIN_SOURCES); diff --git a/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/kotlin/KotlinJvmBinaryClass.java b/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/kotlin/KotlinJvmBinaryClass.java index 61cfe10b753..50ec310c9e3 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/kotlin/KotlinJvmBinaryClass.java +++ b/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/kotlin/KotlinJvmBinaryClass.java @@ -51,11 +51,14 @@ public interface KotlinJvmBinaryClass { } interface AnnotationArgumentVisitor { - // TODO: arrays, annotations, java.lang.Class - void visit(@NotNull Name name, @Nullable Object value); + // TODO: annotations, java.lang.Class + void visit(@Nullable Name name, @Nullable Object value); void visitEnum(@NotNull Name name, @NotNull JvmClassName enumClassName, @NotNull Name enumEntryName); + @Nullable + AnnotationArgumentVisitor visitArray(@NotNull Name name); + void visitEnd(); } } diff --git a/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/kotlin/header/KotlinClassFileHeader.java b/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/kotlin/header/KotlinClassFileHeader.java index 7167623cdc1..ad05edde39f 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/kotlin/header/KotlinClassFileHeader.java +++ b/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/kotlin/header/KotlinClassFileHeader.java @@ -18,25 +18,14 @@ package org.jetbrains.jet.lang.resolve.kotlin.header; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.asm4.ClassReader; import org.jetbrains.jet.lang.resolve.kotlin.KotlinJvmBinaryClass; -import java.io.IOException; - -import static org.jetbrains.asm4.ClassReader.*; - public abstract class KotlinClassFileHeader { @Nullable public static KotlinClassFileHeader readKotlinHeaderFromClassFile(@NotNull KotlinJvmBinaryClass kotlinClass) { - try { - ClassReader reader = new ClassReader(kotlinClass.getFile().contentsToByteArray()); - ReadDataFromAnnotationVisitor visitor = new ReadDataFromAnnotationVisitor(); - reader.accept(visitor, SKIP_CODE | SKIP_FRAMES | SKIP_DEBUG); - return visitor.createHeader(kotlinClass); - } - catch (IOException e) { - throw new RuntimeException(e); - } + ReadDataFromAnnotationVisitor visitor = new ReadDataFromAnnotationVisitor(); + kotlinClass.loadClassAnnotations(visitor); + return visitor.createHeader(kotlinClass); } private final int version; diff --git a/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/kotlin/header/ReadDataFromAnnotationVisitor.java b/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/kotlin/header/ReadDataFromAnnotationVisitor.java index 2f26cb25aaa..712f9a8e787 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/kotlin/header/ReadDataFromAnnotationVisitor.java +++ b/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/kotlin/header/ReadDataFromAnnotationVisitor.java @@ -19,20 +19,20 @@ package org.jetbrains.jet.lang.resolve.kotlin.header; import com.intellij.openapi.diagnostic.Logger; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.asm4.AnnotationVisitor; -import org.jetbrains.asm4.ClassVisitor; -import org.jetbrains.asm4.Opcodes; import org.jetbrains.jet.lang.resolve.java.AbiVersionUtil; import org.jetbrains.jet.lang.resolve.java.JvmAnnotationNames; import org.jetbrains.jet.lang.resolve.java.JvmClassName; import org.jetbrains.jet.lang.resolve.kotlin.KotlinJvmBinaryClass; +import org.jetbrains.jet.lang.resolve.name.Name; import java.util.ArrayList; import java.util.List; import static org.jetbrains.jet.lang.resolve.java.AbiVersionUtil.isAbiVersionCompatible; +import static org.jetbrains.jet.lang.resolve.kotlin.KotlinJvmBinaryClass.AnnotationArgumentVisitor; +import static org.jetbrains.jet.lang.resolve.kotlin.KotlinJvmBinaryClass.AnnotationVisitor; -/* package */ class ReadDataFromAnnotationVisitor extends ClassVisitor { +/* package */ class ReadDataFromAnnotationVisitor implements AnnotationVisitor { private static final Logger LOG = Logger.getInstance(ReadDataFromAnnotationVisitor.class); @SuppressWarnings("deprecation") @@ -51,9 +51,9 @@ import static org.jetbrains.jet.lang.resolve.java.AbiVersionUtil.isAbiVersionCom } @Nullable - private static HeaderType byDescriptor(@NotNull String desc) { + private static HeaderType byClassName(@NotNull JvmClassName className) { for (HeaderType headerType : HeaderType.values()) { - if (desc.equals(headerType.annotation.getDescriptor())) { + if (className.equals(headerType.annotation)) { return headerType; } } @@ -67,10 +67,6 @@ import static org.jetbrains.jet.lang.resolve.java.AbiVersionUtil.isAbiVersionCom @Nullable private HeaderType foundType = null; - public ReadDataFromAnnotationVisitor() { - super(Opcodes.ASM4); - } - @Nullable public KotlinClassFileHeader createHeader(@NotNull KotlinJvmBinaryClass kotlinClass) { if (foundType == null) { @@ -102,9 +98,10 @@ import static org.jetbrains.jet.lang.resolve.java.AbiVersionUtil.isAbiVersionCom return new SerializedDataHeader(version, annotationData, kind); } + @Nullable @Override - public AnnotationVisitor visitAnnotation(String desc, boolean visible) { - HeaderType newType = HeaderType.byDescriptor(desc); + public AnnotationArgumentVisitor visitAnnotation(@NotNull JvmClassName annotationClassName) { + HeaderType newType = HeaderType.byClassName(annotationClassName); if (newType == null) return null; if (foundType != null) { @@ -115,41 +112,51 @@ import static org.jetbrains.jet.lang.resolve.java.AbiVersionUtil.isAbiVersionCom foundType = newType; if (newType == HeaderType.CLASS || newType == HeaderType.PACKAGE) { - return kotlinClassOrPackageVisitor(desc); + return kotlinClassOrPackageVisitor(annotationClassName); } else if (newType == HeaderType.PACKAGE_FRAGMENT) { - return kotlinPackageFragmentVisitor(desc); + return kotlinPackageFragmentVisitor(annotationClassName); } return null; } + @Override + public void visitEnd() { + } + @NotNull - private AnnotationVisitor kotlinClassOrPackageVisitor(final String desc) { - return new AnnotationVisitor(Opcodes.ASM4) { + private AnnotationArgumentVisitor kotlinClassOrPackageVisitor(@NotNull final JvmClassName annotationClassName) { + return new AnnotationArgumentVisitor() { @Override - public void visit(String name, Object value) { - visitIntValueForSupportedAnnotation(name, value, desc); + public void visit(@Nullable Name name, @Nullable Object value) { + visitIntValueForSupportedAnnotation(name, value, annotationClassName); } @Override - public AnnotationVisitor visitArray(String name) { - if (name.equals(JvmAnnotationNames.DATA_FIELD_NAME)) { + public void visitEnum(@NotNull Name name, @NotNull JvmClassName enumClassName, @NotNull Name enumEntryName) { + unexpectedArgument(name, annotationClassName); + } + + @Override + @Nullable + public AnnotationArgumentVisitor visitArray(@NotNull Name name) { + if (name.asString().equals(JvmAnnotationNames.DATA_FIELD_NAME)) { return stringArrayVisitor(); } else if (isAbiVersionCompatible(version)) { - throw new IllegalStateException("Unexpected array argument " + name + " for annotation " + desc); + throw new IllegalStateException("Unexpected array argument " + name + " for annotation " + annotationClassName); } - return super.visitArray(name); + return null; } @NotNull - private AnnotationVisitor stringArrayVisitor() { + private AnnotationArgumentVisitor stringArrayVisitor() { final List strings = new ArrayList(1); - return new AnnotationVisitor(Opcodes.ASM4) { + return new AnnotationArgumentVisitor() { @Override - public void visit(String name, Object value) { + public void visit(@Nullable Name name, @Nullable Object value) { if (!(value instanceof String)) { throw new IllegalStateException("Unexpected argument value: " + value); } @@ -157,31 +164,69 @@ import static org.jetbrains.jet.lang.resolve.java.AbiVersionUtil.isAbiVersionCom strings.add((String) value); } + @Override + public void visitEnum(@NotNull Name name, @NotNull JvmClassName enumClassName, @NotNull Name enumEntryName) { + unexpectedArgument(name, annotationClassName); + } + + @Nullable + @Override + public AnnotationArgumentVisitor visitArray(@NotNull Name name) { + return unexpectedArgument(name, annotationClassName); + } + @Override public void visitEnd() { annotationData = strings.toArray(new String[strings.size()]); } }; } - }; - } - @NotNull - private AnnotationVisitor kotlinPackageFragmentVisitor(final String desc) { - return new AnnotationVisitor(Opcodes.ASM4) { @Override - public void visit(String name, Object value) { - visitIntValueForSupportedAnnotation(name, value, desc); + public void visitEnd() { } }; } - private void visitIntValueForSupportedAnnotation(@NotNull String name, @NotNull Object value, @NotNull String desc) { - if (name.equals(JvmAnnotationNames.ABI_VERSION_FIELD_NAME)) { - version = (Integer) value; + @NotNull + private AnnotationArgumentVisitor kotlinPackageFragmentVisitor(@NotNull final JvmClassName annotationClassName) { + return new AnnotationArgumentVisitor() { + @Override + public void visit(@Nullable Name name, @Nullable Object value) { + visitIntValueForSupportedAnnotation(name, value, annotationClassName); + } + + @Override + public void visitEnum(@NotNull Name name, @NotNull JvmClassName enumClassName, @NotNull Name enumEntryName) { + unexpectedArgument(name, annotationClassName); + } + + @Nullable + @Override + public AnnotationArgumentVisitor visitArray(@NotNull Name name) { + return unexpectedArgument(name, annotationClassName); + } + + @Override + public void visitEnd() { + } + }; + } + + private void visitIntValueForSupportedAnnotation(@Nullable Name name, @Nullable Object value, @NotNull JvmClassName className) { + if (name != null && name.asString().equals(JvmAnnotationNames.ABI_VERSION_FIELD_NAME)) { + version = value == null ? AbiVersionUtil.INVALID_VERSION : (Integer) value; } - else if (isAbiVersionCompatible(version)) { - throw new IllegalStateException("Unexpected argument " + name + " for annotation " + desc); + else { + unexpectedArgument(name, className); } } + + @Nullable + private AnnotationArgumentVisitor unexpectedArgument(@Nullable Name name, @NotNull JvmClassName annotationClassName) { + if (isAbiVersionCompatible(version)) { + throw new IllegalStateException("Unexpected argument " + name + " for annotation " + annotationClassName); + } + return null; + } }