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:
+7
-6
@@ -17,7 +17,6 @@
|
|||||||
package org.jetbrains.jet.cli.common.messages;
|
package org.jetbrains.jet.cli.common.messages;
|
||||||
|
|
||||||
import com.intellij.openapi.util.text.StringUtil;
|
import com.intellij.openapi.util.text.StringUtil;
|
||||||
import com.intellij.psi.PsiClass;
|
|
||||||
import com.intellij.psi.PsiElement;
|
import com.intellij.psi.PsiElement;
|
||||||
import com.intellij.psi.PsiErrorElement;
|
import com.intellij.psi.PsiErrorElement;
|
||||||
import com.intellij.psi.PsiModifierListOwner;
|
import com.intellij.psi.PsiModifierListOwner;
|
||||||
@@ -43,6 +42,7 @@ import org.jetbrains.jet.lang.resolve.java.JvmAbi;
|
|||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import static com.intellij.openapi.util.io.FileUtil.toSystemDependentName;
|
||||||
import static org.jetbrains.jet.lang.diagnostics.DiagnosticUtils.sortedDiagnostics;
|
import static org.jetbrains.jet.lang.diagnostics.DiagnosticUtils.sortedDiagnostics;
|
||||||
|
|
||||||
public final class AnalyzerWithCompilerReport {
|
public final class AnalyzerWithCompilerReport {
|
||||||
@@ -143,13 +143,14 @@ public final class AnalyzerWithCompilerReport {
|
|||||||
assert analyzeExhaust != null;
|
assert analyzeExhaust != null;
|
||||||
BindingContext bindingContext = analyzeExhaust.getBindingContext();
|
BindingContext bindingContext = analyzeExhaust.getBindingContext();
|
||||||
|
|
||||||
Collection<PsiClass> psiClasses = bindingContext.getKeys(AbiVersionUtil.ABI_VERSION_ERRORS);
|
Collection<AbiVersionUtil.AbiVersionErrorLocation> errorLocations = bindingContext.getKeys(AbiVersionUtil.ABI_VERSION_ERRORS);
|
||||||
for (PsiClass psiClass : psiClasses) {
|
for (AbiVersionUtil.AbiVersionErrorLocation abiVersionErrorLocation : errorLocations) {
|
||||||
Integer abiVersion = bindingContext.get(AbiVersionUtil.ABI_VERSION_ERRORS, psiClass);
|
Integer abiVersion = bindingContext.get(AbiVersionUtil.ABI_VERSION_ERRORS, abiVersionErrorLocation);
|
||||||
messageCollectorWrapper.report(CompilerMessageSeverity.ERROR,
|
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,
|
"Its ABI version is " + abiVersion + ", expected ABI version is " + JvmAbi.VERSION,
|
||||||
MessageUtil.psiElementToMessageLocation(psiClass));
|
CompilerMessageLocation.create(toSystemDependentName(abiVersionErrorLocation.getPath()), 0, 0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,26 +16,60 @@
|
|||||||
|
|
||||||
package org.jetbrains.jet.lang.resolve.java;
|
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.annotations.NotNull;
|
||||||
import org.jetbrains.jet.lang.resolve.BindingTrace;
|
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.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;
|
||||||
|
|
||||||
public class AbiVersionUtil {
|
public final class AbiVersionUtil {
|
||||||
public static final WritableSlice<PsiClass, Integer> ABI_VERSION_ERRORS =
|
public static final WritableSlice<AbiVersionErrorLocation, Integer> ABI_VERSION_ERRORS =
|
||||||
new BasicWritableSlice<PsiClass, Integer>(Slices.ONLY_REWRITE_TO_EQUAL, true);
|
new BasicWritableSlice<AbiVersionErrorLocation, 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 reportIncompatibleAbiVersion(@NotNull PsiClass psiClass, int version, @NotNull BindingTrace trace) {
|
@NotNull
|
||||||
trace.record(ABI_VERSION_ERRORS, psiClass, version);
|
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() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
-12
@@ -23,8 +23,6 @@ import com.intellij.psi.util.PsiFormatUtil;
|
|||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.jet.lang.descriptors.*;
|
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.FqName;
|
||||||
import org.jetbrains.jet.lang.resolve.name.Name;
|
import org.jetbrains.jet.lang.resolve.name.Name;
|
||||||
import org.jetbrains.jet.lang.types.JetType;
|
import org.jetbrains.jet.lang.types.JetType;
|
||||||
@@ -138,16 +136,6 @@ public final class DescriptorResolverUtils {
|
|||||||
return isEnumClassObject(ownerDescriptor) == shouldBeInEnumClassObject(member);
|
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) {
|
public static boolean isObjectMethodInInterface(@NotNull PsiMember member) {
|
||||||
if (!(member instanceof PsiMethod)) {
|
if (!(member instanceof PsiMethod)) {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
+5
-8
@@ -131,15 +131,12 @@ public final class DeserializedDescriptorResolver {
|
|||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private static String[] readData(@NotNull VirtualFile virtualFile, @NotNull ErrorReporter reporter) {
|
private static String[] readData(@NotNull VirtualFile virtualFile, @NotNull ErrorReporter reporter) {
|
||||||
KotlinClassFileHeader headerData = KotlinClassFileHeader.readKotlinHeaderFromClassFile(virtualFile);
|
KotlinClassFileHeader header = KotlinClassFileHeader.readKotlinHeaderFromClassFile(virtualFile);
|
||||||
int version = headerData.getVersion();
|
int version = header.getVersion();
|
||||||
String[] annotationData = headerData.getAnnotationData();
|
if (!isAbiVersionCompatible(version) && header.getType() != KotlinClassFileHeader.HeaderType.NONE) {
|
||||||
if (isAbiVersionCompatible(version)) {
|
|
||||||
return annotationData;
|
|
||||||
}
|
|
||||||
if (annotationData != null) {
|
|
||||||
reporter.reportIncompatibleAbiVersion(version);
|
reporter.reportIncompatibleAbiVersion(version);
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
return null;
|
return header.getAnnotationData();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+39
-16
@@ -21,6 +21,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;
|
||||||
|
|
||||||
public final class KotlinClassFileHeader {
|
public final class KotlinClassFileHeader {
|
||||||
@NotNull
|
@NotNull
|
||||||
@@ -42,9 +43,12 @@ public final class KotlinClassFileHeader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
public enum HeaderType {
|
public enum HeaderType {
|
||||||
CLASS(JvmAnnotationNames.KOTLIN_CLASS),
|
CLASS(JvmAnnotationNames.KOTLIN_CLASS),
|
||||||
PACKAGE(JvmAnnotationNames.KOTLIN_PACKAGE),
|
PACKAGE(JvmAnnotationNames.KOTLIN_PACKAGE),
|
||||||
|
OLD_CLASS(JvmAnnotationNames.OLD_JET_CLASS_ANNOTATION),
|
||||||
|
OLD_PACKAGE(JvmAnnotationNames.OLD_JET_PACKAGE_CLASS_ANNOTATION),
|
||||||
NONE(null);
|
NONE(null);
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@@ -53,6 +57,24 @@ public final class KotlinClassFileHeader {
|
|||||||
HeaderType(@Nullable JvmClassName annotation) {
|
HeaderType(@Nullable JvmClassName annotation) {
|
||||||
correspondingAnnotation = 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;
|
private int version = AbiVersionUtil.INVALID_VERSION;
|
||||||
@@ -73,8 +95,11 @@ public final class KotlinClassFileHeader {
|
|||||||
return type;
|
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() {
|
public boolean isKotlinCompiledFile() {
|
||||||
return type != HeaderType.NONE;
|
return type.isValidAnnotation() && isAbiVersionCompatible(version);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@@ -119,20 +144,18 @@ public final class KotlinClassFileHeader {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AnnotationVisitor visitAnnotation(final String desc, boolean visible) {
|
public AnnotationVisitor visitAnnotation(final String desc, boolean visible) {
|
||||||
for (HeaderType headerType : HeaderType.values()) {
|
HeaderType headerTypeByAnnotation = HeaderType.byDescriptor(desc);
|
||||||
JvmClassName annotation = headerType.correspondingAnnotation;
|
if (headerTypeByAnnotation == HeaderType.NONE) {
|
||||||
if (annotation == null) {
|
return null;
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (desc.equals(annotation.getDescriptor())) {
|
|
||||||
if (type != HeaderType.NONE) {
|
|
||||||
throw new IllegalStateException(
|
|
||||||
"Both " + type.correspondingAnnotation + " and " + headerType.correspondingAnnotation + " present!");
|
|
||||||
}
|
|
||||||
type = headerType;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
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 null;
|
||||||
}
|
}
|
||||||
return new AnnotationVisitor(Opcodes.ASM4) {
|
return new AnnotationVisitor(Opcodes.ASM4) {
|
||||||
@@ -141,7 +164,7 @@ public final class KotlinClassFileHeader {
|
|||||||
if (name.equals(JvmAnnotationNames.ABI_VERSION_FIELD_NAME)) {
|
if (name.equals(JvmAnnotationNames.ABI_VERSION_FIELD_NAME)) {
|
||||||
version = (Integer) value;
|
version = (Integer) value;
|
||||||
}
|
}
|
||||||
else if (AbiVersionUtil.isAbiVersionCompatible(version)) {
|
else if (isAbiVersionCompatible(version)) {
|
||||||
throw new IllegalStateException("Unexpected argument " + name + " for annotation " + desc);
|
throw new IllegalStateException("Unexpected argument " + name + " for annotation " + desc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -151,7 +174,7 @@ public final class KotlinClassFileHeader {
|
|||||||
if (name.equals(JvmAnnotationNames.DATA_FIELD_NAME)) {
|
if (name.equals(JvmAnnotationNames.DATA_FIELD_NAME)) {
|
||||||
return stringArrayVisitor();
|
return stringArrayVisitor();
|
||||||
}
|
}
|
||||||
else if (AbiVersionUtil.isAbiVersionCompatible(version)) {
|
else if (isAbiVersionCompatible(version)) {
|
||||||
throw new IllegalStateException("Unexpected array argument " + name + " for annotation " + desc);
|
throw new IllegalStateException("Unexpected array argument " + name + " for annotation " + desc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +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$/wrongAbiVersion.kt: (4, 3) Unresolved reference: bar
|
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/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: (-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/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
|
COMPILATION_ERROR
|
||||||
|
|||||||
Reference in New Issue
Block a user