diff --git a/compiler/frontend.java/frontend.java.iml b/compiler/frontend.java/frontend.java.iml
index 5cd8c2e9746..de19dcc7a1b 100644
--- a/compiler/frontend.java/frontend.java.iml
+++ b/compiler/frontend.java/frontend.java.iml
@@ -14,6 +14,7 @@
+
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 939b5484818..91c70499799 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
@@ -18,6 +18,19 @@ package org.jetbrains.jet.lang.resolve.kotlin;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jetbrains.asm4.ClassReader;
+import org.jetbrains.asm4.ClassVisitor;
+import org.jetbrains.asm4.FieldVisitor;
+import org.jetbrains.asm4.MethodVisitor;
+import org.jetbrains.jet.lang.resolve.java.JvmClassName;
+import org.jetbrains.jet.lang.resolve.name.Name;
+import org.jetbrains.jet.utils.ExceptionUtils;
+
+import java.io.IOException;
+
+import static org.jetbrains.asm4.ClassReader.*;
+import static org.jetbrains.asm4.Opcodes.ASM4;
public class VirtualFileKotlinClass implements KotlinJvmBinaryClass {
private final VirtualFile file;
@@ -32,6 +45,104 @@ public class VirtualFileKotlinClass implements KotlinJvmBinaryClass {
return file;
}
+ @Override
+ public void loadClassAnnotations(@NotNull final AnnotationVisitor annotationVisitor) {
+ try {
+ new ClassReader(file.contentsToByteArray()).accept(new ClassVisitor(ASM4) {
+ @Override
+ public org.jetbrains.asm4.AnnotationVisitor visitAnnotation(String desc, boolean visible) {
+ return convertAnnotationVisitor(annotationVisitor, desc);
+ }
+
+ @Override
+ public void visitEnd() {
+ annotationVisitor.visitEnd();
+ }
+ }, SKIP_CODE | SKIP_DEBUG | SKIP_FRAMES);
+ }
+ catch (IOException e) {
+ throw ExceptionUtils.rethrow(e);
+ }
+ }
+
+ @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;
+
+ return new org.jetbrains.asm4.AnnotationVisitor(ASM4) {
+ @Override
+ public void visit(String name, Object value) {
+ v.visit(Name.identifier(name), value);
+ }
+
+ @Override
+ public void visitEnum(String name, String desc, String value) {
+ v.visitEnum(Name.identifier(name), classNameFromAsmDesc(desc), Name.identifier(value));
+ }
+
+ @Override
+ public void visitEnd() {
+ v.visitEnd();
+ }
+ };
+ }
+
+ @Override
+ public void loadMemberAnnotations(@NotNull final MemberVisitor memberVisitor) {
+ try {
+ new ClassReader(file.contentsToByteArray()).accept(new ClassVisitor(ASM4) {
+ @Override
+ public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) {
+ final AnnotationVisitor v = memberVisitor.visitField(Name.guess(name), desc);
+ if (v == null) return null;
+
+ return new FieldVisitor(ASM4) {
+ @Override
+ public org.jetbrains.asm4.AnnotationVisitor visitAnnotation(String desc, boolean visible) {
+ return convertAnnotationVisitor(v, desc);
+ }
+
+ @Override
+ public void visitEnd() {
+ v.visitEnd();
+ }
+ };
+ }
+
+ @Override
+ public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
+ final AnnotationVisitor v = memberVisitor.visitMethod(Name.guess(name), desc);
+ if (v == null) return null;
+
+ return new MethodVisitor(ASM4) {
+ @Override
+ public org.jetbrains.asm4.AnnotationVisitor visitAnnotation(String desc, boolean visible) {
+ return convertAnnotationVisitor(v, desc);
+ }
+
+ @Override
+ public void visitEnd() {
+ super.visitEnd();
+ }
+ };
+ }
+ }, SKIP_CODE | SKIP_DEBUG | SKIP_FRAMES);
+ }
+ catch (IOException e) {
+ throw ExceptionUtils.rethrow(e);
+ }
+ }
+
+ @NotNull
+ private static JvmClassName classNameFromAsmDesc(@NotNull String desc) {
+ assert desc.startsWith("L") && desc.endsWith(";") : "Not a JVM descriptor: " + desc;
+ return JvmClassName.byInternalName(desc.substring(1, desc.length() - 1));
+ }
+
@Override
public int hashCode() {
return file.hashCode();
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 8616b795382..8ba6bb3dd1c 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
@@ -19,7 +19,6 @@ package org.jetbrains.jet.lang.resolve.kotlin;
import com.intellij.openapi.diagnostic.Logger;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
-import org.jetbrains.asm4.*;
import org.jetbrains.jet.descriptors.serialization.JavaProtoBuf;
import org.jetbrains.jet.descriptors.serialization.NameResolver;
import org.jetbrains.jet.descriptors.serialization.ProtoBuf;
@@ -32,6 +31,7 @@ import org.jetbrains.jet.lang.resolve.constants.EnumValue;
import org.jetbrains.jet.lang.resolve.constants.ErrorValue;
import org.jetbrains.jet.lang.resolve.java.JvmAbi;
import org.jetbrains.jet.lang.resolve.java.JvmAnnotationNames;
+import org.jetbrains.jet.lang.resolve.java.JvmClassName;
import org.jetbrains.jet.lang.resolve.java.PackageClassUtils;
import org.jetbrains.jet.lang.resolve.java.resolver.DescriptorResolverUtils;
import org.jetbrains.jet.lang.resolve.java.resolver.JavaAnnotationArgumentResolver;
@@ -47,7 +47,6 @@ import javax.inject.Inject;
import java.io.IOException;
import java.util.*;
-import static org.jetbrains.asm4.ClassReader.*;
import static org.jetbrains.jet.lang.resolve.java.DescriptorSearchRule.IGNORE_KOTLIN_SOURCES;
import static org.jetbrains.jet.lang.resolve.kotlin.DeserializedResolverUtils.kotlinFqNameToJavaFqName;
import static org.jetbrains.jet.lang.resolve.kotlin.DeserializedResolverUtils.naiveKotlinFqName;
@@ -123,56 +122,54 @@ public class AnnotationDescriptorDeserializer implements AnnotationDeserializer
private List loadClassAnnotationsFromClass(@NotNull KotlinJvmBinaryClass kotlinClass) throws IOException {
final List result = new ArrayList();
- new ClassReader(kotlinClass.getFile().contentsToByteArray()).accept(new ClassVisitor(Opcodes.ASM4) {
+ kotlinClass.loadClassAnnotations(new KotlinJvmBinaryClass.AnnotationVisitor() {
+ @Nullable
@Override
- public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
- return resolveAnnotation(desc, result);
+ public KotlinJvmBinaryClass.AnnotationArgumentVisitor visitAnnotation(@NotNull JvmClassName className) {
+ return resolveAnnotation(className, result);
}
- }, SKIP_CODE | SKIP_DEBUG | SKIP_FRAMES);
+
+ @Override
+ public void visitEnd() {
+ }
+ });
return result;
}
- private static boolean ignoreAnnotation(@NotNull String desc) {
+ private static boolean ignoreAnnotation(@NotNull JvmClassName className) {
// TODO: JvmAbi.JETBRAINS_NOT_NULL_ANNOTATION ?
- return desc.equals(JvmAnnotationNames.KOTLIN_CLASS.getDescriptor())
- || desc.equals(JvmAnnotationNames.KOTLIN_PACKAGE.getDescriptor())
- || desc.startsWith("Ljet/runtime/typeinfo/");
- }
-
- @NotNull
- private static FqName convertJvmDescriptorToFqName(@NotNull String desc) {
- assert desc.startsWith("L") && desc.endsWith(";") : "Not a JVM descriptor: " + desc;
- String fqName = desc.substring(1, desc.length() - 1).replace('$', '.').replace('/', '.');
- return new FqName(fqName);
+ return className.equals(JvmAnnotationNames.KOTLIN_CLASS)
+ || className.equals(JvmAnnotationNames.KOTLIN_PACKAGE)
+ || className.getInternalName().startsWith("jet/runtime/typeinfo/");
}
@Nullable
- private AnnotationVisitor resolveAnnotation(@NotNull String desc, @NotNull final List result) {
- if (ignoreAnnotation(desc)) return null;
+ private KotlinJvmBinaryClass.AnnotationArgumentVisitor resolveAnnotation(
+ @NotNull JvmClassName className,
+ @NotNull final List result
+ ) {
+ if (ignoreAnnotation(className)) return null;
- FqName annotationFqName = convertJvmDescriptorToFqName(desc);
- final ClassDescriptor annotationClass = resolveAnnotationClass(annotationFqName);
+ final ClassDescriptor annotationClass = resolveAnnotationClass(className);
final AnnotationDescriptor annotation = new AnnotationDescriptor();
annotation.setAnnotationType(annotationClass.getDefaultType());
- return new AnnotationVisitor(Opcodes.ASM4) {
- // TODO: arrays, annotations, java.lang.Class
+ return new KotlinJvmBinaryClass.AnnotationArgumentVisitor() {
@Override
- public void visit(String name, Object value) {
+ 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));
}
@Override
- public void visitEnum(String name, String desc, String value) {
- FqName fqName = convertJvmDescriptorToFqName(desc);
- setArgumentValueByName(name, enumEntryValue(fqName, Name.identifier(value)));
+ public void visitEnum(@NotNull Name name, @NotNull JvmClassName enumClassName, @NotNull Name enumEntryName) {
+ setArgumentValueByName(name, enumEntryValue(enumClassName, enumEntryName));
}
@NotNull
- private CompileTimeConstant> enumEntryValue(@NotNull FqName enumFqName, @NotNull Name name) {
- ClassDescriptor enumClass = javaClassResolver.resolveClass(enumFqName, IGNORE_KOTLIN_SOURCES);
+ private CompileTimeConstant> enumEntryValue(@NotNull JvmClassName enumClassName, @NotNull Name name) {
+ ClassDescriptor enumClass = javaClassResolver.resolveClass(enumClassName.getFqName(), IGNORE_KOTLIN_SOURCES);
if (enumClass != null && enumClass.getKind() == ClassKind.ENUM_CLASS) {
ClassDescriptor classObject = enumClass.getClassObjectDescriptor();
if (classObject != null) {
@@ -185,7 +182,7 @@ public class AnnotationDescriptorDeserializer implements AnnotationDeserializer
}
}
}
- return ErrorValue.create("Unresolved enum entry: " + enumFqName + "." + name);
+ return ErrorValue.create("Unresolved enum entry: " + enumClassName.getFqName() + "." + name);
}
@Override
@@ -193,9 +190,8 @@ public class AnnotationDescriptorDeserializer implements AnnotationDeserializer
result.add(annotation);
}
- private void setArgumentValueByName(@NotNull String name, @NotNull CompileTimeConstant> argumentValue) {
- ValueParameterDescriptor parameter =
- DescriptorResolverUtils.getAnnotationParameterByName(Name.identifier(name), annotationClass);
+ private void setArgumentValueByName(@NotNull Name name, @NotNull CompileTimeConstant> argumentValue) {
+ ValueParameterDescriptor parameter = DescriptorResolverUtils.getAnnotationParameterByName(name, annotationClass);
if (parameter != null) {
annotation.setValueArgument(parameter, argumentValue);
}
@@ -204,8 +200,8 @@ public class AnnotationDescriptorDeserializer implements AnnotationDeserializer
}
@NotNull
- private ClassDescriptor resolveAnnotationClass(@NotNull FqName fqName) {
- ClassDescriptor annotationClass = javaClassResolver.resolveClass(fqName, IGNORE_KOTLIN_SOURCES);
+ private ClassDescriptor resolveAnnotationClass(@NotNull JvmClassName className) {
+ ClassDescriptor annotationClass = javaClassResolver.resolveClass(className.getFqName(), IGNORE_KOTLIN_SOURCES);
return annotationClass != null ? annotationClass : ErrorUtils.getErrorClass();
}
@@ -301,11 +297,11 @@ public class AnnotationDescriptorDeserializer implements AnnotationDeserializer
JavaProtoBuf.JavaFieldSignature field = propertySignature.getField();
String type = new SignatureDeserializer(nameResolver).typeDescriptor(field.getType());
Name name = nameResolver.getName(field.getName());
- return MemberSignature.fromFieldNameAndDesc(name.asString(), type);
+ return MemberSignature.fromFieldNameAndDesc(name, type);
}
else if (propertySignature.hasSyntheticMethodName()) {
Name name = nameResolver.getName(propertySignature.getSyntheticMethodName());
- return MemberSignature.fromMethodNameAndDesc(name.asString(), JvmAbi.ANNOTATED_PROPERTY_METHOD_SIGNATURE);
+ return MemberSignature.fromMethodNameAndDesc(name, JvmAbi.ANNOTATED_PROPERTY_METHOD_SIGNATURE);
}
}
break;
@@ -319,47 +315,39 @@ public class AnnotationDescriptorDeserializer implements AnnotationDeserializer
final Map> memberAnnotations =
new HashMap>();
- new ClassReader(kotlinClass.getFile().contentsToByteArray()).accept(new ClassVisitor(Opcodes.ASM4) {
+ kotlinClass.loadMemberAnnotations(new KotlinJvmBinaryClass.MemberVisitor() {
+ @Nullable
@Override
- public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
- final MemberSignature methodSignature = MemberSignature.fromMethodNameAndDesc(name, desc);
- final List result = new ArrayList();
+ public KotlinJvmBinaryClass.AnnotationVisitor visitMethod(@NotNull Name name, @NotNull String desc) {
+ return annotationVisitor(MemberSignature.fromMethodNameAndDesc(name, desc));
+ }
- return new MethodVisitor(Opcodes.ASM4) {
+ @Nullable
+ @Override
+ public KotlinJvmBinaryClass.AnnotationVisitor visitField(@NotNull Name name, @NotNull String desc) {
+ return annotationVisitor(MemberSignature.fromFieldNameAndDesc(name, desc));
+ }
+
+ @NotNull
+ private KotlinJvmBinaryClass.AnnotationVisitor annotationVisitor(@NotNull final MemberSignature signature) {
+ return new KotlinJvmBinaryClass.AnnotationVisitor() {
+ private final List result = new ArrayList();
+
+ @Nullable
@Override
- public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
- return resolveAnnotation(desc, result);
+ public KotlinJvmBinaryClass.AnnotationArgumentVisitor visitAnnotation(@NotNull JvmClassName className) {
+ return resolveAnnotation(className, result);
}
@Override
public void visitEnd() {
if (!result.isEmpty()) {
- memberAnnotations.put(methodSignature, result);
+ memberAnnotations.put(signature, result);
}
}
};
}
-
- @Override
- public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) {
- final MemberSignature fieldSignature = MemberSignature.fromFieldNameAndDesc(name, desc);
- final List result = new ArrayList();
-
- return new FieldVisitor(Opcodes.ASM4) {
- @Override
- public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
- return resolveAnnotation(desc, result);
- }
-
- @Override
- public void visitEnd() {
- if (!result.isEmpty()) {
- memberAnnotations.put(fieldSignature, result);
- }
- }
- };
- }
- }, SKIP_CODE | SKIP_DEBUG | SKIP_FRAMES);
+ });
return memberAnnotations;
}
@@ -374,13 +362,13 @@ public class AnnotationDescriptorDeserializer implements AnnotationDeserializer
}
@NotNull
- public static MemberSignature fromMethodNameAndDesc(@NotNull String name, @NotNull String desc) {
- return new MemberSignature(name + desc);
+ public static MemberSignature fromMethodNameAndDesc(@NotNull Name name, @NotNull String desc) {
+ return new MemberSignature(name.asString() + desc);
}
@NotNull
- public static MemberSignature fromFieldNameAndDesc(@NotNull String name, @NotNull String desc) {
- return new MemberSignature(name + "#" + desc);
+ public static MemberSignature fromFieldNameAndDesc(@NotNull Name name, @NotNull String desc) {
+ return new MemberSignature(name.asString() + "#" + desc);
}
@Override
@@ -411,7 +399,7 @@ public class AnnotationDescriptorDeserializer implements AnnotationDeserializer
@NotNull
public MemberSignature methodSignature(@NotNull JavaProtoBuf.JavaMethodSignature signature) {
- String name = nameResolver.getName(signature.getName()).asString();
+ Name name = nameResolver.getName(signature.getName());
StringBuilder sb = new StringBuilder();
sb.append('(');
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 b4b70d89477..a4ba321d8eb 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
@@ -18,8 +18,41 @@ package org.jetbrains.jet.lang.resolve.kotlin;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jetbrains.jet.lang.resolve.java.JvmClassName;
+import org.jetbrains.jet.lang.resolve.name.Name;
public interface KotlinJvmBinaryClass {
@NotNull
VirtualFile getFile();
+
+ void loadClassAnnotations(@NotNull AnnotationVisitor visitor);
+
+ void loadMemberAnnotations(@NotNull MemberVisitor visitor);
+
+ interface MemberVisitor {
+ // TODO: abstract signatures for methods and fields instead of ASM 'desc' strings?
+
+ @Nullable
+ AnnotationVisitor visitMethod(@NotNull Name name, @NotNull String desc);
+
+ @Nullable
+ AnnotationVisitor visitField(@NotNull Name name, @NotNull String desc);
+ }
+
+ interface AnnotationVisitor {
+ @Nullable
+ AnnotationArgumentVisitor visitAnnotation(@NotNull JvmClassName className);
+
+ void visitEnd();
+ }
+
+ interface AnnotationArgumentVisitor {
+ // TODO: arrays, annotations, java.lang.Class
+ void visit(@NotNull Name name, @Nullable Object value);
+
+ void visitEnum(@NotNull Name name, @NotNull JvmClassName enumClassName, @NotNull Name enumEntryName);
+
+ void visitEnd();
+ }
}