Report error on generating calls to binary incompatible classes
This commit is contained in:
@@ -16,12 +16,12 @@
|
||||
|
||||
package org.jetbrains.kotlin.cli;
|
||||
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import kotlin.Charsets;
|
||||
import kotlin.Pair;
|
||||
import kotlin.io.FilesKt;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.kotlin.cli.common.CLICompiler;
|
||||
@@ -30,6 +30,7 @@ import org.jetbrains.kotlin.cli.common.KotlinVersion;
|
||||
import org.jetbrains.kotlin.cli.js.K2JSCompiler;
|
||||
import org.jetbrains.kotlin.cli.jvm.K2JVMCompiler;
|
||||
import org.jetbrains.kotlin.load.kotlin.JvmMetadataVersion;
|
||||
import org.jetbrains.kotlin.serialization.deserialization.BinaryVersion;
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils;
|
||||
import org.jetbrains.kotlin.test.Tmpdir;
|
||||
import org.jetbrains.kotlin.utils.ExceptionUtilsKt;
|
||||
@@ -58,7 +59,7 @@ public class CliBaseTest {
|
||||
try {
|
||||
System.setErr(new PrintStream(bytes));
|
||||
ExitCode exitCode = CLICompiler.doMainNoExit(compiler, ArrayUtil.toStringArray(args));
|
||||
return Pair.create(bytes.toString("utf-8"), exitCode);
|
||||
return new Pair<String, ExitCode>(bytes.toString("utf-8"), exitCode);
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw ExceptionUtilsKt.rethrow(e);
|
||||
@@ -70,9 +71,19 @@ public class CliBaseTest {
|
||||
|
||||
@NotNull
|
||||
public static String getNormalizedCompilerOutput(@NotNull String pureOutput, @NotNull ExitCode exitCode, @NotNull String testDataDir) {
|
||||
return getNormalizedCompilerOutput(pureOutput, exitCode, testDataDir, JvmMetadataVersion.INSTANCE);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static String getNormalizedCompilerOutput(
|
||||
@NotNull String pureOutput,
|
||||
@NotNull ExitCode exitCode,
|
||||
@NotNull String testDataDir,
|
||||
@NotNull BinaryVersion version
|
||||
) {
|
||||
String normalizedOutputWithoutExitCode = pureOutput
|
||||
.replace(new File(testDataDir).getAbsolutePath(), "$TESTDATA_DIR$")
|
||||
.replace("expected version is " + JvmMetadataVersion.INSTANCE, "expected version is $ABI_VERSION$")
|
||||
.replace("expected version is " + version, "expected version is $ABI_VERSION$")
|
||||
.replace("\\", "/")
|
||||
.replace(KotlinVersion.VERSION, "$VERSION$");
|
||||
|
||||
@@ -95,7 +106,7 @@ public class CliBaseTest {
|
||||
Pair<String, ExitCode> outputAndExitCode =
|
||||
executeCompilerGrabOutput(compiler, readArgs(testDataDir + "/" + testName.getMethodName() + ".args", testDataDir,
|
||||
tmpdir.getTmpDir().getPath()));
|
||||
String actual = getNormalizedCompilerOutput(outputAndExitCode.first, outputAndExitCode.second, testDataDir);
|
||||
String actual = getNormalizedCompilerOutput(outputAndExitCode.getFirst(), outputAndExitCode.getSecond(), testDataDir);
|
||||
|
||||
KotlinTestUtils.assertEqualsToFile(new File(testDataDir + "/" + testName.getMethodName() + ".out"), actual);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright 2010-2016 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.kotlin.cli
|
||||
|
||||
import com.intellij.ide.highlighter.JavaClassFileType
|
||||
import com.intellij.testFramework.UsefulTestCase
|
||||
import org.jetbrains.kotlin.cli.common.ExitCode
|
||||
import org.jetbrains.kotlin.cli.jvm.K2JVMCompiler
|
||||
import org.jetbrains.kotlin.codegen.AsmUtil
|
||||
import org.jetbrains.kotlin.jvm.compiler.LoadDescriptorUtil
|
||||
import org.jetbrains.kotlin.load.java.JvmAnnotationNames
|
||||
import org.jetbrains.kotlin.load.java.JvmBytecodeBinaryVersion
|
||||
import org.jetbrains.kotlin.test.ConfigurationKind
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils
|
||||
import org.jetbrains.org.objectweb.asm.*
|
||||
import java.io.File
|
||||
|
||||
class WrongBytecodeVersionTest : UsefulTestCase() {
|
||||
private val incompatibleVersion = JvmBytecodeBinaryVersion(42, 0, 0).toArray()
|
||||
|
||||
private fun doTest(relativeDirectory: String) {
|
||||
val directory = KotlinTestUtils.getTestDataPathBase() + relativeDirectory
|
||||
val librarySource = File(directory, "A.kt")
|
||||
val usageSource = File(directory, "B.kt")
|
||||
|
||||
val tmpdir = KotlinTestUtils.tmpDir(javaClass.simpleName)
|
||||
LoadDescriptorUtil.compileKotlinToDirAndGetAnalysisResult(
|
||||
listOf(librarySource), tmpdir, testRootDisposable, ConfigurationKind.ALL, false
|
||||
)
|
||||
|
||||
for (classFile in File(tmpdir, "library").listFiles { file -> file.extension == JavaClassFileType.INSTANCE.defaultExtension }) {
|
||||
changeVersionInBytecode(classFile)
|
||||
}
|
||||
|
||||
val (output, exitCode) = CliBaseTest.executeCompilerGrabOutput(K2JVMCompiler(), listOf(
|
||||
usageSource.path,
|
||||
"-classpath", tmpdir.path,
|
||||
"-d", tmpdir.path
|
||||
))
|
||||
|
||||
assertEquals("Compilation error expected", ExitCode.COMPILATION_ERROR, exitCode)
|
||||
|
||||
val normalized = CliBaseTest.getNormalizedCompilerOutput(output, exitCode, tmpdir.path, JvmBytecodeBinaryVersion.INSTANCE)
|
||||
|
||||
KotlinTestUtils.assertEqualsToFile(File(directory, "output.txt"), normalized)
|
||||
}
|
||||
|
||||
private fun changeVersionInBytecode(file: File) {
|
||||
val writer = ClassWriter(0)
|
||||
ClassReader(file.inputStream()).accept(object : ClassVisitor(Opcodes.ASM5, writer) {
|
||||
override fun visitAnnotation(desc: String, visible: Boolean): AnnotationVisitor? {
|
||||
val superVisitor = super.visitAnnotation(desc, visible)!!
|
||||
if (desc == AsmUtil.asmDescByFqNameWithoutInnerClasses(JvmAnnotationNames.METADATA)) {
|
||||
return object : AnnotationVisitor(Opcodes.ASM5, superVisitor) {
|
||||
override fun visit(name: String?, value: Any) {
|
||||
val updatedValue: Any =
|
||||
if (name == JvmAnnotationNames.BYTECODE_VERSION_FIELD_NAME) incompatibleVersion
|
||||
else value
|
||||
super.visit(name, updatedValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
return superVisitor
|
||||
}
|
||||
}, 0)
|
||||
file.writeBytes(writer.toByteArray())
|
||||
}
|
||||
|
||||
fun testSimple() {
|
||||
doTest("/bytecodeVersion/simple")
|
||||
}
|
||||
}
|
||||
+15
-14
@@ -18,9 +18,9 @@ package org.jetbrains.kotlin.jvm.compiler;
|
||||
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import kotlin.Pair;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.kotlin.analyzer.AnalysisResult;
|
||||
import org.jetbrains.kotlin.cli.CliBaseTest;
|
||||
@@ -75,6 +75,11 @@ public class CompileKotlinAgainstCustomBinariesTest extends TestCaseWithTmpdir {
|
||||
);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private String normalizeOutput(@NotNull Pair<String, ExitCode> output) {
|
||||
return CliBaseTest.getNormalizedCompilerOutput(output.getFirst(), output.getSecond(), getTestDataDirectory().getPath());
|
||||
}
|
||||
|
||||
private void doTestWithTxt(@NotNull File... extraClassPath) throws Exception {
|
||||
PackageViewDescriptor packageView = analyzeFileToPackageView(extraClassPath);
|
||||
|
||||
@@ -154,25 +159,23 @@ public class CompileKotlinAgainstCustomBinariesTest extends TestCaseWithTmpdir {
|
||||
|
||||
File libSrc = new File(getTestDataDirectory(), "library/test/lib.kt");
|
||||
|
||||
Pair<String, ExitCode> pair1 = CliBaseTest.executeCompilerGrabOutput(new K2JVMCompiler(), Arrays.asList(
|
||||
Pair<String, ExitCode> outputLib = CliBaseTest.executeCompilerGrabOutput(new K2JVMCompiler(), Arrays.asList(
|
||||
libSrc.getPath(),
|
||||
"-classpath", tmpdir.getPath(),
|
||||
"-d", tmpdir.getPath()
|
||||
));
|
||||
|
||||
String outputLib = CliBaseTest.getNormalizedCompilerOutput(pair1.first, pair1.second, getTestDataDirectory().getPath());
|
||||
|
||||
File mainSrc = new File(getTestDataDirectory(), "main.kt");
|
||||
|
||||
Pair<String, ExitCode> pair2 = CliBaseTest.executeCompilerGrabOutput(new K2JVMCompiler(), Arrays.asList(
|
||||
Pair<String, ExitCode> outputMain = CliBaseTest.executeCompilerGrabOutput(new K2JVMCompiler(), Arrays.asList(
|
||||
mainSrc.getPath(),
|
||||
"-classpath", tmpdir.getPath(),
|
||||
"-d", tmpdir.getPath()
|
||||
));
|
||||
|
||||
String outputMain = CliBaseTest.getNormalizedCompilerOutput(pair2.first, pair2.second, getTestDataDirectory().getPath());
|
||||
|
||||
KotlinTestUtils.assertEqualsToFile(new File(getTestDataDirectory(), "output.txt"), outputLib + "\n" + outputMain);
|
||||
KotlinTestUtils.assertEqualsToFile(
|
||||
new File(getTestDataDirectory(), "output.txt"), normalizeOutput(outputLib) + "\n" + normalizeOutput(outputMain)
|
||||
);
|
||||
}
|
||||
|
||||
public void testDuplicateObjectInBinaryAndSources() throws Exception {
|
||||
@@ -237,14 +240,13 @@ public class CompileKotlinAgainstCustomBinariesTest extends TestCaseWithTmpdir {
|
||||
|
||||
File source = new File(getTestDataDirectory(), "source.kt");
|
||||
|
||||
Pair<String, ExitCode> pair = CliBaseTest.executeCompilerGrabOutput(new K2JVMCompiler(), Arrays.asList(
|
||||
Pair<String, ExitCode> output = CliBaseTest.executeCompilerGrabOutput(new K2JVMCompiler(), Arrays.asList(
|
||||
source.getPath(),
|
||||
"-classpath", tmpdir.getPath(),
|
||||
"-d", tmpdir.getPath()
|
||||
));
|
||||
String output = CliBaseTest.getNormalizedCompilerOutput(pair.first, pair.second, getTestDataDirectory().getPath());
|
||||
|
||||
KotlinTestUtils.assertEqualsToFile(new File(getTestDataDirectory(), "output.txt"), output);
|
||||
KotlinTestUtils.assertEqualsToFile(new File(getTestDataDirectory(), "output.txt"), normalizeOutput(output));
|
||||
}
|
||||
|
||||
public void testIncompleteHierarchyInKotlin() throws Exception {
|
||||
@@ -254,14 +256,13 @@ public class CompileKotlinAgainstCustomBinariesTest extends TestCaseWithTmpdir {
|
||||
|
||||
File source = new File(getTestDataDirectory(), "source.kt");
|
||||
|
||||
Pair<String, ExitCode> pair = CliBaseTest.executeCompilerGrabOutput(new K2JVMCompiler(), Arrays.asList(
|
||||
Pair<String, ExitCode> output = CliBaseTest.executeCompilerGrabOutput(new K2JVMCompiler(), Arrays.asList(
|
||||
source.getPath(),
|
||||
"-classpath", library.getPath(),
|
||||
"-d", tmpdir.getPath()
|
||||
));
|
||||
String output = CliBaseTest.getNormalizedCompilerOutput(pair.first, pair.second, getTestDataDirectory().getPath());
|
||||
|
||||
KotlinTestUtils.assertEqualsToFile(new File(getTestDataDirectory(), "output.txt"), output);
|
||||
KotlinTestUtils.assertEqualsToFile(new File(getTestDataDirectory(), "output.txt"), normalizeOutput(output));
|
||||
}
|
||||
|
||||
/*test source mapping generation when source info is absent*/
|
||||
|
||||
Reference in New Issue
Block a user