From 2c527d89ab935f1ce1210ddeb77e3414a76cb677 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Mon, 12 Dec 2016 19:17:52 +0300 Subject: [PATCH] Improve diagnostics for runtime versions consistency checker - report the diagnostic on the actual problematic file - output the list of all runtime jars if min version != max version --- .../messages/CompilerMessageLocation.kt | 15 ++++---- .../messages/AnalyzerWithCompilerReport.kt | 3 +- .../JvmRuntimeVersionsConsistencyChecker.kt | 31 ++++++++++------ .../cli/jvm/compiler/KotlinCoreEnvironment.kt | 37 +++++++++---------- 4 files changed, 46 insertions(+), 40 deletions(-) diff --git a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/messages/CompilerMessageLocation.kt b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/messages/CompilerMessageLocation.kt index 013eb183c49..fc0def65fc3 100644 --- a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/messages/CompilerMessageLocation.kt +++ b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/messages/CompilerMessageLocation.kt @@ -28,14 +28,15 @@ data class CompilerMessageLocation private constructor( path + (if (line != -1 || column != -1) " ($line:$column)" else "") companion object { - @JvmField val NO_LOCATION: CompilerMessageLocation = CompilerMessageLocation(null, -1, -1, null) + @JvmField + val NO_LOCATION: CompilerMessageLocation = create(null) - @JvmStatic fun create( - path: String?, - line: Int, - column: Int, - lineContent: String? - ): CompilerMessageLocation = + @JvmStatic + fun create(path: String?): CompilerMessageLocation = + CompilerMessageLocation(path, -1, -1, null) + + @JvmStatic + fun create(path: String?, line: Int, column: Int, lineContent: String?): CompilerMessageLocation = if (path == null) NO_LOCATION else CompilerMessageLocation(path, line, column, lineContent) private val serialVersionUID: Long = 8228357578L 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 640b5716450..ca492e605e3 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 @@ -229,9 +229,8 @@ class AnalyzerWithCompilerReport(private val messageCollector: MessageCollector) severity, "Class '" + JvmClassName.byClassId(data.classId) + "' was compiled with an incompatible version of Kotlin. " + "The binary version of its bytecode is " + data.actualVersion + ", expected version is " + data.expectedVersion, - CompilerMessageLocation.create(toSystemDependentName(data.filePath), -1, -1, null) + CompilerMessageLocation.create(toSystemDependentName(data.filePath)) ) } - } } diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/JvmRuntimeVersionsConsistencyChecker.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/JvmRuntimeVersionsConsistencyChecker.kt index 4cd498392f1..11c56aca239 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/JvmRuntimeVersionsConsistencyChecker.kt +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/JvmRuntimeVersionsConsistencyChecker.kt @@ -17,6 +17,7 @@ package org.jetbrains.kotlin.cli.jvm import com.intellij.openapi.diagnostic.Logger +import com.intellij.openapi.vfs.VfsUtilCore import com.intellij.openapi.vfs.VirtualFile import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity @@ -106,9 +107,9 @@ object JvmRuntimeVersionsConsistencyChecker { fun checkCompilerClasspathConsistency( messageCollector: MessageCollector, languageVersionSettings: LanguageVersionSettings?, - classpathJars: List + classpathJarRoots: List ) { - val runtimeJarsInfo = collectRuntimeJarsInfo(classpathJars) + val runtimeJarsInfo = collectRuntimeJarsInfo(classpathJarRoots) if (!runtimeJarsInfo.hasAnyJarsToCheck) return val languageVersion = @@ -128,13 +129,13 @@ object JvmRuntimeVersionsConsistencyChecker { private fun checkNotNewerThanCompiler(messageCollector: MessageCollector, jar: KotlinLibraryFile) { if (jar.version > CURRENT_COMPILER_VERSION) { - messageCollector.issue("Run-time JAR file $jar is newer than compiler version $CURRENT_COMPILER_VERSION") + messageCollector.issue(jar.file, "Runtime JAR file has version ${jar.version} which is newer than compiler version $CURRENT_COMPILER_VERSION") } } private fun checkCompatibleWithLanguageVersion(messageCollector: MessageCollector, jar: KotlinLibraryFile, languageVersion: MavenComparableVersion) { if (jar.version < languageVersion) { - messageCollector.issue("Run-time JAR file $jar is older than required for language version $languageVersion") + messageCollector.issue(jar.file, "Runtime JAR file has version ${jar.version} which is older than required for language version $languageVersion") } } @@ -143,31 +144,37 @@ object JvmRuntimeVersionsConsistencyChecker { val newestCoreJar = runtimeJarsInfo.coreJars.maxBy { it.version } ?: return if (oldestCoreJar.version != newestCoreJar.version) { - messageCollector.issue("Run-time JAR file $oldestCoreJar is not compatible with JAR file $newestCoreJar") + messageCollector.issue(null, buildString { + appendln("Runtime JAR files in the classpath must have the same version. These files were found in the classpath:") + for (jar in runtimeJarsInfo.coreJars) { + appendln(" ${jar.file.path} (version ${jar.version})") + } + }.trimEnd()) } } - private fun MessageCollector.issue(message: String) { - report(VERSION_ISSUE_SEVERITY, message, CompilerMessageLocation.NO_LOCATION) + private fun MessageCollector.issue(file: VirtualFile?, message: String) { + report(VERSION_ISSUE_SEVERITY, message, CompilerMessageLocation.create(file?.let(VfsUtilCore::virtualToIoFile)?.path)) } - private fun collectRuntimeJarsInfo(classpathJars: List): RuntimeJarsInfo { + private fun collectRuntimeJarsInfo(classpathJarRoots: List): RuntimeJarsInfo { val kotlinCoreJars = ArrayList(2) - for (jar in classpathJars) { + for (jarRoot in classpathJarRoots) { val manifest = try { - val manifestFile = jar.findFileByRelativePath(MANIFEST_MF) ?: continue + val manifestFile = jarRoot.findFileByRelativePath(MANIFEST_MF) ?: continue Manifest(manifestFile.inputStream) } catch (e: Exception) { continue } - val runtimeComponent = getKotlinRuntimeComponent(jar, manifest) ?: continue + val runtimeComponent = getKotlinRuntimeComponent(jarRoot, manifest) ?: continue val version = manifest.getKotlinLanguageVersion() if (runtimeComponent == KOTLIN_RUNTIME_COMPONENT_CORE) { - kotlinCoreJars.add(KotlinLibraryFile(runtimeComponent, jar, version)) + val jarFile = VfsUtilCore.getVirtualFileForJar(jarRoot) ?: continue + kotlinCoreJars.add(KotlinLibraryFile(runtimeComponent, jarFile, version)) } } diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinCoreEnvironment.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinCoreEnvironment.kt index c863831400c..6a1e93886ad 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinCoreEnvironment.kt +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinCoreEnvironment.kt @@ -158,8 +158,8 @@ class KotlinCoreEnvironment private constructor( val messageCollector = configuration.get(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY) if (messageCollector != null) { val languageVersionSettings = configuration.get(CommonConfigurationKeys.LANGUAGE_VERSION_SETTINGS) - val classpathJars = initialRoots.mapNotNull { if (it.type == JavaRoot.RootType.BINARY) it.file else null } - JvmRuntimeVersionsConsistencyChecker.checkCompilerClasspathConsistency(messageCollector, languageVersionSettings, classpathJars) + val classpathJarRoots = initialRoots.mapNotNull { (file, type) -> if (type == JavaRoot.RootType.BINARY) file else null } + JvmRuntimeVersionsConsistencyChecker.checkCompilerClasspathConsistency(messageCollector, languageVersionSettings, classpathJarRoots) } // REPL and kapt2 update classpath dynamically @@ -206,27 +206,26 @@ class KotlinCoreEnvironment private constructor( } private fun Iterable.classpathRoots(): List = - filterIsInstance(JvmContentRoot::class.java).mapNotNull { - javaRoot -> contentRootToVirtualFile(javaRoot)?.let { virtualFile -> - - val prefixPackageFqName = (javaRoot as? JavaSourceRoot)?.packagePrefix?.let { - if (isValidJavaFqName(it)) { - FqName(it) + filterIsInstance(JvmContentRoot::class.java).mapNotNull { javaRoot -> + contentRootToVirtualFile(javaRoot)?.let { virtualFile -> + val prefixPackageFqName = (javaRoot as? JavaSourceRoot)?.packagePrefix?.let { + if (isValidJavaFqName(it)) { + FqName(it) + } + else { + report(WARNING, "Invalid package prefix name is ignored: $it") + null + } } - else { - report(WARNING, "Invalid package prefix name is ignored: $it") - null + + val rootType = when (javaRoot) { + is JavaSourceRoot -> JavaRoot.RootType.SOURCE + is JvmClasspathRoot -> JavaRoot.RootType.BINARY + else -> throw IllegalStateException() } - } - val rootType = when (javaRoot) { - is JavaSourceRoot -> JavaRoot.RootType.SOURCE - is JvmClasspathRoot -> JavaRoot.RootType.BINARY - else -> throw IllegalStateException() + JavaRoot(virtualFile, rootType, prefixPackageFqName) } - - JavaRoot(virtualFile, rootType, prefixPackageFqName) - } } private fun updateClasspathFromRootsIndex(index: JvmDependenciesIndex) {