Store ABI version along with serialized descriptors

KotlinInfo annotation now has a version() field, which should be equal to the
compiler's JvmAbi.VERSION in order for this class to properly load and be used.

Create ErrorReporter class, which has a trace to which it can report errors
(now only related to ABI version). This is done because a dependency of
DeserializedDescriptorResolver from BindingTrace would be confusing.
Implementation of ErrorReporter will probably need to change when we untie
deserialization from java-resolve.

Check if PsiClass is actually a compiled class before trying to load serialized
data from it: otherwise it can be a Java source, as was in wrongAbiVersion()
test, and ASM will fail when trying to read that file. Rewrite the test so that
it now has a compiled Kotlin classes to check against (also include sources to
recompile this binary data later, although it won't probably be needed)
This commit is contained in:
Alexander Udalov
2013-07-09 21:04:39 +04:00
parent cc4fd008ad
commit 6ae81c3ade
20 changed files with 170 additions and 68 deletions
@@ -228,6 +228,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
ClassData data = new ClassData(createNameResolver(serializer.getNameTable()), classProto); ClassData data = new ClassData(createNameResolver(serializer.getNameTable()), classProto);
AnnotationVisitor av = v.getVisitor().visitAnnotation(JvmStdlibNames.KOTLIN_INFO_CLASS.getDescriptor(), true); AnnotationVisitor av = v.getVisitor().visitAnnotation(JvmStdlibNames.KOTLIN_INFO_CLASS.getDescriptor(), true);
av.visit("version", JvmAbi.VERSION);
AnnotationVisitor array = av.visitArray("data"); AnnotationVisitor array = av.visitArray("data");
for (String string : JavaProtoBufUtil.encodeBytes(data.toBytes())) { for (String string : JavaProtoBufUtil.encodeBytes(data.toBytes())) {
array.visit(null, string); array.visit(null, string);
@@ -162,6 +162,7 @@ public class NamespaceCodegen extends MemberCodegen {
PackageData data = new PackageData(createNameResolver(serializer.getNameTable()), packageProto.build()); PackageData data = new PackageData(createNameResolver(serializer.getNameTable()), packageProto.build());
AnnotationVisitor av = v.getClassBuilder().newAnnotation(JvmStdlibNames.KOTLIN_INFO_CLASS.getDescriptor(), true); AnnotationVisitor av = v.getClassBuilder().newAnnotation(JvmStdlibNames.KOTLIN_INFO_CLASS.getDescriptor(), true);
av.visit("version", JvmAbi.VERSION);
AnnotationVisitor array = av.visitArray("data"); AnnotationVisitor array = av.visitArray("data");
for (String string : JavaProtoBufUtil.encodeBytes(data.toBytes())) { for (String string : JavaProtoBufUtil.encodeBytes(data.toBytes())) {
array.visit(null, string); array.visit(null, string);
@@ -35,6 +35,7 @@ import org.jetbrains.jet.lang.resolve.java.resolver.JavaValueParameterResolver;
import org.jetbrains.jet.lang.resolve.java.resolver.JavaSignatureResolver; import org.jetbrains.jet.lang.resolve.java.resolver.JavaSignatureResolver;
import org.jetbrains.jet.lang.resolve.java.resolver.DeserializedDescriptorResolver; import org.jetbrains.jet.lang.resolve.java.resolver.DeserializedDescriptorResolver;
import org.jetbrains.jet.lang.resolve.java.resolver.AnnotationDescriptorDeserializer; import org.jetbrains.jet.lang.resolve.java.resolver.AnnotationDescriptorDeserializer;
import org.jetbrains.jet.lang.resolve.java.resolver.ErrorReporter;
import org.jetbrains.jet.lang.resolve.java.resolver.JavaNamespaceResolver; import org.jetbrains.jet.lang.resolve.java.resolver.JavaNamespaceResolver;
import org.jetbrains.jet.lang.resolve.java.resolver.JavaConstructorResolver; import org.jetbrains.jet.lang.resolve.java.resolver.JavaConstructorResolver;
import org.jetbrains.jet.lang.resolve.java.resolver.JavaInnerClassResolver; import org.jetbrains.jet.lang.resolve.java.resolver.JavaInnerClassResolver;
@@ -64,6 +65,7 @@ public class InjectorForJavaDescriptorResolver {
private final JavaSignatureResolver javaSignatureResolver; private final JavaSignatureResolver javaSignatureResolver;
private final DeserializedDescriptorResolver deserializedDescriptorResolver; private final DeserializedDescriptorResolver deserializedDescriptorResolver;
private final AnnotationDescriptorDeserializer annotationDescriptorDeserializer; private final AnnotationDescriptorDeserializer annotationDescriptorDeserializer;
private final ErrorReporter errorReporter;
private final JavaNamespaceResolver javaNamespaceResolver; private final JavaNamespaceResolver javaNamespaceResolver;
private final JavaConstructorResolver javaConstructorResolver; private final JavaConstructorResolver javaConstructorResolver;
private final JavaInnerClassResolver javaInnerClassResolver; private final JavaInnerClassResolver javaInnerClassResolver;
@@ -93,6 +95,7 @@ public class InjectorForJavaDescriptorResolver {
this.javaSignatureResolver = new JavaSignatureResolver(); this.javaSignatureResolver = new JavaSignatureResolver();
this.deserializedDescriptorResolver = new DeserializedDescriptorResolver(); this.deserializedDescriptorResolver = new DeserializedDescriptorResolver();
this.annotationDescriptorDeserializer = new AnnotationDescriptorDeserializer(); this.annotationDescriptorDeserializer = new AnnotationDescriptorDeserializer();
this.errorReporter = new ErrorReporter();
this.javaNamespaceResolver = new JavaNamespaceResolver(); this.javaNamespaceResolver = new JavaNamespaceResolver();
this.javaConstructorResolver = new JavaConstructorResolver(); this.javaConstructorResolver = new JavaConstructorResolver();
this.javaInnerClassResolver = new JavaInnerClassResolver(); this.javaInnerClassResolver = new JavaInnerClassResolver();
@@ -155,12 +158,15 @@ public class InjectorForJavaDescriptorResolver {
javaSignatureResolver.setJavaSemanticServices(javaSemanticServices); javaSignatureResolver.setJavaSemanticServices(javaSemanticServices);
deserializedDescriptorResolver.setAnnotationDeserializer(annotationDescriptorDeserializer); deserializedDescriptorResolver.setAnnotationDeserializer(annotationDescriptorDeserializer);
deserializedDescriptorResolver.setErrorReporter(errorReporter);
deserializedDescriptorResolver.setJavaClassResolver(javaClassResolver); deserializedDescriptorResolver.setJavaClassResolver(javaClassResolver);
deserializedDescriptorResolver.setJavaNamespaceResolver(javaNamespaceResolver); deserializedDescriptorResolver.setJavaNamespaceResolver(javaNamespaceResolver);
annotationDescriptorDeserializer.setJavaClassResolver(javaClassResolver); annotationDescriptorDeserializer.setJavaClassResolver(javaClassResolver);
annotationDescriptorDeserializer.setPsiClassFinder(psiClassFinder); annotationDescriptorDeserializer.setPsiClassFinder(psiClassFinder);
errorReporter.setTrace(bindingTrace);
javaNamespaceResolver.setDeserializedDescriptorResolver(deserializedDescriptorResolver); javaNamespaceResolver.setDeserializedDescriptorResolver(deserializedDescriptorResolver);
javaNamespaceResolver.setJavaSemanticServices(javaSemanticServices); javaNamespaceResolver.setJavaSemanticServices(javaSemanticServices);
javaNamespaceResolver.setPsiClassFinder(psiClassFinder); javaNamespaceResolver.setPsiClassFinder(psiClassFinder);
@@ -35,6 +35,7 @@ import org.jetbrains.jet.lang.resolve.java.resolver.JavaValueParameterResolver;
import org.jetbrains.jet.lang.resolve.java.resolver.JavaSignatureResolver; import org.jetbrains.jet.lang.resolve.java.resolver.JavaSignatureResolver;
import org.jetbrains.jet.lang.resolve.java.resolver.DeserializedDescriptorResolver; import org.jetbrains.jet.lang.resolve.java.resolver.DeserializedDescriptorResolver;
import org.jetbrains.jet.lang.resolve.java.resolver.AnnotationDescriptorDeserializer; import org.jetbrains.jet.lang.resolve.java.resolver.AnnotationDescriptorDeserializer;
import org.jetbrains.jet.lang.resolve.java.resolver.ErrorReporter;
import org.jetbrains.jet.lang.resolve.java.resolver.JavaNamespaceResolver; import org.jetbrains.jet.lang.resolve.java.resolver.JavaNamespaceResolver;
import org.jetbrains.jet.lang.resolve.java.resolver.JavaConstructorResolver; import org.jetbrains.jet.lang.resolve.java.resolver.JavaConstructorResolver;
import org.jetbrains.jet.lang.resolve.java.resolver.JavaInnerClassResolver; import org.jetbrains.jet.lang.resolve.java.resolver.JavaInnerClassResolver;
@@ -64,6 +65,7 @@ public class InjectorForJavaSemanticServices {
private final JavaSignatureResolver javaSignatureResolver; private final JavaSignatureResolver javaSignatureResolver;
private final DeserializedDescriptorResolver deserializedDescriptorResolver; private final DeserializedDescriptorResolver deserializedDescriptorResolver;
private final AnnotationDescriptorDeserializer annotationDescriptorDeserializer; private final AnnotationDescriptorDeserializer annotationDescriptorDeserializer;
private final ErrorReporter errorReporter;
private final JavaNamespaceResolver javaNamespaceResolver; private final JavaNamespaceResolver javaNamespaceResolver;
private final JavaConstructorResolver javaConstructorResolver; private final JavaConstructorResolver javaConstructorResolver;
private final JavaInnerClassResolver javaInnerClassResolver; private final JavaInnerClassResolver javaInnerClassResolver;
@@ -91,6 +93,7 @@ public class InjectorForJavaSemanticServices {
this.javaSignatureResolver = new JavaSignatureResolver(); this.javaSignatureResolver = new JavaSignatureResolver();
this.deserializedDescriptorResolver = new DeserializedDescriptorResolver(); this.deserializedDescriptorResolver = new DeserializedDescriptorResolver();
this.annotationDescriptorDeserializer = new AnnotationDescriptorDeserializer(); this.annotationDescriptorDeserializer = new AnnotationDescriptorDeserializer();
this.errorReporter = new ErrorReporter();
this.javaNamespaceResolver = new JavaNamespaceResolver(); this.javaNamespaceResolver = new JavaNamespaceResolver();
this.javaConstructorResolver = new JavaConstructorResolver(); this.javaConstructorResolver = new JavaConstructorResolver();
this.javaInnerClassResolver = new JavaInnerClassResolver(); this.javaInnerClassResolver = new JavaInnerClassResolver();
@@ -155,12 +158,15 @@ public class InjectorForJavaSemanticServices {
javaSignatureResolver.setJavaSemanticServices(javaSemanticServices); javaSignatureResolver.setJavaSemanticServices(javaSemanticServices);
deserializedDescriptorResolver.setAnnotationDeserializer(annotationDescriptorDeserializer); deserializedDescriptorResolver.setAnnotationDeserializer(annotationDescriptorDeserializer);
deserializedDescriptorResolver.setErrorReporter(errorReporter);
deserializedDescriptorResolver.setJavaClassResolver(javaClassResolver); deserializedDescriptorResolver.setJavaClassResolver(javaClassResolver);
deserializedDescriptorResolver.setJavaNamespaceResolver(javaNamespaceResolver); deserializedDescriptorResolver.setJavaNamespaceResolver(javaNamespaceResolver);
annotationDescriptorDeserializer.setJavaClassResolver(javaClassResolver); annotationDescriptorDeserializer.setJavaClassResolver(javaClassResolver);
annotationDescriptorDeserializer.setPsiClassFinder(psiClassFinder); annotationDescriptorDeserializer.setPsiClassFinder(psiClassFinder);
errorReporter.setTrace(bindingTrace);
javaNamespaceResolver.setDeserializedDescriptorResolver(deserializedDescriptorResolver); javaNamespaceResolver.setDeserializedDescriptorResolver(deserializedDescriptorResolver);
javaNamespaceResolver.setJavaSemanticServices(javaSemanticServices); javaNamespaceResolver.setJavaSemanticServices(javaSemanticServices);
javaNamespaceResolver.setPsiClassFinder(psiClassFinder); javaNamespaceResolver.setPsiClassFinder(psiClassFinder);
@@ -60,6 +60,7 @@ import org.jetbrains.jet.lang.resolve.java.resolver.JavaValueParameterResolver;
import org.jetbrains.jet.lang.resolve.java.resolver.JavaSignatureResolver; import org.jetbrains.jet.lang.resolve.java.resolver.JavaSignatureResolver;
import org.jetbrains.jet.lang.resolve.java.resolver.DeserializedDescriptorResolver; import org.jetbrains.jet.lang.resolve.java.resolver.DeserializedDescriptorResolver;
import org.jetbrains.jet.lang.resolve.java.resolver.AnnotationDescriptorDeserializer; import org.jetbrains.jet.lang.resolve.java.resolver.AnnotationDescriptorDeserializer;
import org.jetbrains.jet.lang.resolve.java.resolver.ErrorReporter;
import org.jetbrains.jet.lang.resolve.java.resolver.JavaNamespaceResolver; import org.jetbrains.jet.lang.resolve.java.resolver.JavaNamespaceResolver;
import org.jetbrains.jet.lang.resolve.java.resolver.JavaConstructorResolver; import org.jetbrains.jet.lang.resolve.java.resolver.JavaConstructorResolver;
import org.jetbrains.jet.lang.resolve.java.resolver.JavaInnerClassResolver; import org.jetbrains.jet.lang.resolve.java.resolver.JavaInnerClassResolver;
@@ -114,6 +115,7 @@ public class InjectorForTopDownAnalyzerForJvm implements InjectorForTopDownAnaly
private final JavaSignatureResolver javaSignatureResolver; private final JavaSignatureResolver javaSignatureResolver;
private final DeserializedDescriptorResolver deserializedDescriptorResolver; private final DeserializedDescriptorResolver deserializedDescriptorResolver;
private final AnnotationDescriptorDeserializer annotationDescriptorDeserializer; private final AnnotationDescriptorDeserializer annotationDescriptorDeserializer;
private final ErrorReporter errorReporter;
private final JavaNamespaceResolver javaNamespaceResolver; private final JavaNamespaceResolver javaNamespaceResolver;
private final JavaConstructorResolver javaConstructorResolver; private final JavaConstructorResolver javaConstructorResolver;
private final JavaInnerClassResolver javaInnerClassResolver; private final JavaInnerClassResolver javaInnerClassResolver;
@@ -169,6 +171,7 @@ public class InjectorForTopDownAnalyzerForJvm implements InjectorForTopDownAnaly
this.javaSignatureResolver = new JavaSignatureResolver(); this.javaSignatureResolver = new JavaSignatureResolver();
this.deserializedDescriptorResolver = new DeserializedDescriptorResolver(); this.deserializedDescriptorResolver = new DeserializedDescriptorResolver();
this.annotationDescriptorDeserializer = new AnnotationDescriptorDeserializer(); this.annotationDescriptorDeserializer = new AnnotationDescriptorDeserializer();
this.errorReporter = new ErrorReporter();
this.javaNamespaceResolver = new JavaNamespaceResolver(); this.javaNamespaceResolver = new JavaNamespaceResolver();
this.javaConstructorResolver = new JavaConstructorResolver(); this.javaConstructorResolver = new JavaConstructorResolver();
this.javaInnerClassResolver = new JavaInnerClassResolver(); this.javaInnerClassResolver = new JavaInnerClassResolver();
@@ -333,12 +336,15 @@ public class InjectorForTopDownAnalyzerForJvm implements InjectorForTopDownAnaly
javaSignatureResolver.setJavaSemanticServices(javaSemanticServices); javaSignatureResolver.setJavaSemanticServices(javaSemanticServices);
deserializedDescriptorResolver.setAnnotationDeserializer(annotationDescriptorDeserializer); deserializedDescriptorResolver.setAnnotationDeserializer(annotationDescriptorDeserializer);
deserializedDescriptorResolver.setErrorReporter(errorReporter);
deserializedDescriptorResolver.setJavaClassResolver(javaClassResolver); deserializedDescriptorResolver.setJavaClassResolver(javaClassResolver);
deserializedDescriptorResolver.setJavaNamespaceResolver(javaNamespaceResolver); deserializedDescriptorResolver.setJavaNamespaceResolver(javaNamespaceResolver);
annotationDescriptorDeserializer.setJavaClassResolver(javaClassResolver); annotationDescriptorDeserializer.setJavaClassResolver(javaClassResolver);
annotationDescriptorDeserializer.setPsiClassFinder(psiClassFinder); annotationDescriptorDeserializer.setPsiClassFinder(psiClassFinder);
errorReporter.setTrace(bindingTrace);
javaNamespaceResolver.setDeserializedDescriptorResolver(deserializedDescriptorResolver); javaNamespaceResolver.setDeserializedDescriptorResolver(deserializedDescriptorResolver);
javaNamespaceResolver.setJavaSemanticServices(javaSemanticServices); javaNamespaceResolver.setJavaSemanticServices(javaSemanticServices);
javaNamespaceResolver.setPsiClassFinder(psiClassFinder); javaNamespaceResolver.setPsiClassFinder(psiClassFinder);
@@ -19,7 +19,6 @@ package org.jetbrains.jet.lang.resolve.java;
import com.intellij.psi.PsiClass; import com.intellij.psi.PsiClass;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.resolve.BindingTrace; import org.jetbrains.jet.lang.resolve.BindingTrace;
import org.jetbrains.jet.lang.resolve.java.kt.PsiAnnotationWithAbiVersion;
import org.jetbrains.jet.util.slicedmap.BasicWritableSlice; import org.jetbrains.jet.util.slicedmap.BasicWritableSlice;
import org.jetbrains.jet.util.slicedmap.Slices; import org.jetbrains.jet.util.slicedmap.Slices;
import org.jetbrains.jet.util.slicedmap.WritableSlice; import org.jetbrains.jet.util.slicedmap.WritableSlice;
@@ -29,19 +28,20 @@ public class AbiVersionUtil {
new BasicWritableSlice<PsiClass, Integer>(Slices.ONLY_REWRITE_TO_EQUAL, true); new BasicWritableSlice<PsiClass, Integer>(Slices.ONLY_REWRITE_TO_EQUAL, true);
public static final int INVALID_VERSION = -1; public static final int INVALID_VERSION = -1;
private AbiVersionUtil() {
}
public static boolean isAbiVersionCompatible(int abiVersion) { public static boolean isAbiVersionCompatible(int abiVersion) {
return abiVersion == JvmAbi.VERSION; return abiVersion == JvmAbi.VERSION;
} }
public static void checkAbiVersion( public static void checkAbiVersion(@NotNull PsiClass psiClass, int version, @NotNull BindingTrace trace) {
@NotNull PsiClass psiClass, if (!isAbiVersionCompatible(version)) {
@NotNull PsiAnnotationWithAbiVersion versionAnnotation, reportIncompatibleAbiVersion(psiClass, version, trace);
@NotNull BindingTrace trace) { }
if (!versionAnnotation.isDefined()) return; }
int abiVersion = versionAnnotation.getAbiVersion(); public static void reportIncompatibleAbiVersion(@NotNull PsiClass psiClass, int version, @NotNull BindingTrace trace) {
if (isAbiVersionCompatible(abiVersion)) return; trace.record(ABI_VERSION_ERRORS, psiClass, version);
trace.record(ABI_VERSION_ERRORS, psiClass, abiVersion);
} }
} }
@@ -26,7 +26,7 @@ public class JvmAbi {
* This constant is used to identify binary format (class file) versions * This constant is used to identify binary format (class file) versions
* If you change class file metadata format and/or naming conventions, please increase this number * If you change class file metadata format and/or naming conventions, please increase this number
*/ */
public static final int VERSION = 6; public static final int VERSION = 7;
public static final String TRAIT_IMPL_CLASS_NAME = "$TImpl"; public static final String TRAIT_IMPL_CLASS_NAME = "$TImpl";
public static final String TRAIT_IMPL_SUFFIX = "$" + TRAIT_IMPL_CLASS_NAME; public static final String TRAIT_IMPL_SUFFIX = "$" + TRAIT_IMPL_CLASS_NAME;
@@ -31,6 +31,7 @@ import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
import org.jetbrains.jet.lang.descriptors.ClassOrNamespaceDescriptor; import org.jetbrains.jet.lang.descriptors.ClassOrNamespaceDescriptor;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor; import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor;
import org.jetbrains.jet.lang.resolve.java.AbiVersionUtil;
import org.jetbrains.jet.lang.resolve.java.JvmStdlibNames; import org.jetbrains.jet.lang.resolve.java.JvmStdlibNames;
import org.jetbrains.jet.lang.resolve.lazy.storage.LockBasedStorageManager; import org.jetbrains.jet.lang.resolve.lazy.storage.LockBasedStorageManager;
import org.jetbrains.jet.lang.resolve.name.FqName; import org.jetbrains.jet.lang.resolve.name.FqName;
@@ -44,6 +45,7 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import static org.jetbrains.asm4.ClassReader.*; import static org.jetbrains.asm4.ClassReader.*;
import static org.jetbrains.jet.lang.resolve.java.AbiVersionUtil.isAbiVersionCompatible;
import static org.jetbrains.jet.lang.resolve.java.DescriptorSearchRule.INCLUDE_KOTLIN; import static org.jetbrains.jet.lang.resolve.java.DescriptorSearchRule.INCLUDE_KOTLIN;
import static org.jetbrains.jet.lang.resolve.java.resolver.DeserializedResolverUtils.getVirtualFile; import static org.jetbrains.jet.lang.resolve.java.resolver.DeserializedResolverUtils.getVirtualFile;
import static org.jetbrains.jet.lang.resolve.java.resolver.DeserializedResolverUtils.kotlinFqNameToJavaFqName; import static org.jetbrains.jet.lang.resolve.java.resolver.DeserializedResolverUtils.kotlinFqNameToJavaFqName;
@@ -59,6 +61,8 @@ public final class DeserializedDescriptorResolver {
private JavaClassResolver javaClassResolver; private JavaClassResolver javaClassResolver;
private ErrorReporter errorReporter;
@NotNull @NotNull
private final DescriptorFinder javaDescriptorFinder = new DescriptorFinder() { private final DescriptorFinder javaDescriptorFinder = new DescriptorFinder() {
@Nullable @Nullable
@@ -89,6 +93,11 @@ public final class DeserializedDescriptorResolver {
this.javaClassResolver = javaClassResolver; this.javaClassResolver = javaClassResolver;
} }
@Inject
public void setErrorReporter(ErrorReporter errorReporter) {
this.errorReporter = errorReporter;
}
@Nullable @Nullable
public ClassDescriptor resolveClass( public ClassDescriptor resolveClass(
@NotNull FqName fqName, @NotNull FqName fqName,
@@ -97,28 +106,25 @@ public final class DeserializedDescriptorResolver {
) { ) {
VirtualFile virtualFile = getVirtualFile(psiClass, fqName, containingDeclaration); VirtualFile virtualFile = getVirtualFile(psiClass, fqName, containingDeclaration);
if (virtualFile == null) { if (virtualFile == null) {
// TODO: use ErrorReporter here
return null; return null;
} }
ClassData classData = readClassDataFromClassFile(virtualFile); ClassData classData = readClassDataFromClassFile(virtualFile, psiClass);
if (classData == null) { if (classData == null) {
return null; return null;
} }
return deserializeClass(classData, fqName, containingDeclaration); return deserializeClass(classData, fqName, containingDeclaration);
} }
@NotNull @Nullable
public JetScope createKotlinPackageScope( public JetScope createKotlinPackageScope(@NotNull PsiClass kotlinPackagePsiClass, @NotNull NamespaceDescriptor packageDescriptor) {
@NotNull FqName fqName,
@NotNull PsiClass kotlinPackagePsiClass,
@NotNull NamespaceDescriptor packageDescriptor
) {
VirtualFile virtualFile = kotlinPackagePsiClass.getContainingFile().getVirtualFile(); VirtualFile virtualFile = kotlinPackagePsiClass.getContainingFile().getVirtualFile();
if (virtualFile == null) { if (virtualFile == null) {
throw new IllegalStateException("Could not find virtual file for " + fqName.asString()); return null;
} }
PackageData packageData = readPackageDataFromClassFile(virtualFile); PackageData packageData = readPackageDataFromClassFile(virtualFile, kotlinPackagePsiClass);
if (packageData == null) { if (packageData == null) {
throw new IllegalStateException("No KotlinInfo annotation stored for " + fqName.asString()); return null;
} }
return DeserializedPackageMemberScope.createScopeFromPackageData(packageDescriptor, packageData, javaDescriptorFinder, return DeserializedPackageMemberScope.createScopeFromPackageData(packageDescriptor, packageData, javaDescriptorFinder,
annotationDeserializer, storageManager); annotationDeserializer, storageManager);
@@ -143,33 +149,32 @@ public final class DeserializedDescriptorResolver {
} }
@Nullable @Nullable
private static ClassData readClassDataFromClassFile(@NotNull VirtualFile virtualFile) { private ClassData readClassDataFromClassFile(@NotNull VirtualFile virtualFile, @NotNull PsiClass psiClass) {
String[] data = getKotlinInfoDataFromClassFile(virtualFile); String[] data = readData(virtualFile, psiClass);
if (data == null) return null; return data == null ? null : JavaProtoBufUtil.readClassDataFrom(data);
return JavaProtoBufUtil.readClassDataFrom(data);
} }
@Nullable @Nullable
private static PackageData readPackageDataFromClassFile(@NotNull VirtualFile virtualFile) { private PackageData readPackageDataFromClassFile(@NotNull VirtualFile virtualFile, @NotNull PsiClass psiClass) {
String[] data = getKotlinInfoDataFromClassFile(virtualFile); String[] data = readData(virtualFile, psiClass);
if (data == null) return null; return data == null ? null : JavaProtoBufUtil.readPackageDataFrom(data);
return JavaProtoBufUtil.readPackageDataFrom(data);
} }
@Nullable @Nullable
private static String[] getKotlinInfoDataFromClassFile(@NotNull VirtualFile virtualFile) { private String[] readData(@NotNull VirtualFile virtualFile, @NotNull PsiClass psiClass) {
GetKotlinInfoDataVisitor visitor = visitClassFile(virtualFile); GetKotlinInfoDataVisitor visitor = visitClassFile(virtualFile);
if (visitor == null) { int version = visitor.getVersion();
return null;
}
String[] data = visitor.getData(); String[] data = visitor.getData();
if (data == null) { if (isAbiVersionCompatible(version)) {
return null; return data;
} }
return data; if (data != null) {
errorReporter.reportIncompatibleAbiVersion(psiClass, version);
}
return null;
} }
@Nullable @NotNull
private static GetKotlinInfoDataVisitor visitClassFile(@NotNull VirtualFile virtualFile) { private static GetKotlinInfoDataVisitor visitClassFile(@NotNull VirtualFile virtualFile) {
try { try {
InputStream inputStream = virtualFile.getInputStream(); InputStream inputStream = virtualFile.getInputStream();
@@ -193,6 +198,8 @@ public final class DeserializedDescriptorResolver {
super(Opcodes.ASM4); super(Opcodes.ASM4);
} }
private int version = AbiVersionUtil.INVALID_VERSION;
@Nullable @Nullable
private String[] data = null; private String[] data = null;
@@ -204,11 +211,29 @@ public final class DeserializedDescriptorResolver {
return new AnnotationVisitor(Opcodes.ASM4) { return new AnnotationVisitor(Opcodes.ASM4) {
@Override @Override
public AnnotationVisitor visitArray(String name) { public void visit(String name, Object value) {
if (!name.equals("data")) { if (name.equals("version")) {
version = (Integer) value;
}
else if (isAbiVersionCompatible(version)) {
throw new IllegalStateException("Unexpected argument " + name + " for annotation " + KOTLIN_INFO_TYPE); throw new IllegalStateException("Unexpected argument " + name + " for annotation " + KOTLIN_INFO_TYPE);
} }
}
@Override
public AnnotationVisitor visitArray(String name) {
if (name.equals("data")) {
return stringArrayVisitor();
}
else if (isAbiVersionCompatible(version)) {
throw new IllegalStateException("Unexpected array argument " + name + " for annotation " + KOTLIN_INFO_TYPE);
}
return super.visitArray(name);
}
@NotNull
private AnnotationVisitor stringArrayVisitor() {
final List<String> strings = new ArrayList<String>(1); final List<String> strings = new ArrayList<String>(1);
return new AnnotationVisitor(Opcodes.ASM4) { return new AnnotationVisitor(Opcodes.ASM4) {
@Override @Override
@@ -229,6 +254,10 @@ public final class DeserializedDescriptorResolver {
}; };
} }
public int getVersion() {
return version;
}
@Nullable @Nullable
public String[] getData() { public String[] getData() {
return data; return data;
@@ -0,0 +1,37 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.lang.resolve.java.resolver;
import com.intellij.psi.PsiClass;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.resolve.BindingTrace;
import org.jetbrains.jet.lang.resolve.java.AbiVersionUtil;
import javax.inject.Inject;
public class ErrorReporter {
private BindingTrace trace;
@Inject
public void setTrace(BindingTrace trace) {
this.trace = trace;
}
public void reportIncompatibleAbiVersion(@NotNull PsiClass psiClass, int version) {
AbiVersionUtil.reportIncompatibleAbiVersion(psiClass, version, trace);
}
}
@@ -237,7 +237,6 @@ public final class JavaClassResolver {
@NotNull FqName fqName, @NotNull PsiClass psiClass, @NotNull FqName fqName, @NotNull PsiClass psiClass,
@NotNull PostponedTasks taskList @NotNull PostponedTasks taskList
) { ) {
checkFqNamesAreConsistent(psiClass, fqName); checkFqNamesAreConsistent(psiClass, fqName);
DescriptorResolverUtils.checkPsiClassIsNotJet(psiClass); DescriptorResolverUtils.checkPsiClassIsNotJet(psiClass);
@@ -267,7 +266,9 @@ public final class JavaClassResolver {
@NotNull ClassOrNamespaceDescriptor containingDeclaration @NotNull ClassOrNamespaceDescriptor containingDeclaration
) { ) {
JetClassAnnotation jetClassAnnotation = JetClassAnnotation.get(psiClass); JetClassAnnotation jetClassAnnotation = JetClassAnnotation.get(psiClass);
AbiVersionUtil.checkAbiVersion(psiClass, jetClassAnnotation, trace); if (jetClassAnnotation.isDefined()) {
AbiVersionUtil.checkAbiVersion(psiClass, jetClassAnnotation.getAbiVersion(), trace);
}
ClassKind kind = getClassKind(psiClass, jetClassAnnotation); ClassKind kind = getClassKind(psiClass, jetClassAnnotation);
ClassPsiDeclarationProvider classData = semanticServices.getPsiDeclarationProviderFactory().createBinaryClassData(psiClass); ClassPsiDeclarationProvider classData = semanticServices.getPsiDeclarationProviderFactory().createBinaryClassData(psiClass);
@@ -19,6 +19,7 @@ package org.jetbrains.jet.lang.resolve.java.resolver;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import com.intellij.psi.*; import com.intellij.psi.*;
import com.intellij.psi.impl.compiled.ClsClassImpl;
import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@@ -36,6 +37,7 @@ import org.jetbrains.jet.lang.resolve.java.provider.MembersCache;
import org.jetbrains.jet.lang.resolve.java.scope.JavaBaseScope; import org.jetbrains.jet.lang.resolve.java.scope.JavaBaseScope;
import org.jetbrains.jet.lang.resolve.java.scope.JavaClassStaticMembersScope; import org.jetbrains.jet.lang.resolve.java.scope.JavaClassStaticMembersScope;
import org.jetbrains.jet.lang.resolve.java.scope.JavaPackageScopeWithoutMembers; import org.jetbrains.jet.lang.resolve.java.scope.JavaPackageScopeWithoutMembers;
import org.jetbrains.jet.lang.resolve.java.wrapper.PsiClassWrapper;
import org.jetbrains.jet.lang.resolve.name.FqName; import org.jetbrains.jet.lang.resolve.name.FqName;
import org.jetbrains.jet.lang.resolve.scopes.JetScope; import org.jetbrains.jet.lang.resolve.scopes.JetScope;
@@ -44,6 +46,8 @@ import java.util.Collections;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import static org.jetbrains.jet.lang.resolve.java.AbiVersionUtil.INVALID_VERSION;
public final class JavaNamespaceResolver { public final class JavaNamespaceResolver {
@NotNull @NotNull
@@ -160,12 +164,24 @@ public final class JavaNamespaceResolver {
if (psiPackage != null) { if (psiPackage != null) {
PsiClass psiClass = getPsiClassForJavaPackageScope(fqName); PsiClass psiClass = getPsiClassForJavaPackageScope(fqName);
trace.record(JavaBindingContext.JAVA_NAMESPACE_KIND, namespaceDescriptor, JavaNamespaceKind.PROPER); trace.record(JavaBindingContext.JAVA_NAMESPACE_KIND, namespaceDescriptor, JavaNamespaceKind.PROPER);
if (psiClass == null || !isCompiledKotlinClass(psiClass)) {
return new JavaPackageScopeWithoutMembers(namespaceDescriptor, javaSemanticServices.getPsiDeclarationProviderFactory() if (psiClass != null) {
.createDeclarationProviderForNamespaceWithoutMembers(psiPackage), fqName, javaSemanticServices); boolean compiledKotlinClass = isCompiledKotlinClass(psiClass);
if (isOldKotlinPackageClass(psiClass) && !compiledKotlinClass) {
// If psiClass has old annotations (@JetPackage) but doesn't have @KotlinInfo, report ABI version error
AbiVersionUtil.checkAbiVersion(psiClass, INVALID_VERSION, trace);
}
if (compiledKotlinClass) {
// If psiClass has @KotlinInfo (regardless of whether it has @JetPackage or not), deserialize it to Kotlin descriptor.
// Note that @KotlinInfo may still have an old ABI version, in which case null is returned by createKotlinPackageScope
JetScope kotlinPackageScope = deserializedDescriptorResolver.createKotlinPackageScope(psiClass, namespaceDescriptor);
if (kotlinPackageScope != null) return kotlinPackageScope;
}
} }
return createScopeForKotlinPackageClass(fqName, namespaceDescriptor, psiClass); // Otherwise (if psiClass is null or doesn't have a supported Kotlin annotation), it's a Java class and the package is empty
return new JavaPackageScopeWithoutMembers(namespaceDescriptor, javaSemanticServices.getPsiDeclarationProviderFactory()
.createDeclarationProviderForNamespaceWithoutMembers(psiPackage), fqName, javaSemanticServices);
} }
PsiClass psiClass = psiClassFinder.findPsiClass(fqName, PsiClassFinder.RuntimeClassesHandleMode.IGNORE); PsiClass psiClass = psiClassFinder.findPsiClass(fqName, PsiClassFinder.RuntimeClassesHandleMode.IGNORE);
@@ -185,19 +201,21 @@ public final class JavaNamespaceResolver {
fqName, javaSemanticServices); fqName, javaSemanticServices);
} }
private static boolean isCompiledKotlinClass(@NotNull PsiClass psiClass) { private static boolean isOldKotlinPackageClass(@NotNull PsiClass psiClass) {
PsiModifierList list = psiClass.getModifierList(); return new PsiClassWrapper(psiClass).getJetPackageClass().isDefined();
return list != null && list.findAnnotation(JvmStdlibNames.KOTLIN_INFO_CLASS.getFqName().asString()) != null;
} }
@NotNull private static boolean isCompiledKotlinClass(@NotNull PsiClass psiClass) {
private JetScope createScopeForKotlinPackageClass( // TODO: merge this method with DescriptorResolverUtils#isKotlinClass
@NotNull FqName fqName, // NOTE: we need to check against ClsClassImpl because it can be a Java source, pretending to be a Kotlin class.
@NotNull NamespaceDescriptor namespaceDescriptor, // In that case we can't really read the annotation from psiClass's virtual file
@NotNull PsiClass psiClass if (psiClass instanceof ClsClassImpl) {
) { PsiModifierList list = psiClass.getModifierList();
//TODO: check abi version if (list != null) {
return deserializedDescriptorResolver.createKotlinPackageScope(fqName, psiClass, namespaceDescriptor); return list.findAnnotation(JvmStdlibNames.KOTLIN_INFO_CLASS.getFqName().asString()) != null;
}
}
return false;
} }
private void cache(@NotNull FqName fqName, @Nullable JetScope packageScope) { private void cache(@NotNull FqName fqName, @Nullable JetScope packageScope) {
+3 -2
View File
@@ -1,4 +1,5 @@
WARNING: $TESTDATA_DIR$/wrongAbiVersion.kt: (3, 9) Parameter 'x' is never used WARNING: $TESTDATA_DIR$/wrongAbiVersion.kt: (3, 9) Parameter 'x' is never used
ERROR: $TESTDATA_DIR$/wrongAbiVersionLib/wrong/WrongPackage.java: (3, 1) Class 'wrong.WrongPackage' was compiled with an incompatible version of Kotlin. Its ABI version is -1, expected ABI version is 6 ERROR: $TESTDATA_DIR$/wrongAbiVersion.kt: (4, 3) Unresolved reference: bar
ERROR: $TESTDATA_DIR$/wrongAbiVersionLib/ClassWithWrongAbiVersion.java: (3, 1) Class 'ClassWithWrongAbiVersion' was compiled with an incompatible version of Kotlin. Its ABI version is -1, expected ABI version is 6 ERROR: $TESTDATA_DIR$/wrongAbiVersionLib/wrong/WrongPackage.class: (-1, 135) Class 'wrong.WrongPackage' was compiled with an incompatible version of Kotlin. Its ABI version is -1, expected ABI version is 7
ERROR: $TESTDATA_DIR$/wrongAbiVersionLib/ClassWithWrongAbiVersion.class: (-1, 119) Class 'ClassWithWrongAbiVersion' was compiled with an incompatible version of Kotlin. Its ABI version is -1, expected ABI version is 7
COMPILATION_ERROR COMPILATION_ERROR
@@ -1,4 +0,0 @@
import jet.runtime.typeinfo.JetClass;
@JetClass("Ljava/lang/Object;", 16, -1)
class ClassWithWrongAbiVersion {}
@@ -0,0 +1 @@
class ClassWithWrongAbiVersion
@@ -0,0 +1,3 @@
package wrong
fun bar() {}
@@ -1,6 +0,0 @@
package wrong;
@jet.runtime.typeinfo.JetPackageClass(abiVersion = -1)
public class WrongPackage {
public static void bar() {}
}
+2
View File
@@ -21,5 +21,7 @@ import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
public @interface KotlinInfo { public @interface KotlinInfo {
int version();
String[] data(); String[] data();
} }