Report incompatible metadata version error correctly

Similarly to pre-release classes, load metadata for the class anyway and allow
the resolution to select it as the result and prohibit its usage in the end
with the special diagnostic reported in MissingDependencyClassChecker
This commit is contained in:
Alexander Udalov
2016-12-06 21:21:41 +03:00
parent d204fa91cc
commit b943ed26f3
20 changed files with 243 additions and 42 deletions
@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.cli;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.ArrayUtil;
import kotlin.Pair;
@@ -72,8 +73,10 @@ public abstract class AbstractCliTest extends TestCaseWithTmpdir {
@NotNull String testDataDir,
@NotNull BinaryVersion version
) {
String testDataAbsoluteDir = new File(testDataDir).getAbsolutePath();
String normalizedOutputWithoutExitCode = pureOutput
.replace(new File(testDataDir).getAbsolutePath(), "$TESTDATA_DIR$")
.replace(testDataAbsoluteDir, "$TESTDATA_DIR$")
.replace(FileUtil.toSystemIndependentName(testDataAbsoluteDir), "$TESTDATA_DIR$")
.replace(PathUtil.getKotlinPathsForDistDirectory().getHomePath().getAbsolutePath(), "$PROJECT_DIR$")
.replace("expected version is " + version, "expected version is $ABI_VERSION$")
.replace("\\", "/")
@@ -22,9 +22,11 @@ import com.intellij.openapi.util.io.FileUtil;
import kotlin.Pair;
import kotlin.collections.SetsKt;
import kotlin.io.FilesKt;
import kotlin.jvm.functions.Function2;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.analyzer.AnalysisResult;
import org.jetbrains.kotlin.cli.AbstractCliTest;
import org.jetbrains.kotlin.cli.WrongBytecodeVersionTest;
import org.jetbrains.kotlin.cli.common.ExitCode;
import org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport;
import org.jetbrains.kotlin.cli.common.messages.MessageRenderer;
@@ -37,6 +39,7 @@ import org.jetbrains.kotlin.config.CompilerConfiguration;
import org.jetbrains.kotlin.config.KotlinCompilerVersion;
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
import org.jetbrains.kotlin.descriptors.PackageViewDescriptor;
import org.jetbrains.kotlin.load.java.JvmAnnotationNames;
import org.jetbrains.kotlin.load.kotlin.DeserializedDescriptorResolver;
import org.jetbrains.kotlin.load.kotlin.JvmMetadataVersion;
import org.jetbrains.kotlin.resolve.BindingContext;
@@ -92,7 +95,7 @@ public class CompileKotlinAgainstCustomBinariesTest extends TestCaseWithTmpdir {
private String normalizeOutput(@NotNull Pair<String, ExitCode> output) {
return AbstractCliTest.getNormalizedCompilerOutput(
output.getFirst(), output.getSecond(), getTestDataDirectory().getPath(), JvmMetadataVersion.INSTANCE
);
).replace(FileUtil.toSystemIndependentName(tmpdir.getAbsolutePath()), "$TMP_DIR$");
}
private void doTestWithTxt(@NotNull File... extraClassPath) throws Exception {
@@ -134,6 +137,20 @@ public class CompileKotlinAgainstCustomBinariesTest extends TestCaseWithTmpdir {
@NotNull
private static File copyJarFileWithoutEntry(@NotNull File jarPath, @NotNull String... entriesToDelete) {
return transformJar(jarPath, new Function2<String, byte[], byte[]>() {
@Override
public byte[] invoke(String s, byte[] bytes) {
return bytes;
}
}, entriesToDelete);
}
@NotNull
private static File transformJar(
@NotNull File jarPath,
@NotNull Function2<String, byte[], byte[]> transformEntry,
@NotNull String... entriesToDelete
) {
try {
File outputFile = new File(jarPath.getParentFile(), FileUtil.getNameWithoutExtension(jarPath) + "-after.jar");
Set<String> toDelete = SetsKt.setOf(entriesToDelete);
@@ -144,11 +161,16 @@ public class CompileKotlinAgainstCustomBinariesTest extends TestCaseWithTmpdir {
try {
for (Enumeration<JarEntry> enumeration = jar.entries(); enumeration.hasMoreElements(); ) {
JarEntry jarEntry = enumeration.nextElement();
if (toDelete.contains(jarEntry.getName())) {
String name = jarEntry.getName();
if (toDelete.contains(name)) {
continue;
}
output.putNextEntry(jarEntry);
output.write(FileUtil.loadBytes(jar.getInputStream(jarEntry)));
byte[] bytes = FileUtil.loadBytes(jar.getInputStream(jarEntry));
byte[] newBytes = name.endsWith(".class") ? transformEntry.invoke(name, bytes) : bytes;
JarEntry newEntry = new JarEntry(name);
newEntry.setSize(newBytes.length);
output.putNextEntry(newEntry);
output.write(newBytes);
output.closeEntry();
}
}
@@ -228,6 +250,23 @@ public class CompileKotlinAgainstCustomBinariesTest extends TestCaseWithTmpdir {
KotlinTestUtils.assertEqualsToFile(new File(getTestDataDirectory(), "output.txt"), normalizeOutput(output));
}
private void doTestKotlinLibraryWithWrongMetadataVersion(@NotNull String libraryName, @NotNull String... additionalOptions) throws Exception {
final int[] version = new JvmMetadataVersion(42, 0, 0).toArray();
File library = transformJar(compileLibrary(libraryName), new Function2<String, byte[], byte[]>() {
@Override
public byte[] invoke(String name, byte[] bytes) {
return WrongBytecodeVersionTest.Companion.transformMetadataInClassFile(bytes, new Function2<String, Object, Object>() {
@Override
public Object invoke(String name, Object value) {
return JvmAnnotationNames.METADATA_VERSION_FIELD_NAME.equals(name) ? version : null;
}
});
}
});
Pair<String, ExitCode> output = compileKotlin("source.kt", tmpdir, Arrays.asList(additionalOptions), library);
KotlinTestUtils.assertEqualsToFile(new File(getTestDataDirectory(), "output.txt"), normalizeOutput(output));
}
@SuppressWarnings("deprecation")
private void doTestPreReleaseKotlinLibrary(@NotNull String libraryName, @NotNull String... additionalOptions) throws Exception {
// Compiles the library with the "pre-release" flag, then compiles a usage of this library in the release mode
@@ -377,6 +416,17 @@ public class CompileKotlinAgainstCustomBinariesTest extends TestCaseWithTmpdir {
}
*/
public void testWrongMetadataVersion() throws Exception {
doTestKotlinLibraryWithWrongMetadataVersion("library");
}
/*
// TODO: refactor and uncomment
public void testWrongMetadataVersionSkipVersionCheck() throws Exception {
doTestKotlinLibraryWithWrongMetadataVersion("library", "-Xskip-metadata-version-check");
}
*/
/*test source mapping generation when source info is absent*/
public void testInlineFunWithoutDebugInfo() throws Exception {
compileKotlin("sourceInline.kt", tmpdir);