Clean-up: Split nativeLibrariesUtil.kt into separate files in idea-gradle
This commit is contained in:
+1
-1
@@ -21,7 +21,7 @@ import com.intellij.util.PathUtilRt
|
|||||||
import com.intellij.util.concurrency.AppExecutorUtil
|
import com.intellij.util.concurrency.AppExecutorUtil
|
||||||
import org.jetbrains.concurrency.CancellablePromise
|
import org.jetbrains.concurrency.CancellablePromise
|
||||||
import org.jetbrains.kotlin.idea.caches.project.getModuleInfosFromIdeaModel
|
import org.jetbrains.kotlin.idea.caches.project.getModuleInfosFromIdeaModel
|
||||||
import org.jetbrains.kotlin.idea.configuration.KotlinNativeLibraryNameUtil
|
import org.jetbrains.kotlin.idea.configuration.klib.KotlinNativeLibraryNameUtil
|
||||||
import org.jetbrains.kotlin.idea.versions.UnsupportedAbiVersionNotificationPanelProvider
|
import org.jetbrains.kotlin.idea.versions.UnsupportedAbiVersionNotificationPanelProvider
|
||||||
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
|
||||||
|
|||||||
+1
-1
@@ -21,7 +21,7 @@ import com.intellij.util.PathUtilRt
|
|||||||
import com.intellij.util.concurrency.AppExecutorUtil
|
import com.intellij.util.concurrency.AppExecutorUtil
|
||||||
import org.jetbrains.concurrency.CancellablePromise
|
import org.jetbrains.concurrency.CancellablePromise
|
||||||
import org.jetbrains.kotlin.idea.caches.project.getModuleInfosFromIdeaModel
|
import org.jetbrains.kotlin.idea.caches.project.getModuleInfosFromIdeaModel
|
||||||
import org.jetbrains.kotlin.idea.configuration.KotlinNativeLibraryNameUtil
|
import org.jetbrains.kotlin.idea.configuration.klib.KotlinNativeLibraryNameUtil
|
||||||
import org.jetbrains.kotlin.idea.versions.UnsupportedAbiVersionNotificationPanelProvider
|
import org.jetbrains.kotlin.idea.versions.UnsupportedAbiVersionNotificationPanelProvider
|
||||||
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
|
||||||
|
|||||||
+1
@@ -45,6 +45,7 @@ import org.jetbrains.kotlin.gradle.CompilerArgumentsBySourceSet
|
|||||||
import org.jetbrains.kotlin.ide.konan.NativeLibraryKind
|
import org.jetbrains.kotlin.ide.konan.NativeLibraryKind
|
||||||
import org.jetbrains.kotlin.idea.compiler.configuration.KotlinCommonCompilerArgumentsHolder
|
import org.jetbrains.kotlin.idea.compiler.configuration.KotlinCommonCompilerArgumentsHolder
|
||||||
import org.jetbrains.kotlin.idea.configuration.GradlePropertiesFileFacade.Companion.KOTLIN_CODE_STYLE_GRADLE_SETTING
|
import org.jetbrains.kotlin.idea.configuration.GradlePropertiesFileFacade.Companion.KOTLIN_CODE_STYLE_GRADLE_SETTING
|
||||||
|
import org.jetbrains.kotlin.idea.configuration.klib.KotlinNativeLibraryNameUtil.KOTLIN_NATIVE_LIBRARY_PREFIX
|
||||||
import org.jetbrains.kotlin.idea.facet.*
|
import org.jetbrains.kotlin.idea.facet.*
|
||||||
import org.jetbrains.kotlin.idea.formatter.ProjectCodeStyleImporter
|
import org.jetbrains.kotlin.idea.formatter.ProjectCodeStyleImporter
|
||||||
import org.jetbrains.kotlin.idea.framework.CommonLibraryKind
|
import org.jetbrains.kotlin.idea.framework.CommonLibraryKind
|
||||||
|
|||||||
+3
@@ -35,6 +35,9 @@ import org.jetbrains.kotlin.config.LanguageFeature
|
|||||||
import org.jetbrains.kotlin.gradle.*
|
import org.jetbrains.kotlin.gradle.*
|
||||||
import org.jetbrains.kotlin.idea.configuration.GradlePropertiesFileFacade.Companion.KOTLIN_NOT_IMPORTED_COMMON_SOURCE_SETS_SETTING
|
import org.jetbrains.kotlin.idea.configuration.GradlePropertiesFileFacade.Companion.KOTLIN_NOT_IMPORTED_COMMON_SOURCE_SETS_SETTING
|
||||||
import org.jetbrains.kotlin.idea.configuration.KotlinMPPGradleProjectResolver.Companion.fullName
|
import org.jetbrains.kotlin.idea.configuration.KotlinMPPGradleProjectResolver.Companion.fullName
|
||||||
|
import org.jetbrains.kotlin.idea.configuration.klib.KotlinNativeLibraryNameUtil.KOTLIN_NATIVE_LIBRARY_PREFIX
|
||||||
|
import org.jetbrains.kotlin.idea.configuration.klib.KotlinNativeLibrariesDependencySubstitutor
|
||||||
|
import org.jetbrains.kotlin.idea.configuration.klib.KotlinNativeLibrariesFixer
|
||||||
import org.jetbrains.kotlin.idea.platform.IdePlatformKindTooling
|
import org.jetbrains.kotlin.idea.platform.IdePlatformKindTooling
|
||||||
import org.jetbrains.kotlin.util.removeSuffixIfPresent
|
import org.jetbrains.kotlin.util.removeSuffixIfPresent
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
|
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
|
||||||
|
|||||||
+141
@@ -0,0 +1,141 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2020 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.klib
|
||||||
|
|
||||||
|
import com.intellij.openapi.diagnostic.Logger
|
||||||
|
import com.intellij.openapi.roots.DependencyScope
|
||||||
|
import com.intellij.openapi.util.Key
|
||||||
|
import org.gradle.tooling.model.idea.IdeaModule
|
||||||
|
import org.jetbrains.kotlin.gradle.KotlinMPPGradleModel
|
||||||
|
import org.jetbrains.kotlin.idea.configuration.buildClasspathData
|
||||||
|
import org.jetbrains.kotlin.idea.inspections.gradle.findKotlinPluginVersion
|
||||||
|
import org.jetbrains.kotlin.konan.library.KONAN_STDLIB_NAME
|
||||||
|
import org.jetbrains.plugins.gradle.ExternalDependencyId
|
||||||
|
import org.jetbrains.plugins.gradle.model.*
|
||||||
|
import org.jetbrains.plugins.gradle.service.project.ProjectResolverContext
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
// KT-29613, KT-29783
|
||||||
|
internal class KotlinNativeLibrariesDependencySubstitutor(
|
||||||
|
mppModel: KotlinMPPGradleModel,
|
||||||
|
private val gradleModule: IdeaModule,
|
||||||
|
private val resolverCtx: ProjectResolverContext
|
||||||
|
) {
|
||||||
|
// Substitutes `ExternalDependency` entries that represent KLIBs with new dependency entries with proper type and name:
|
||||||
|
// - every `FileCollectionDependency` is checked whether it points to an existing KLIB, and substituted if it is
|
||||||
|
// - similarly for every `ExternalLibraryDependency` with `groupId == "Kotlin/Native"` (legacy KLIB provided by Gradle plugin <= 1.3.20)
|
||||||
|
fun substituteDependencies(dependencies: Collection<ExternalDependency>): List<ExternalDependency> {
|
||||||
|
val result = ArrayList(dependencies)
|
||||||
|
for (i in 0 until result.size) {
|
||||||
|
val dependency = result[i]
|
||||||
|
val dependencySubstitute = when (dependency) {
|
||||||
|
is FileCollectionDependency -> getFileCollectionDependencySubstitute(dependency)
|
||||||
|
is ExternalLibraryDependency -> getExternalLibraryDependencySubstitute(dependency)
|
||||||
|
else -> DependencySubstitute.NoSubstitute
|
||||||
|
}
|
||||||
|
|
||||||
|
val newDependency = (dependencySubstitute as? DependencySubstitute.YesSubstitute)?.substitute ?: continue
|
||||||
|
result[i] = newDependency
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
private val ProjectResolverContext.dependencySubstitutionCache
|
||||||
|
get() = getUserData(KLIB_DEPENDENCY_SUBSTITUTION_CACHE) ?: putUserDataIfAbsent(KLIB_DEPENDENCY_SUBSTITUTION_CACHE, HashMap())
|
||||||
|
|
||||||
|
private val klibInfoProvider: KlibInfoProvider? by lazy {
|
||||||
|
val kotlinNativeHome = mppModel.kotlinNativeHome.takeIf { it != KotlinMPPGradleModel.NO_KOTLIN_NATIVE_HOME }?.let(::File)
|
||||||
|
|
||||||
|
if (kotlinNativeHome == null) {
|
||||||
|
LOG.warn(
|
||||||
|
"""
|
||||||
|
Can't obtain Kotlin/Native home path in Kotlin Gradle plugin.
|
||||||
|
${KotlinMPPGradleModel::class.java.simpleName} is $mppModel.
|
||||||
|
${KotlinNativeLibrariesDependencySubstitutor::class.java.simpleName} will run in idle mode. No dependencies will be substituted.
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
|
||||||
|
null
|
||||||
|
} else
|
||||||
|
KlibInfoProvider(kotlinNativeHome = kotlinNativeHome)
|
||||||
|
}
|
||||||
|
|
||||||
|
private val kotlinVersion: String? by lazy {
|
||||||
|
// first, try to figure out Kotlin plugin version by classpath (the default approach)
|
||||||
|
val classpathData = buildClasspathData(gradleModule, resolverCtx)
|
||||||
|
val versionFromClasspath = findKotlinPluginVersion(classpathData)
|
||||||
|
|
||||||
|
if (versionFromClasspath == null) {
|
||||||
|
// then, examine Kotlin MPP Gradle model
|
||||||
|
val versionFromModel = mppModel.targets
|
||||||
|
.asSequence()
|
||||||
|
.flatMap { it.compilations.asSequence() }
|
||||||
|
.mapNotNull { it.kotlinTaskProperties.pluginVersion?.takeIf(String::isNotBlank) }
|
||||||
|
.firstOrNull()
|
||||||
|
|
||||||
|
if (versionFromModel == null) {
|
||||||
|
LOG.warn(
|
||||||
|
"""
|
||||||
|
Can't obtain Kotlin Gradle plugin version for ${gradleModule.name} module.
|
||||||
|
Build classpath is ${classpathData.classpathEntries.flatMap { it.classesFile }}.
|
||||||
|
${KotlinMPPGradleModel::class.java.simpleName} is $mppModel.
|
||||||
|
${KotlinNativeLibrariesDependencySubstitutor::class.java.simpleName} will run in idle mode. No dependencies will be substituted.
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
|
||||||
|
null
|
||||||
|
} else
|
||||||
|
versionFromModel
|
||||||
|
} else
|
||||||
|
versionFromClasspath
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getFileCollectionDependencySubstitute(dependency: FileCollectionDependency): DependencySubstitute =
|
||||||
|
resolverCtx.dependencySubstitutionCache.getOrPut(dependency.id) {
|
||||||
|
val libraryFile = dependency.files.firstOrNull() ?: return@getOrPut DependencySubstitute.NoSubstitute
|
||||||
|
buildSubstituteIfNecessary(libraryFile)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getExternalLibraryDependencySubstitute(dependency: ExternalLibraryDependency): DependencySubstitute =
|
||||||
|
resolverCtx.dependencySubstitutionCache.getOrPut(dependency.id) {
|
||||||
|
val libraryFile = dependency.file ?: return@getOrPut DependencySubstitute.NoSubstitute
|
||||||
|
buildSubstituteIfNecessary(libraryFile)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun buildSubstituteIfNecessary(libraryFile: File): DependencySubstitute {
|
||||||
|
// need to check whether `library` points to a real KLIB,
|
||||||
|
// and if answer is yes then build a new dependency that will substitute original one
|
||||||
|
val klib = klibInfoProvider?.getKlibInfo(libraryFile) as? NativeDistributionKlibInfo ?: return DependencySubstitute.NoSubstitute
|
||||||
|
val nonNullKotlinVersion = kotlinVersion ?: return DependencySubstitute.NoSubstitute
|
||||||
|
|
||||||
|
val newLibraryName = KotlinNativeLibraryNameUtil.buildIDELibraryName(nonNullKotlinVersion, klib.name, klib.target?.name)
|
||||||
|
|
||||||
|
val substitute = DefaultExternalMultiLibraryDependency().apply {
|
||||||
|
classpathOrder = if (klib.name == KONAN_STDLIB_NAME) -1 else 0 // keep stdlib upper
|
||||||
|
name = newLibraryName
|
||||||
|
packaging = DEFAULT_PACKAGING
|
||||||
|
files += klib.path
|
||||||
|
sources += klib.sourcePaths
|
||||||
|
scope = DependencyScope.PROVIDED.name
|
||||||
|
}
|
||||||
|
|
||||||
|
return DependencySubstitute.YesSubstitute(substitute)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val DEFAULT_PACKAGING = "jar"
|
||||||
|
|
||||||
|
private val LOG = Logger.getInstance(KotlinNativeLibrariesDependencySubstitutor::class.java)
|
||||||
|
|
||||||
|
private val KLIB_DEPENDENCY_SUBSTITUTION_CACHE =
|
||||||
|
Key.create<MutableMap<ExternalDependencyId, DependencySubstitute>>("KLIB_DEPENDENCY_SUBSTITUTION_CACHE")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private sealed class DependencySubstitute {
|
||||||
|
object NoSubstitute : DependencySubstitute()
|
||||||
|
class YesSubstitute(val substitute: ExternalMultiLibraryDependency) : DependencySubstitute()
|
||||||
|
}
|
||||||
+74
@@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2020 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.klib
|
||||||
|
|
||||||
|
import com.intellij.openapi.externalSystem.model.DataNode
|
||||||
|
import com.intellij.openapi.externalSystem.model.ProjectKeys
|
||||||
|
import com.intellij.openapi.externalSystem.model.project.LibraryData
|
||||||
|
import com.intellij.openapi.externalSystem.model.project.LibraryDependencyData
|
||||||
|
import com.intellij.openapi.externalSystem.model.project.LibraryLevel
|
||||||
|
import com.intellij.openapi.externalSystem.model.project.ProjectData
|
||||||
|
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil
|
||||||
|
import com.intellij.openapi.roots.libraries.Library
|
||||||
|
import org.jetbrains.kotlin.idea.configuration.klib.KotlinNativeLibraryNameUtil.GRADLE_LIBRARY_PREFIX
|
||||||
|
import org.jetbrains.kotlin.idea.configuration.klib.KotlinNativeLibraryNameUtil.KOTLIN_NATIVE_LIBRARY_PREFIX
|
||||||
|
import org.jetbrains.plugins.gradle.model.data.GradleSourceSetData
|
||||||
|
import org.jetbrains.plugins.gradle.service.project.GradleProjectResolverUtil
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gradle IDE plugin creates [LibraryData] nodes with internal name consisting of two parts:
|
||||||
|
* - mandatory "Gradle: " prefix
|
||||||
|
* - and library name
|
||||||
|
* Then internal name is propagated to IDE [Library] object, and is displayed in IDE as "Gradle: <LIBRARY_NAME>".
|
||||||
|
* [KotlinNativeLibrariesFixer] removes "Gradle: " prefix from all [LibraryData] items representing KLIBs to make them
|
||||||
|
* look more friendly.
|
||||||
|
*
|
||||||
|
* Also, [KotlinNativeLibrariesFixer] makes sure that all KLIBs from Kotlin/Native distribution are added to IDE project model
|
||||||
|
* as project-level libraries. This is necessary until the appropriate fix in IDEA will be implemented (for details see IDEA-211451).
|
||||||
|
*/
|
||||||
|
internal object KotlinNativeLibrariesFixer {
|
||||||
|
fun applyTo(ownerNode: DataNode<GradleSourceSetData>, ideProject: DataNode<ProjectData>) {
|
||||||
|
for (libraryDependencyNode in ExternalSystemApiUtil.findAll(ownerNode, ProjectKeys.LIBRARY_DEPENDENCY)) {
|
||||||
|
val libraryData = libraryDependencyNode.data.target
|
||||||
|
|
||||||
|
// Only KLIBs from Kotlin/Native distribution can have such prefix:
|
||||||
|
if (libraryData.internalName.startsWith("$GRADLE_LIBRARY_PREFIX$KOTLIN_NATIVE_LIBRARY_PREFIX")) {
|
||||||
|
fixLibraryName(libraryData)
|
||||||
|
addLibraryToProjectModel(libraryData, ideProject)
|
||||||
|
fixLibraryDependencyLevel(libraryDependencyNode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun fixLibraryName(libraryData: LibraryData) {
|
||||||
|
libraryData.internalName = libraryData.internalName.substringAfter(GRADLE_LIBRARY_PREFIX)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun addLibraryToProjectModel(libraryData: LibraryData, ideProject: DataNode<ProjectData>) {
|
||||||
|
GradleProjectResolverUtil.linkProjectLibrary(ideProject, libraryData)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun fixLibraryDependencyLevel(oldDependencyNode: DataNode<LibraryDependencyData>) {
|
||||||
|
val oldDependency = oldDependencyNode.data
|
||||||
|
if (oldDependency.level == LibraryLevel.PROJECT) return // nothing to do
|
||||||
|
|
||||||
|
val newDependency = LibraryDependencyData(oldDependency.ownerModule, oldDependency.target, LibraryLevel.PROJECT).apply {
|
||||||
|
scope = oldDependency.scope
|
||||||
|
order = oldDependency.order
|
||||||
|
isExported = oldDependency.isExported
|
||||||
|
}
|
||||||
|
|
||||||
|
val parentNode = oldDependencyNode.parent ?: return
|
||||||
|
val childNodes = oldDependencyNode.children
|
||||||
|
|
||||||
|
val newDependencyNode = parentNode.createChild(oldDependencyNode.key, newDependency)
|
||||||
|
for (child in childNodes) {
|
||||||
|
newDependencyNode.addChild(child)
|
||||||
|
}
|
||||||
|
|
||||||
|
oldDependencyNode.clear(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
+63
@@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2020 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.klib
|
||||||
|
|
||||||
|
import com.intellij.openapi.externalSystem.model.DataNode
|
||||||
|
import com.intellij.openapi.externalSystem.model.ProjectKeys
|
||||||
|
import com.intellij.openapi.externalSystem.model.project.LibraryData
|
||||||
|
import com.intellij.openapi.externalSystem.model.project.ProjectData
|
||||||
|
import com.intellij.openapi.externalSystem.service.project.IdeModifiableModelsProvider
|
||||||
|
import com.intellij.openapi.externalSystem.service.project.IdeUIModifiableModelsProvider
|
||||||
|
import com.intellij.openapi.externalSystem.service.project.manage.AbstractProjectDataService
|
||||||
|
import com.intellij.openapi.externalSystem.util.ExternalSystemConstants
|
||||||
|
import com.intellij.openapi.externalSystem.util.Order
|
||||||
|
import com.intellij.openapi.project.Project
|
||||||
|
import com.intellij.openapi.roots.LibraryOrderEntry
|
||||||
|
import com.intellij.openapi.roots.libraries.Library
|
||||||
|
import org.jetbrains.kotlin.idea.configuration.klib.KotlinNativeLibraryNameUtil.KOTLIN_NATIVE_LIBRARY_PREFIX_PLUS_SPACE
|
||||||
|
|
||||||
|
// KT-30490. This `ProjectDataService` must be executed immediately after
|
||||||
|
// `com.intellij.openapi.externalSystem.service.project.manage.LibraryDataService` to clean-up KLIBs before any other actions taken on them.
|
||||||
|
@Order(ExternalSystemConstants.BUILTIN_LIBRARY_DATA_SERVICE_ORDER + 1) // force order
|
||||||
|
class KotlinNativeLibraryDataService : AbstractProjectDataService<LibraryData, Library>() {
|
||||||
|
override fun getTargetDataKey() = ProjectKeys.LIBRARY
|
||||||
|
|
||||||
|
// See also `com.intellij.openapi.externalSystem.service.project.manage.LibraryDataService.postProcess()`
|
||||||
|
override fun postProcess(
|
||||||
|
toImport: MutableCollection<DataNode<LibraryData>>,
|
||||||
|
projectData: ProjectData?,
|
||||||
|
project: Project,
|
||||||
|
modelsProvider: IdeModifiableModelsProvider
|
||||||
|
) {
|
||||||
|
if (projectData == null || modelsProvider is IdeUIModifiableModelsProvider) return
|
||||||
|
|
||||||
|
val librariesModel = modelsProvider.modifiableProjectLibrariesModel
|
||||||
|
val potentialOrphans = HashMap<String, Library>()
|
||||||
|
|
||||||
|
librariesModel.libraries.forEach { library ->
|
||||||
|
val libraryName = library.name?.takeIf { it.startsWith(KOTLIN_NATIVE_LIBRARY_PREFIX_PLUS_SPACE) } ?: return@forEach
|
||||||
|
potentialOrphans[libraryName] = library
|
||||||
|
}
|
||||||
|
|
||||||
|
if (potentialOrphans.isEmpty()) return
|
||||||
|
|
||||||
|
modelsProvider.modules.forEach { module ->
|
||||||
|
modelsProvider.getOrderEntries(module).forEach inner@{ orderEntry ->
|
||||||
|
val libraryOrderEntry = orderEntry as? LibraryOrderEntry ?: return@inner
|
||||||
|
if (libraryOrderEntry.isModuleLevel) return@inner
|
||||||
|
|
||||||
|
val libraryName = (libraryOrderEntry.library?.name ?: libraryOrderEntry.libraryName)
|
||||||
|
?.takeIf { it.startsWith(KOTLIN_NATIVE_LIBRARY_PREFIX_PLUS_SPACE) } ?: return@inner
|
||||||
|
|
||||||
|
potentialOrphans.remove(libraryName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
potentialOrphans.keys.forEach { libraryName ->
|
||||||
|
librariesModel.getLibraryByName(libraryName)?.let { librariesModel.removeLibrary(it) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+34
@@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2020 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.klib
|
||||||
|
|
||||||
|
object KotlinNativeLibraryNameUtil {
|
||||||
|
internal const val KOTLIN_NATIVE_LIBRARY_PREFIX = "Kotlin/Native"
|
||||||
|
internal const val KOTLIN_NATIVE_LIBRARY_PREFIX_PLUS_SPACE = "$KOTLIN_NATIVE_LIBRARY_PREFIX "
|
||||||
|
internal const val GRADLE_LIBRARY_PREFIX = "Gradle: "
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
@@ -1,288 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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 com.intellij.openapi.diagnostic.Logger
|
|
||||||
import com.intellij.openapi.externalSystem.model.DataNode
|
|
||||||
import com.intellij.openapi.externalSystem.model.ProjectKeys
|
|
||||||
import com.intellij.openapi.externalSystem.model.project.LibraryData
|
|
||||||
import com.intellij.openapi.externalSystem.model.project.LibraryDependencyData
|
|
||||||
import com.intellij.openapi.externalSystem.model.project.LibraryLevel
|
|
||||||
import com.intellij.openapi.externalSystem.model.project.ProjectData
|
|
||||||
import com.intellij.openapi.externalSystem.service.project.IdeModifiableModelsProvider
|
|
||||||
import com.intellij.openapi.externalSystem.service.project.IdeUIModifiableModelsProvider
|
|
||||||
import com.intellij.openapi.externalSystem.service.project.manage.AbstractProjectDataService
|
|
||||||
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil
|
|
||||||
import com.intellij.openapi.externalSystem.util.ExternalSystemConstants
|
|
||||||
import com.intellij.openapi.externalSystem.util.Order
|
|
||||||
import com.intellij.openapi.project.Project
|
|
||||||
import com.intellij.openapi.roots.DependencyScope
|
|
||||||
import com.intellij.openapi.roots.LibraryOrderEntry
|
|
||||||
import com.intellij.openapi.roots.libraries.Library
|
|
||||||
import com.intellij.openapi.util.Key
|
|
||||||
import org.gradle.tooling.model.idea.IdeaModule
|
|
||||||
import org.jetbrains.kotlin.gradle.KotlinMPPGradleModel
|
|
||||||
import org.jetbrains.kotlin.idea.configuration.DependencySubstitute.NoSubstitute
|
|
||||||
import org.jetbrains.kotlin.idea.configuration.DependencySubstitute.YesSubstitute
|
|
||||||
import org.jetbrains.kotlin.idea.configuration.KotlinNativeLibraryNameUtil.buildIDELibraryName
|
|
||||||
import org.jetbrains.kotlin.idea.configuration.klib.KlibInfoProvider
|
|
||||||
import org.jetbrains.kotlin.idea.configuration.klib.NativeDistributionKlibInfo
|
|
||||||
import org.jetbrains.kotlin.idea.inspections.gradle.findKotlinPluginVersion
|
|
||||||
import org.jetbrains.kotlin.konan.library.KONAN_STDLIB_NAME
|
|
||||||
import org.jetbrains.plugins.gradle.ExternalDependencyId
|
|
||||||
import org.jetbrains.plugins.gradle.model.*
|
|
||||||
import org.jetbrains.plugins.gradle.model.data.GradleSourceSetData
|
|
||||||
import org.jetbrains.plugins.gradle.service.project.GradleProjectResolverUtil
|
|
||||||
import org.jetbrains.plugins.gradle.service.project.ProjectResolverContext
|
|
||||||
import java.io.File
|
|
||||||
|
|
||||||
// KT-30490. This `ProjectDataService` must be executed immediately after
|
|
||||||
// `com.intellij.openapi.externalSystem.service.project.manage.LibraryDataService` to clean-up KLIBs before any other actions taken on them.
|
|
||||||
@Order(ExternalSystemConstants.BUILTIN_LIBRARY_DATA_SERVICE_ORDER + 1) // force order
|
|
||||||
class KotlinNativeLibraryDataService : AbstractProjectDataService<LibraryData, Library>() {
|
|
||||||
override fun getTargetDataKey() = ProjectKeys.LIBRARY
|
|
||||||
|
|
||||||
// See also `com.intellij.openapi.externalSystem.service.project.manage.LibraryDataService.postProcess()`
|
|
||||||
override fun postProcess(
|
|
||||||
toImport: MutableCollection<DataNode<LibraryData>>,
|
|
||||||
projectData: ProjectData?,
|
|
||||||
project: Project,
|
|
||||||
modelsProvider: IdeModifiableModelsProvider
|
|
||||||
) {
|
|
||||||
if (projectData == null || modelsProvider is IdeUIModifiableModelsProvider) return
|
|
||||||
|
|
||||||
val librariesModel = modelsProvider.modifiableProjectLibrariesModel
|
|
||||||
val potentialOrphans = HashMap<String, Library>()
|
|
||||||
|
|
||||||
librariesModel.libraries.forEach { library ->
|
|
||||||
val libraryName = library.name?.takeIf { it.startsWith(KOTLIN_NATIVE_LIBRARY_PREFIX_PLUS_SPACE) } ?: return@forEach
|
|
||||||
potentialOrphans[libraryName] = library
|
|
||||||
}
|
|
||||||
|
|
||||||
if (potentialOrphans.isEmpty()) return
|
|
||||||
|
|
||||||
modelsProvider.modules.forEach { module ->
|
|
||||||
modelsProvider.getOrderEntries(module).forEach inner@{ orderEntry ->
|
|
||||||
val libraryOrderEntry = orderEntry as? LibraryOrderEntry ?: return@inner
|
|
||||||
if (libraryOrderEntry.isModuleLevel) return@inner
|
|
||||||
|
|
||||||
val libraryName = (libraryOrderEntry.library?.name ?: libraryOrderEntry.libraryName)
|
|
||||||
?.takeIf { it.startsWith(KOTLIN_NATIVE_LIBRARY_PREFIX_PLUS_SPACE) } ?: return@inner
|
|
||||||
|
|
||||||
potentialOrphans.remove(libraryName)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
potentialOrphans.keys.forEach { libraryName ->
|
|
||||||
librariesModel.getLibraryByName(libraryName)?.let { librariesModel.removeLibrary(it) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// KT-29613, KT-29783
|
|
||||||
internal class KotlinNativeLibrariesDependencySubstitutor(
|
|
||||||
mppModel: KotlinMPPGradleModel,
|
|
||||||
private val gradleModule: IdeaModule,
|
|
||||||
private val resolverCtx: ProjectResolverContext
|
|
||||||
) {
|
|
||||||
// Substitutes `ExternalDependency` entries that represent KLIBs with new dependency entries with proper type and name:
|
|
||||||
// - every `FileCollectionDependency` is checked whether it points to an existing KLIB, and substituted if it is
|
|
||||||
// - similarly for every `ExternalLibraryDependency` with `groupId == "Kotlin/Native"` (legacy KLIB provided by Gradle plugin <= 1.3.20)
|
|
||||||
fun substituteDependencies(dependencies: Collection<ExternalDependency>): List<ExternalDependency> {
|
|
||||||
val result = ArrayList(dependencies)
|
|
||||||
for (i in 0 until result.size) {
|
|
||||||
val dependency = result[i]
|
|
||||||
val dependencySubstitute = when (dependency) {
|
|
||||||
is FileCollectionDependency -> getFileCollectionDependencySubstitute(dependency)
|
|
||||||
is ExternalLibraryDependency -> getExternalLibraryDependencySubstitute(dependency)
|
|
||||||
else -> NoSubstitute
|
|
||||||
}
|
|
||||||
|
|
||||||
val newDependency = (dependencySubstitute as? YesSubstitute)?.substitute ?: continue
|
|
||||||
result[i] = newDependency
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
private val ProjectResolverContext.dependencySubstitutionCache
|
|
||||||
get() = getUserData(KLIB_DEPENDENCY_SUBSTITUTION_CACHE) ?: putUserDataIfAbsent(KLIB_DEPENDENCY_SUBSTITUTION_CACHE, HashMap())
|
|
||||||
|
|
||||||
private val klibInfoProvider: KlibInfoProvider? by lazy {
|
|
||||||
val kotlinNativeHome = mppModel.kotlinNativeHome.takeIf { it != KotlinMPPGradleModel.NO_KOTLIN_NATIVE_HOME }?.let(::File)
|
|
||||||
|
|
||||||
if (kotlinNativeHome == null) {
|
|
||||||
LOG.warn(
|
|
||||||
"""
|
|
||||||
Can't obtain Kotlin/Native home path in Kotlin Gradle plugin.
|
|
||||||
${KotlinMPPGradleModel::class.java.simpleName} is $mppModel.
|
|
||||||
${KotlinNativeLibrariesDependencySubstitutor::class.java.simpleName} will run in idle mode. No dependencies will be substituted.
|
|
||||||
""".trimIndent()
|
|
||||||
)
|
|
||||||
|
|
||||||
null
|
|
||||||
} else
|
|
||||||
KlibInfoProvider(kotlinNativeHome = kotlinNativeHome)
|
|
||||||
}
|
|
||||||
|
|
||||||
private val kotlinVersion: String? by lazy {
|
|
||||||
// first, try to figure out Kotlin plugin version by classpath (the default approach)
|
|
||||||
val classpathData = buildClasspathData(gradleModule, resolverCtx)
|
|
||||||
val versionFromClasspath = findKotlinPluginVersion(classpathData)
|
|
||||||
|
|
||||||
if (versionFromClasspath == null) {
|
|
||||||
// then, examine Kotlin MPP Gradle model
|
|
||||||
val versionFromModel = mppModel.targets
|
|
||||||
.asSequence()
|
|
||||||
.flatMap { it.compilations.asSequence() }
|
|
||||||
.mapNotNull { it.kotlinTaskProperties.pluginVersion?.takeIf(String::isNotBlank) }
|
|
||||||
.firstOrNull()
|
|
||||||
|
|
||||||
if (versionFromModel == null) {
|
|
||||||
LOG.warn(
|
|
||||||
"""
|
|
||||||
Can't obtain Kotlin Gradle plugin version for ${gradleModule.name} module.
|
|
||||||
Build classpath is ${classpathData.classpathEntries.flatMap { it.classesFile }}.
|
|
||||||
${KotlinMPPGradleModel::class.java.simpleName} is $mppModel.
|
|
||||||
${KotlinNativeLibrariesDependencySubstitutor::class.java.simpleName} will run in idle mode. No dependencies will be substituted.
|
|
||||||
""".trimIndent()
|
|
||||||
)
|
|
||||||
|
|
||||||
null
|
|
||||||
} else
|
|
||||||
versionFromModel
|
|
||||||
} else
|
|
||||||
versionFromClasspath
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getFileCollectionDependencySubstitute(dependency: FileCollectionDependency): DependencySubstitute =
|
|
||||||
resolverCtx.dependencySubstitutionCache.getOrPut(dependency.id) {
|
|
||||||
val libraryFile = dependency.files.firstOrNull() ?: return@getOrPut NoSubstitute
|
|
||||||
buildSubstituteIfNecessary(libraryFile)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getExternalLibraryDependencySubstitute(dependency: ExternalLibraryDependency): DependencySubstitute =
|
|
||||||
resolverCtx.dependencySubstitutionCache.getOrPut(dependency.id) {
|
|
||||||
val libraryFile = dependency.file ?: return@getOrPut NoSubstitute
|
|
||||||
buildSubstituteIfNecessary(libraryFile)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun buildSubstituteIfNecessary(libraryFile: File): DependencySubstitute {
|
|
||||||
// need to check whether `library` points to a real KLIB,
|
|
||||||
// and if answer is yes then build a new dependency that will substitute original one
|
|
||||||
val klib = klibInfoProvider?.getKlibInfo(libraryFile) as? NativeDistributionKlibInfo ?: return NoSubstitute
|
|
||||||
val nonNullKotlinVersion = kotlinVersion ?: return NoSubstitute
|
|
||||||
|
|
||||||
val newLibraryName = buildIDELibraryName(nonNullKotlinVersion, klib.name, klib.target?.name)
|
|
||||||
|
|
||||||
val substitute = DefaultExternalMultiLibraryDependency().apply {
|
|
||||||
classpathOrder = if (klib.name == KONAN_STDLIB_NAME) -1 else 0 // keep stdlib upper
|
|
||||||
name = newLibraryName
|
|
||||||
packaging = DEFAULT_PACKAGING
|
|
||||||
files += klib.path
|
|
||||||
sources += klib.sourcePaths
|
|
||||||
scope = DependencyScope.PROVIDED.name
|
|
||||||
}
|
|
||||||
|
|
||||||
return YesSubstitute(substitute)
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
private const val DEFAULT_PACKAGING = "jar"
|
|
||||||
|
|
||||||
private val LOG = Logger.getInstance(KotlinNativeLibrariesDependencySubstitutor::class.java)
|
|
||||||
|
|
||||||
private val KLIB_DEPENDENCY_SUBSTITUTION_CACHE =
|
|
||||||
Key.create<MutableMap<ExternalDependencyId, DependencySubstitute>>("KLIB_DEPENDENCY_SUBSTITUTION_CACHE")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gradle IDE plugin creates [LibraryData] nodes with internal name consisting of two parts:
|
|
||||||
* - mandatory "Gradle: " prefix
|
|
||||||
* - and library name
|
|
||||||
* Then internal name is propagated to IDE [Library] object, and is displayed in IDE as "Gradle: <LIBRARY_NAME>".
|
|
||||||
* [KotlinNativeLibrariesFixer] removes "Gradle: " prefix from all [LibraryData] items representing KLIBs to make them
|
|
||||||
* look more friendly.
|
|
||||||
*
|
|
||||||
* Also, [KotlinNativeLibrariesFixer] makes sure that all KLIBs from Kotlin/Native distribution are added to IDE project model
|
|
||||||
* as project-level libraries. This is necessary until the appropriate fix in IDEA will be implemented (for details see IDEA-211451).
|
|
||||||
*/
|
|
||||||
internal object KotlinNativeLibrariesFixer {
|
|
||||||
fun applyTo(ownerNode: DataNode<GradleSourceSetData>, ideProject: DataNode<ProjectData>) {
|
|
||||||
for (libraryDependencyNode in ExternalSystemApiUtil.findAll(ownerNode, ProjectKeys.LIBRARY_DEPENDENCY)) {
|
|
||||||
val libraryData = libraryDependencyNode.data.target
|
|
||||||
|
|
||||||
// Only KLIBs from Kotlin/Native distribution can have such prefix:
|
|
||||||
if (libraryData.internalName.startsWith("$GRADLE_LIBRARY_PREFIX$KOTLIN_NATIVE_LIBRARY_PREFIX")) {
|
|
||||||
fixLibraryName(libraryData)
|
|
||||||
addLibraryToProjectModel(libraryData, ideProject)
|
|
||||||
fixLibraryDependencyLevel(libraryDependencyNode)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun fixLibraryName(libraryData: LibraryData) {
|
|
||||||
libraryData.internalName = libraryData.internalName.substringAfter(GRADLE_LIBRARY_PREFIX)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun addLibraryToProjectModel(libraryData: LibraryData, ideProject: DataNode<ProjectData>) {
|
|
||||||
GradleProjectResolverUtil.linkProjectLibrary(ideProject, libraryData)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun fixLibraryDependencyLevel(oldDependencyNode: DataNode<LibraryDependencyData>) {
|
|
||||||
val oldDependency = oldDependencyNode.data
|
|
||||||
if (oldDependency.level == LibraryLevel.PROJECT) return // nothing to do
|
|
||||||
|
|
||||||
val newDependency = LibraryDependencyData(oldDependency.ownerModule, oldDependency.target, LibraryLevel.PROJECT).apply {
|
|
||||||
scope = oldDependency.scope
|
|
||||||
order = oldDependency.order
|
|
||||||
isExported = oldDependency.isExported
|
|
||||||
}
|
|
||||||
|
|
||||||
val parentNode = oldDependencyNode.parent ?: return
|
|
||||||
val childNodes = oldDependencyNode.children
|
|
||||||
|
|
||||||
val newDependencyNode = parentNode.createChild(oldDependencyNode.key, newDependency)
|
|
||||||
for (child in childNodes) {
|
|
||||||
newDependencyNode.addChild(child)
|
|
||||||
}
|
|
||||||
|
|
||||||
oldDependencyNode.clear(true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private sealed class DependencySubstitute {
|
|
||||||
object NoSubstitute : 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"
|
|
||||||
private const val KOTLIN_NATIVE_LIBRARY_PREFIX_PLUS_SPACE = "$KOTLIN_NATIVE_LIBRARY_PREFIX "
|
|
||||||
private const val GRADLE_LIBRARY_PREFIX = "Gradle: "
|
|
||||||
+5
-5
@@ -1,14 +1,14 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
* Copyright 2010-2020 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.
|
* 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
|
package org.jetbrains.kotlin.idea.configuration.klib
|
||||||
|
|
||||||
import junit.framework.TestCase
|
import junit.framework.TestCase
|
||||||
import org.jetbrains.kotlin.idea.configuration.KotlinNativeLibraryNameUtil.buildIDELibraryName
|
import org.jetbrains.kotlin.idea.configuration.klib.KotlinNativeLibraryNameUtil.buildIDELibraryName
|
||||||
import org.jetbrains.kotlin.idea.configuration.KotlinNativeLibraryNameUtil.isGradleLibraryName
|
import org.jetbrains.kotlin.idea.configuration.klib.KotlinNativeLibraryNameUtil.isGradleLibraryName
|
||||||
import org.jetbrains.kotlin.idea.configuration.KotlinNativeLibraryNameUtil.parseIDELibraryName
|
import org.jetbrains.kotlin.idea.configuration.klib.KotlinNativeLibraryNameUtil.parseIDELibraryName
|
||||||
|
|
||||||
class KotlinNativeLibraryNameUtilTest : TestCase() {
|
class KotlinNativeLibraryNameUtilTest : TestCase() {
|
||||||
|
|
||||||
@@ -25,7 +25,7 @@
|
|||||||
<externalProjectDataService implementation="org.jetbrains.kotlin.idea.configuration.KotlinGradleLibraryDataService"/>
|
<externalProjectDataService implementation="org.jetbrains.kotlin.idea.configuration.KotlinGradleLibraryDataService"/>
|
||||||
<externalProjectDataService implementation="org.jetbrains.kotlin.idea.configuration.KotlinTargetDataService"/>
|
<externalProjectDataService implementation="org.jetbrains.kotlin.idea.configuration.KotlinTargetDataService"/>
|
||||||
<externalProjectDataService implementation="org.jetbrains.kotlin.idea.KotlinJavaMPPSourceSetDataService"/>
|
<externalProjectDataService implementation="org.jetbrains.kotlin.idea.KotlinJavaMPPSourceSetDataService"/>
|
||||||
<externalProjectDataService implementation="org.jetbrains.kotlin.idea.configuration.KotlinNativeLibraryDataService"/>
|
<externalProjectDataService implementation="org.jetbrains.kotlin.idea.configuration.klib.KotlinNativeLibraryDataService"/>
|
||||||
<externalSystemTaskNotificationListener implementation="org.jetbrains.kotlin.idea.scripting.gradle.GradleScriptDefinitionsUpdater"/>
|
<externalSystemTaskNotificationListener implementation="org.jetbrains.kotlin.idea.scripting.gradle.GradleScriptDefinitionsUpdater"/>
|
||||||
<editorNotificationProvider implementation="org.jetbrains.kotlin.idea.scripting.gradle.GradleScriptOutOfSourceNotificationProvider"/>
|
<editorNotificationProvider implementation="org.jetbrains.kotlin.idea.scripting.gradle.GradleScriptOutOfSourceNotificationProvider"/>
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
<externalProjectDataService implementation="org.jetbrains.kotlin.idea.configuration.KotlinGradleLibraryDataService"/>
|
<externalProjectDataService implementation="org.jetbrains.kotlin.idea.configuration.KotlinGradleLibraryDataService"/>
|
||||||
<externalProjectDataService implementation="org.jetbrains.kotlin.idea.configuration.KotlinTargetDataService"/>
|
<externalProjectDataService implementation="org.jetbrains.kotlin.idea.configuration.KotlinTargetDataService"/>
|
||||||
<externalProjectDataService implementation="org.jetbrains.kotlin.idea.KotlinJavaMPPSourceSetDataService"/>
|
<externalProjectDataService implementation="org.jetbrains.kotlin.idea.KotlinJavaMPPSourceSetDataService"/>
|
||||||
<externalProjectDataService implementation="org.jetbrains.kotlin.idea.configuration.KotlinNativeLibraryDataService"/>
|
<externalProjectDataService implementation="org.jetbrains.kotlin.idea.configuration.klib.KotlinNativeLibraryDataService"/>
|
||||||
<externalSystemTaskNotificationListener implementation="org.jetbrains.kotlin.idea.scripting.gradle.GradleScriptDefinitionsUpdater"/>
|
<externalSystemTaskNotificationListener implementation="org.jetbrains.kotlin.idea.scripting.gradle.GradleScriptDefinitionsUpdater"/>
|
||||||
<editorNotificationProvider implementation="org.jetbrains.kotlin.idea.scripting.gradle.GradleScriptOutOfSourceNotificationProvider"/>
|
<editorNotificationProvider implementation="org.jetbrains.kotlin.idea.scripting.gradle.GradleScriptOutOfSourceNotificationProvider"/>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user