diff --git a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/configuration/KotlinExternalSystemSyncListener.kt b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/configuration/KotlinExternalSystemSyncListener.kt
index 87d24190d0b..4a991c1835a 100644
--- a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/configuration/KotlinExternalSystemSyncListener.kt
+++ b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/configuration/KotlinExternalSystemSyncListener.kt
@@ -25,10 +25,12 @@ import org.jetbrains.kotlin.idea.configuration.ui.KotlinConfigurationCheckerComp
class KotlinExternalSystemSyncListener : ExternalSystemTaskNotificationListenerAdapter() {
override fun onStart(id: ExternalSystemTaskId, workingDir: String) {
val project = id.findResolvedProject() ?: return
+ KotlinMigrationProjectComponent.getInstance(project).onImportAboutToStart()
KotlinConfigurationCheckerComponent.getInstance(project).syncStarted()
}
override fun onEnd(id: ExternalSystemTaskId) {
+ // At this point changes might be still not applied to project structure yet.
val project = id.findResolvedProject() ?: return
KotlinConfigurationCheckerComponent.getInstance(project).syncDone()
}
diff --git a/idea/src/META-INF/plugin.xml b/idea/src/META-INF/plugin.xml
index d7f36c053d6..6b971be67b5 100644
--- a/idea/src/META-INF/plugin.xml
+++ b/idea/src/META-INF/plugin.xml
@@ -64,6 +64,9 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio.
org.jetbrains.kotlin.idea.completion.CompletionBindingContextProvider
org.jetbrains.kotlin.idea.completion.CompletionBindingContextProvider
+
+ org.jetbrains.kotlin.idea.configuration.KotlinMigrationProjectComponent
+
diff --git a/idea/src/META-INF/plugin.xml.172 b/idea/src/META-INF/plugin.xml.172
index 48db081be0c..6d6d2dc52b0 100644
--- a/idea/src/META-INF/plugin.xml.172
+++ b/idea/src/META-INF/plugin.xml.172
@@ -64,6 +64,9 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio.
org.jetbrains.kotlin.idea.completion.CompletionBindingContextProvider
org.jetbrains.kotlin.idea.completion.CompletionBindingContextProvider
+
+ org.jetbrains.kotlin.idea.configuration.KotlinMigrationProjectComponent
+
diff --git a/idea/src/META-INF/plugin.xml.173 b/idea/src/META-INF/plugin.xml.173
index f7feb282dc7..b3af22a346e 100644
--- a/idea/src/META-INF/plugin.xml.173
+++ b/idea/src/META-INF/plugin.xml.173
@@ -64,6 +64,9 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio.
org.jetbrains.kotlin.idea.completion.CompletionBindingContextProvider
org.jetbrains.kotlin.idea.completion.CompletionBindingContextProvider
+
+ org.jetbrains.kotlin.idea.configuration.KotlinMigrationProjectComponent
+
diff --git a/idea/src/META-INF/plugin.xml.182 b/idea/src/META-INF/plugin.xml.182
index 77fdde98ce1..6410db0b84e 100644
--- a/idea/src/META-INF/plugin.xml.182
+++ b/idea/src/META-INF/plugin.xml.182
@@ -65,6 +65,9 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio.
org.jetbrains.kotlin.idea.completion.CompletionBindingContextProvider
org.jetbrains.kotlin.idea.completion.CompletionBindingContextProvider
+
+ org.jetbrains.kotlin.idea.configuration.KotlinMigrationProjectComponent
+
diff --git a/idea/src/META-INF/plugin.xml.as31 b/idea/src/META-INF/plugin.xml.as31
index 49bdc914a4a..6e59334ba17 100644
--- a/idea/src/META-INF/plugin.xml.as31
+++ b/idea/src/META-INF/plugin.xml.as31
@@ -64,6 +64,9 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio.
org.jetbrains.kotlin.idea.completion.CompletionBindingContextProvider
org.jetbrains.kotlin.idea.completion.CompletionBindingContextProvider
+
+ org.jetbrains.kotlin.idea.configuration.KotlinMigrationProjectComponent
+
diff --git a/idea/src/META-INF/plugin.xml.as32 b/idea/src/META-INF/plugin.xml.as32
index 03e6c7f9005..36ac4affcf9 100644
--- a/idea/src/META-INF/plugin.xml.as32
+++ b/idea/src/META-INF/plugin.xml.as32
@@ -64,6 +64,9 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio.
org.jetbrains.kotlin.idea.completion.CompletionBindingContextProvider
org.jetbrains.kotlin.idea.completion.CompletionBindingContextProvider
+
+ org.jetbrains.kotlin.idea.configuration.KotlinMigrationProjectComponent
+
diff --git a/idea/src/META-INF/plugin.xml.as33 b/idea/src/META-INF/plugin.xml.as33
index bdae3986f3e..ec95911bd7f 100644
--- a/idea/src/META-INF/plugin.xml.as33
+++ b/idea/src/META-INF/plugin.xml.as33
@@ -63,6 +63,9 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio.
org.jetbrains.kotlin.idea.completion.CompletionBindingContextProvider
org.jetbrains.kotlin.idea.completion.CompletionBindingContextProvider
+
+ org.jetbrains.kotlin.idea.configuration.KotlinMigrationProjectComponent
+
diff --git a/idea/src/org/jetbrains/kotlin/idea/configuration/KotlinMigrationProjectComponent.kt b/idea/src/org/jetbrains/kotlin/idea/configuration/KotlinMigrationProjectComponent.kt
new file mode 100644
index 00000000000..6c2de283eab
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/configuration/KotlinMigrationProjectComponent.kt
@@ -0,0 +1,177 @@
+/*
+ * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
+ * that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.idea.configuration
+
+import com.intellij.openapi.application.ApplicationManager
+import com.intellij.openapi.externalSystem.service.project.manage.ProjectDataImportListener
+import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil
+import com.intellij.openapi.module.ModuleManager
+import com.intellij.openapi.project.Project
+import com.intellij.openapi.roots.ProjectRootManager
+import com.intellij.openapi.roots.libraries.Library
+import com.intellij.util.CommonProcessors
+import com.intellij.util.text.VersionComparatorUtil
+import org.jetbrains.kotlin.config.ApiVersion
+import org.jetbrains.kotlin.config.LanguageVersion
+import org.jetbrains.kotlin.config.LanguageVersionSettings
+import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl
+import org.jetbrains.kotlin.idea.framework.GRADLE_SYSTEM_ID
+import org.jetbrains.kotlin.idea.framework.MAVEN_SYSTEM_ID
+import org.jetbrains.kotlin.idea.project.languageVersionSettings
+import org.jetbrains.kotlin.idea.util.application.runReadAction
+import org.jetbrains.kotlin.idea.versions.LibInfo
+
+class KotlinMigrationProjectComponent(val project: Project) {
+ private var old: MigrationState? = null
+ private var new: MigrationState? = null
+
+ init {
+ val connection = project.messageBus.connect()
+ connection.subscribe(ProjectDataImportListener.TOPIC, ProjectDataImportListener {
+ KotlinMigrationProjectComponent.getInstance(project).onImportFinished()
+ })
+ }
+
+ @Synchronized
+ fun onImportAboutToStart() {
+ old = MigrationState.build(project)
+ }
+
+ @Synchronized
+ fun onImportFinished() {
+ new = MigrationState.build(project)
+
+ val migrationInfo = prepareMigrationInfo(old, new) ?: return
+
+ if (ApplicationManager.getApplication().isUnitTestMode) {
+ return
+ }
+
+ ApplicationManager.getApplication().invokeLater {
+ // Notify
+ }
+ }
+
+ companion object {
+ fun getInstance(project: Project): KotlinMigrationProjectComponent =
+ project.getComponent(KotlinMigrationProjectComponent::class.java)!!
+
+ private fun prepareMigrationInfo(old: MigrationState?, new: MigrationState?): MigrationInfo? {
+ if (old == null || new == null) {
+ return null
+ }
+
+ val oldLibraryVersion = old.stdlibInfo?.version
+ val newLibraryVersion = new.stdlibInfo?.version
+
+ if (oldLibraryVersion == null || newLibraryVersion == null) {
+ return null
+ }
+
+ if (VersionComparatorUtil.COMPARATOR.compare(newLibraryVersion, oldLibraryVersion) > 0 ||
+ old.apiVersion < new.apiVersion || old.languageVersion < new.languageVersion
+ ) {
+ return MigrationInfo(
+ oldLibraryVersion, newLibraryVersion,
+ old.apiVersion, new.apiVersion,
+ old.languageVersion, new.languageVersion
+ )
+ }
+
+ return null
+ }
+ }
+}
+
+private class MigrationState(
+ var stdlibInfo: LibInfo?,
+ var apiVersion: ApiVersion,
+ var languageVersion: LanguageVersion
+) {
+ companion object {
+ fun build(project: Project): MigrationState {
+ val libraries = maxKotlinLibVersion(project)
+ val languageVersionSettings = collectMaxCompilerSettings(project)
+ return MigrationState(libraries, languageVersionSettings.apiVersion, languageVersionSettings.languageVersion)
+ }
+ }
+}
+
+internal data class MigrationInfo(
+ val oldStdlibVersion: String,
+ val newStdlibVersion: String,
+ val oldApiVersion: ApiVersion,
+ val newApiVersion: ApiVersion,
+ val oldLanguageVersion: LanguageVersion,
+ val newLanguageVersion: LanguageVersion
+)
+
+private const val KOTLIN_GROUP_ID = "org.jetbrains.kotlin"
+
+private fun maxKotlinLibVersion(project: Project): LibInfo? {
+ return runReadAction {
+ var maxStdlibInfo: LibInfo? = null
+
+ val allLibProcessor = CommonProcessors.CollectUniquesProcessor()
+ ProjectRootManager.getInstance(project).orderEntries().forEachLibrary(allLibProcessor)
+
+ for (library in allLibProcessor.results) {
+ if (!ExternalSystemApiUtil.isExternalSystemLibrary(library, GRADLE_SYSTEM_ID) &&
+ !ExternalSystemApiUtil.isExternalSystemLibrary(library, MAVEN_SYSTEM_ID)
+ ) {
+ continue
+ }
+
+ if (library.name?.contains(" $KOTLIN_GROUP_ID:kotlin-stdlib") != true) {
+ continue
+ }
+
+ val libName = library.name ?: continue
+
+ val version = libName.substringAfterLastNullable(":") ?: continue
+ val artifactId = libName.substringBeforeLastNullable(":")?.substringAfterLastNullable(":") ?: continue
+
+ if (version.isBlank() || artifactId.isBlank()) continue
+
+ if (maxStdlibInfo == null || VersionComparatorUtil.COMPARATOR.compare(version, maxStdlibInfo.version) > 0) {
+ maxStdlibInfo = LibInfo(KOTLIN_GROUP_ID, artifactId, version)
+ }
+ }
+
+ maxStdlibInfo
+ }
+}
+
+private fun collectMaxCompilerSettings(project: Project): LanguageVersionSettings {
+ return runReadAction {
+ var maxApiVersion: ApiVersion? = null
+ var maxLanguageVersion: LanguageVersion? = null
+
+ for (module in ModuleManager.getInstance(project).modules) {
+ val languageVersionSettings = module.languageVersionSettings
+
+ if (maxApiVersion == null || languageVersionSettings.apiVersion > maxApiVersion) {
+ maxApiVersion = languageVersionSettings.apiVersion
+ }
+
+ if (maxLanguageVersion == null || languageVersionSettings.languageVersion > maxLanguageVersion) {
+ maxLanguageVersion = languageVersionSettings.languageVersion
+ }
+ }
+
+ LanguageVersionSettingsImpl(maxLanguageVersion ?: LanguageVersion.LATEST_STABLE, maxApiVersion ?: ApiVersion.LATEST_STABLE)
+ }
+}
+
+fun String.substringBeforeLastNullable(delimiter: String, missingDelimiterValue: String? = null): String? {
+ val index = lastIndexOf(delimiter)
+ return if (index == -1) missingDelimiterValue else substring(0, index)
+}
+
+fun String.substringAfterLastNullable(delimiter: String, missingDelimiterValue: String? = null): String? {
+ val index = lastIndexOf(delimiter)
+ return if (index == -1) missingDelimiterValue else substring(index + 1, length)
+}
\ No newline at end of file
diff --git a/idea/src/org/jetbrains/kotlin/idea/versions/KotlinRuntimeLibraryUtil.kt b/idea/src/org/jetbrains/kotlin/idea/versions/KotlinRuntimeLibraryUtil.kt
index 26cff443aee..b469795d1f8 100644
--- a/idea/src/org/jetbrains/kotlin/idea/versions/KotlinRuntimeLibraryUtil.kt
+++ b/idea/src/org/jetbrains/kotlin/idea/versions/KotlinRuntimeLibraryUtil.kt
@@ -280,7 +280,8 @@ val LOG = Logger.getInstance("org.jetbrains.kotlin.idea.versions.KotlinRuntimeLi
data class LibInfo(
val groupId: String,
- val name: String
+ val name: String,
+ val version: String = "0.0.0"
)
data class DeprecatedLibInfo(
diff --git a/idea/src/org/jetbrains/kotlin/idea/versions/KotlinRuntimeLibraryUtil.kt.172 b/idea/src/org/jetbrains/kotlin/idea/versions/KotlinRuntimeLibraryUtil.kt.172
index 4ecba8f836f..f23a1612d54 100644
--- a/idea/src/org/jetbrains/kotlin/idea/versions/KotlinRuntimeLibraryUtil.kt.172
+++ b/idea/src/org/jetbrains/kotlin/idea/versions/KotlinRuntimeLibraryUtil.kt.172
@@ -280,7 +280,8 @@ val LOG = Logger.getInstance("org.jetbrains.kotlin.idea.versions.KotlinRuntimeLi
data class LibInfo(
val groupId: String,
- val name: String
+ val name: String,
+ val version: String = "0.0.0"
)
data class DeprecatedLibInfo(