diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/common/messages/AnalyzerWithCompilerReport.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/common/messages/AnalyzerWithCompilerReport.kt index 03d501013fc..786649a9a2e 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/common/messages/AnalyzerWithCompilerReport.kt +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/common/messages/AnalyzerWithCompilerReport.kt @@ -42,6 +42,7 @@ import org.jetbrains.kotlin.resolve.jvm.JvmClassName import org.jetbrains.kotlin.serialization.deserialization.BinaryVersion import java.util.* + class AnalyzerWithCompilerReport(collector: MessageCollector) { private val messageCollector: MessageSeverityCollector = MessageSeverityCollector(collector) @@ -51,7 +52,8 @@ class AnalyzerWithCompilerReport(collector: MessageCollector) { val bindingContext = analysisResult.bindingContext val classes = bindingContext.getKeys(TraceBasedErrorReporter.INCOMPLETE_HIERARCHY) if (!classes.isEmpty()) { - val message = StringBuilder("Supertypes of the following classes cannot be resolved. " + "Please make sure you have the required dependencies in the classpath:\n") + val message = StringBuilder("Supertypes of the following classes cannot be resolved. " + + "Please make sure you have the required dependencies in the classpath:\n") for (descriptor in classes) { val fqName = DescriptorUtils.getFqName(descriptor).asString() val unresolved = bindingContext.get(TraceBasedErrorReporter.INCOMPLETE_HIERARCHY, descriptor) @@ -116,9 +118,19 @@ class AnalyzerWithCompilerReport(collector: MessageCollector) { return messageCollector.anyReported(CompilerMessageSeverity.ERROR) } - fun analyzeAndReport(files: Collection, analyzer: () -> AnalysisResult) { - analysisResult = analyzer.invoke() + interface Analyzer { + fun analyze(): AnalysisResult + + fun reportEnvironmentErrors() { + } + } + + fun analyzeAndReport(files: Collection, analyzer: Analyzer) { + analysisResult = analyzer.analyze() reportSyntaxErrors(files) + if (analysisResult.bindingContext.diagnostics.any { it.isValid && it.severity == Severity.ERROR }) { + analyzer.reportEnvironmentErrors() + } val abiVersionErrors = abiVersionErrors reportDiagnostics(analysisResult.bindingContext.diagnostics, messageCollector, !abiVersionErrors.isEmpty()) if (hasErrors()) { diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/js/K2JSCompiler.java b/compiler/cli/src/org/jetbrains/kotlin/cli/js/K2JSCompiler.java index 5ff011aa2e7..8771e153e74 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/js/K2JSCompiler.java +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/js/K2JSCompiler.java @@ -25,7 +25,6 @@ import com.intellij.util.Function; import com.intellij.util.SmartList; import com.intellij.util.containers.ContainerUtil; import kotlin.Unit; -import kotlin.jvm.functions.Function0; import kotlin.jvm.functions.Function1; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -232,11 +231,16 @@ public class K2JSCompiler extends CLICompiler { private static AnalyzerWithCompilerReport analyzeAndReportErrors(@NotNull MessageCollector messageCollector, @NotNull final List sources, @NotNull final Config config) { AnalyzerWithCompilerReport analyzerWithCompilerReport = new AnalyzerWithCompilerReport(messageCollector); - analyzerWithCompilerReport.analyzeAndReport(sources, new Function0() { + analyzerWithCompilerReport.analyzeAndReport(sources, new AnalyzerWithCompilerReport.Analyzer() { + @NotNull @Override - public AnalysisResult invoke() { + public AnalysisResult analyze() { return TopDownAnalyzerFacadeForJS.analyzeFiles(sources, config); } + + @Override + public void reportEnvironmentErrors() { + } }); return analyzerWithCompilerReport; } diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinToJVMBytecodeCompiler.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinToJVMBytecodeCompiler.kt index 2996bb0f0fb..e25c5dff964 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinToJVMBytecodeCompiler.kt +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinToJVMBytecodeCompiler.kt @@ -16,15 +16,13 @@ package org.jetbrains.kotlin.cli.jvm.compiler +import com.intellij.openapi.util.io.JarUtil import org.jetbrains.kotlin.analyzer.AnalysisResult import org.jetbrains.kotlin.asJava.FilteredJvmDiagnostics import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys import org.jetbrains.kotlin.cli.common.CompilerPluginContext import org.jetbrains.kotlin.cli.common.ExitCode -import org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport -import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity -import org.jetbrains.kotlin.cli.common.messages.MessageCollector -import org.jetbrains.kotlin.cli.common.messages.MessageUtil +import org.jetbrains.kotlin.cli.common.messages.* import org.jetbrains.kotlin.cli.common.output.outputUtils.writeAll import org.jetbrains.kotlin.cli.jvm.K2JVMCompiler import org.jetbrains.kotlin.cli.jvm.config.* @@ -46,11 +44,13 @@ import org.jetbrains.kotlin.resolve.jvm.JvmClassName import org.jetbrains.kotlin.resolve.jvm.TopDownAnalyzerFacadeForJVM import org.jetbrains.kotlin.util.PerformanceCounter import org.jetbrains.kotlin.utils.KotlinPaths +import org.jetbrains.kotlin.utils.PathUtil import java.io.File import java.lang.reflect.Constructor import java.lang.reflect.InvocationTargetException import java.net.URLClassLoader import java.util.concurrent.TimeUnit +import java.util.jar.Attributes object KotlinToJVMBytecodeCompiler { @@ -102,7 +102,7 @@ object KotlinToJVMBytecodeCompiler { moduleVisibilityManager.addFriendPath(path) } - val targetDescription = "in targets [" + chunk.joinToString { input -> input.getModuleName() + "-" + input.getModuleType() } + "]" + val targetDescription = "in targets [" + chunk.joinToString { input -> input.getModuleName() + "-" + input.getModuleType() } + "]" val result = analyze(environment, targetDescription) ?: return false ProgressIndicatorAndCompilationCanceledStatus.checkCanceled() @@ -270,18 +270,24 @@ object KotlinToJVMBytecodeCompiler { val analysisStart = PerformanceCounter.currentTime() val analyzerWithCompilerReport = AnalyzerWithCompilerReport(collector) analyzerWithCompilerReport.analyzeAndReport( - environment.getSourceFiles(), { - val sharedTrace = CliLightClassGenerationSupport.NoScopeRecordCliBindingTrace() - val moduleContext = TopDownAnalyzerFacadeForJVM.createContextWithSealedModule(environment.project, - environment.getModuleName()) + environment.getSourceFiles(), object : AnalyzerWithCompilerReport.Analyzer { + override fun analyze(): AnalysisResult { + val sharedTrace = CliLightClassGenerationSupport.NoScopeRecordCliBindingTrace() + val moduleContext = TopDownAnalyzerFacadeForJVM.createContextWithSealedModule(environment.project, + environment.getModuleName()) - TopDownAnalyzerFacadeForJVM.analyzeFilesWithJavaIntegrationWithCustomContext( - moduleContext, - environment.getSourceFiles(), - sharedTrace, - environment.configuration.get(JVMConfigurationKeys.MODULES), - environment.configuration.get(JVMConfigurationKeys.INCREMENTAL_COMPILATION_COMPONENTS), - JvmPackagePartProvider(environment)) + return TopDownAnalyzerFacadeForJVM.analyzeFilesWithJavaIntegrationWithCustomContext( + moduleContext, + environment.getSourceFiles(), + sharedTrace, + environment.configuration.get(JVMConfigurationKeys.MODULES), + environment.configuration.get(JVMConfigurationKeys.INCREMENTAL_COMPILATION_COMPONENTS), + JvmPackagePartProvider(environment)) + } + + override fun reportEnvironmentErrors() { + reportRuntimeConflicts(collector, environment.configuration.jvmClasspathRoots) + } }) val analysisNanos = PerformanceCounter.currentTime() - analysisStart val message = "ANALYZE: " + environment.getSourceFiles().size + " files (" + @@ -397,4 +403,24 @@ object KotlinToJVMBytecodeCompiler { assert(result != null) { "Message collector not specified in compiler configuration" } return result!! } + + private fun reportRuntimeConflicts(messageCollector: MessageCollector, jvmClasspathRoots: List) { + fun String.removeIdeaVersionSuffix(): String { + val versionIndex = indexOfAny(arrayListOf("-IJ", "-Idea")) + return if (versionIndex >= 0) substring(0, versionIndex) else this + } + + val runtimes = jvmClasspathRoots.filter { it.name == PathUtil.KOTLIN_JAVA_RUNTIME_JAR && it.exists() } + + val runtimeVersions = runtimes.map { + JarUtil.getJarAttribute(it, Attributes.Name.IMPLEMENTATION_VERSION).orEmpty().removeIdeaVersionSuffix() + } + + if (runtimeVersions.toSet().size > 1) { + messageCollector.report(CompilerMessageSeverity.ERROR, + "Conflicting versions of Kotlin runtime on classpath: " + runtimes.joinToString { it.path }, + CompilerMessageLocation.NO_LOCATION) + } + } } + diff --git a/compiler/testData/cli/jvm/conflictingRuntimeVersion.args b/compiler/testData/cli/jvm/conflictingRuntimeVersion.args new file mode 100644 index 00000000000..4ba510281f2 --- /dev/null +++ b/compiler/testData/cli/jvm/conflictingRuntimeVersion.args @@ -0,0 +1,5 @@ +$TESTDATA_DIR$/conflictingRuntimeVersions.kt +-classpath +$TESTDATA_DIR$/kotlin-runtime-4584-stub/kotlin-runtime.jar +-d +$TEMP_DIR$ diff --git a/compiler/testData/cli/jvm/conflictingRuntimeVersion.out b/compiler/testData/cli/jvm/conflictingRuntimeVersion.out new file mode 100644 index 00000000000..9521d8c8be1 --- /dev/null +++ b/compiler/testData/cli/jvm/conflictingRuntimeVersion.out @@ -0,0 +1,5 @@ +error: conflicting versions of Kotlin runtime on classpath: compiler/testData/cli/jvm/kotlin-runtime-4584-stub/kotlin-runtime.jar, $PROJECT_DIR$/lib/kotlin-runtime.jar +compiler/testData/cli/jvm/conflictingRuntimeVersions.kt:1:9: error: unresolved reference: unresolvedFunction +val f = unresolvedFunction() + ^ +COMPILATION_ERROR \ No newline at end of file diff --git a/compiler/testData/cli/jvm/conflictingRuntimeVersionNoError.args b/compiler/testData/cli/jvm/conflictingRuntimeVersionNoError.args new file mode 100644 index 00000000000..f468c786298 --- /dev/null +++ b/compiler/testData/cli/jvm/conflictingRuntimeVersionNoError.args @@ -0,0 +1,5 @@ +$TESTDATA_DIR$/simple.kt +-classpath +$TESTDATA_DIR$/kotlin-runtime-4584-stub/kotlin-runtime.jar +-d +$TEMP_DIR$ diff --git a/compiler/testData/cli/jvm/conflictingRuntimeVersionNoError.out b/compiler/testData/cli/jvm/conflictingRuntimeVersionNoError.out new file mode 100644 index 00000000000..a0aba9318ad --- /dev/null +++ b/compiler/testData/cli/jvm/conflictingRuntimeVersionNoError.out @@ -0,0 +1 @@ +OK \ No newline at end of file diff --git a/compiler/testData/cli/jvm/conflictingRuntimeVersions.kt b/compiler/testData/cli/jvm/conflictingRuntimeVersions.kt new file mode 100644 index 00000000000..39dd7f75cad --- /dev/null +++ b/compiler/testData/cli/jvm/conflictingRuntimeVersions.kt @@ -0,0 +1 @@ +val f = unresolvedFunction() diff --git a/compiler/testData/cli/jvm/kotlin-runtime-4584-stub/kotlin-runtime.jar b/compiler/testData/cli/jvm/kotlin-runtime-4584-stub/kotlin-runtime.jar new file mode 100644 index 00000000000..16c58570900 Binary files /dev/null and b/compiler/testData/cli/jvm/kotlin-runtime-4584-stub/kotlin-runtime.jar differ diff --git a/compiler/tests/org/jetbrains/kotlin/cli/CliBaseTest.java b/compiler/tests/org/jetbrains/kotlin/cli/CliBaseTest.java index de15f64738d..dfeb2dfe850 100644 --- a/compiler/tests/org/jetbrains/kotlin/cli/CliBaseTest.java +++ b/compiler/tests/org/jetbrains/kotlin/cli/CliBaseTest.java @@ -34,6 +34,7 @@ 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; +import org.jetbrains.kotlin.utils.PathUtil; import org.junit.Rule; import org.junit.rules.TestName; @@ -83,6 +84,7 @@ public class CliBaseTest { ) { String normalizedOutputWithoutExitCode = pureOutput .replace(new File(testDataDir).getAbsolutePath(), "$TESTDATA_DIR$") + .replace(PathUtil.getKotlinPathsForDistDirectory().getHomePath().getAbsolutePath(), "$PROJECT_DIR$") .replace("expected version is " + version, "expected version is $ABI_VERSION$") .replace("\\", "/") .replace(KotlinVersion.VERSION, "$VERSION$"); diff --git a/compiler/tests/org/jetbrains/kotlin/cli/KotlincExecutableTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/cli/KotlincExecutableTestGenerated.java index 1e23f2a3c72..38282e1031a 100644 --- a/compiler/tests/org/jetbrains/kotlin/cli/KotlincExecutableTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/cli/KotlincExecutableTestGenerated.java @@ -73,6 +73,18 @@ public class KotlincExecutableTestGenerated extends AbstractKotlincExecutableTes doJvmTest(fileName); } + @TestMetadata("conflictingRuntimeVersion.args") + public void testConflictingRuntimeVersion() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/cli/jvm/conflictingRuntimeVersion.args"); + doJvmTest(fileName); + } + + @TestMetadata("conflictingRuntimeVersionNoError.args") + public void testConflictingRuntimeVersionNoError() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/cli/jvm/conflictingRuntimeVersionNoError.args"); + doJvmTest(fileName); + } + @TestMetadata("diagnosticsOrder.args") public void testDiagnosticsOrder() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/cli/jvm/diagnosticsOrder.args"); diff --git a/libraries/kotlin.test/shared/pom.xml b/libraries/kotlin.test/shared/pom.xml index da45fd238b4..4d86c0ef78a 100644 --- a/libraries/kotlin.test/shared/pom.xml +++ b/libraries/kotlin.test/shared/pom.xml @@ -161,6 +161,11 @@ kotlin/internal/OnlyInputTypes* kotlin/internal + + + true + + diff --git a/libraries/pom.xml b/libraries/pom.xml index b164b4af3a9..ec5c537c07a 100644 --- a/libraries/pom.xml +++ b/libraries/pom.xml @@ -228,6 +228,16 @@ + + maven-jar-plugin + + + + true + + + + diff --git a/libraries/tools/kotlin-reflect/pom.xml b/libraries/tools/kotlin-reflect/pom.xml index 59a35382fab..88a45423f1a 100644 --- a/libraries/tools/kotlin-reflect/pom.xml +++ b/libraries/tools/kotlin-reflect/pom.xml @@ -50,6 +50,13 @@ org.apache.maven.plugins maven-jar-plugin 2.6 + + + + true + + + empty-javadoc-jar