JS: support -Xskip-metadata-version-check for incompatible ABI libraries
Allow the compiler to read such libraries without any errors, at the risk of crashing with an exception. Also fix a minor bug in the diagnostic message in LibrarySourcesConfig and in the corresponding test in KotlinJpsBuildTest
This commit is contained in:
+11
@@ -0,0 +1,11 @@
|
|||||||
|
package a
|
||||||
|
|
||||||
|
open class A {
|
||||||
|
class Nested
|
||||||
|
|
||||||
|
fun method() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun foo() {}
|
||||||
|
var bar = 42
|
||||||
|
typealias TA = String
|
||||||
+2
@@ -0,0 +1,2 @@
|
|||||||
|
error: file '$TMP_DIR$/library.meta.js' was compiled with an incompatible version of Kotlin. The binary version of its metadata is 42.0.0, expected version is 1.0.0
|
||||||
|
COMPILATION_ERROR
|
||||||
+15
@@ -0,0 +1,15 @@
|
|||||||
|
package usage
|
||||||
|
|
||||||
|
import a.*
|
||||||
|
|
||||||
|
fun baz(param: A, nested: A.Nested) {
|
||||||
|
val constructor = A()
|
||||||
|
val nested = A.Nested()
|
||||||
|
val methodCall = param.method()
|
||||||
|
val supertype = object : A() {}
|
||||||
|
|
||||||
|
val x = foo()
|
||||||
|
val y = bar
|
||||||
|
bar = 239
|
||||||
|
val z: TA = ""
|
||||||
|
}
|
||||||
+11
@@ -0,0 +1,11 @@
|
|||||||
|
package a
|
||||||
|
|
||||||
|
open class A {
|
||||||
|
class Nested
|
||||||
|
|
||||||
|
fun method() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun foo() {}
|
||||||
|
var bar = 42
|
||||||
|
typealias TA = String
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
OK
|
||||||
+16
@@ -0,0 +1,16 @@
|
|||||||
|
@file:Suppress("UNUSED_VARIABLE", "UNUSED_PARAMETER")
|
||||||
|
package usage
|
||||||
|
|
||||||
|
import a.*
|
||||||
|
|
||||||
|
fun baz(param: A, nested: A.Nested) {
|
||||||
|
val constructor = A()
|
||||||
|
val nested2 = A.Nested()
|
||||||
|
val methodCall = param.method()
|
||||||
|
val supertype = object : A() {}
|
||||||
|
|
||||||
|
val x = foo()
|
||||||
|
val y = bar
|
||||||
|
bar = 239
|
||||||
|
val z: TA = ""
|
||||||
|
}
|
||||||
+25
@@ -25,6 +25,7 @@ import kotlin.Pair;
|
|||||||
import kotlin.collections.SetsKt;
|
import kotlin.collections.SetsKt;
|
||||||
import kotlin.io.FilesKt;
|
import kotlin.io.FilesKt;
|
||||||
import kotlin.jvm.functions.Function2;
|
import kotlin.jvm.functions.Function2;
|
||||||
|
import kotlin.text.Charsets;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.kotlin.analyzer.AnalysisResult;
|
import org.jetbrains.kotlin.analyzer.AnalysisResult;
|
||||||
@@ -52,6 +53,7 @@ import org.jetbrains.kotlin.test.*;
|
|||||||
import org.jetbrains.kotlin.test.util.DescriptorValidator;
|
import org.jetbrains.kotlin.test.util.DescriptorValidator;
|
||||||
import org.jetbrains.kotlin.test.util.RecursiveDescriptorComparator;
|
import org.jetbrains.kotlin.test.util.RecursiveDescriptorComparator;
|
||||||
import org.jetbrains.kotlin.utils.ExceptionUtilsKt;
|
import org.jetbrains.kotlin.utils.ExceptionUtilsKt;
|
||||||
|
import org.jetbrains.kotlin.utils.JsMetadataVersion;
|
||||||
import org.jetbrains.kotlin.utils.StringsKt;
|
import org.jetbrains.kotlin.utils.StringsKt;
|
||||||
import org.jetbrains.org.objectweb.asm.ClassReader;
|
import org.jetbrains.org.objectweb.asm.ClassReader;
|
||||||
import org.jetbrains.org.objectweb.asm.ClassVisitor;
|
import org.jetbrains.org.objectweb.asm.ClassVisitor;
|
||||||
@@ -316,6 +318,21 @@ public class CompileKotlinAgainstCustomBinariesTest extends TestCaseWithTmpdir {
|
|||||||
KotlinTestUtils.assertEqualsToFile(new File(getTestDataDirectory(), "output.txt"), normalizeOutput(output));
|
KotlinTestUtils.assertEqualsToFile(new File(getTestDataDirectory(), "output.txt"), normalizeOutput(output));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void doTestKotlinLibraryWithWrongMetadataVersionJs(@NotNull String libraryName, @NotNull String... additionalOptions) {
|
||||||
|
compileLibrary(new K2JSCompiler(), libraryName, new File(tmpdir, "library.js"), Collections.<String>emptyList());
|
||||||
|
|
||||||
|
File library = new File(tmpdir, "library.meta.js");
|
||||||
|
FilesKt.writeText(library, FilesKt.readText(library, Charsets.UTF_8).replace(
|
||||||
|
"(" + JsMetadataVersion.INSTANCE.toInteger() + ", ",
|
||||||
|
"(" + new JsMetadataVersion(42, 0, 0).toInteger() + ", "
|
||||||
|
), Charsets.UTF_8);
|
||||||
|
|
||||||
|
Pair<String, ExitCode> output = compileKotlin(
|
||||||
|
new K2JSCompiler(), "source.kt", new File(tmpdir, "usage.js"), Arrays.asList(additionalOptions), library
|
||||||
|
);
|
||||||
|
KotlinTestUtils.assertEqualsToFile(new File(getTestDataDirectory(), "output.txt"), normalizeOutput(output));
|
||||||
|
}
|
||||||
|
|
||||||
private void doTestPreReleaseKotlinLibrary(
|
private void doTestPreReleaseKotlinLibrary(
|
||||||
@NotNull CLICompiler<?> compiler,
|
@NotNull CLICompiler<?> compiler,
|
||||||
@NotNull String libraryName,
|
@NotNull String libraryName,
|
||||||
@@ -492,6 +509,10 @@ public class CompileKotlinAgainstCustomBinariesTest extends TestCaseWithTmpdir {
|
|||||||
doTestKotlinLibraryWithWrongMetadataVersion("library", null);
|
doTestKotlinLibraryWithWrongMetadataVersion("library", null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testWrongMetadataVersionJs() throws Exception {
|
||||||
|
doTestKotlinLibraryWithWrongMetadataVersionJs("library");
|
||||||
|
}
|
||||||
|
|
||||||
public void testWrongMetadataVersionBadMetadata() throws Exception {
|
public void testWrongMetadataVersionBadMetadata() throws Exception {
|
||||||
doTestKotlinLibraryWithWrongMetadataVersion(
|
doTestKotlinLibraryWithWrongMetadataVersion(
|
||||||
"library",
|
"library",
|
||||||
@@ -532,6 +553,10 @@ public class CompileKotlinAgainstCustomBinariesTest extends TestCaseWithTmpdir {
|
|||||||
doTestKotlinLibraryWithWrongMetadataVersion("library", null, "-Xskip-metadata-version-check");
|
doTestKotlinLibraryWithWrongMetadataVersion("library", null, "-Xskip-metadata-version-check");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testWrongMetadataVersionJsSkipVersionCheck() throws Exception {
|
||||||
|
doTestKotlinLibraryWithWrongMetadataVersionJs("library", "-Xskip-metadata-version-check");
|
||||||
|
}
|
||||||
|
|
||||||
/*test source mapping generation when source info is absent*/
|
/*test source mapping generation when source info is absent*/
|
||||||
public void testInlineFunWithoutDebugInfo() throws Exception {
|
public void testInlineFunWithoutDebugInfo() throws Exception {
|
||||||
compileKotlin("sourceInline.kt", tmpdir);
|
compileKotlin("sourceInline.kt", tmpdir);
|
||||||
|
|||||||
@@ -393,7 +393,7 @@ class KotlinJpsBuildTest : AbstractKotlinJpsBuildTestCase() {
|
|||||||
|
|
||||||
val warnings = buildResult.getMessages(BuildMessage.Kind.WARNING)
|
val warnings = buildResult.getMessages(BuildMessage.Kind.WARNING)
|
||||||
assertEquals("Warning about duplicate module definition: $warnings", 1, warnings.size)
|
assertEquals("Warning about duplicate module definition: $warnings", 1, warnings.size)
|
||||||
assertEquals("Module \"srcAndTests\" is defined in more, than one file", warnings[0].messageText)
|
assertEquals("Module \"srcAndTests\" is defined in more than one file", warnings[0].messageText)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun testKotlinJavaScriptProjectWithTwoSrcModuleDependency() {
|
fun testKotlinJavaScriptProjectWithTwoSrcModuleDependency() {
|
||||||
|
|||||||
@@ -21,9 +21,7 @@ import com.intellij.util.SmartList;
|
|||||||
import kotlin.collections.CollectionsKt;
|
import kotlin.collections.CollectionsKt;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.kotlin.config.CommonConfigurationKeys;
|
import org.jetbrains.kotlin.config.*;
|
||||||
import org.jetbrains.kotlin.config.CommonConfigurationKeysKt;
|
|
||||||
import org.jetbrains.kotlin.config.CompilerConfiguration;
|
|
||||||
import org.jetbrains.kotlin.descriptors.PackageFragmentProvider;
|
import org.jetbrains.kotlin.descriptors.PackageFragmentProvider;
|
||||||
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl;
|
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl;
|
||||||
import org.jetbrains.kotlin.js.resolve.JsPlatform;
|
import org.jetbrains.kotlin.js.resolve.JsPlatform;
|
||||||
@@ -121,7 +119,9 @@ public abstract class JsConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private JsModuleDescriptor<ModuleDescriptorImpl> createModuleDescriptor(KotlinJavascriptMetadata metadata) {
|
private JsModuleDescriptor<ModuleDescriptorImpl> createModuleDescriptor(KotlinJavascriptMetadata metadata) {
|
||||||
assert metadata.getVersion().isCompatible() :
|
LanguageVersionSettings languageVersionSettings = CommonConfigurationKeysKt.getLanguageVersionSettings(configuration);
|
||||||
|
assert metadata.getVersion().isCompatible() ||
|
||||||
|
languageVersionSettings.isFlagEnabled(AnalysisFlags.getSkipMetadataVersionCheck()) :
|
||||||
"Expected JS metadata version " + JsMetadataVersion.INSTANCE + ", but actual metadata version is " + metadata.getVersion();
|
"Expected JS metadata version " + JsMetadataVersion.INSTANCE + ", but actual metadata version is " + metadata.getVersion();
|
||||||
|
|
||||||
ModuleDescriptorImpl moduleDescriptor = new ModuleDescriptorImpl(
|
ModuleDescriptorImpl moduleDescriptor = new ModuleDescriptorImpl(
|
||||||
@@ -130,7 +130,7 @@ public abstract class JsConfig {
|
|||||||
|
|
||||||
JsModuleDescriptor<PackageFragmentProvider> rawDescriptor = KotlinJavascriptSerializationUtil.readModule(
|
JsModuleDescriptor<PackageFragmentProvider> rawDescriptor = KotlinJavascriptSerializationUtil.readModule(
|
||||||
metadata.getBody(), storageManager, moduleDescriptor,
|
metadata.getBody(), storageManager, moduleDescriptor,
|
||||||
new CompilerDeserializationConfiguration(CommonConfigurationKeysKt.getLanguageVersionSettings(configuration))
|
new CompilerDeserializationConfiguration(languageVersionSettings)
|
||||||
);
|
);
|
||||||
|
|
||||||
PackageFragmentProvider provider = rawDescriptor.getData();
|
PackageFragmentProvider provider = rawDescriptor.getData();
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import kotlin.Unit;
|
|||||||
import kotlin.jvm.functions.Function1;
|
import kotlin.jvm.functions.Function1;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.jetbrains.kotlin.config.AnalysisFlags;
|
||||||
import org.jetbrains.kotlin.config.CompilerConfiguration;
|
import org.jetbrains.kotlin.config.CompilerConfiguration;
|
||||||
import org.jetbrains.kotlin.utils.JsMetadataVersion;
|
import org.jetbrains.kotlin.utils.JsMetadataVersion;
|
||||||
import org.jetbrains.kotlin.utils.KotlinJavascriptMetadata;
|
import org.jetbrains.kotlin.utils.KotlinJavascriptMetadata;
|
||||||
@@ -38,6 +39,7 @@ import java.util.HashSet;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import static org.jetbrains.kotlin.config.CommonConfigurationKeysKt.getLanguageVersionSettings;
|
||||||
import static org.jetbrains.kotlin.utils.PathUtil.getKotlinPathsForDistDirectory;
|
import static org.jetbrains.kotlin.utils.PathUtil.getKotlinPathsForDistDirectory;
|
||||||
|
|
||||||
public class LibrarySourcesConfig extends JsConfig {
|
public class LibrarySourcesConfig extends JsConfig {
|
||||||
@@ -100,6 +102,9 @@ public class LibrarySourcesConfig extends JsConfig {
|
|||||||
|
|
||||||
Set<String> modules = new HashSet<String>();
|
Set<String> modules = new HashSet<String>();
|
||||||
|
|
||||||
|
boolean skipMetadataVersionCheck =
|
||||||
|
getLanguageVersionSettings(getConfiguration()).isFlagEnabled(AnalysisFlags.getSkipMetadataVersionCheck());
|
||||||
|
|
||||||
for (String path : libraries) {
|
for (String path : libraries) {
|
||||||
VirtualFile file;
|
VirtualFile file;
|
||||||
|
|
||||||
@@ -128,15 +133,16 @@ public class LibrarySourcesConfig extends JsConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (KotlinJavascriptMetadata metadata : metadataList) {
|
for (KotlinJavascriptMetadata metadata : metadataList) {
|
||||||
if (!metadata.getVersion().isCompatible()) {
|
if (!metadata.getVersion().isCompatible() && !skipMetadataVersionCheck) {
|
||||||
report.error("File '" + path + "' was compiled with an incompatible version of Kotlin. " +
|
report.error("File '" + path + "' was compiled with an incompatible version of Kotlin. " +
|
||||||
"The binary version of its metadata is " + metadata.getVersion() +
|
"The binary version of its metadata is " + metadata.getVersion() +
|
||||||
", expected version is " + JsMetadataVersion.INSTANCE);
|
", expected version is " + JsMetadataVersion.INSTANCE);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (!modules.add(metadata.getModuleName())) {
|
if (!modules.add(metadata.getModuleName())) {
|
||||||
report.warning("Module \"" + metadata.getModuleName() + "\" is defined in more, than one file");
|
report.warning("Module \"" + metadata.getModuleName() + "\" is defined in more than one file");
|
||||||
}}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (action != null) {
|
if (action != null) {
|
||||||
action.invoke(file);
|
action.invoke(file);
|
||||||
|
|||||||
Reference in New Issue
Block a user