Rework invalid abi version reporting

KotlinClassFileHeader is aware of older annotations
Psi is not used to report invalid Abi version in CLI
This commit is contained in:
Pavel V. Talanov
2013-08-23 17:44:30 +04:00
parent 223c6007d2
commit 4e29aad1c1
6 changed files with 96 additions and 53 deletions
@@ -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<PsiClass, Integer> ABI_VERSION_ERRORS =
new BasicWritableSlice<PsiClass, Integer>(Slices.ONLY_REWRITE_TO_EQUAL, true);
public final class AbiVersionUtil {
public static final WritableSlice<AbiVersionErrorLocation, Integer> ABI_VERSION_ERRORS =
new BasicWritableSlice<AbiVersionErrorLocation, Integer>(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() {
}
}
@@ -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;
@@ -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();
}
}
@@ -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);
}