diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java index 7281a619e98..e97b5e76306 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java @@ -228,6 +228,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { ClassData data = new ClassData(createNameResolver(serializer.getNameTable()), classProto); AnnotationVisitor av = v.getVisitor().visitAnnotation(JvmStdlibNames.KOTLIN_INFO_CLASS.getDescriptor(), true); + av.visit("version", JvmAbi.VERSION); AnnotationVisitor array = av.visitArray("data"); for (String string : JavaProtoBufUtil.encodeBytes(data.toBytes())) { array.visit(null, string); diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/NamespaceCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/NamespaceCodegen.java index 3742e06a0b6..825d2ee525c 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/NamespaceCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/NamespaceCodegen.java @@ -162,6 +162,7 @@ public class NamespaceCodegen extends MemberCodegen { PackageData data = new PackageData(createNameResolver(serializer.getNameTable()), packageProto.build()); AnnotationVisitor av = v.getClassBuilder().newAnnotation(JvmStdlibNames.KOTLIN_INFO_CLASS.getDescriptor(), true); + av.visit("version", JvmAbi.VERSION); AnnotationVisitor array = av.visitArray("data"); for (String string : JavaProtoBufUtil.encodeBytes(data.toBytes())) { array.visit(null, string); diff --git a/compiler/frontend.java/src/org/jetbrains/jet/di/InjectorForJavaDescriptorResolver.java b/compiler/frontend.java/src/org/jetbrains/jet/di/InjectorForJavaDescriptorResolver.java index 6a86f6e7178..2d850541ad2 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/di/InjectorForJavaDescriptorResolver.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/di/InjectorForJavaDescriptorResolver.java @@ -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.DeserializedDescriptorResolver; 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.JavaConstructorResolver; import org.jetbrains.jet.lang.resolve.java.resolver.JavaInnerClassResolver; @@ -64,6 +65,7 @@ public class InjectorForJavaDescriptorResolver { private final JavaSignatureResolver javaSignatureResolver; private final DeserializedDescriptorResolver deserializedDescriptorResolver; private final AnnotationDescriptorDeserializer annotationDescriptorDeserializer; + private final ErrorReporter errorReporter; private final JavaNamespaceResolver javaNamespaceResolver; private final JavaConstructorResolver javaConstructorResolver; private final JavaInnerClassResolver javaInnerClassResolver; @@ -93,6 +95,7 @@ public class InjectorForJavaDescriptorResolver { this.javaSignatureResolver = new JavaSignatureResolver(); this.deserializedDescriptorResolver = new DeserializedDescriptorResolver(); this.annotationDescriptorDeserializer = new AnnotationDescriptorDeserializer(); + this.errorReporter = new ErrorReporter(); this.javaNamespaceResolver = new JavaNamespaceResolver(); this.javaConstructorResolver = new JavaConstructorResolver(); this.javaInnerClassResolver = new JavaInnerClassResolver(); @@ -155,12 +158,15 @@ public class InjectorForJavaDescriptorResolver { javaSignatureResolver.setJavaSemanticServices(javaSemanticServices); deserializedDescriptorResolver.setAnnotationDeserializer(annotationDescriptorDeserializer); + deserializedDescriptorResolver.setErrorReporter(errorReporter); deserializedDescriptorResolver.setJavaClassResolver(javaClassResolver); deserializedDescriptorResolver.setJavaNamespaceResolver(javaNamespaceResolver); annotationDescriptorDeserializer.setJavaClassResolver(javaClassResolver); annotationDescriptorDeserializer.setPsiClassFinder(psiClassFinder); + errorReporter.setTrace(bindingTrace); + javaNamespaceResolver.setDeserializedDescriptorResolver(deserializedDescriptorResolver); javaNamespaceResolver.setJavaSemanticServices(javaSemanticServices); javaNamespaceResolver.setPsiClassFinder(psiClassFinder); diff --git a/compiler/frontend.java/src/org/jetbrains/jet/di/InjectorForJavaSemanticServices.java b/compiler/frontend.java/src/org/jetbrains/jet/di/InjectorForJavaSemanticServices.java index cd5b86fe6c9..9ffac62baee 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/di/InjectorForJavaSemanticServices.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/di/InjectorForJavaSemanticServices.java @@ -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.DeserializedDescriptorResolver; 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.JavaConstructorResolver; import org.jetbrains.jet.lang.resolve.java.resolver.JavaInnerClassResolver; @@ -64,6 +65,7 @@ public class InjectorForJavaSemanticServices { private final JavaSignatureResolver javaSignatureResolver; private final DeserializedDescriptorResolver deserializedDescriptorResolver; private final AnnotationDescriptorDeserializer annotationDescriptorDeserializer; + private final ErrorReporter errorReporter; private final JavaNamespaceResolver javaNamespaceResolver; private final JavaConstructorResolver javaConstructorResolver; private final JavaInnerClassResolver javaInnerClassResolver; @@ -91,6 +93,7 @@ public class InjectorForJavaSemanticServices { this.javaSignatureResolver = new JavaSignatureResolver(); this.deserializedDescriptorResolver = new DeserializedDescriptorResolver(); this.annotationDescriptorDeserializer = new AnnotationDescriptorDeserializer(); + this.errorReporter = new ErrorReporter(); this.javaNamespaceResolver = new JavaNamespaceResolver(); this.javaConstructorResolver = new JavaConstructorResolver(); this.javaInnerClassResolver = new JavaInnerClassResolver(); @@ -155,12 +158,15 @@ public class InjectorForJavaSemanticServices { javaSignatureResolver.setJavaSemanticServices(javaSemanticServices); deserializedDescriptorResolver.setAnnotationDeserializer(annotationDescriptorDeserializer); + deserializedDescriptorResolver.setErrorReporter(errorReporter); deserializedDescriptorResolver.setJavaClassResolver(javaClassResolver); deserializedDescriptorResolver.setJavaNamespaceResolver(javaNamespaceResolver); annotationDescriptorDeserializer.setJavaClassResolver(javaClassResolver); annotationDescriptorDeserializer.setPsiClassFinder(psiClassFinder); + errorReporter.setTrace(bindingTrace); + javaNamespaceResolver.setDeserializedDescriptorResolver(deserializedDescriptorResolver); javaNamespaceResolver.setJavaSemanticServices(javaSemanticServices); javaNamespaceResolver.setPsiClassFinder(psiClassFinder); diff --git a/compiler/frontend.java/src/org/jetbrains/jet/di/InjectorForTopDownAnalyzerForJvm.java b/compiler/frontend.java/src/org/jetbrains/jet/di/InjectorForTopDownAnalyzerForJvm.java index 28aacbca79c..41f97159f72 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/di/InjectorForTopDownAnalyzerForJvm.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/di/InjectorForTopDownAnalyzerForJvm.java @@ -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.DeserializedDescriptorResolver; 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.JavaConstructorResolver; import org.jetbrains.jet.lang.resolve.java.resolver.JavaInnerClassResolver; @@ -114,6 +115,7 @@ public class InjectorForTopDownAnalyzerForJvm implements InjectorForTopDownAnaly private final JavaSignatureResolver javaSignatureResolver; private final DeserializedDescriptorResolver deserializedDescriptorResolver; private final AnnotationDescriptorDeserializer annotationDescriptorDeserializer; + private final ErrorReporter errorReporter; private final JavaNamespaceResolver javaNamespaceResolver; private final JavaConstructorResolver javaConstructorResolver; private final JavaInnerClassResolver javaInnerClassResolver; @@ -169,6 +171,7 @@ public class InjectorForTopDownAnalyzerForJvm implements InjectorForTopDownAnaly this.javaSignatureResolver = new JavaSignatureResolver(); this.deserializedDescriptorResolver = new DeserializedDescriptorResolver(); this.annotationDescriptorDeserializer = new AnnotationDescriptorDeserializer(); + this.errorReporter = new ErrorReporter(); this.javaNamespaceResolver = new JavaNamespaceResolver(); this.javaConstructorResolver = new JavaConstructorResolver(); this.javaInnerClassResolver = new JavaInnerClassResolver(); @@ -333,12 +336,15 @@ public class InjectorForTopDownAnalyzerForJvm implements InjectorForTopDownAnaly javaSignatureResolver.setJavaSemanticServices(javaSemanticServices); deserializedDescriptorResolver.setAnnotationDeserializer(annotationDescriptorDeserializer); + deserializedDescriptorResolver.setErrorReporter(errorReporter); deserializedDescriptorResolver.setJavaClassResolver(javaClassResolver); deserializedDescriptorResolver.setJavaNamespaceResolver(javaNamespaceResolver); annotationDescriptorDeserializer.setJavaClassResolver(javaClassResolver); annotationDescriptorDeserializer.setPsiClassFinder(psiClassFinder); + errorReporter.setTrace(bindingTrace); + javaNamespaceResolver.setDeserializedDescriptorResolver(deserializedDescriptorResolver); javaNamespaceResolver.setJavaSemanticServices(javaSemanticServices); javaNamespaceResolver.setPsiClassFinder(psiClassFinder); diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/AbiVersionUtil.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/AbiVersionUtil.java index 8772d9474a8..a19d5317bbc 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/AbiVersionUtil.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/AbiVersionUtil.java @@ -19,7 +19,6 @@ package org.jetbrains.jet.lang.resolve.java; import com.intellij.psi.PsiClass; import org.jetbrains.annotations.NotNull; 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.Slices; import org.jetbrains.jet.util.slicedmap.WritableSlice; @@ -29,19 +28,20 @@ public class AbiVersionUtil { new BasicWritableSlice(Slices.ONLY_REWRITE_TO_EQUAL, true); public static final int INVALID_VERSION = -1; + private AbiVersionUtil() { + } + public static boolean isAbiVersionCompatible(int abiVersion) { return abiVersion == JvmAbi.VERSION; } - public static void checkAbiVersion( - @NotNull PsiClass psiClass, - @NotNull PsiAnnotationWithAbiVersion versionAnnotation, - @NotNull BindingTrace trace) { - if (!versionAnnotation.isDefined()) return; + public static void checkAbiVersion(@NotNull PsiClass psiClass, int version, @NotNull BindingTrace trace) { + if (!isAbiVersionCompatible(version)) { + reportIncompatibleAbiVersion(psiClass, version, trace); + } + } - int abiVersion = versionAnnotation.getAbiVersion(); - if (isAbiVersionCompatible(abiVersion)) return; - - trace.record(ABI_VERSION_ERRORS, psiClass, abiVersion); + public static void reportIncompatibleAbiVersion(@NotNull PsiClass psiClass, int version, @NotNull BindingTrace trace) { + trace.record(ABI_VERSION_ERRORS, psiClass, version); } } diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JvmAbi.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JvmAbi.java index 35e1e2c48cb..9fb2d4b0d62 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JvmAbi.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JvmAbi.java @@ -26,7 +26,7 @@ public class JvmAbi { * 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 */ - 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_SUFFIX = "$" + TRAIT_IMPL_CLASS_NAME; diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/DeserializedDescriptorResolver.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/DeserializedDescriptorResolver.java index 1379985b82f..fcd9d4ed0ce 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/DeserializedDescriptorResolver.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/DeserializedDescriptorResolver.java @@ -31,6 +31,7 @@ import org.jetbrains.jet.lang.descriptors.ClassDescriptor; import org.jetbrains.jet.lang.descriptors.ClassOrNamespaceDescriptor; import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; 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.lazy.storage.LockBasedStorageManager; import org.jetbrains.jet.lang.resolve.name.FqName; @@ -44,6 +45,7 @@ import java.util.ArrayList; import java.util.List; 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.resolver.DeserializedResolverUtils.getVirtualFile; import static org.jetbrains.jet.lang.resolve.java.resolver.DeserializedResolverUtils.kotlinFqNameToJavaFqName; @@ -59,6 +61,8 @@ public final class DeserializedDescriptorResolver { private JavaClassResolver javaClassResolver; + private ErrorReporter errorReporter; + @NotNull private final DescriptorFinder javaDescriptorFinder = new DescriptorFinder() { @Nullable @@ -89,6 +93,11 @@ public final class DeserializedDescriptorResolver { this.javaClassResolver = javaClassResolver; } + @Inject + public void setErrorReporter(ErrorReporter errorReporter) { + this.errorReporter = errorReporter; + } + @Nullable public ClassDescriptor resolveClass( @NotNull FqName fqName, @@ -97,28 +106,25 @@ public final class DeserializedDescriptorResolver { ) { VirtualFile virtualFile = getVirtualFile(psiClass, fqName, containingDeclaration); if (virtualFile == null) { + // TODO: use ErrorReporter here return null; } - ClassData classData = readClassDataFromClassFile(virtualFile); + ClassData classData = readClassDataFromClassFile(virtualFile, psiClass); if (classData == null) { return null; } return deserializeClass(classData, fqName, containingDeclaration); } - @NotNull - public JetScope createKotlinPackageScope( - @NotNull FqName fqName, - @NotNull PsiClass kotlinPackagePsiClass, - @NotNull NamespaceDescriptor packageDescriptor - ) { + @Nullable + public JetScope createKotlinPackageScope(@NotNull PsiClass kotlinPackagePsiClass, @NotNull NamespaceDescriptor packageDescriptor) { VirtualFile virtualFile = kotlinPackagePsiClass.getContainingFile().getVirtualFile(); 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) { - throw new IllegalStateException("No KotlinInfo annotation stored for " + fqName.asString()); + return null; } return DeserializedPackageMemberScope.createScopeFromPackageData(packageDescriptor, packageData, javaDescriptorFinder, annotationDeserializer, storageManager); @@ -143,33 +149,32 @@ public final class DeserializedDescriptorResolver { } @Nullable - private static ClassData readClassDataFromClassFile(@NotNull VirtualFile virtualFile) { - String[] data = getKotlinInfoDataFromClassFile(virtualFile); - if (data == null) return null; - return JavaProtoBufUtil.readClassDataFrom(data); + private ClassData readClassDataFromClassFile(@NotNull VirtualFile virtualFile, @NotNull PsiClass psiClass) { + String[] data = readData(virtualFile, psiClass); + return data == null ? null : JavaProtoBufUtil.readClassDataFrom(data); } @Nullable - private static PackageData readPackageDataFromClassFile(@NotNull VirtualFile virtualFile) { - String[] data = getKotlinInfoDataFromClassFile(virtualFile); - if (data == null) return null; - return JavaProtoBufUtil.readPackageDataFrom(data); + private PackageData readPackageDataFromClassFile(@NotNull VirtualFile virtualFile, @NotNull PsiClass psiClass) { + String[] data = readData(virtualFile, psiClass); + return data == null ? null : JavaProtoBufUtil.readPackageDataFrom(data); } @Nullable - private static String[] getKotlinInfoDataFromClassFile(@NotNull VirtualFile virtualFile) { + private String[] readData(@NotNull VirtualFile virtualFile, @NotNull PsiClass psiClass) { GetKotlinInfoDataVisitor visitor = visitClassFile(virtualFile); - if (visitor == null) { - return null; - } + int version = visitor.getVersion(); String[] data = visitor.getData(); - if (data == null) { - return null; + if (isAbiVersionCompatible(version)) { + return data; } - return data; + if (data != null) { + errorReporter.reportIncompatibleAbiVersion(psiClass, version); + } + return null; } - @Nullable + @NotNull private static GetKotlinInfoDataVisitor visitClassFile(@NotNull VirtualFile virtualFile) { try { InputStream inputStream = virtualFile.getInputStream(); @@ -193,6 +198,8 @@ public final class DeserializedDescriptorResolver { super(Opcodes.ASM4); } + private int version = AbiVersionUtil.INVALID_VERSION; + @Nullable private String[] data = null; @@ -204,11 +211,29 @@ public final class DeserializedDescriptorResolver { return new AnnotationVisitor(Opcodes.ASM4) { @Override - public AnnotationVisitor visitArray(String name) { - if (!name.equals("data")) { + public void visit(String name, Object value) { + if (name.equals("version")) { + version = (Integer) value; + } + else if (isAbiVersionCompatible(version)) { 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 strings = new ArrayList(1); return new AnnotationVisitor(Opcodes.ASM4) { @Override @@ -229,6 +254,10 @@ public final class DeserializedDescriptorResolver { }; } + public int getVersion() { + return version; + } + @Nullable public String[] getData() { return data; diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/ErrorReporter.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/ErrorReporter.java new file mode 100644 index 00000000000..adc14558715 --- /dev/null +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/ErrorReporter.java @@ -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); + } +} diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/JavaClassResolver.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/JavaClassResolver.java index fb137f3bb32..5dfb7efe856 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/JavaClassResolver.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/JavaClassResolver.java @@ -237,7 +237,6 @@ public final class JavaClassResolver { @NotNull FqName fqName, @NotNull PsiClass psiClass, @NotNull PostponedTasks taskList ) { - checkFqNamesAreConsistent(psiClass, fqName); DescriptorResolverUtils.checkPsiClassIsNotJet(psiClass); @@ -267,7 +266,9 @@ public final class JavaClassResolver { @NotNull ClassOrNamespaceDescriptor containingDeclaration ) { JetClassAnnotation jetClassAnnotation = JetClassAnnotation.get(psiClass); - AbiVersionUtil.checkAbiVersion(psiClass, jetClassAnnotation, trace); + if (jetClassAnnotation.isDefined()) { + AbiVersionUtil.checkAbiVersion(psiClass, jetClassAnnotation.getAbiVersion(), trace); + } ClassKind kind = getClassKind(psiClass, jetClassAnnotation); ClassPsiDeclarationProvider classData = semanticServices.getPsiDeclarationProviderFactory().createBinaryClassData(psiClass); diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/JavaNamespaceResolver.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/JavaNamespaceResolver.java index a1dde414e8e..a0a145940d9 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/JavaNamespaceResolver.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/JavaNamespaceResolver.java @@ -19,6 +19,7 @@ package org.jetbrains.jet.lang.resolve.java.resolver; import com.google.common.collect.Maps; import com.google.common.collect.Sets; import com.intellij.psi.*; +import com.intellij.psi.impl.compiled.ClsClassImpl; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; 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.JavaClassStaticMembersScope; 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.scopes.JetScope; @@ -44,6 +46,8 @@ import java.util.Collections; import java.util.Map; import java.util.Set; +import static org.jetbrains.jet.lang.resolve.java.AbiVersionUtil.INVALID_VERSION; + public final class JavaNamespaceResolver { @NotNull @@ -160,12 +164,24 @@ public final class JavaNamespaceResolver { if (psiPackage != null) { PsiClass psiClass = getPsiClassForJavaPackageScope(fqName); trace.record(JavaBindingContext.JAVA_NAMESPACE_KIND, namespaceDescriptor, JavaNamespaceKind.PROPER); - if (psiClass == null || !isCompiledKotlinClass(psiClass)) { - return new JavaPackageScopeWithoutMembers(namespaceDescriptor, javaSemanticServices.getPsiDeclarationProviderFactory() - .createDeclarationProviderForNamespaceWithoutMembers(psiPackage), fqName, javaSemanticServices); + + if (psiClass != null) { + 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); @@ -185,19 +201,21 @@ public final class JavaNamespaceResolver { fqName, javaSemanticServices); } - private static boolean isCompiledKotlinClass(@NotNull PsiClass psiClass) { - PsiModifierList list = psiClass.getModifierList(); - return list != null && list.findAnnotation(JvmStdlibNames.KOTLIN_INFO_CLASS.getFqName().asString()) != null; + private static boolean isOldKotlinPackageClass(@NotNull PsiClass psiClass) { + return new PsiClassWrapper(psiClass).getJetPackageClass().isDefined(); } - @NotNull - private JetScope createScopeForKotlinPackageClass( - @NotNull FqName fqName, - @NotNull NamespaceDescriptor namespaceDescriptor, - @NotNull PsiClass psiClass - ) { - //TODO: check abi version - return deserializedDescriptorResolver.createKotlinPackageScope(fqName, psiClass, namespaceDescriptor); + private static boolean isCompiledKotlinClass(@NotNull PsiClass psiClass) { + // TODO: merge this method with DescriptorResolverUtils#isKotlinClass + // NOTE: we need to check against ClsClassImpl because it can be a Java source, pretending to be a Kotlin class. + // In that case we can't really read the annotation from psiClass's virtual file + if (psiClass instanceof ClsClassImpl) { + PsiModifierList list = psiClass.getModifierList(); + if (list != null) { + return list.findAnnotation(JvmStdlibNames.KOTLIN_INFO_CLASS.getFqName().asString()) != null; + } + } + return false; } private void cache(@NotNull FqName fqName, @Nullable JetScope packageScope) { diff --git a/compiler/testData/cli/wrongAbiVersion.out b/compiler/testData/cli/wrongAbiVersion.out index 236c621093d..6f14bcff9a6 100644 --- a/compiler/testData/cli/wrongAbiVersion.out +++ b/compiler/testData/cli/wrongAbiVersion.out @@ -1,4 +1,5 @@ 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$/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$/wrongAbiVersion.kt: (4, 3) Unresolved reference: bar +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 diff --git a/compiler/testData/cli/wrongAbiVersionLib/ClassWithWrongAbiVersion.class b/compiler/testData/cli/wrongAbiVersionLib/ClassWithWrongAbiVersion.class new file mode 100644 index 00000000000..545a65280b8 Binary files /dev/null and b/compiler/testData/cli/wrongAbiVersionLib/ClassWithWrongAbiVersion.class differ diff --git a/compiler/testData/cli/wrongAbiVersionLib/ClassWithWrongAbiVersion.java b/compiler/testData/cli/wrongAbiVersionLib/ClassWithWrongAbiVersion.java deleted file mode 100644 index cf36db25305..00000000000 --- a/compiler/testData/cli/wrongAbiVersionLib/ClassWithWrongAbiVersion.java +++ /dev/null @@ -1,4 +0,0 @@ -import jet.runtime.typeinfo.JetClass; - -@JetClass("Ljava/lang/Object;", 16, -1) -class ClassWithWrongAbiVersion {} \ No newline at end of file diff --git a/compiler/testData/cli/wrongAbiVersionLib/wrong-class-source b/compiler/testData/cli/wrongAbiVersionLib/wrong-class-source new file mode 100644 index 00000000000..907bb17a366 --- /dev/null +++ b/compiler/testData/cli/wrongAbiVersionLib/wrong-class-source @@ -0,0 +1 @@ +class ClassWithWrongAbiVersion diff --git a/compiler/testData/cli/wrongAbiVersionLib/wrong-package-source b/compiler/testData/cli/wrongAbiVersionLib/wrong-package-source new file mode 100644 index 00000000000..892a3f84924 --- /dev/null +++ b/compiler/testData/cli/wrongAbiVersionLib/wrong-package-source @@ -0,0 +1,3 @@ +package wrong + +fun bar() {} diff --git a/compiler/testData/cli/wrongAbiVersionLib/wrong/WrongPackage$src$wrong$af7e96c9.class b/compiler/testData/cli/wrongAbiVersionLib/wrong/WrongPackage$src$wrong$af7e96c9.class new file mode 100644 index 00000000000..6ab6c032b75 Binary files /dev/null and b/compiler/testData/cli/wrongAbiVersionLib/wrong/WrongPackage$src$wrong$af7e96c9.class differ diff --git a/compiler/testData/cli/wrongAbiVersionLib/wrong/WrongPackage.class b/compiler/testData/cli/wrongAbiVersionLib/wrong/WrongPackage.class new file mode 100644 index 00000000000..5dbc33f71ed Binary files /dev/null and b/compiler/testData/cli/wrongAbiVersionLib/wrong/WrongPackage.class differ diff --git a/compiler/testData/cli/wrongAbiVersionLib/wrong/WrongPackage.java b/compiler/testData/cli/wrongAbiVersionLib/wrong/WrongPackage.java deleted file mode 100644 index d5656b88e39..00000000000 --- a/compiler/testData/cli/wrongAbiVersionLib/wrong/WrongPackage.java +++ /dev/null @@ -1,6 +0,0 @@ -package wrong; - -@jet.runtime.typeinfo.JetPackageClass(abiVersion = -1) -public class WrongPackage { - public static void bar() {} -} \ No newline at end of file diff --git a/runtime/src/jet/KotlinInfo.java b/runtime/src/jet/KotlinInfo.java index 8e9398a2f42..404beb5743a 100644 --- a/runtime/src/jet/KotlinInfo.java +++ b/runtime/src/jet/KotlinInfo.java @@ -21,5 +21,7 @@ import java.lang.annotation.RetentionPolicy; @Retention(RetentionPolicy.RUNTIME) public @interface KotlinInfo { + int version(); + String[] data(); }