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
This commit is contained in:
+8
-7
@@ -28,14 +28,15 @@ data class CompilerMessageLocation private constructor(
|
|||||||
path + (if (line != -1 || column != -1) " ($line:$column)" else "")
|
path + (if (line != -1 || column != -1) " ($line:$column)" else "")
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@JvmField val NO_LOCATION: CompilerMessageLocation = CompilerMessageLocation(null, -1, -1, null)
|
@JvmField
|
||||||
|
val NO_LOCATION: CompilerMessageLocation = create(null)
|
||||||
|
|
||||||
@JvmStatic fun create(
|
@JvmStatic
|
||||||
path: String?,
|
fun create(path: String?): CompilerMessageLocation =
|
||||||
line: Int,
|
CompilerMessageLocation(path, -1, -1, null)
|
||||||
column: Int,
|
|
||||||
lineContent: String?
|
@JvmStatic
|
||||||
): CompilerMessageLocation =
|
fun create(path: String?, line: Int, column: Int, lineContent: String?): CompilerMessageLocation =
|
||||||
if (path == null) NO_LOCATION else CompilerMessageLocation(path, line, column, lineContent)
|
if (path == null) NO_LOCATION else CompilerMessageLocation(path, line, column, lineContent)
|
||||||
|
|
||||||
private val serialVersionUID: Long = 8228357578L
|
private val serialVersionUID: Long = 8228357578L
|
||||||
|
|||||||
+1
-2
@@ -229,9 +229,8 @@ class AnalyzerWithCompilerReport(private val messageCollector: MessageCollector)
|
|||||||
severity,
|
severity,
|
||||||
"Class '" + JvmClassName.byClassId(data.classId) + "' was compiled with an incompatible version of Kotlin. " +
|
"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,
|
"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))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+19
-12
@@ -17,6 +17,7 @@
|
|||||||
package org.jetbrains.kotlin.cli.jvm
|
package org.jetbrains.kotlin.cli.jvm
|
||||||
|
|
||||||
import com.intellij.openapi.diagnostic.Logger
|
import com.intellij.openapi.diagnostic.Logger
|
||||||
|
import com.intellij.openapi.vfs.VfsUtilCore
|
||||||
import com.intellij.openapi.vfs.VirtualFile
|
import com.intellij.openapi.vfs.VirtualFile
|
||||||
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation
|
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation
|
||||||
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
|
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
|
||||||
@@ -106,9 +107,9 @@ object JvmRuntimeVersionsConsistencyChecker {
|
|||||||
fun checkCompilerClasspathConsistency(
|
fun checkCompilerClasspathConsistency(
|
||||||
messageCollector: MessageCollector,
|
messageCollector: MessageCollector,
|
||||||
languageVersionSettings: LanguageVersionSettings?,
|
languageVersionSettings: LanguageVersionSettings?,
|
||||||
classpathJars: List<VirtualFile>
|
classpathJarRoots: List<VirtualFile>
|
||||||
) {
|
) {
|
||||||
val runtimeJarsInfo = collectRuntimeJarsInfo(classpathJars)
|
val runtimeJarsInfo = collectRuntimeJarsInfo(classpathJarRoots)
|
||||||
if (!runtimeJarsInfo.hasAnyJarsToCheck) return
|
if (!runtimeJarsInfo.hasAnyJarsToCheck) return
|
||||||
|
|
||||||
val languageVersion =
|
val languageVersion =
|
||||||
@@ -128,13 +129,13 @@ object JvmRuntimeVersionsConsistencyChecker {
|
|||||||
|
|
||||||
private fun checkNotNewerThanCompiler(messageCollector: MessageCollector, jar: KotlinLibraryFile) {
|
private fun checkNotNewerThanCompiler(messageCollector: MessageCollector, jar: KotlinLibraryFile) {
|
||||||
if (jar.version > CURRENT_COMPILER_VERSION) {
|
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) {
|
private fun checkCompatibleWithLanguageVersion(messageCollector: MessageCollector, jar: KotlinLibraryFile, languageVersion: MavenComparableVersion) {
|
||||||
if (jar.version < languageVersion) {
|
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
|
val newestCoreJar = runtimeJarsInfo.coreJars.maxBy { it.version } ?: return
|
||||||
|
|
||||||
if (oldestCoreJar.version != newestCoreJar.version) {
|
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) {
|
private fun MessageCollector.issue(file: VirtualFile?, message: String) {
|
||||||
report(VERSION_ISSUE_SEVERITY, message, CompilerMessageLocation.NO_LOCATION)
|
report(VERSION_ISSUE_SEVERITY, message, CompilerMessageLocation.create(file?.let(VfsUtilCore::virtualToIoFile)?.path))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun collectRuntimeJarsInfo(classpathJars: List<VirtualFile>): RuntimeJarsInfo {
|
private fun collectRuntimeJarsInfo(classpathJarRoots: List<VirtualFile>): RuntimeJarsInfo {
|
||||||
val kotlinCoreJars = ArrayList<KotlinLibraryFile>(2)
|
val kotlinCoreJars = ArrayList<KotlinLibraryFile>(2)
|
||||||
|
|
||||||
for (jar in classpathJars) {
|
for (jarRoot in classpathJarRoots) {
|
||||||
val manifest = try {
|
val manifest = try {
|
||||||
val manifestFile = jar.findFileByRelativePath(MANIFEST_MF) ?: continue
|
val manifestFile = jarRoot.findFileByRelativePath(MANIFEST_MF) ?: continue
|
||||||
Manifest(manifestFile.inputStream)
|
Manifest(manifestFile.inputStream)
|
||||||
}
|
}
|
||||||
catch (e: Exception) {
|
catch (e: Exception) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
val runtimeComponent = getKotlinRuntimeComponent(jar, manifest) ?: continue
|
val runtimeComponent = getKotlinRuntimeComponent(jarRoot, manifest) ?: continue
|
||||||
val version = manifest.getKotlinLanguageVersion()
|
val version = manifest.getKotlinLanguageVersion()
|
||||||
|
|
||||||
if (runtimeComponent == KOTLIN_RUNTIME_COMPONENT_CORE) {
|
if (runtimeComponent == KOTLIN_RUNTIME_COMPONENT_CORE) {
|
||||||
kotlinCoreJars.add(KotlinLibraryFile(runtimeComponent, jar, version))
|
val jarFile = VfsUtilCore.getVirtualFileForJar(jarRoot) ?: continue
|
||||||
|
kotlinCoreJars.add(KotlinLibraryFile(runtimeComponent, jarFile, version))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -158,8 +158,8 @@ class KotlinCoreEnvironment private constructor(
|
|||||||
val messageCollector = configuration.get(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY)
|
val messageCollector = configuration.get(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY)
|
||||||
if (messageCollector != null) {
|
if (messageCollector != null) {
|
||||||
val languageVersionSettings = configuration.get(CommonConfigurationKeys.LANGUAGE_VERSION_SETTINGS)
|
val languageVersionSettings = configuration.get(CommonConfigurationKeys.LANGUAGE_VERSION_SETTINGS)
|
||||||
val classpathJars = initialRoots.mapNotNull { if (it.type == JavaRoot.RootType.BINARY) it.file else null }
|
val classpathJarRoots = initialRoots.mapNotNull { (file, type) -> if (type == JavaRoot.RootType.BINARY) file else null }
|
||||||
JvmRuntimeVersionsConsistencyChecker.checkCompilerClasspathConsistency(messageCollector, languageVersionSettings, classpathJars)
|
JvmRuntimeVersionsConsistencyChecker.checkCompilerClasspathConsistency(messageCollector, languageVersionSettings, classpathJarRoots)
|
||||||
}
|
}
|
||||||
|
|
||||||
// REPL and kapt2 update classpath dynamically
|
// REPL and kapt2 update classpath dynamically
|
||||||
@@ -206,27 +206,26 @@ class KotlinCoreEnvironment private constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun Iterable<ContentRoot>.classpathRoots(): List<JavaRoot> =
|
private fun Iterable<ContentRoot>.classpathRoots(): List<JavaRoot> =
|
||||||
filterIsInstance(JvmContentRoot::class.java).mapNotNull {
|
filterIsInstance(JvmContentRoot::class.java).mapNotNull { javaRoot ->
|
||||||
javaRoot -> contentRootToVirtualFile(javaRoot)?.let { virtualFile ->
|
contentRootToVirtualFile(javaRoot)?.let { virtualFile ->
|
||||||
|
val prefixPackageFqName = (javaRoot as? JavaSourceRoot)?.packagePrefix?.let {
|
||||||
val prefixPackageFqName = (javaRoot as? JavaSourceRoot)?.packagePrefix?.let {
|
if (isValidJavaFqName(it)) {
|
||||||
if (isValidJavaFqName(it)) {
|
FqName(it)
|
||||||
FqName(it)
|
}
|
||||||
|
else {
|
||||||
|
report(WARNING, "Invalid package prefix name is ignored: $it")
|
||||||
|
null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
report(WARNING, "Invalid package prefix name is ignored: $it")
|
val rootType = when (javaRoot) {
|
||||||
null
|
is JavaSourceRoot -> JavaRoot.RootType.SOURCE
|
||||||
|
is JvmClasspathRoot -> JavaRoot.RootType.BINARY
|
||||||
|
else -> throw IllegalStateException()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
val rootType = when (javaRoot) {
|
JavaRoot(virtualFile, rootType, prefixPackageFqName)
|
||||||
is JavaSourceRoot -> JavaRoot.RootType.SOURCE
|
|
||||||
is JvmClasspathRoot -> JavaRoot.RootType.BINARY
|
|
||||||
else -> throw IllegalStateException()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
JavaRoot(virtualFile, rootType, prefixPackageFqName)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateClasspathFromRootsIndex(index: JvmDependenciesIndex) {
|
private fun updateClasspathFromRootsIndex(index: JvmDependenciesIndex) {
|
||||||
|
|||||||
Reference in New Issue
Block a user