report presence of multiple different versions of kotlin-runtime on the classpath as compilation error if other compilation errors have occurred

This commit is contained in:
Dmitry Jemerov
2016-01-19 13:51:35 +01:00
parent 4f5b2ec4b4
commit ccef1ad49e
14 changed files with 117 additions and 22 deletions
@@ -42,6 +42,7 @@ import org.jetbrains.kotlin.resolve.jvm.JvmClassName
import org.jetbrains.kotlin.serialization.deserialization.BinaryVersion import org.jetbrains.kotlin.serialization.deserialization.BinaryVersion
import java.util.* import java.util.*
class AnalyzerWithCompilerReport(collector: MessageCollector) { class AnalyzerWithCompilerReport(collector: MessageCollector) {
private val messageCollector: MessageSeverityCollector = MessageSeverityCollector(collector) private val messageCollector: MessageSeverityCollector = MessageSeverityCollector(collector)
@@ -51,7 +52,8 @@ class AnalyzerWithCompilerReport(collector: MessageCollector) {
val bindingContext = analysisResult.bindingContext val bindingContext = analysisResult.bindingContext
val classes = bindingContext.getKeys(TraceBasedErrorReporter.INCOMPLETE_HIERARCHY) val classes = bindingContext.getKeys(TraceBasedErrorReporter.INCOMPLETE_HIERARCHY)
if (!classes.isEmpty()) { 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) { for (descriptor in classes) {
val fqName = DescriptorUtils.getFqName(descriptor).asString() val fqName = DescriptorUtils.getFqName(descriptor).asString()
val unresolved = bindingContext.get(TraceBasedErrorReporter.INCOMPLETE_HIERARCHY, descriptor) val unresolved = bindingContext.get(TraceBasedErrorReporter.INCOMPLETE_HIERARCHY, descriptor)
@@ -116,9 +118,19 @@ class AnalyzerWithCompilerReport(collector: MessageCollector) {
return messageCollector.anyReported(CompilerMessageSeverity.ERROR) return messageCollector.anyReported(CompilerMessageSeverity.ERROR)
} }
fun analyzeAndReport(files: Collection<KtFile>, analyzer: () -> AnalysisResult) { interface Analyzer {
analysisResult = analyzer.invoke() fun analyze(): AnalysisResult
fun reportEnvironmentErrors() {
}
}
fun analyzeAndReport(files: Collection<KtFile>, analyzer: Analyzer) {
analysisResult = analyzer.analyze()
reportSyntaxErrors(files) reportSyntaxErrors(files)
if (analysisResult.bindingContext.diagnostics.any { it.isValid && it.severity == Severity.ERROR }) {
analyzer.reportEnvironmentErrors()
}
val abiVersionErrors = abiVersionErrors val abiVersionErrors = abiVersionErrors
reportDiagnostics(analysisResult.bindingContext.diagnostics, messageCollector, !abiVersionErrors.isEmpty()) reportDiagnostics(analysisResult.bindingContext.diagnostics, messageCollector, !abiVersionErrors.isEmpty())
if (hasErrors()) { if (hasErrors()) {
@@ -25,7 +25,6 @@ import com.intellij.util.Function;
import com.intellij.util.SmartList; import com.intellij.util.SmartList;
import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.ContainerUtil;
import kotlin.Unit; import kotlin.Unit;
import kotlin.jvm.functions.Function0;
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;
@@ -232,11 +231,16 @@ public class K2JSCompiler extends CLICompiler<K2JSCompilerArguments> {
private static AnalyzerWithCompilerReport analyzeAndReportErrors(@NotNull MessageCollector messageCollector, private static AnalyzerWithCompilerReport analyzeAndReportErrors(@NotNull MessageCollector messageCollector,
@NotNull final List<KtFile> sources, @NotNull final Config config) { @NotNull final List<KtFile> sources, @NotNull final Config config) {
AnalyzerWithCompilerReport analyzerWithCompilerReport = new AnalyzerWithCompilerReport(messageCollector); AnalyzerWithCompilerReport analyzerWithCompilerReport = new AnalyzerWithCompilerReport(messageCollector);
analyzerWithCompilerReport.analyzeAndReport(sources, new Function0<AnalysisResult>() { analyzerWithCompilerReport.analyzeAndReport(sources, new AnalyzerWithCompilerReport.Analyzer() {
@NotNull
@Override @Override
public AnalysisResult invoke() { public AnalysisResult analyze() {
return TopDownAnalyzerFacadeForJS.analyzeFiles(sources, config); return TopDownAnalyzerFacadeForJS.analyzeFiles(sources, config);
} }
@Override
public void reportEnvironmentErrors() {
}
}); });
return analyzerWithCompilerReport; return analyzerWithCompilerReport;
} }
@@ -16,15 +16,13 @@
package org.jetbrains.kotlin.cli.jvm.compiler package org.jetbrains.kotlin.cli.jvm.compiler
import com.intellij.openapi.util.io.JarUtil
import org.jetbrains.kotlin.analyzer.AnalysisResult import org.jetbrains.kotlin.analyzer.AnalysisResult
import org.jetbrains.kotlin.asJava.FilteredJvmDiagnostics import org.jetbrains.kotlin.asJava.FilteredJvmDiagnostics
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
import org.jetbrains.kotlin.cli.common.CompilerPluginContext import org.jetbrains.kotlin.cli.common.CompilerPluginContext
import org.jetbrains.kotlin.cli.common.ExitCode import org.jetbrains.kotlin.cli.common.ExitCode
import org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport import org.jetbrains.kotlin.cli.common.messages.*
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.output.outputUtils.writeAll import org.jetbrains.kotlin.cli.common.output.outputUtils.writeAll
import org.jetbrains.kotlin.cli.jvm.K2JVMCompiler import org.jetbrains.kotlin.cli.jvm.K2JVMCompiler
import org.jetbrains.kotlin.cli.jvm.config.* 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.resolve.jvm.TopDownAnalyzerFacadeForJVM
import org.jetbrains.kotlin.util.PerformanceCounter import org.jetbrains.kotlin.util.PerformanceCounter
import org.jetbrains.kotlin.utils.KotlinPaths import org.jetbrains.kotlin.utils.KotlinPaths
import org.jetbrains.kotlin.utils.PathUtil
import java.io.File import java.io.File
import java.lang.reflect.Constructor import java.lang.reflect.Constructor
import java.lang.reflect.InvocationTargetException import java.lang.reflect.InvocationTargetException
import java.net.URLClassLoader import java.net.URLClassLoader
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import java.util.jar.Attributes
object KotlinToJVMBytecodeCompiler { object KotlinToJVMBytecodeCompiler {
@@ -102,7 +102,7 @@ object KotlinToJVMBytecodeCompiler {
moduleVisibilityManager.addFriendPath(path) 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 val result = analyze(environment, targetDescription) ?: return false
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled() ProgressIndicatorAndCompilationCanceledStatus.checkCanceled()
@@ -270,18 +270,24 @@ object KotlinToJVMBytecodeCompiler {
val analysisStart = PerformanceCounter.currentTime() val analysisStart = PerformanceCounter.currentTime()
val analyzerWithCompilerReport = AnalyzerWithCompilerReport(collector) val analyzerWithCompilerReport = AnalyzerWithCompilerReport(collector)
analyzerWithCompilerReport.analyzeAndReport( analyzerWithCompilerReport.analyzeAndReport(
environment.getSourceFiles(), { environment.getSourceFiles(), object : AnalyzerWithCompilerReport.Analyzer {
val sharedTrace = CliLightClassGenerationSupport.NoScopeRecordCliBindingTrace() override fun analyze(): AnalysisResult {
val moduleContext = TopDownAnalyzerFacadeForJVM.createContextWithSealedModule(environment.project, val sharedTrace = CliLightClassGenerationSupport.NoScopeRecordCliBindingTrace()
environment.getModuleName()) val moduleContext = TopDownAnalyzerFacadeForJVM.createContextWithSealedModule(environment.project,
environment.getModuleName())
TopDownAnalyzerFacadeForJVM.analyzeFilesWithJavaIntegrationWithCustomContext( return TopDownAnalyzerFacadeForJVM.analyzeFilesWithJavaIntegrationWithCustomContext(
moduleContext, moduleContext,
environment.getSourceFiles(), environment.getSourceFiles(),
sharedTrace, sharedTrace,
environment.configuration.get(JVMConfigurationKeys.MODULES), environment.configuration.get(JVMConfigurationKeys.MODULES),
environment.configuration.get(JVMConfigurationKeys.INCREMENTAL_COMPILATION_COMPONENTS), environment.configuration.get(JVMConfigurationKeys.INCREMENTAL_COMPILATION_COMPONENTS),
JvmPackagePartProvider(environment)) JvmPackagePartProvider(environment))
}
override fun reportEnvironmentErrors() {
reportRuntimeConflicts(collector, environment.configuration.jvmClasspathRoots)
}
}) })
val analysisNanos = PerformanceCounter.currentTime() - analysisStart val analysisNanos = PerformanceCounter.currentTime() - analysisStart
val message = "ANALYZE: " + environment.getSourceFiles().size + " files (" + val message = "ANALYZE: " + environment.getSourceFiles().size + " files (" +
@@ -397,4 +403,24 @@ object KotlinToJVMBytecodeCompiler {
assert(result != null) { "Message collector not specified in compiler configuration" } assert(result != null) { "Message collector not specified in compiler configuration" }
return result!! return result!!
} }
private fun reportRuntimeConflicts(messageCollector: MessageCollector, jvmClasspathRoots: List<File>) {
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)
}
}
} }
@@ -0,0 +1,5 @@
$TESTDATA_DIR$/conflictingRuntimeVersions.kt
-classpath
$TESTDATA_DIR$/kotlin-runtime-4584-stub/kotlin-runtime.jar
-d
$TEMP_DIR$
@@ -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
@@ -0,0 +1,5 @@
$TESTDATA_DIR$/simple.kt
-classpath
$TESTDATA_DIR$/kotlin-runtime-4584-stub/kotlin-runtime.jar
-d
$TEMP_DIR$
@@ -0,0 +1 @@
OK
@@ -0,0 +1 @@
val f = unresolvedFunction()
@@ -34,6 +34,7 @@ import org.jetbrains.kotlin.serialization.deserialization.BinaryVersion;
import org.jetbrains.kotlin.test.KotlinTestUtils; import org.jetbrains.kotlin.test.KotlinTestUtils;
import org.jetbrains.kotlin.test.Tmpdir; import org.jetbrains.kotlin.test.Tmpdir;
import org.jetbrains.kotlin.utils.ExceptionUtilsKt; import org.jetbrains.kotlin.utils.ExceptionUtilsKt;
import org.jetbrains.kotlin.utils.PathUtil;
import org.junit.Rule; import org.junit.Rule;
import org.junit.rules.TestName; import org.junit.rules.TestName;
@@ -83,6 +84,7 @@ public class CliBaseTest {
) { ) {
String normalizedOutputWithoutExitCode = pureOutput String normalizedOutputWithoutExitCode = pureOutput
.replace(new File(testDataDir).getAbsolutePath(), "$TESTDATA_DIR$") .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("expected version is " + version, "expected version is $ABI_VERSION$")
.replace("\\", "/") .replace("\\", "/")
.replace(KotlinVersion.VERSION, "$VERSION$"); .replace(KotlinVersion.VERSION, "$VERSION$");
@@ -73,6 +73,18 @@ public class KotlincExecutableTestGenerated extends AbstractKotlincExecutableTes
doJvmTest(fileName); 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") @TestMetadata("diagnosticsOrder.args")
public void testDiagnosticsOrder() throws Exception { public void testDiagnosticsOrder() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/cli/jvm/diagnosticsOrder.args"); String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/cli/jvm/diagnosticsOrder.args");
+5
View File
@@ -161,6 +161,11 @@
<exclude>kotlin/internal/OnlyInputTypes*</exclude> <exclude>kotlin/internal/OnlyInputTypes*</exclude>
<exclude>kotlin/internal</exclude> <exclude>kotlin/internal</exclude>
</excludes> </excludes>
<archive>
<manifest>
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
</manifest>
</archive>
</configuration> </configuration>
</plugin> </plugin>
</plugins> </plugins>
+10
View File
@@ -228,6 +228,16 @@
</executions> </executions>
</plugin> </plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifest>
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
</manifest>
</archive>
</configuration>
</plugin>
</plugins> </plugins>
</build> </build>
+7
View File
@@ -50,6 +50,13 @@
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId> <artifactId>maven-jar-plugin</artifactId>
<version>2.6</version> <version>2.6</version>
<configuration>
<archive>
<manifest>
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
</manifest>
</archive>
</configuration>
<executions> <executions>
<execution> <execution>
<id>empty-javadoc-jar</id> <id>empty-javadoc-jar</id>