diff --git a/compiler/cli/src/org/jetbrains/jet/cli/common/messages/AnalyzerWithCompilerReport.java b/compiler/cli/src/org/jetbrains/jet/cli/common/messages/AnalyzerWithCompilerReport.java index 1a912f62614..0b3e8e5cce1 100644 --- a/compiler/cli/src/org/jetbrains/jet/cli/common/messages/AnalyzerWithCompilerReport.java +++ b/compiler/cli/src/org/jetbrains/jet/cli/common/messages/AnalyzerWithCompilerReport.java @@ -17,7 +17,6 @@ package org.jetbrains.jet.cli.common.messages; import com.intellij.openapi.util.text.StringUtil; -import com.intellij.psi.PsiClass; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiErrorElement; import com.intellij.psi.PsiModifierListOwner; @@ -43,6 +42,7 @@ import org.jetbrains.jet.lang.resolve.java.JvmAbi; import java.util.Collection; import java.util.List; +import static com.intellij.openapi.util.io.FileUtil.toSystemDependentName; import static org.jetbrains.jet.lang.diagnostics.DiagnosticUtils.sortedDiagnostics; public final class AnalyzerWithCompilerReport { @@ -143,13 +143,14 @@ public final class AnalyzerWithCompilerReport { assert analyzeExhaust != null; BindingContext bindingContext = analyzeExhaust.getBindingContext(); - Collection psiClasses = bindingContext.getKeys(AbiVersionUtil.ABI_VERSION_ERRORS); - for (PsiClass psiClass : psiClasses) { - Integer abiVersion = bindingContext.get(AbiVersionUtil.ABI_VERSION_ERRORS, psiClass); + Collection errorLocations = bindingContext.getKeys(AbiVersionUtil.ABI_VERSION_ERRORS); + for (AbiVersionUtil.AbiVersionErrorLocation abiVersionErrorLocation : errorLocations) { + Integer abiVersion = bindingContext.get(AbiVersionUtil.ABI_VERSION_ERRORS, abiVersionErrorLocation); messageCollectorWrapper.report(CompilerMessageSeverity.ERROR, - "Class '" + psiClass.getQualifiedName() + "' was compiled with an incompatible version of Kotlin. " + + "Class '" + abiVersionErrorLocation.getClassFqName().asString() + + "' was compiled with an incompatible version of Kotlin. " + "Its ABI version is " + abiVersion + ", expected ABI version is " + JvmAbi.VERSION, - MessageUtil.psiElementToMessageLocation(psiClass)); + CompilerMessageLocation.create(toSystemDependentName(abiVersionErrorLocation.getPath()), 0, 0)); } } 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 ae9b496f014..343053c5707 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 @@ -16,26 +16,60 @@ package org.jetbrains.jet.lang.resolve.java; -import com.intellij.psi.PsiClass; +import com.intellij.openapi.vfs.VirtualFile; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.resolve.BindingTrace; +import org.jetbrains.jet.lang.resolve.java.resolver.ErrorReporter; +import org.jetbrains.jet.lang.resolve.name.FqName; import org.jetbrains.jet.util.slicedmap.BasicWritableSlice; import org.jetbrains.jet.util.slicedmap.Slices; import org.jetbrains.jet.util.slicedmap.WritableSlice; -public class AbiVersionUtil { - public static final WritableSlice ABI_VERSION_ERRORS = - new BasicWritableSlice(Slices.ONLY_REWRITE_TO_EQUAL, true); +public final class AbiVersionUtil { + public static final WritableSlice ABI_VERSION_ERRORS = + 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 reportIncompatibleAbiVersion(@NotNull PsiClass psiClass, int version, @NotNull BindingTrace trace) { - trace.record(ABI_VERSION_ERRORS, psiClass, version); + @NotNull + public static ErrorReporter abiVersionErrorReporter( + @NotNull final VirtualFile file, + @NotNull final FqName classFqName, + @NotNull final BindingTrace trace + ) { + return new ErrorReporter() { + @Override + public void reportIncompatibleAbiVersion(int actualVersion) { + trace.record(ABI_VERSION_ERRORS, new AbiVersionErrorLocation(classFqName, file), actualVersion); + } + }; + } + + public static final class AbiVersionErrorLocation { + @NotNull + private final FqName classFqName; + @NotNull + private final VirtualFile file; + + public AbiVersionErrorLocation(@NotNull FqName name, @NotNull VirtualFile file) { + this.classFqName = name; + this.file = file; + } + + @NotNull + public FqName getClassFqName() { + return classFqName; + } + + @NotNull + public String getPath() { + return file.getPath(); + } + } + + private AbiVersionUtil() { } } diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/DescriptorResolverUtils.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/DescriptorResolverUtils.java index a002e43979c..94813d2c707 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/DescriptorResolverUtils.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/DescriptorResolverUtils.java @@ -23,8 +23,6 @@ import com.intellij.psi.util.PsiFormatUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.*; -import org.jetbrains.jet.lang.resolve.BindingTrace; -import org.jetbrains.jet.lang.resolve.java.resolver.ErrorReporter; import org.jetbrains.jet.lang.resolve.name.FqName; import org.jetbrains.jet.lang.resolve.name.Name; import org.jetbrains.jet.lang.types.JetType; @@ -138,16 +136,6 @@ public final class DescriptorResolverUtils { return isEnumClassObject(ownerDescriptor) == shouldBeInEnumClassObject(member); } - @NotNull - public static ErrorReporter createPsiBasedErrorReporter(@NotNull final PsiClass psiClass, @NotNull final BindingTrace trace) { - return new ErrorReporter() { - @Override - public void reportIncompatibleAbiVersion(int actualVersion) { - AbiVersionUtil.reportIncompatibleAbiVersion(psiClass, actualVersion, trace); - } - }; - } - public static boolean isObjectMethodInInterface(@NotNull PsiMember member) { if (!(member instanceof PsiMethod)) { return false; 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 46c4f6c5ab7..e7ba7fe071f 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 @@ -131,15 +131,12 @@ public final class DeserializedDescriptorResolver { @Nullable private static String[] readData(@NotNull VirtualFile virtualFile, @NotNull ErrorReporter reporter) { - KotlinClassFileHeader headerData = KotlinClassFileHeader.readKotlinHeaderFromClassFile(virtualFile); - int version = headerData.getVersion(); - String[] annotationData = headerData.getAnnotationData(); - if (isAbiVersionCompatible(version)) { - return annotationData; - } - if (annotationData != null) { + KotlinClassFileHeader header = KotlinClassFileHeader.readKotlinHeaderFromClassFile(virtualFile); + int version = header.getVersion(); + if (!isAbiVersionCompatible(version) && header.getType() != KotlinClassFileHeader.HeaderType.NONE) { reporter.reportIncompatibleAbiVersion(version); + return null; } - return null; + return header.getAnnotationData(); } } diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/KotlinClassFileHeader.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/KotlinClassFileHeader.java index 490cfc88e87..a63ca5eda7c 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/KotlinClassFileHeader.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/KotlinClassFileHeader.java @@ -21,6 +21,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; public final class KotlinClassFileHeader { @NotNull @@ -42,9 +43,12 @@ public final class KotlinClassFileHeader { } } + @SuppressWarnings("deprecation") public enum HeaderType { CLASS(JvmAnnotationNames.KOTLIN_CLASS), PACKAGE(JvmAnnotationNames.KOTLIN_PACKAGE), + OLD_CLASS(JvmAnnotationNames.OLD_JET_CLASS_ANNOTATION), + OLD_PACKAGE(JvmAnnotationNames.OLD_JET_PACKAGE_CLASS_ANNOTATION), NONE(null); @Nullable @@ -53,6 +57,24 @@ public final class KotlinClassFileHeader { HeaderType(@Nullable JvmClassName annotation) { correspondingAnnotation = annotation; } + + boolean isValidAnnotation() { + return this == CLASS || this == PACKAGE; + } + + @NotNull + public static HeaderType byDescriptor(@NotNull String desc) { + for (HeaderType headerType : HeaderType.values()) { + JvmClassName annotation = headerType.correspondingAnnotation; + if (annotation == null) { + continue; + } + if (desc.equals(annotation.getDescriptor())) { + return headerType; + } + } + return NONE; + } } private int version = AbiVersionUtil.INVALID_VERSION; @@ -73,8 +95,11 @@ public final class KotlinClassFileHeader { return type; } + /* + Checks that this is a header for compiled Kotlin file with correct abi version which can be processed by compiler or the IDE. + */ public boolean isKotlinCompiledFile() { - return type != HeaderType.NONE; + return type.isValidAnnotation() && isAbiVersionCompatible(version); } @NotNull @@ -119,20 +144,18 @@ public final class KotlinClassFileHeader { @Override public AnnotationVisitor visitAnnotation(final String desc, boolean visible) { - for (HeaderType headerType : HeaderType.values()) { - JvmClassName annotation = headerType.correspondingAnnotation; - if (annotation == null) { - continue; - } - if (desc.equals(annotation.getDescriptor())) { - if (type != HeaderType.NONE) { - throw new IllegalStateException( - "Both " + type.correspondingAnnotation + " and " + headerType.correspondingAnnotation + " present!"); - } - type = headerType; - } + HeaderType headerTypeByAnnotation = HeaderType.byDescriptor(desc); + if (headerTypeByAnnotation == HeaderType.NONE) { + return null; } - if (type == HeaderType.NONE) { + if (headerTypeByAnnotation.isValidAnnotation() && type.isValidAnnotation()) { + throw new IllegalStateException("Both " + type.correspondingAnnotation + " and " + + headerTypeByAnnotation.correspondingAnnotation + " present!"); + } + if (!type.isValidAnnotation()) { + type = headerTypeByAnnotation; + } + if (!headerTypeByAnnotation.isValidAnnotation()) { return null; } return new AnnotationVisitor(Opcodes.ASM4) { @@ -141,7 +164,7 @@ public final class KotlinClassFileHeader { if (name.equals(JvmAnnotationNames.ABI_VERSION_FIELD_NAME)) { version = (Integer) value; } - else if (AbiVersionUtil.isAbiVersionCompatible(version)) { + else if (isAbiVersionCompatible(version)) { throw new IllegalStateException("Unexpected argument " + name + " for annotation " + desc); } } @@ -151,7 +174,7 @@ public final class KotlinClassFileHeader { if (name.equals(JvmAnnotationNames.DATA_FIELD_NAME)) { return stringArrayVisitor(); } - else if (AbiVersionUtil.isAbiVersionCompatible(version)) { + else if (isAbiVersionCompatible(version)) { throw new IllegalStateException("Unexpected array argument " + name + " for annotation " + desc); } diff --git a/compiler/testData/cli/wrongAbiVersion.out b/compiler/testData/cli/wrongAbiVersion.out index 6f14bcff9a6..d8ee22b66b5 100644 --- a/compiler/testData/cli/wrongAbiVersion.out +++ b/compiler/testData/cli/wrongAbiVersion.out @@ -1,5 +1,5 @@ WARNING: $TESTDATA_DIR$/wrongAbiVersion.kt: (3, 9) Parameter 'x' is never used 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 +ERROR: $TESTDATA_DIR$/wrongAbiVersionLib/wrong/WrongPackage.class: (0, 0) 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: (0, 0) Class 'ClassWithWrongAbiVersion' was compiled with an incompatible version of Kotlin. Its ABI version is -1, expected ABI version is 7 COMPILATION_ERROR