Fix: Notify user in IDE on K/N KLIBs with incompatible ABI version
Issue #KT-34159
This commit is contained in:
+212
@@ -0,0 +1,212 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* 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.ide.konan
|
||||||
|
|
||||||
|
import com.intellij.ProjectTopics
|
||||||
|
import com.intellij.notification.*
|
||||||
|
import com.intellij.openapi.Disposable
|
||||||
|
import com.intellij.openapi.application.ApplicationManager
|
||||||
|
import com.intellij.openapi.components.ProjectComponent
|
||||||
|
import com.intellij.openapi.project.Project
|
||||||
|
import com.intellij.openapi.project.guessProjectDir
|
||||||
|
import com.intellij.openapi.roots.ModuleRootEvent
|
||||||
|
import com.intellij.openapi.roots.ModuleRootListener
|
||||||
|
import com.intellij.openapi.util.text.StringUtilRt
|
||||||
|
import com.intellij.util.PathUtilRt
|
||||||
|
import org.jetbrains.kotlin.idea.caches.project.getModuleInfosFromIdeaModel
|
||||||
|
import org.jetbrains.kotlin.idea.configuration.KotlinNativeLibraryNameUtil
|
||||||
|
import org.jetbrains.kotlin.idea.versions.UnsupportedAbiVersionNotificationPanelProvider
|
||||||
|
import org.jetbrains.kotlin.idea.versions.bundledRuntimeVersion
|
||||||
|
import org.jetbrains.kotlin.konan.library.KONAN_STDLIB_NAME
|
||||||
|
import org.jetbrains.kotlin.library.KotlinAbiVersion
|
||||||
|
|
||||||
|
/** TODO: merge [KotlinNativeABICompatibilityChecker] in the future with [UnsupportedAbiVersionNotificationPanelProvider], KT-34525 */
|
||||||
|
class KotlinNativeABICompatibilityChecker(private val project: Project) : ProjectComponent, Disposable {
|
||||||
|
|
||||||
|
private sealed class LibraryGroup(private val ordinal: Int) : Comparable<LibraryGroup> {
|
||||||
|
|
||||||
|
override fun compareTo(other: LibraryGroup) = when {
|
||||||
|
this == other -> 0
|
||||||
|
this is FromDistribution && other is FromDistribution -> kotlinVersion.compareTo(other.kotlinVersion)
|
||||||
|
else -> ordinal.compareTo(other.ordinal)
|
||||||
|
}
|
||||||
|
|
||||||
|
data class FromDistribution(val kotlinVersion: String) : LibraryGroup(0)
|
||||||
|
object ThirdParty : LibraryGroup(1)
|
||||||
|
object User : LibraryGroup(2)
|
||||||
|
}
|
||||||
|
|
||||||
|
private val cachedIncompatibleLibraries = HashSet<String>()
|
||||||
|
|
||||||
|
init {
|
||||||
|
project.messageBus.connect().subscribe(ProjectTopics.PROJECT_ROOTS, object : ModuleRootListener {
|
||||||
|
override fun rootsChanged(event: ModuleRootEvent) {
|
||||||
|
// run when project roots are changes, e.g. on project import
|
||||||
|
validateKotlinNativeLibraries()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun projectOpened() {
|
||||||
|
// run when project is opened
|
||||||
|
validateKotlinNativeLibraries()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun validateKotlinNativeLibraries() {
|
||||||
|
if (ApplicationManager.getApplication().isUnitTestMode || project.isDisposed)
|
||||||
|
return
|
||||||
|
|
||||||
|
val librariesToNotify = getLibrariesToNotifyAbout()
|
||||||
|
if (librariesToNotify.isEmpty())
|
||||||
|
return
|
||||||
|
|
||||||
|
val librariesByGroups = HashMap<Pair<LibraryGroup, Boolean>, MutableList<Pair<String, String>>>()
|
||||||
|
librariesToNotify.forEach { (libraryRoot, libraryInfo) ->
|
||||||
|
val isOldAbi = (libraryInfo.safeAbiVersion?.version ?: 0) < KotlinAbiVersion.CURRENT.version
|
||||||
|
val (libraryName, libraryGroup) = parseIDELibraryName(libraryInfo)
|
||||||
|
librariesByGroups.computeIfAbsent(libraryGroup to isOldAbi) { mutableListOf() } += libraryName to libraryRoot
|
||||||
|
}
|
||||||
|
|
||||||
|
librariesByGroups.keys.sortedWith(
|
||||||
|
compareBy(
|
||||||
|
{ (libraryGroup, _) -> libraryGroup },
|
||||||
|
{ (_, isOldAbi) -> isOldAbi }
|
||||||
|
)
|
||||||
|
).forEach { key ->
|
||||||
|
|
||||||
|
val (libraryGroup, isOldAbi) = key
|
||||||
|
val libraries =
|
||||||
|
librariesByGroups.getValue(key).sortedWith(compareBy(LIBRARY_NAME_COMPARATOR) { (libraryName, _) -> libraryName })
|
||||||
|
|
||||||
|
val compilerVersionText = if (isOldAbi) "an older" else "a newer"
|
||||||
|
|
||||||
|
val message = when (libraryGroup) {
|
||||||
|
is LibraryGroup.FromDistribution -> {
|
||||||
|
val libraryNamesInOneLine =
|
||||||
|
libraries.joinToString(limit = MAX_LIBRARY_NAMES_IN_ONE_LINE) { (libraryName, _) -> libraryName }
|
||||||
|
|
||||||
|
"""
|
||||||
|
|There are ${libraries.size} libraries from the Kotlin/Native ${libraryGroup.kotlinVersion} distribution attached to the project: $libraryNamesInOneLine
|
||||||
|
|
|
||||||
|
|These libraries were compiled with $compilerVersionText Kotlin/Native compiler and can't be read in IDE. Please edit Gradle buildfile(s) to use Kotlin Gradle plugin version ${bundledRuntimeVersion()}. Then re-import the project in IDE.
|
||||||
|
""".trimMargin()
|
||||||
|
}
|
||||||
|
is LibraryGroup.ThirdParty -> {
|
||||||
|
if (libraries.size == 1) {
|
||||||
|
"""
|
||||||
|
|There is a third-party library attached to the project that was compiled with $compilerVersionText Kotlin/Native compiler and can't be read in IDE: ${libraries.single().first}
|
||||||
|
|
|
||||||
|
|Please edit Gradle buildfile(s) and specify library version compatible with Kotlin/Native ${bundledRuntimeVersion()}. Then re-import the project in IDE.
|
||||||
|
""".trimMargin()
|
||||||
|
} else {
|
||||||
|
val librariesLineByLine = libraries.joinToString(separator = "\n") { (libraryName, _) -> libraryName }
|
||||||
|
|
||||||
|
"""
|
||||||
|
|There are ${libraries.size} third-party libraries attached to the project that were compiled with $compilerVersionText Kotlin/Native compiler and can't be read in IDE:
|
||||||
|
|$librariesLineByLine
|
||||||
|
|
|
||||||
|
|Please edit Gradle buildfile(s) and specify library versions compatible with Kotlin/Native ${bundledRuntimeVersion()}. Then re-import the project in IDE.
|
||||||
|
""".trimMargin()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is LibraryGroup.User -> {
|
||||||
|
val projectRoot = project.guessProjectDir()?.canonicalPath
|
||||||
|
|
||||||
|
fun getLibraryTextToPrint(libraryNameAndRoot: Pair<String, String>): String {
|
||||||
|
val (libraryName, libraryRoot) = libraryNameAndRoot
|
||||||
|
|
||||||
|
val relativeRoot = projectRoot?.let {
|
||||||
|
libraryRoot.substringAfter(projectRoot)
|
||||||
|
.takeIf { it != libraryRoot }
|
||||||
|
?.trimStart('/', '\\')
|
||||||
|
?.let { "${'$'}project/$it" }
|
||||||
|
} ?: libraryRoot
|
||||||
|
|
||||||
|
return "\"$libraryName\" at $relativeRoot"
|
||||||
|
}
|
||||||
|
|
||||||
|
if (libraries.size == 1) {
|
||||||
|
"""
|
||||||
|
|There is a library attached to the project that was compiled with $compilerVersionText Kotlin/Native compiler and can't be read in IDE:
|
||||||
|
|${getLibraryTextToPrint(libraries.single())}
|
||||||
|
|
|
||||||
|
|Please edit Gradle buildfile(s) to use Kotlin Gradle plugin version ${bundledRuntimeVersion()}. Then rebuild the project and re-import it in IDE.
|
||||||
|
""".trimMargin()
|
||||||
|
} else {
|
||||||
|
val librariesLineByLine = libraries.joinToString(separator = "\n", transform = ::getLibraryTextToPrint)
|
||||||
|
|
||||||
|
"""
|
||||||
|
|There are ${libraries.size} libraries attached to the project that were compiled with $compilerVersionText Kotlin/Native compiler and can't be read in IDE:
|
||||||
|
|$librariesLineByLine
|
||||||
|
|
|
||||||
|
|Please edit Gradle buildfile(s) to use Kotlin Gradle plugin version ${bundledRuntimeVersion()}. Then rebuild the project and re-import it in IDE.
|
||||||
|
""".trimMargin()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Notification(
|
||||||
|
NOTIFICATION_GROUP_ID,
|
||||||
|
NOTIFICATION_TITLE,
|
||||||
|
StringUtilRt.convertLineSeparators(message, "<br/>"),
|
||||||
|
NotificationType.ERROR,
|
||||||
|
null
|
||||||
|
).notify(project)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getLibrariesToNotifyAbout(): Map<String, NativeLibraryInfo> = synchronized(this) {
|
||||||
|
val incompatibleLibraries = getModuleInfosFromIdeaModel(project).asSequence()
|
||||||
|
.filterIsInstance<NativeLibraryInfo>()
|
||||||
|
.filter { it.safeAbiVersion != KotlinAbiVersion.CURRENT }
|
||||||
|
.associateBy { it.libraryRoot }
|
||||||
|
|
||||||
|
val newEntries = if (cachedIncompatibleLibraries.isNotEmpty())
|
||||||
|
incompatibleLibraries.filterKeys { it !in cachedIncompatibleLibraries }
|
||||||
|
else
|
||||||
|
incompatibleLibraries
|
||||||
|
|
||||||
|
cachedIncompatibleLibraries.clear()
|
||||||
|
cachedIncompatibleLibraries.addAll(incompatibleLibraries.keys)
|
||||||
|
|
||||||
|
return newEntries
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns pair of library name and library group
|
||||||
|
private fun parseIDELibraryName(libraryInfo: NativeLibraryInfo): Pair<String, LibraryGroup> {
|
||||||
|
val ideLibraryName = libraryInfo.library.name?.takeIf(String::isNotEmpty)
|
||||||
|
if (ideLibraryName != null) {
|
||||||
|
KotlinNativeLibraryNameUtil.parseIDELibraryName(ideLibraryName)?.let { (kotlinVersion, libraryName) ->
|
||||||
|
return libraryName to LibraryGroup.FromDistribution(kotlinVersion)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (KotlinNativeLibraryNameUtil.isGradleLibraryName(ideLibraryName))
|
||||||
|
return ideLibraryName to LibraryGroup.ThirdParty
|
||||||
|
}
|
||||||
|
|
||||||
|
return (ideLibraryName ?: PathUtilRt.getFileName(libraryInfo.libraryRoot)) to LibraryGroup.User
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun dispose() = synchronized(this) {
|
||||||
|
cachedIncompatibleLibraries.clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val LIBRARY_NAME_COMPARATOR = Comparator<String> { libraryName1, libraryName2 ->
|
||||||
|
when {
|
||||||
|
libraryName1 == libraryName2 -> 0
|
||||||
|
libraryName1 == KONAN_STDLIB_NAME -> -1 // stdlib must go the first
|
||||||
|
libraryName2 == KONAN_STDLIB_NAME -> 1
|
||||||
|
else -> libraryName1.compareTo(libraryName2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private const val MAX_LIBRARY_NAMES_IN_ONE_LINE = 5
|
||||||
|
|
||||||
|
private const val NOTIFICATION_TITLE = "Incompatible Kotlin/Native libraries"
|
||||||
|
private const val NOTIFICATION_GROUP_ID = NOTIFICATION_TITLE
|
||||||
|
}
|
||||||
|
}
|
||||||
+26
-2
@@ -24,6 +24,7 @@ import org.gradle.tooling.model.idea.IdeaModule
|
|||||||
import org.jetbrains.kotlin.gradle.KotlinMPPGradleModel
|
import org.jetbrains.kotlin.gradle.KotlinMPPGradleModel
|
||||||
import org.jetbrains.kotlin.idea.configuration.DependencySubstitute.NoSubstitute
|
import org.jetbrains.kotlin.idea.configuration.DependencySubstitute.NoSubstitute
|
||||||
import org.jetbrains.kotlin.idea.configuration.DependencySubstitute.YesSubstitute
|
import org.jetbrains.kotlin.idea.configuration.DependencySubstitute.YesSubstitute
|
||||||
|
import org.jetbrains.kotlin.idea.configuration.KotlinNativeLibraryNameUtil.buildIDELibraryName
|
||||||
import org.jetbrains.kotlin.idea.inspections.gradle.findKotlinPluginVersion
|
import org.jetbrains.kotlin.idea.inspections.gradle.findKotlinPluginVersion
|
||||||
import org.jetbrains.kotlin.idea.versions.bundledRuntimeVersion
|
import org.jetbrains.kotlin.idea.versions.bundledRuntimeVersion
|
||||||
import org.jetbrains.kotlin.konan.library.KONAN_STDLIB_NAME
|
import org.jetbrains.kotlin.konan.library.KONAN_STDLIB_NAME
|
||||||
@@ -155,8 +156,7 @@ internal class KotlinNativeLibrariesDependencySubstitutor(
|
|||||||
val library = libraryProvider.getLibrary(libraryFile) ?: return NoSubstitute
|
val library = libraryProvider.getLibrary(libraryFile) ?: return NoSubstitute
|
||||||
val nonNullKotlinVersion = kotlinVersion ?: return NoSubstitute
|
val nonNullKotlinVersion = kotlinVersion ?: return NoSubstitute
|
||||||
|
|
||||||
val platformNamePart = library.platform?.let { " [$it]" }.orEmpty()
|
val newLibraryName = buildIDELibraryName(nonNullKotlinVersion, library.name, library.platform)
|
||||||
val newLibraryName = "$KOTLIN_NATIVE_LIBRARY_PREFIX_PLUS_SPACE$nonNullKotlinVersion - ${library.name}$platformNamePart"
|
|
||||||
|
|
||||||
val substitute = DefaultExternalMultiLibraryDependency().apply {
|
val substitute = DefaultExternalMultiLibraryDependency().apply {
|
||||||
classpathOrder = if (library.name == KONAN_STDLIB_NAME) -1 else 0 // keep stdlib upper
|
classpathOrder = if (library.name == KONAN_STDLIB_NAME) -1 else 0 // keep stdlib upper
|
||||||
@@ -240,6 +240,30 @@ private sealed class DependencySubstitute {
|
|||||||
class YesSubstitute(val substitute: ExternalMultiLibraryDependency) : DependencySubstitute()
|
class YesSubstitute(val substitute: ExternalMultiLibraryDependency) : DependencySubstitute()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
object KotlinNativeLibraryNameUtil {
|
||||||
|
private val IDE_LIBRARY_NAME_REGEX = Regex("^$KOTLIN_NATIVE_LIBRARY_PREFIX_PLUS_SPACE([^\\s]+) - ([^\\s]+)( \\[([\\w]+)\\])?$")
|
||||||
|
|
||||||
|
// Builds the name of Kotlin/Native library that is a part of Kotlin/Native distribution
|
||||||
|
// as it will be displayed in IDE UI.
|
||||||
|
fun buildIDELibraryName(kotlinVersion: String, libraryName: String, platform: String?): String {
|
||||||
|
val platformNamePart = platform?.let { " [$it]" }.orEmpty()
|
||||||
|
return "$KOTLIN_NATIVE_LIBRARY_PREFIX_PLUS_SPACE$kotlinVersion - $libraryName$platformNamePart"
|
||||||
|
}
|
||||||
|
|
||||||
|
// N.B. Returns null if this is not IDE name of Kotlin/Native library.
|
||||||
|
fun parseIDELibraryName(ideLibraryName: String): Triple<String, String, String?>? {
|
||||||
|
val match = IDE_LIBRARY_NAME_REGEX.matchEntire(ideLibraryName) ?: return null
|
||||||
|
|
||||||
|
val kotlinVersion = match.groups[1]!!.value
|
||||||
|
val libraryName = match.groups[2]!!.value
|
||||||
|
val platform = match.groups[4]?.value
|
||||||
|
|
||||||
|
return Triple(kotlinVersion, libraryName, platform)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isGradleLibraryName(ideLibraryName: String) = ideLibraryName.startsWith(GRADLE_LIBRARY_PREFIX)
|
||||||
|
}
|
||||||
|
|
||||||
internal const val KOTLIN_NATIVE_LIBRARY_PREFIX = "Kotlin/Native"
|
internal const val KOTLIN_NATIVE_LIBRARY_PREFIX = "Kotlin/Native"
|
||||||
private const val KOTLIN_NATIVE_LIBRARY_PREFIX_PLUS_SPACE = "$KOTLIN_NATIVE_LIBRARY_PREFIX "
|
private const val KOTLIN_NATIVE_LIBRARY_PREFIX_PLUS_SPACE = "$KOTLIN_NATIVE_LIBRARY_PREFIX "
|
||||||
private const val KOTLIN_NATIVE_LEGACY_GROUP_ID = KOTLIN_NATIVE_LIBRARY_PREFIX
|
private const val KOTLIN_NATIVE_LEGACY_GROUP_ID = KOTLIN_NATIVE_LIBRARY_PREFIX
|
||||||
|
|||||||
+54
@@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* 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 junit.framework.TestCase
|
||||||
|
import org.jetbrains.kotlin.idea.configuration.KotlinNativeLibraryNameUtil.buildIDELibraryName
|
||||||
|
import org.jetbrains.kotlin.idea.configuration.KotlinNativeLibraryNameUtil.isGradleLibraryName
|
||||||
|
import org.jetbrains.kotlin.idea.configuration.KotlinNativeLibraryNameUtil.parseIDELibraryName
|
||||||
|
|
||||||
|
class KotlinNativeLibraryNameUtilTest : TestCase() {
|
||||||
|
|
||||||
|
fun testBuildIDELibraryName() {
|
||||||
|
assertEquals(
|
||||||
|
"Kotlin/Native 1.3.60 - stdlib",
|
||||||
|
buildIDELibraryName("1.3.60", "stdlib", null)
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
"Kotlin/Native 1.3.60-eap-23 - Accelerate [macos_x64]",
|
||||||
|
buildIDELibraryName("1.3.60-eap-23", "Accelerate", "macos_x64")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testParseIDELibraryName() {
|
||||||
|
assertEquals(
|
||||||
|
Triple("1.3.60", "stdlib", null),
|
||||||
|
parseIDELibraryName("Kotlin/Native 1.3.60 - stdlib")
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
Triple("1.3.60-eap-23", "Accelerate", "macos_x64"),
|
||||||
|
parseIDELibraryName("Kotlin/Native 1.3.60-eap-23 - Accelerate [macos_x64]")
|
||||||
|
)
|
||||||
|
|
||||||
|
assertNull(parseIDELibraryName("Kotlin/Native - something unexpected"))
|
||||||
|
|
||||||
|
assertNull(parseIDELibraryName("foo.klib"))
|
||||||
|
|
||||||
|
assertNull(parseIDELibraryName("Gradle: some:third-party-library:1.2"))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testIsGradleLibraryName() {
|
||||||
|
assertFalse(isGradleLibraryName("Kotlin/Native 1.3.60 - stdlib"))
|
||||||
|
|
||||||
|
assertFalse(isGradleLibraryName("Kotlin/Native 1.3.60-eap-23 - Accelerate [macos_x64]"))
|
||||||
|
|
||||||
|
assertFalse(isGradleLibraryName("foo.klib"))
|
||||||
|
|
||||||
|
assertTrue(isGradleLibraryName("Gradle: some:third-party-library:1.2"))
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
@@ -324,6 +324,7 @@ class UnsupportedAbiVersionNotificationPanelProvider(private val project: Projec
|
|||||||
val badRoots = when {
|
val badRoots = when {
|
||||||
platform.isJvm() -> getLibraryRootsWithAbiIncompatibleKotlinClasses(module)
|
platform.isJvm() -> getLibraryRootsWithAbiIncompatibleKotlinClasses(module)
|
||||||
platform.isJs() -> getLibraryRootsWithAbiIncompatibleForKotlinJs(module)
|
platform.isJs() -> getLibraryRootsWithAbiIncompatibleForKotlinJs(module)
|
||||||
|
// TODO: also check it for Native KT-34525
|
||||||
else -> return emptyList()
|
else -> return emptyList()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+12
-14
@@ -27,7 +27,8 @@ import org.jetbrains.kotlin.descriptors.PackageFragmentProvider
|
|||||||
import org.jetbrains.kotlin.descriptors.impl.CompositePackageFragmentProvider
|
import org.jetbrains.kotlin.descriptors.impl.CompositePackageFragmentProvider
|
||||||
import org.jetbrains.kotlin.descriptors.konan.DeserializedKlibModuleOrigin
|
import org.jetbrains.kotlin.descriptors.konan.DeserializedKlibModuleOrigin
|
||||||
import org.jetbrains.kotlin.descriptors.konan.KlibModuleOrigin
|
import org.jetbrains.kotlin.descriptors.konan.KlibModuleOrigin
|
||||||
import org.jetbrains.kotlin.ide.konan.NativeLibraryInfo.Companion.isAbiCompatible
|
import org.jetbrains.kotlin.ide.konan.NativeLibraryInfo.Companion.safeAbiVersion
|
||||||
|
import org.jetbrains.kotlin.ide.konan.NativeLibraryInfo.Companion.isCompatible
|
||||||
import org.jetbrains.kotlin.ide.konan.analyzer.NativeResolverForModuleFactory
|
import org.jetbrains.kotlin.ide.konan.analyzer.NativeResolverForModuleFactory
|
||||||
import org.jetbrains.kotlin.idea.caches.project.LibraryInfo
|
import org.jetbrains.kotlin.idea.caches.project.LibraryInfo
|
||||||
import org.jetbrains.kotlin.idea.caches.project.lazyClosure
|
import org.jetbrains.kotlin.idea.caches.project.lazyClosure
|
||||||
@@ -47,7 +48,6 @@ import org.jetbrains.kotlin.resolve.TargetEnvironment
|
|||||||
import org.jetbrains.kotlin.serialization.konan.impl.KlibMetadataModuleDescriptorFactoryImpl
|
import org.jetbrains.kotlin.serialization.konan.impl.KlibMetadataModuleDescriptorFactoryImpl
|
||||||
import org.jetbrains.kotlin.storage.StorageManager
|
import org.jetbrains.kotlin.storage.StorageManager
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import kotlin.LazyThreadSafetyMode.PUBLICATION
|
|
||||||
|
|
||||||
fun KotlinLibrary.createPackageFragmentProvider(
|
fun KotlinLibrary.createPackageFragmentProvider(
|
||||||
storageManager: StorageManager,
|
storageManager: StorageManager,
|
||||||
@@ -55,7 +55,7 @@ fun KotlinLibrary.createPackageFragmentProvider(
|
|||||||
moduleDescriptor: ModuleDescriptor
|
moduleDescriptor: ModuleDescriptor
|
||||||
): PackageFragmentProvider? {
|
): PackageFragmentProvider? {
|
||||||
|
|
||||||
if (!isAbiCompatible) return null
|
if (!safeAbiVersion.isCompatible) return null
|
||||||
|
|
||||||
val libraryProto = CachingIdeKonanLibraryMetadataLoader.loadModuleHeader(this)
|
val libraryProto = CachingIdeKonanLibraryMetadataLoader.loadModuleHeader(this)
|
||||||
|
|
||||||
@@ -78,7 +78,7 @@ class NativePlatformKindResolution : IdePlatformKindResolution {
|
|||||||
return library.getFiles(OrderRootType.CLASSES).mapNotNull { file ->
|
return library.getFiles(OrderRootType.CLASSES).mapNotNull { file ->
|
||||||
if (!isLibraryFileForPlatform(file)) return@createLibraryInfo emptyList()
|
if (!isLibraryFileForPlatform(file)) return@createLibraryInfo emptyList()
|
||||||
val path = PathUtil.getLocalPath(file) ?: return@createLibraryInfo emptyList()
|
val path = PathUtil.getLocalPath(file) ?: return@createLibraryInfo emptyList()
|
||||||
NativeLibraryInfo(project, library, File(path))
|
NativeLibraryInfo(project, library, path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -185,19 +185,16 @@ private fun createKotlinNativeBuiltIns(moduleInfo: ModuleInfo, projectContext: P
|
|||||||
private fun ModuleInfo.findNativeStdlib(): NativeLibraryInfo? =
|
private fun ModuleInfo.findNativeStdlib(): NativeLibraryInfo? =
|
||||||
dependencies().lazyClosure { it.dependencies() }
|
dependencies().lazyClosure { it.dependencies() }
|
||||||
.filterIsInstance<NativeLibraryInfo>()
|
.filterIsInstance<NativeLibraryInfo>()
|
||||||
.firstOrNull { it.isStdlib && it.isAbiCompatible }
|
.firstOrNull { it.isStdlib && it.safeAbiVersion.isCompatible }
|
||||||
|
|
||||||
class NativeLibraryInfo(project: Project, library: Library, root: File) : LibraryInfo(project, library) {
|
class NativeLibraryInfo(project: Project, library: Library, val libraryRoot: String) : LibraryInfo(project, library) {
|
||||||
|
|
||||||
private val nativeLibrary = createKotlinLibrary(root)
|
private val nativeLibrary = createKotlinLibrary(File(libraryRoot))
|
||||||
|
|
||||||
private val roots = listOf(root.absolutePath)
|
val isStdlib get() = libraryRoot.endsWith(KONAN_STDLIB_NAME)
|
||||||
|
val safeAbiVersion get() = nativeLibrary.safeAbiVersion
|
||||||
|
|
||||||
val isStdlib by lazy(PUBLICATION) { roots.first().endsWith(KONAN_STDLIB_NAME) }
|
override fun getLibraryRoots() = listOf(libraryRoot)
|
||||||
|
|
||||||
val isAbiCompatible get() = nativeLibrary.isAbiCompatible
|
|
||||||
|
|
||||||
override fun getLibraryRoots() = roots
|
|
||||||
|
|
||||||
override val capabilities: Map<ModuleDescriptor.Capability<*>, Any?>
|
override val capabilities: Map<ModuleDescriptor.Capability<*>, Any?>
|
||||||
get() {
|
get() {
|
||||||
@@ -216,7 +213,8 @@ class NativeLibraryInfo(project: Project, library: Library, root: File) : Librar
|
|||||||
companion object {
|
companion object {
|
||||||
val NATIVE_LIBRARY_CAPABILITY = ModuleDescriptor.Capability<KotlinLibrary>("KotlinNativeLibrary")
|
val NATIVE_LIBRARY_CAPABILITY = ModuleDescriptor.Capability<KotlinLibrary>("KotlinNativeLibrary")
|
||||||
|
|
||||||
val KotlinLibrary.isAbiCompatible get() = this.readSafe(null) { versions.abiVersion } == KotlinAbiVersion.CURRENT
|
internal val KotlinLibrary.safeAbiVersion get() = this.readSafe(null) { versions.abiVersion }
|
||||||
|
internal val KotlinAbiVersion?.isCompatible get() = this == KotlinAbiVersion.CURRENT
|
||||||
|
|
||||||
private fun <T> KotlinLibrary.readSafe(defaultValue: T, action: KotlinLibrary.() -> T) = try {
|
private fun <T> KotlinLibrary.readSafe(defaultValue: T, action: KotlinLibrary.() -> T) = try {
|
||||||
action()
|
action()
|
||||||
|
|||||||
@@ -1,4 +1,9 @@
|
|||||||
<idea-plugin xmlns:xi="http://www.w3.org/2001/XInclude">
|
<idea-plugin xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||||
|
<project-components>
|
||||||
|
<component>
|
||||||
|
<implementation-class>org.jetbrains.kotlin.ide.konan.KotlinNativeABICompatibilityChecker</implementation-class>
|
||||||
|
</component>
|
||||||
|
</project-components>
|
||||||
<application-components>
|
<application-components>
|
||||||
<component>
|
<component>
|
||||||
<implementation-class>org.jetbrains.kotlin.ide.konan.decompiler.KotlinNativeLoadingMetadataCache</implementation-class>
|
<implementation-class>org.jetbrains.kotlin.ide.konan.decompiler.KotlinNativeLoadingMetadataCache</implementation-class>
|
||||||
|
|||||||
Reference in New Issue
Block a user