Re-structure KotlinMPPGradleProjectResolver.populateModuleDependencies
This commit is contained in:
+60
-325
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.idea.configuration
|
|||||||
|
|
||||||
import com.google.common.graph.GraphBuilder
|
import com.google.common.graph.GraphBuilder
|
||||||
import com.google.common.graph.Graphs
|
import com.google.common.graph.Graphs
|
||||||
|
import com.intellij.build.events.MessageEvent
|
||||||
import com.intellij.ide.plugins.PluginManager
|
import com.intellij.ide.plugins.PluginManager
|
||||||
import com.intellij.openapi.extensions.PluginId
|
import com.intellij.openapi.extensions.PluginId
|
||||||
import com.intellij.openapi.externalSystem.model.DataNode
|
import com.intellij.openapi.externalSystem.model.DataNode
|
||||||
@@ -39,10 +40,17 @@ import org.jetbrains.kotlin.config.ExternalSystemRunTask
|
|||||||
import org.jetbrains.kotlin.config.ExternalSystemTestRunTask
|
import org.jetbrains.kotlin.config.ExternalSystemTestRunTask
|
||||||
import org.jetbrains.kotlin.config.LanguageFeature
|
import org.jetbrains.kotlin.config.LanguageFeature
|
||||||
import org.jetbrains.kotlin.gradle.*
|
import org.jetbrains.kotlin.gradle.*
|
||||||
|
import org.jetbrains.kotlin.idea.PlatformVersion
|
||||||
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.klib.KotlinNativeLibrariesDependencySubstitutor
|
import org.jetbrains.kotlin.idea.configuration.klib.KotlinNativeLibrariesDependencySubstitutor
|
||||||
import org.jetbrains.kotlin.idea.configuration.klib.KotlinNativeLibrariesFixer
|
import org.jetbrains.kotlin.idea.configuration.klib.KotlinNativeLibrariesFixer
|
||||||
import org.jetbrains.kotlin.idea.configuration.klib.KotlinNativeLibraryNameUtil.KOTLIN_NATIVE_LIBRARY_PREFIX_PLUS_SPACE
|
import org.jetbrains.kotlin.idea.configuration.klib.KotlinNativeLibraryNameUtil.KOTLIN_NATIVE_LIBRARY_PREFIX_PLUS_SPACE
|
||||||
|
import org.jetbrains.kotlin.idea.configuration.mpp.createPopulateModuleDependenciesContext
|
||||||
|
import org.jetbrains.kotlin.idea.configuration.mpp.getCompilations
|
||||||
|
import org.jetbrains.kotlin.idea.configuration.mpp.populateModuleDependenciesByCompilations
|
||||||
|
import org.jetbrains.kotlin.idea.configuration.mpp.populateModuleDependenciesBySourceSetVisibilityGraph
|
||||||
|
import org.jetbrains.kotlin.idea.configuration.utils.UnsafeTestSourceSetHeuristicApi
|
||||||
|
import org.jetbrains.kotlin.idea.configuration.utils.predictedProductionSourceSetName
|
||||||
import org.jetbrains.kotlin.idea.platform.IdePlatformKindTooling
|
import org.jetbrains.kotlin.idea.platform.IdePlatformKindTooling
|
||||||
import org.jetbrains.kotlin.idea.util.NotNullableCopyableDataNodeUserDataProperty
|
import org.jetbrains.kotlin.idea.util.NotNullableCopyableDataNodeUserDataProperty
|
||||||
import org.jetbrains.kotlin.util.removeSuffixIfPresent
|
import org.jetbrains.kotlin.util.removeSuffixIfPresent
|
||||||
@@ -94,7 +102,7 @@ open class KotlinMPPGradleProjectResolver : AbstractProjectResolverExtensionComp
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun populateModuleContentRoots(gradleModule: IdeaModule, ideModule: DataNode<ModuleData>) {
|
override fun populateModuleContentRoots(gradleModule: IdeaModule, ideModule: DataNode<ModuleData>) {
|
||||||
val mppModel = resolverCtx.getExtraProject(gradleModule, KotlinMPPGradleModel::class.java)
|
val mppModel = resolverCtx.getMppModel(gradleModule)
|
||||||
if (mppModel == null) {
|
if (mppModel == null) {
|
||||||
return super.populateModuleContentRoots(gradleModule, ideModule)
|
return super.populateModuleContentRoots(gradleModule, ideModule)
|
||||||
} else {
|
} else {
|
||||||
@@ -117,7 +125,9 @@ open class KotlinMPPGradleProjectResolver : AbstractProjectResolverExtensionComp
|
|||||||
val projectDataNode = ideModule.getDataNode(ProjectKeys.PROJECT)!!
|
val projectDataNode = ideModule.getDataNode(ProjectKeys.PROJECT)!!
|
||||||
val moduleOutputsMap = projectDataNode.getUserData(MODULES_OUTPUTS)!!
|
val moduleOutputsMap = projectDataNode.getUserData(MODULES_OUTPUTS)!!
|
||||||
val outputDirs = HashSet<String>()
|
val outputDirs = HashSet<String>()
|
||||||
processCompilations(gradleModule, mppModel, ideModule, resolverCtx) { dataNode, compilation ->
|
getCompilations(gradleModule, mppModel, ideModule, resolverCtx)
|
||||||
|
.filterNot { (_, compilation) -> delegateToAndroidPlugin(compilation) }
|
||||||
|
.forEach { (dataNode, compilation) ->
|
||||||
var gradleOutputMap = dataNode.getUserData(GradleProjectResolver.GRADLE_OUTPUTS)
|
var gradleOutputMap = dataNode.getUserData(GradleProjectResolver.GRADLE_OUTPUTS)
|
||||||
if (gradleOutputMap == null) {
|
if (gradleOutputMap == null) {
|
||||||
gradleOutputMap = MultiMap.create()
|
gradleOutputMap = MultiMap.create()
|
||||||
@@ -228,7 +238,7 @@ open class KotlinMPPGradleProjectResolver : AbstractProjectResolverExtensionComp
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun Collection<ExternalDependency>.modifyDependenciesOnMppModules(
|
internal fun Collection<ExternalDependency>.modifyDependenciesOnMppModules(
|
||||||
ideProject: DataNode<ProjectData>,
|
ideProject: DataNode<ProjectData>,
|
||||||
resolverCtx: ProjectResolverContext
|
resolverCtx: ProjectResolverContext
|
||||||
) {
|
) {
|
||||||
@@ -289,8 +299,8 @@ open class KotlinMPPGradleProjectResolver : AbstractProjectResolverExtensionComp
|
|||||||
val path = toCanonicalPath(target.jar!!.archiveFile!!.absolutePath)
|
val path = toCanonicalPath(target.jar!!.archiveFile!!.absolutePath)
|
||||||
val currentModules = userData[path] ?: ArrayList<String>().apply { userData[path] = this }
|
val currentModules = userData[path] ?: ArrayList<String>().apply { userData[path] = this }
|
||||||
// Test modules should not be added. Otherwise we could get dependnecy of java.mail on jvmTest
|
// Test modules should not be added. Otherwise we could get dependnecy of java.mail on jvmTest
|
||||||
val allSourceSets = target.compilations.filter { !it.isTestModule }.flatMap { it.allSourceSets }.toSet()
|
val allSourceSets = target.compilations.filter { !it.isTestModule }.flatMap { it.declaredSourceSets }.toSet()
|
||||||
val availableViaDependsOn = allSourceSets.flatMap { it.dependsOnSourceSets }.mapNotNull { mppModel.sourceSets[it] }
|
val availableViaDependsOn = allSourceSets.flatMap { it.allDependsOnSourceSets }.mapNotNull { mppModel.sourceSetsByName[it] }
|
||||||
allSourceSets.union(availableViaDependsOn).forEach { sourceSet ->
|
allSourceSets.union(availableViaDependsOn).forEach { sourceSet ->
|
||||||
currentModules.add(getKotlinModuleId(gradleModule, sourceSet, resolverCtx))
|
currentModules.add(getKotlinModuleId(gradleModule, sourceSet, resolverCtx))
|
||||||
}
|
}
|
||||||
@@ -362,7 +372,7 @@ open class KotlinMPPGradleProjectResolver : AbstractProjectResolverExtensionComp
|
|||||||
resolverCtx
|
resolverCtx
|
||||||
) ?: continue
|
) ?: continue
|
||||||
kotlinSourceSet.externalSystemRunTasks =
|
kotlinSourceSet.externalSystemRunTasks =
|
||||||
compilation.allSourceSets.firstNotNullResult { sourceSetToRunTasks[it] } ?: emptyList()
|
compilation.declaredSourceSets.firstNotNullResult { sourceSetToRunTasks[it] } ?: emptyList()
|
||||||
|
|
||||||
if (compilation.platform == KotlinPlatform.JVM || compilation.platform == KotlinPlatform.ANDROID) {
|
if (compilation.platform == KotlinPlatform.JVM || compilation.platform == KotlinPlatform.ANDROID) {
|
||||||
compilationData.targetCompatibility = (kotlinSourceSet.compilerArguments as? K2JVMCompilerArguments)?.jvmTarget
|
compilationData.targetCompatibility = (kotlinSourceSet.compilerArguments as? K2JVMCompilerArguments)?.jvmTarget
|
||||||
@@ -374,9 +384,9 @@ open class KotlinMPPGradleProjectResolver : AbstractProjectResolverExtensionComp
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (sourceSet in compilation.allSourceSets) {
|
for (sourceSet in compilation.declaredSourceSets) {
|
||||||
sourceSetToCompilationData.getOrPut(sourceSet.name) { LinkedHashSet() } += compilationData
|
sourceSetToCompilationData.getOrPut(sourceSet.name) { LinkedHashSet() } += compilationData
|
||||||
for (dependentSourceSetName in sourceSet.dependsOnSourceSets) {
|
for (dependentSourceSetName in sourceSet.allDependsOnSourceSets) {
|
||||||
sourceSetToCompilationData.getOrPut(dependentSourceSetName) { LinkedHashSet() } += compilationData
|
sourceSetToCompilationData.getOrPut(dependentSourceSetName) { LinkedHashSet() } += compilationData
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -394,9 +404,9 @@ open class KotlinMPPGradleProjectResolver : AbstractProjectResolverExtensionComp
|
|||||||
}
|
}
|
||||||
|
|
||||||
val ignoreCommonSourceSets by lazy { externalProject.notImportedCommonSourceSets() }
|
val ignoreCommonSourceSets by lazy { externalProject.notImportedCommonSourceSets() }
|
||||||
for (sourceSet in mppModel.sourceSets.values) {
|
for (sourceSet in mppModel.sourceSetsByName.values) {
|
||||||
if (delegateToAndroidPlugin(sourceSet)) continue
|
if (delegateToAndroidPlugin(sourceSet)) continue
|
||||||
if (sourceSet.actualPlatforms.supports(KotlinPlatform.COMMON) && ignoreCommonSourceSets) continue
|
if (sourceSet.actualPlatforms.platforms.singleOrNull() == KotlinPlatform.COMMON && ignoreCommonSourceSets) continue
|
||||||
val moduleId = getKotlinModuleId(gradleModule, sourceSet, resolverCtx)
|
val moduleId = getKotlinModuleId(gradleModule, sourceSet, resolverCtx)
|
||||||
val existingSourceSetDataNode = sourceSetMap[moduleId]?.first
|
val existingSourceSetDataNode = sourceSetMap[moduleId]?.first
|
||||||
if (existingSourceSetDataNode?.kotlinSourceSet != null) continue
|
if (existingSourceSetDataNode?.kotlinSourceSet != null) continue
|
||||||
@@ -410,15 +420,14 @@ open class KotlinMPPGradleProjectResolver : AbstractProjectResolverExtensionComp
|
|||||||
it.group = externalProject.group
|
it.group = externalProject.group
|
||||||
it.version = externalProject.version
|
it.version = externalProject.version
|
||||||
|
|
||||||
val name = sourceSet.name
|
if (sourceSet.isTestModule) {
|
||||||
val baseName = name.removeSuffix("Test")
|
|
||||||
if (baseName != name) {
|
|
||||||
it.productionModuleId = getInternalModuleName(
|
it.productionModuleId = getInternalModuleName(
|
||||||
gradleModule,
|
gradleModule,
|
||||||
externalProject,
|
externalProject,
|
||||||
sourceSet,
|
sourceSet,
|
||||||
resolverCtx,
|
resolverCtx,
|
||||||
baseName + "Main"
|
@OptIn(UnsafeTestSourceSetHeuristicApi::class)
|
||||||
|
predictedProductionSourceSetName(sourceSet.name)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -430,7 +439,7 @@ open class KotlinMPPGradleProjectResolver : AbstractProjectResolverExtensionComp
|
|||||||
.mapNotNull { compilationData -> compilationData.targetCompatibility }
|
.mapNotNull { compilationData -> compilationData.targetCompatibility }
|
||||||
.minWithOrNull(VersionComparatorUtil.COMPARATOR)
|
.minWithOrNull(VersionComparatorUtil.COMPARATOR)
|
||||||
|
|
||||||
if (sourceSet.actualPlatforms.getSinglePlatform() == KotlinPlatform.NATIVE) {
|
if (sourceSet.actualPlatforms.singleOrNull() == KotlinPlatform.NATIVE) {
|
||||||
it.konanTargets = compilationDataRecords
|
it.konanTargets = compilationDataRecords
|
||||||
.flatMap { compilationData -> compilationData.konanTargets }
|
.flatMap { compilationData -> compilationData.konanTargets }
|
||||||
.toSet()
|
.toSet()
|
||||||
@@ -438,7 +447,7 @@ open class KotlinMPPGradleProjectResolver : AbstractProjectResolverExtensionComp
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val kotlinSourceSet = createSourceSetInfo(sourceSet, gradleModule, resolverCtx) ?: continue
|
val kotlinSourceSet = createSourceSetInfo(mppModel, sourceSet, gradleModule, resolverCtx) ?: continue
|
||||||
kotlinSourceSet.externalSystemRunTasks = sourceSetToRunTasks[sourceSet] ?: emptyList()
|
kotlinSourceSet.externalSystemRunTasks = sourceSetToRunTasks[sourceSet] ?: emptyList()
|
||||||
|
|
||||||
val sourceSetDataNode =
|
val sourceSetDataNode =
|
||||||
@@ -495,15 +504,15 @@ open class KotlinMPPGradleProjectResolver : AbstractProjectResolverExtensionComp
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
val allRunTasks = testRunTasks + nativeMainRunTasks
|
val allRunTasks = testRunTasks + nativeMainRunTasks
|
||||||
compilation.allSourceSets.forEach { sourceSet ->
|
compilation.declaredSourceSets.forEach { sourceSet ->
|
||||||
sourceSetToRunTasks.getOrPut(sourceSet) { LinkedHashSet() } += allRunTasks
|
sourceSetToRunTasks.getOrPut(sourceSet) { LinkedHashSet() } += allRunTasks
|
||||||
sourceSet.dependsOnSourceSets.forEach { dependentModule ->
|
mppModel.resolveAllDependsOnSourceSets(sourceSet).forEach { dependentModule ->
|
||||||
dependsOnReverseGraph.getOrPut(dependentModule) { LinkedHashSet() } += sourceSet
|
dependsOnReverseGraph.getOrPut(dependentModule.name) { LinkedHashSet() } += sourceSet
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mppModel.sourceSets.forEach { (sourceSetName, sourceSet) ->
|
mppModel.sourceSetsByName.forEach { (sourceSetName, sourceSet) ->
|
||||||
dependsOnReverseGraph[sourceSetName]?.forEach { dependingSourceSet ->
|
dependsOnReverseGraph[sourceSetName]?.forEach { dependingSourceSet ->
|
||||||
sourceSetToRunTasks.getOrPut(sourceSet) { LinkedHashSet() } += sourceSetToRunTasks[dependingSourceSet] ?: emptyList()
|
sourceSetToRunTasks.getOrPut(sourceSet) { LinkedHashSet() } += sourceSetToRunTasks[dependingSourceSet] ?: emptyList()
|
||||||
}
|
}
|
||||||
@@ -519,7 +528,7 @@ open class KotlinMPPGradleProjectResolver : AbstractProjectResolverExtensionComp
|
|||||||
val mppModel = resolverCtx.getMppModel(gradleModule) ?: return
|
val mppModel = resolverCtx.getMppModel(gradleModule) ?: return
|
||||||
val sourceSetToPackagePrefix = mppModel.targets.flatMap { it.compilations }
|
val sourceSetToPackagePrefix = mppModel.targets.flatMap { it.compilations }
|
||||||
.flatMap { compilation ->
|
.flatMap { compilation ->
|
||||||
compilation.allSourceSets.map { sourceSet -> sourceSet.name to compilation.kotlinTaskProperties.packagePrefix }
|
compilation.declaredSourceSets.map { sourceSet -> sourceSet.name to compilation.kotlinTaskProperties.packagePrefix }
|
||||||
}
|
}
|
||||||
.toMap()
|
.toMap()
|
||||||
if (resolverCtx.getExtraProject(gradleModule, ExternalProject::class.java) == null) return
|
if (resolverCtx.getExtraProject(gradleModule, ExternalProject::class.java) == null) return
|
||||||
@@ -563,7 +572,7 @@ open class KotlinMPPGradleProjectResolver : AbstractProjectResolverExtensionComp
|
|||||||
mppModelPureKotlinSourceFolders + ideModule.pureKotlinSourceFolders
|
mppModelPureKotlinSourceFolders + ideModule.pureKotlinSourceFolders
|
||||||
}
|
}
|
||||||
|
|
||||||
private data class CompilationWithDependencies(
|
internal data class CompilationWithDependencies(
|
||||||
val compilation: KotlinCompilation,
|
val compilation: KotlinCompilation,
|
||||||
val substitutedDependencies: List<ExternalDependency>
|
val substitutedDependencies: List<ExternalDependency>
|
||||||
) {
|
) {
|
||||||
@@ -581,275 +590,17 @@ open class KotlinMPPGradleProjectResolver : AbstractProjectResolverExtensionComp
|
|||||||
ideModule: DataNode<ModuleData>,
|
ideModule: DataNode<ModuleData>,
|
||||||
resolverCtx: ProjectResolverContext
|
resolverCtx: ProjectResolverContext
|
||||||
) {
|
) {
|
||||||
val mppModel = resolverCtx.getMppModel(gradleModule) ?: return
|
val context = createPopulateModuleDependenciesContext(
|
||||||
mppModel.dependencyMap.values.modifyDependenciesOnMppModules(ideProject, resolverCtx)
|
gradleModule = gradleModule,
|
||||||
val sourceSetMap = ideProject.getUserData(GradleProjectResolver.RESOLVED_SOURCE_SETS) ?: return
|
ideProject = ideProject,
|
||||||
val artifactsMap = ideProject.getUserData(CONFIGURATION_ARTIFACTS) ?: return
|
ideModule = ideModule,
|
||||||
val substitutor = KotlinNativeLibrariesDependencySubstitutor(mppModel, gradleModule, resolverCtx)
|
resolverCtx = resolverCtx
|
||||||
val sourceSetToCompilations = mutableMapOf<String, MutableList<CompilationWithDependencies>>()
|
) ?: return
|
||||||
val processedModuleIds = HashSet<String>()
|
populateModuleDependenciesByCompilations(context)
|
||||||
processCompilations(gradleModule, mppModel, ideModule, resolverCtx) { dataNode, compilation ->
|
populateModuleDependenciesBySourceSetVisibilityGraph(context)
|
||||||
if (processedModuleIds.add(getKotlinModuleId(gradleModule, compilation, resolverCtx))) {
|
|
||||||
val substitutedDependencies =
|
|
||||||
substitutor.substituteDependencies(compilation.dependencies.mapNotNull { mppModel.dependencyMap[it] })
|
|
||||||
buildDependencies(
|
|
||||||
resolverCtx,
|
|
||||||
sourceSetMap,
|
|
||||||
artifactsMap,
|
|
||||||
dataNode,
|
|
||||||
preprocessDependencies(substitutedDependencies),
|
|
||||||
ideProject
|
|
||||||
)
|
|
||||||
KotlinNativeLibrariesFixer.applyTo(dataNode, ideProject)
|
|
||||||
for (sourceSet in compilation.allSourceSets) {
|
|
||||||
(sourceSet.dependsOnSourceSets + sourceSet.name).forEach {
|
|
||||||
sourceSetToCompilations
|
|
||||||
.getOrPut(it) { mutableListOf() }
|
|
||||||
.add(CompilationWithDependencies(compilation, substitutedDependencies))
|
|
||||||
}
|
|
||||||
if (sourceSet.fullName() == compilation.fullName()) continue
|
|
||||||
val targetDataNode = getSiblingKotlinModuleData(sourceSet, gradleModule, ideModule, resolverCtx) ?: continue
|
|
||||||
addDependency(dataNode, targetDataNode, sourceSet.isTestModule)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
val sourceSetGraph = GraphBuilder.directed().build<KotlinSourceSet>()
|
|
||||||
processSourceSets(gradleModule, mppModel, ideModule, resolverCtx) { dataNode, sourceSet ->
|
|
||||||
sourceSetGraph.addNode(sourceSet)
|
|
||||||
val productionSourceSet = dataNode
|
|
||||||
?.data
|
|
||||||
?.productionModuleId
|
|
||||||
?.let { ideModule.findChildModuleByInternalName(it) }
|
|
||||||
?.kotlinSourceSet
|
|
||||||
?.kotlinModule
|
|
||||||
?.toSourceSet(mppModel)
|
|
||||||
if (productionSourceSet != null) {
|
|
||||||
sourceSetGraph.putEdge(sourceSet, productionSourceSet)
|
|
||||||
}
|
|
||||||
for (targetSourceSetName in sourceSet.dependsOnSourceSets) {
|
|
||||||
val targetSourceSet = mppModel.sourceSets[targetSourceSetName] ?: continue
|
|
||||||
sourceSetGraph.putEdge(sourceSet, targetSourceSet)
|
|
||||||
}
|
|
||||||
// Workaround: Non-android source sets have commonMain/commonTest in their dependsOn
|
|
||||||
// Remove when the same is implemented for Android modules as well
|
|
||||||
if (sourceSet.actualPlatforms.supports(KotlinPlatform.ANDROID)) {
|
|
||||||
val commonSourceSetName = if (sourceSet.isTestModule) {
|
|
||||||
KotlinSourceSet.COMMON_TEST_SOURCE_SET_NAME
|
|
||||||
} else {
|
|
||||||
KotlinSourceSet.COMMON_MAIN_SOURCE_SET_NAME
|
|
||||||
}
|
|
||||||
val commonSourceSet = mppModel.sourceSets[commonSourceSetName]
|
|
||||||
if (commonSourceSet != null && commonSourceSet != sourceSet) {
|
|
||||||
sourceSetGraph.putEdge(sourceSet, commonSourceSet)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
val closedSourceSetGraph = Graphs.transitiveClosure(sourceSetGraph)
|
|
||||||
for (sourceSet in closedSourceSetGraph.nodes()) {
|
|
||||||
val isAndroid = delegateToAndroidPlugin(sourceSet)
|
|
||||||
val fromDataNode = if (isAndroid) {
|
|
||||||
ideModule
|
|
||||||
} else {
|
|
||||||
getSiblingKotlinModuleData(sourceSet, gradleModule, ideModule, resolverCtx)
|
|
||||||
} ?: continue
|
|
||||||
val dependeeSourceSets = closedSourceSetGraph.successors(sourceSet)
|
|
||||||
val sourceSetInfos = if (isAndroid) {
|
|
||||||
ideModule.kotlinAndroidSourceSets?.filter {
|
|
||||||
(it.kotlinModule as? KotlinCompilation)?.allSourceSets?.contains(sourceSet) ?: false
|
|
||||||
} ?: emptyList()
|
|
||||||
} else {
|
|
||||||
listOfNotNull(fromDataNode.kotlinSourceSet)
|
|
||||||
}
|
|
||||||
for (sourceSetInfo in sourceSetInfos) {
|
|
||||||
if (sourceSetInfo.kotlinModule is KotlinCompilation) {
|
|
||||||
val selfName = sourceSetInfo.kotlinModule.fullName()
|
|
||||||
sourceSetInfo.addSourceSets(dependeeSourceSets, selfName, gradleModule, resolverCtx)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (delegateToAndroidPlugin(sourceSet)) continue
|
|
||||||
for (dependeeSourceSet in dependeeSourceSets) {
|
|
||||||
val toDataNode = getSiblingKotlinModuleData(dependeeSourceSet, gradleModule, ideModule, resolverCtx) ?: continue
|
|
||||||
addDependency(fromDataNode, toDataNode, dependeeSourceSet.isTestModule)
|
|
||||||
}
|
|
||||||
if (processedModuleIds.add(getKotlinModuleId(gradleModule, sourceSet, resolverCtx))) {
|
|
||||||
val mergedSubstitutedDependencies = LinkedHashSet<KotlinDependency>().apply {
|
|
||||||
val forceNativeDependencyPropagation: Boolean
|
|
||||||
val excludeInheritedNativeDependencies: Boolean
|
|
||||||
if (mppModel.extraFeatures.isHMPPEnabled && sourceSet.actualPlatforms.getSinglePlatform() == KotlinPlatform.NATIVE) {
|
|
||||||
forceNativeDependencyPropagation = mppModel.extraFeatures.isNativeDependencyPropagationEnabled
|
|
||||||
excludeInheritedNativeDependencies = !forceNativeDependencyPropagation
|
|
||||||
} else {
|
|
||||||
forceNativeDependencyPropagation = false
|
|
||||||
excludeInheritedNativeDependencies = false
|
|
||||||
}
|
|
||||||
addAll(substitutor.substituteDependencies(sourceSet))
|
|
||||||
|
|
||||||
dependeeSourceSets.flatMapTo(this) { dependeeSourceSet ->
|
|
||||||
substitutor.substituteDependencies(dependeeSourceSet).run {
|
|
||||||
if (excludeInheritedNativeDependencies)
|
|
||||||
filter { !it.name.startsWith(KOTLIN_NATIVE_LIBRARY_PREFIX_PLUS_SPACE) }
|
|
||||||
else this
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (forceNativeDependencyPropagation) {
|
|
||||||
sourceSetToCompilations[sourceSet.name]?.let { compilations ->
|
|
||||||
addAll(propagatedNativeDependencies(compilations))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mppModel.extraFeatures.isHMPPEnabled) {
|
|
||||||
addAll(propagatedPlatformDependencies(mppModel, sourceSet))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
buildDependencies(
|
|
||||||
resolverCtx,
|
|
||||||
sourceSetMap,
|
|
||||||
artifactsMap,
|
|
||||||
fromDataNode,
|
|
||||||
preprocessDependencies(mergedSubstitutedDependencies),
|
|
||||||
ideProject
|
|
||||||
)
|
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
KotlinNativeLibrariesFixer.applyTo(fromDataNode as DataNode<GradleSourceSetData>, ideProject)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun KotlinNativeLibrariesDependencySubstitutor.substituteDependencies(kotlinModule: KotlinModule): List<ExternalDependency> =
|
internal fun getSiblingKotlinModuleData(
|
||||||
substituteDependencies(kotlinModule.dependencies.mapNotNull { mppModel.dependencyMap[it] })
|
|
||||||
|
|
||||||
// We can't really commonize native platform libraries yet.
|
|
||||||
// But APIs for different targets may be very similar.
|
|
||||||
// E.g. ios_arm64 and ios_x64 have almost identical platform libraries.
|
|
||||||
// We handle these special cases and resolve common sources for such
|
|
||||||
// targets against libraries of one of them. E.g. common sources for
|
|
||||||
// ios_x64 and ios_arm64 will be resolved against ios_arm64 libraries.
|
|
||||||
//
|
|
||||||
// Currently such special casing is available for Apple platforms
|
|
||||||
// (iOS, watchOS and tvOS) and native Android (ARM, X86).
|
|
||||||
// TODO: Do we need to support user's interop libraries too?
|
|
||||||
private fun propagatedNativeDependencies(compilations: List<CompilationWithDependencies>): List<ExternalDependency> {
|
|
||||||
if (compilations.size <= 1) {
|
|
||||||
return emptyList()
|
|
||||||
}
|
|
||||||
|
|
||||||
val copyFrom = when {
|
|
||||||
compilations.all { it.isAppleCompilation } ->
|
|
||||||
compilations.selectFirstAvailableTarget(
|
|
||||||
"watchos_arm64", "watchos_arm32", "watchos_x64", "watchos_x86",
|
|
||||||
"ios_arm64", "ios_arm32", "ios_x64",
|
|
||||||
"tvos_arm64", "tvos_x64"
|
|
||||||
)
|
|
||||||
compilations.all { it.konanTarget?.startsWith("android") == true } ->
|
|
||||||
compilations.selectFirstAvailableTarget(
|
|
||||||
"android_arm64", "android_arm32", "android_x64", "android_x86"
|
|
||||||
)
|
|
||||||
else -> return emptyList()
|
|
||||||
}
|
|
||||||
|
|
||||||
return copyFrom.dependencyNames.mapNotNull { (name, dependency) ->
|
|
||||||
when {
|
|
||||||
!name.startsWith(KOTLIN_NATIVE_LIBRARY_PREFIX_PLUS_SPACE) -> null // Support only default platform libs for now.
|
|
||||||
compilations.all { it.dependencyNames.containsKey(name) } -> dependency
|
|
||||||
else -> null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Source sets sharing code between JVM and Android are the only intermediate source sets that
|
|
||||||
* can effectively consume a dependency's platform artifact.
|
|
||||||
* When a library only offers a JVM variant, then Android and JVM consume this variant of the library.
|
|
||||||
*
|
|
||||||
* This will be replaced later on by [KT-43450](https://youtrack.jetbrains.com/issue/KT-43450)
|
|
||||||
*
|
|
||||||
* @return all dependencies being present across given JVM and Android compilations that this [sourceSet] can also participates in.
|
|
||||||
*/
|
|
||||||
private fun propagatedPlatformDependencies(
|
|
||||||
mppModel: KotlinMPPGradleModel,
|
|
||||||
sourceSet: KotlinSourceSet,
|
|
||||||
): Set<ExternalDependency> {
|
|
||||||
if (
|
|
||||||
sourceSet.actualPlatforms.platforms.sorted() == listOf(KotlinPlatform.JVM, KotlinPlatform.ANDROID).sorted()
|
|
||||||
) {
|
|
||||||
return mppModel.targets
|
|
||||||
.filter { target -> target.platform == KotlinPlatform.JVM || target.platform == KotlinPlatform.ANDROID }
|
|
||||||
.flatMap { target -> target.compilations }
|
|
||||||
.filter { compilation -> compilation.dependsOnSourceSet(mppModel, sourceSet) }
|
|
||||||
.map { targetCompilations -> targetCompilations.dependencies.mapNotNull(mppModel.dependencyMap::get).toSet() }
|
|
||||||
.reduceOrNull { acc, dependencies -> acc.intersect(dependencies) }.orEmpty()
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return emptySet()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun KotlinCompilation.dependsOnSourceSet(mppModel: KotlinMPPGradleModel, sourceSet: KotlinSourceSet): Boolean {
|
|
||||||
return allSourceSets.any { containedSourceSet -> sourceSet.isOrDependsOnSourceSet(mppModel, containedSourceSet) }
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun KotlinSourceSet.isOrDependsOnSourceSet(mppModel: KotlinMPPGradleModel, sourceSet: KotlinSourceSet): Boolean {
|
|
||||||
if (this == sourceSet) return true
|
|
||||||
return this.dependsOnSourceSets
|
|
||||||
.map { dependencySourceSetName -> mppModel.sourceSets.getValue(dependencySourceSetName) }
|
|
||||||
.any { dependencySourceSet -> dependencySourceSet.isOrDependsOnSourceSet(mppModel, sourceSet) }
|
|
||||||
}
|
|
||||||
|
|
||||||
private val CompilationWithDependencies.isAppleCompilation: Boolean
|
|
||||||
get() = konanTarget?.let {
|
|
||||||
it.startsWith("ios") || it.startsWith("watchos") || it.startsWith("tvos")
|
|
||||||
} ?: false
|
|
||||||
|
|
||||||
private fun Iterable<CompilationWithDependencies>.selectFirstAvailableTarget(@NonNls vararg targetsByPriority: String): CompilationWithDependencies {
|
|
||||||
for (target in targetsByPriority) {
|
|
||||||
val result = firstOrNull { it.konanTarget == target }
|
|
||||||
if (result != null) {
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return first()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun KotlinModule.toSourceSet(mppModel: KotlinMPPGradleModel) = when (this) {
|
|
||||||
is KotlinSourceSet -> this
|
|
||||||
is KotlinCompilation -> mppModel.sourceSets[fullName()]
|
|
||||||
else -> null
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun preprocessDependencies(dependencies: Collection<KotlinDependency>): List<ExternalDependency> {
|
|
||||||
return dependencies
|
|
||||||
.groupBy { it.id }
|
|
||||||
.mapValues { it.value.firstOrNull { it.scope == "COMPILE" } ?: it.value.lastOrNull() }
|
|
||||||
.values
|
|
||||||
.filterNotNull()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun addDependency(fromModule: DataNode<*>, toModule: DataNode<*>, dependOnTestModule: Boolean) {
|
|
||||||
if (fromModule.data == toModule.data) return
|
|
||||||
val fromData = fromModule.data as? ModuleData ?: return
|
|
||||||
val toData = toModule.data as? ModuleData ?: return
|
|
||||||
val existing = fromModule.children.mapNotNull { it.data as? ModuleDependencyData }
|
|
||||||
.filter { it.target.id == (toModule.data as? ModuleData)?.id }
|
|
||||||
val nodeToModify =
|
|
||||||
existing.singleOrNull() ?: existing.firstOrNull { it.scope == DependencyScope.COMPILE } ?: existing.firstOrNull()
|
|
||||||
if (nodeToModify != null) {
|
|
||||||
nodeToModify.scope = DependencyScope.COMPILE
|
|
||||||
nodeToModify.isProductionOnTestDependency = nodeToModify.isProductionOnTestDependency || dependOnTestModule
|
|
||||||
return
|
|
||||||
}
|
|
||||||
val moduleDependencyData = ModuleDependencyData(fromData, toData).also {
|
|
||||||
it.scope = DependencyScope.COMPILE
|
|
||||||
it.isExported = false
|
|
||||||
it.isProductionOnTestDependency = dependOnTestModule
|
|
||||||
}
|
|
||||||
fromModule.createChild(ProjectKeys.MODULE_DEPENDENCY, moduleDependencyData)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getSiblingKotlinModuleData(
|
|
||||||
kotlinModule: KotlinModule,
|
kotlinModule: KotlinModule,
|
||||||
gradleModule: IdeaModule,
|
gradleModule: IdeaModule,
|
||||||
ideModule: DataNode<ModuleData>,
|
ideModule: DataNode<ModuleData>,
|
||||||
@@ -885,36 +636,13 @@ open class KotlinMPPGradleProjectResolver : AbstractProjectResolverExtensionComp
|
|||||||
sourceSetsMap[dataNode.data.id] = dataNode
|
sourceSetsMap[dataNode.data.id] = dataNode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (sourceSet in mppModel.sourceSets.values) {
|
for (sourceSet in mppModel.sourceSetsByName.values) {
|
||||||
val moduleId = getKotlinModuleId(gradleModule, sourceSet, resolverCtx)
|
val moduleId = getKotlinModuleId(gradleModule, sourceSet, resolverCtx)
|
||||||
val moduleDataNode = sourceSetsMap[moduleId]
|
val moduleDataNode = sourceSetsMap[moduleId]
|
||||||
processor(moduleDataNode, sourceSet)
|
processor(moduleDataNode, sourceSet)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun processCompilations(
|
|
||||||
gradleModule: IdeaModule,
|
|
||||||
mppModel: KotlinMPPGradleModel,
|
|
||||||
ideModule: DataNode<ModuleData>,
|
|
||||||
resolverCtx: ProjectResolverContext,
|
|
||||||
processor: (DataNode<GradleSourceSetData>, KotlinCompilation) -> Unit
|
|
||||||
) {
|
|
||||||
val sourceSetsMap = HashMap<String, DataNode<GradleSourceSetData>>()
|
|
||||||
for (dataNode in ExternalSystemApiUtil.findAll(ideModule, GradleSourceSetData.KEY)) {
|
|
||||||
if (dataNode.kotlinSourceSet != null) {
|
|
||||||
sourceSetsMap[dataNode.data.id] = dataNode
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (target in mppModel.targets) {
|
|
||||||
if (delegateToAndroidPlugin(target)) continue
|
|
||||||
for (compilation in target.compilations) {
|
|
||||||
val moduleId = getKotlinModuleId(gradleModule, compilation, resolverCtx)
|
|
||||||
val moduleDataNode = sourceSetsMap[moduleId] ?: continue
|
|
||||||
processor(moduleDataNode, compilation)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private val IdeaModule.jdkNameIfAny
|
private val IdeaModule.jdkNameIfAny
|
||||||
get() = try {
|
get() = try {
|
||||||
jdkName
|
jdkName
|
||||||
@@ -988,7 +716,7 @@ open class KotlinMPPGradleProjectResolver : AbstractProjectResolverExtensionComp
|
|||||||
if (effectiveClassesDir != null) {
|
if (effectiveClassesDir != null) {
|
||||||
sourcesWithTypes += compilation.sourceType to DefaultExternalSourceDirectorySet().also { dirSet ->
|
sourcesWithTypes += compilation.sourceType to DefaultExternalSourceDirectorySet().also { dirSet ->
|
||||||
dirSet.outputDir = effectiveClassesDir
|
dirSet.outputDir = effectiveClassesDir
|
||||||
dirSet.srcDirs = compilation.allSourceSets.flatMapTo(LinkedHashSet()) { it.sourceDirs }
|
dirSet.srcDirs = compilation.declaredSourceSets.flatMapTo(LinkedHashSet()) { it.sourceDirs }
|
||||||
dirSet.gradleOutputDirs += compilation.output.classesDirs
|
dirSet.gradleOutputDirs += compilation.output.classesDirs
|
||||||
dirSet.setInheritedCompilerOutput(false)
|
dirSet.setInheritedCompilerOutput(false)
|
||||||
}
|
}
|
||||||
@@ -996,7 +724,7 @@ open class KotlinMPPGradleProjectResolver : AbstractProjectResolverExtensionComp
|
|||||||
if (resourcesDir != null) {
|
if (resourcesDir != null) {
|
||||||
sourcesWithTypes += compilation.resourceType to DefaultExternalSourceDirectorySet().also { dirSet ->
|
sourcesWithTypes += compilation.resourceType to DefaultExternalSourceDirectorySet().also { dirSet ->
|
||||||
dirSet.outputDir = resourcesDir
|
dirSet.outputDir = resourcesDir
|
||||||
dirSet.srcDirs = compilation.allSourceSets.flatMapTo(LinkedHashSet()) { it.resourceDirs }
|
dirSet.srcDirs = compilation.declaredSourceSets.flatMapTo(LinkedHashSet()) { it.resourceDirs }
|
||||||
dirSet.gradleOutputDirs += resourcesDir
|
dirSet.gradleOutputDirs += resourcesDir
|
||||||
dirSet.setInheritedCompilerOutput(false)
|
dirSet.setInheritedCompilerOutput(false)
|
||||||
}
|
}
|
||||||
@@ -1034,7 +762,9 @@ open class KotlinMPPGradleProjectResolver : AbstractProjectResolverExtensionComp
|
|||||||
private val KotlinModule.resourceType
|
private val KotlinModule.resourceType
|
||||||
get() = if (isTestModule) ExternalSystemSourceType.TEST_RESOURCE else ExternalSystemSourceType.RESOURCE
|
get() = if (isTestModule) ExternalSystemSourceType.TEST_RESOURCE else ExternalSystemSourceType.RESOURCE
|
||||||
|
|
||||||
|
@OptIn(ExperimentalGradleToolingApi::class)
|
||||||
private fun createSourceSetInfo(
|
private fun createSourceSetInfo(
|
||||||
|
mppModel: KotlinMPPGradleModel,
|
||||||
sourceSet: KotlinSourceSet,
|
sourceSet: KotlinSourceSet,
|
||||||
gradleModule: IdeaModule,
|
gradleModule: IdeaModule,
|
||||||
resolverCtx: ProjectResolverContext
|
resolverCtx: ProjectResolverContext
|
||||||
@@ -1044,13 +774,15 @@ open class KotlinMPPGradleProjectResolver : AbstractProjectResolverExtensionComp
|
|||||||
val languageSettings = sourceSet.languageSettings
|
val languageSettings = sourceSet.languageSettings
|
||||||
info.moduleId = getKotlinModuleId(gradleModule, sourceSet, resolverCtx)
|
info.moduleId = getKotlinModuleId(gradleModule, sourceSet, resolverCtx)
|
||||||
info.gradleModuleId = getModuleId(resolverCtx, gradleModule)
|
info.gradleModuleId = getModuleId(resolverCtx, gradleModule)
|
||||||
info.actualPlatforms.addSimplePlatforms(sourceSet.actualPlatforms.platforms)
|
info.actualPlatforms.pushPlatforms(sourceSet.actualPlatforms)
|
||||||
info.isTestModule = sourceSet.isTestModule
|
info.isTestModule = sourceSet.isTestModule
|
||||||
info.dependsOn = sourceSet.dependsOnSourceSets.toList().map {
|
info.dependsOn = mppModel.resolveAllDependsOnSourceSets(sourceSet).map { dependsOnSourceSet ->
|
||||||
getGradleModuleQualifiedName(resolverCtx, gradleModule, it)
|
getGradleModuleQualifiedName(resolverCtx, gradleModule, dependsOnSourceSet.name)
|
||||||
}
|
}
|
||||||
//TODO(auskov): target flours are lost here
|
//TODO(auskov): target flours are lost here
|
||||||
info.compilerArguments = createCompilerArguments(emptyList(), sourceSet.actualPlatforms.getSinglePlatform()).also {
|
info.compilerArguments = createCompilerArguments(
|
||||||
|
emptyList(), sourceSet.actualPlatforms.singleOrNull() ?: KotlinPlatform.COMMON
|
||||||
|
).also {
|
||||||
it.multiPlatform = true
|
it.multiPlatform = true
|
||||||
it.languageVersion = languageSettings.languageVersion
|
it.languageVersion = languageSettings.languageVersion
|
||||||
it.apiVersion = languageSettings.apiVersion
|
it.apiVersion = languageSettings.apiVersion
|
||||||
@@ -1086,9 +818,9 @@ open class KotlinMPPGradleProjectResolver : AbstractProjectResolverExtensionComp
|
|||||||
return KotlinSourceSetInfo(compilation).also { sourceSetInfo ->
|
return KotlinSourceSetInfo(compilation).also { sourceSetInfo ->
|
||||||
sourceSetInfo.moduleId = getKotlinModuleId(gradleModule, compilation, resolverCtx)
|
sourceSetInfo.moduleId = getKotlinModuleId(gradleModule, compilation, resolverCtx)
|
||||||
sourceSetInfo.gradleModuleId = getModuleId(resolverCtx, gradleModule)
|
sourceSetInfo.gradleModuleId = getModuleId(resolverCtx, gradleModule)
|
||||||
sourceSetInfo.actualPlatforms.addSimplePlatforms(listOf(compilation.platform))
|
sourceSetInfo.actualPlatforms.pushPlatforms(listOf(compilation.platform))
|
||||||
sourceSetInfo.isTestModule = compilation.isTestModule
|
sourceSetInfo.isTestModule = compilation.isTestModule
|
||||||
sourceSetInfo.dependsOn = compilation.allSourceSets.flatMap { it.dependsOnSourceSets }.map {
|
sourceSetInfo.dependsOn = compilation.declaredSourceSets.flatMap { it.allDependsOnSourceSets }.map {
|
||||||
getGradleModuleQualifiedName(resolverCtx, gradleModule, it)
|
getGradleModuleQualifiedName(resolverCtx, gradleModule, it)
|
||||||
}.distinct().toList()
|
}.distinct().toList()
|
||||||
sourceSetInfo.compilerArguments =
|
sourceSetInfo.compilerArguments =
|
||||||
@@ -1105,7 +837,7 @@ open class KotlinMPPGradleProjectResolver : AbstractProjectResolverExtensionComp
|
|||||||
/** Checks if our IDE doesn't support such platform */
|
/** Checks if our IDE doesn't support such platform */
|
||||||
private fun KotlinPlatform.isNotSupported() = IdePlatformKindTooling.getToolingIfAny(this) == null
|
private fun KotlinPlatform.isNotSupported() = IdePlatformKindTooling.getToolingIfAny(this) == null
|
||||||
|
|
||||||
private fun KotlinSourceSetInfo.addSourceSets(
|
internal fun KotlinSourceSetInfo.addSourceSets(
|
||||||
sourceSets: Collection<KotlinModule>,
|
sourceSets: Collection<KotlinModule>,
|
||||||
selfName: String,
|
selfName: String,
|
||||||
gradleModule: IdeaModule,
|
gradleModule: IdeaModule,
|
||||||
@@ -1131,7 +863,7 @@ open class KotlinMPPGradleProjectResolver : AbstractProjectResolverExtensionComp
|
|||||||
private fun getKotlinModuleId(gradleModule: IdeaModule, kotlinModule: KotlinModule, resolverCtx: ProjectResolverContext) =
|
private fun getKotlinModuleId(gradleModule: IdeaModule, kotlinModule: KotlinModule, resolverCtx: ProjectResolverContext) =
|
||||||
getGradleModuleQualifiedName(resolverCtx, gradleModule, kotlinModule.fullName())
|
getGradleModuleQualifiedName(resolverCtx, gradleModule, kotlinModule.fullName())
|
||||||
|
|
||||||
private fun getGradleModuleQualifiedName(
|
internal fun getGradleModuleQualifiedName(
|
||||||
resolverCtx: ProjectResolverContext,
|
resolverCtx: ProjectResolverContext,
|
||||||
gradleModule: IdeaModule,
|
gradleModule: IdeaModule,
|
||||||
simpleName: String
|
simpleName: String
|
||||||
@@ -1144,10 +876,13 @@ open class KotlinMPPGradleProjectResolver : AbstractProjectResolverExtensionComp
|
|||||||
ignoreCase = true
|
ignoreCase = true
|
||||||
) ?: false
|
) ?: false
|
||||||
|
|
||||||
private fun delegateToAndroidPlugin(kotlinTarget: KotlinTarget): Boolean =
|
internal fun delegateToAndroidPlugin(compilation: KotlinCompilation): Boolean =
|
||||||
|
androidPluginPresent && compilation.platform == KotlinPlatform.ANDROID
|
||||||
|
|
||||||
|
internal fun delegateToAndroidPlugin(kotlinTarget: KotlinTarget): Boolean =
|
||||||
androidPluginPresent && kotlinTarget.platform == KotlinPlatform.ANDROID
|
androidPluginPresent && kotlinTarget.platform == KotlinPlatform.ANDROID
|
||||||
|
|
||||||
private fun delegateToAndroidPlugin(kotlinSourceSet: KotlinSourceSet): Boolean =
|
internal fun delegateToAndroidPlugin(kotlinSourceSet: KotlinSourceSet): Boolean =
|
||||||
androidPluginPresent && kotlinSourceSet.actualPlatforms.platforms.singleOrNull() == KotlinPlatform.ANDROID
|
androidPluginPresent && kotlinSourceSet.actualPlatforms.platforms.singleOrNull() == KotlinPlatform.ANDROID
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-2
@@ -9,9 +9,11 @@ import com.intellij.openapi.diagnostic.Logger
|
|||||||
import com.intellij.openapi.roots.DependencyScope
|
import com.intellij.openapi.roots.DependencyScope
|
||||||
import com.intellij.openapi.util.Key
|
import com.intellij.openapi.util.Key
|
||||||
import org.gradle.tooling.model.idea.IdeaModule
|
import org.gradle.tooling.model.idea.IdeaModule
|
||||||
|
import org.jetbrains.kotlin.gradle.KotlinDependency
|
||||||
import org.jetbrains.kotlin.gradle.KotlinMPPGradleModel
|
import org.jetbrains.kotlin.gradle.KotlinMPPGradleModel
|
||||||
import org.jetbrains.kotlin.idea.configuration.buildClasspathData
|
import org.jetbrains.kotlin.idea.configuration.buildClasspathData
|
||||||
import org.jetbrains.kotlin.idea.configuration.klib.KotlinNativeLibraryNameUtil.buildIDELibraryName
|
import org.jetbrains.kotlin.idea.configuration.klib.KotlinNativeLibraryNameUtil.buildIDELibraryName
|
||||||
|
import org.jetbrains.kotlin.idea.configuration.mpp.KotlinDependenciesPreprocessor
|
||||||
import org.jetbrains.kotlin.idea.inspections.gradle.findKotlinPluginVersion
|
import org.jetbrains.kotlin.idea.inspections.gradle.findKotlinPluginVersion
|
||||||
import org.jetbrains.kotlin.konan.library.KONAN_STDLIB_NAME
|
import org.jetbrains.kotlin.konan.library.KONAN_STDLIB_NAME
|
||||||
import org.jetbrains.plugins.gradle.ExternalDependencyId
|
import org.jetbrains.plugins.gradle.ExternalDependencyId
|
||||||
@@ -21,10 +23,15 @@ import java.io.File
|
|||||||
|
|
||||||
// KT-29613, KT-29783
|
// KT-29613, KT-29783
|
||||||
internal class KotlinNativeLibrariesDependencySubstitutor(
|
internal class KotlinNativeLibrariesDependencySubstitutor(
|
||||||
val mppModel: KotlinMPPGradleModel,
|
private val mppModel: KotlinMPPGradleModel,
|
||||||
private val gradleModule: IdeaModule,
|
private val gradleModule: IdeaModule,
|
||||||
private val resolverCtx: ProjectResolverContext
|
private val resolverCtx: ProjectResolverContext
|
||||||
) {
|
) : KotlinDependenciesPreprocessor {
|
||||||
|
|
||||||
|
override fun invoke(dependencies: Iterable<KotlinDependency>): List<KotlinDependency> {
|
||||||
|
return substituteDependencies(dependencies.toList())
|
||||||
|
}
|
||||||
|
|
||||||
// Substitutes `ExternalDependency` entries that represent KLIBs with new dependency entries with proper type and name:
|
// 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
|
// - 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)
|
// - similarly for every `ExternalLibraryDependency` with `groupId == "Kotlin/Native"` (legacy KLIB provided by Gradle plugin <= 1.3.20)
|
||||||
|
|||||||
+21
@@ -0,0 +1,21 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2021 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.mpp
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.gradle.KotlinDependency
|
||||||
|
|
||||||
|
internal object DistinctIdKotlinDependenciesPreprocessor : KotlinDependenciesPreprocessor {
|
||||||
|
override fun invoke(dependencies: Iterable<KotlinDependency>): List<KotlinDependency> {
|
||||||
|
return dependencies
|
||||||
|
.groupBy { dependency -> dependency.id }
|
||||||
|
.mapValues { (_, dependenciesWithSameId) ->
|
||||||
|
dependenciesWithSameId.firstOrNull { it.scope == "COMPILE" } ?: dependenciesWithSameId.lastOrNull()
|
||||||
|
}
|
||||||
|
.values
|
||||||
|
.filterNotNull()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+27
@@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2021 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.mpp
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.gradle.KotlinDependency
|
||||||
|
|
||||||
|
internal interface KotlinDependenciesPreprocessor {
|
||||||
|
operator fun invoke(dependencies: Iterable<KotlinDependency>): List<KotlinDependency>
|
||||||
|
}
|
||||||
|
|
||||||
|
internal operator fun KotlinDependenciesPreprocessor.plus(
|
||||||
|
other: KotlinDependenciesPreprocessor
|
||||||
|
): KotlinDependenciesPreprocessor {
|
||||||
|
return SequentialKotlinDependenciesPreprocessor(this, other)
|
||||||
|
}
|
||||||
|
|
||||||
|
private class SequentialKotlinDependenciesPreprocessor(
|
||||||
|
private val first: KotlinDependenciesPreprocessor,
|
||||||
|
private val second: KotlinDependenciesPreprocessor
|
||||||
|
) : KotlinDependenciesPreprocessor {
|
||||||
|
override fun invoke(dependencies: Iterable<KotlinDependency>): List<KotlinDependency> {
|
||||||
|
return second(first(dependencies))
|
||||||
|
}
|
||||||
|
}
|
||||||
+86
@@ -0,0 +1,86 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2021 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.mpp
|
||||||
|
|
||||||
|
import com.intellij.openapi.externalSystem.model.DataNode
|
||||||
|
import com.intellij.openapi.externalSystem.model.project.ModuleData
|
||||||
|
import com.intellij.openapi.externalSystem.model.project.ProjectData
|
||||||
|
import org.gradle.tooling.model.idea.IdeaModule
|
||||||
|
import org.jetbrains.kotlin.gradle.*
|
||||||
|
import org.jetbrains.kotlin.idea.configuration.KotlinMPPGradleProjectResolver
|
||||||
|
import org.jetbrains.kotlin.idea.configuration.KotlinMPPGradleProjectResolver.Companion.CompilationWithDependencies
|
||||||
|
import org.jetbrains.kotlin.idea.configuration.getMppModel
|
||||||
|
import org.jetbrains.kotlin.idea.configuration.klib.KotlinNativeLibrariesDependencySubstitutor
|
||||||
|
import org.jetbrains.plugins.gradle.model.ExternalSourceSet
|
||||||
|
import org.jetbrains.plugins.gradle.model.data.GradleSourceSetData
|
||||||
|
import org.jetbrains.plugins.gradle.service.project.GradleProjectResolver
|
||||||
|
import org.jetbrains.plugins.gradle.service.project.ProjectResolverContext
|
||||||
|
import com.intellij.openapi.util.Pair as IntelliJPair
|
||||||
|
|
||||||
|
|
||||||
|
internal typealias ModuleId = String
|
||||||
|
internal typealias ArtifactPath = String
|
||||||
|
|
||||||
|
internal data class PopulateModuleDependenciesContext(
|
||||||
|
val resolverCtx: ProjectResolverContext,
|
||||||
|
val mppModel: KotlinMPPGradleModel,
|
||||||
|
val gradleModule: IdeaModule,
|
||||||
|
val ideProject: DataNode<ProjectData>,
|
||||||
|
val ideModule: DataNode<ModuleData>,
|
||||||
|
val dependenciesPreprocessor: KotlinDependenciesPreprocessor,
|
||||||
|
val sourceSetMap: Map<ModuleId, IntelliJPair<DataNode<GradleSourceSetData>, ExternalSourceSet>>,
|
||||||
|
val artifactsMap: Map<ArtifactPath, ModuleId>,
|
||||||
|
val processedModuleIds: MutableSet<ModuleId> = mutableSetOf()
|
||||||
|
)
|
||||||
|
|
||||||
|
internal fun KotlinMPPGradleProjectResolver.Companion.createPopulateModuleDependenciesContext(
|
||||||
|
gradleModule: IdeaModule,
|
||||||
|
ideProject: DataNode<ProjectData>,
|
||||||
|
ideModule: DataNode<ModuleData>,
|
||||||
|
resolverCtx: ProjectResolverContext
|
||||||
|
): PopulateModuleDependenciesContext? {
|
||||||
|
val mppModel = resolverCtx.getMppModel(gradleModule) ?: return null
|
||||||
|
mppModel.dependencyMap.values.modifyDependenciesOnMppModules(ideProject, resolverCtx)
|
||||||
|
|
||||||
|
val sourceSetMap = ideProject.getUserData(GradleProjectResolver.RESOLVED_SOURCE_SETS) ?: return null
|
||||||
|
val artifactsMap = ideProject.getUserData(GradleProjectResolver.CONFIGURATION_ARTIFACTS) ?: return null
|
||||||
|
val dependenciesPreprocessor = KotlinNativeLibrariesDependencySubstitutor(mppModel, gradleModule, resolverCtx)
|
||||||
|
.plus(DistinctIdKotlinDependenciesPreprocessor)
|
||||||
|
|
||||||
|
return PopulateModuleDependenciesContext(
|
||||||
|
resolverCtx = resolverCtx,
|
||||||
|
mppModel = mppModel,
|
||||||
|
gradleModule = gradleModule,
|
||||||
|
ideProject = ideProject,
|
||||||
|
ideModule = ideModule,
|
||||||
|
dependenciesPreprocessor = dependenciesPreprocessor,
|
||||||
|
sourceSetMap = sourceSetMap,
|
||||||
|
artifactsMap = artifactsMap,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun PopulateModuleDependenciesContext.getDependencies(module: KotlinModule): List<KotlinDependency> {
|
||||||
|
return dependenciesPreprocessor(module.dependencies.mapNotNull { id -> mppModel.dependencyMap[id] })
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun PopulateModuleDependenciesContext.getCompilationsWithDependencies(
|
||||||
|
sourceSet: KotlinSourceSet
|
||||||
|
): List<CompilationWithDependencies> {
|
||||||
|
return mppModel.getCompilations(sourceSet).map { compilation -> CompilationWithDependencies(compilation, getDependencies(compilation)) }
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun KotlinCompilation.dependsOnSourceSet(mppModel: KotlinMPPGradleModel, sourceSet: KotlinSourceSet): Boolean {
|
||||||
|
return declaredSourceSets.any { containedSourceSet -> sourceSet.isOrDependsOnSourceSet(mppModel, containedSourceSet) }
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun KotlinSourceSet.isOrDependsOnSourceSet(mppModel: KotlinMPPGradleModel, sourceSet: KotlinSourceSet): Boolean {
|
||||||
|
if (this == sourceSet) return true
|
||||||
|
return this.declaredDependsOnSourceSets
|
||||||
|
.map { dependencySourceSetName -> mppModel.sourceSetsByName.getValue(dependencySourceSetName) }
|
||||||
|
.any { dependencySourceSet -> dependencySourceSet.isOrDependsOnSourceSet(mppModel, sourceSet) }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2021 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.mpp
|
||||||
|
|
||||||
|
import com.intellij.openapi.externalSystem.model.DataNode
|
||||||
|
import com.intellij.openapi.externalSystem.model.ProjectKeys
|
||||||
|
import com.intellij.openapi.externalSystem.model.project.ModuleData
|
||||||
|
import com.intellij.openapi.externalSystem.model.project.ModuleDependencyData
|
||||||
|
import com.intellij.openapi.roots.DependencyScope
|
||||||
|
import org.jetbrains.kotlin.idea.configuration.KotlinMPPGradleProjectResolver
|
||||||
|
|
||||||
|
internal fun KotlinMPPGradleProjectResolver.Companion.addDependency(
|
||||||
|
fromModule: DataNode<*>, toModule: DataNode<*>, dependOnTestModule: Boolean
|
||||||
|
) {
|
||||||
|
if (fromModule.data == toModule.data) return
|
||||||
|
val fromData = fromModule.data as? ModuleData ?: return
|
||||||
|
val toData = toModule.data as? ModuleData ?: return
|
||||||
|
|
||||||
|
val existing = fromModule.children.mapNotNull { it.data as? ModuleDependencyData }
|
||||||
|
.filter { it.target.id == (toModule.data as? ModuleData)?.id }
|
||||||
|
|
||||||
|
val nodeToModify = existing.singleOrNull() ?: existing.firstOrNull { it.scope == DependencyScope.COMPILE } ?: existing.firstOrNull()
|
||||||
|
if (nodeToModify != null) {
|
||||||
|
nodeToModify.scope = DependencyScope.COMPILE
|
||||||
|
nodeToModify.isProductionOnTestDependency = nodeToModify.isProductionOnTestDependency || dependOnTestModule
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val moduleDependencyData = ModuleDependencyData(fromData, toData).also {
|
||||||
|
it.scope = DependencyScope.COMPILE
|
||||||
|
it.isExported = false
|
||||||
|
it.isProductionOnTestDependency = dependOnTestModule
|
||||||
|
}
|
||||||
|
|
||||||
|
fromModule.createChild(ProjectKeys.MODULE_DEPENDENCY, moduleDependencyData)
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2021 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.mpp
|
||||||
|
|
||||||
|
import com.intellij.openapi.externalSystem.model.DataNode
|
||||||
|
import com.intellij.openapi.externalSystem.model.project.ProjectData
|
||||||
|
import com.intellij.openapi.util.Pair
|
||||||
|
import org.jetbrains.kotlin.gradle.KotlinDependency
|
||||||
|
import org.jetbrains.kotlin.idea.configuration.KotlinMPPGradleProjectResolver
|
||||||
|
import org.jetbrains.kotlin.idea.configuration.klib.KotlinNativeLibrariesFixer
|
||||||
|
import org.jetbrains.plugins.gradle.model.ExternalSourceSet
|
||||||
|
import org.jetbrains.plugins.gradle.model.data.GradleSourceSetData
|
||||||
|
import org.jetbrains.plugins.gradle.service.project.GradleProjectResolverUtil
|
||||||
|
import org.jetbrains.plugins.gradle.service.project.ProjectResolverContext
|
||||||
|
|
||||||
|
@Throws(IllegalStateException::class)
|
||||||
|
internal fun KotlinMPPGradleProjectResolver.Companion.buildDependencies(
|
||||||
|
resolverCtx: ProjectResolverContext,
|
||||||
|
sourceSetMap: Map<String, Pair<DataNode<GradleSourceSetData>, ExternalSourceSet>>,
|
||||||
|
artifactsMap: Map<ArtifactPath, ModuleId>,
|
||||||
|
ownerDataNode: DataNode<GradleSourceSetData>,
|
||||||
|
dependencies: Collection<KotlinDependency>,
|
||||||
|
ideProject: DataNode<ProjectData>
|
||||||
|
) {
|
||||||
|
GradleProjectResolverUtil.buildDependencies(
|
||||||
|
resolverCtx, sourceSetMap, artifactsMap, ownerDataNode, dependencies, ideProject
|
||||||
|
)
|
||||||
|
KotlinNativeLibrariesFixer.applyTo(ownerDataNode, ideProject)
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2021 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.mpp
|
||||||
|
|
||||||
|
import com.intellij.openapi.externalSystem.model.DataNode
|
||||||
|
import com.intellij.openapi.externalSystem.model.project.ModuleData
|
||||||
|
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil
|
||||||
|
import org.gradle.tooling.model.idea.IdeaModule
|
||||||
|
import org.jetbrains.kotlin.gradle.KotlinCompilation
|
||||||
|
import org.jetbrains.kotlin.gradle.KotlinMPPGradleModel
|
||||||
|
import org.jetbrains.kotlin.idea.configuration.KotlinMPPGradleProjectResolver
|
||||||
|
import org.jetbrains.kotlin.idea.configuration.kotlinSourceSet
|
||||||
|
import org.jetbrains.kotlin.idea.configuration.utils.getKotlinModuleId
|
||||||
|
import org.jetbrains.plugins.gradle.model.data.GradleSourceSetData
|
||||||
|
import org.jetbrains.plugins.gradle.service.project.ProjectResolverContext
|
||||||
|
|
||||||
|
internal fun KotlinMPPGradleProjectResolver.Companion.getCompilations(
|
||||||
|
gradleModule: IdeaModule,
|
||||||
|
mppModel: KotlinMPPGradleModel,
|
||||||
|
ideModule: DataNode<ModuleData>,
|
||||||
|
resolverCtx: ProjectResolverContext
|
||||||
|
): Sequence<Pair<DataNode<GradleSourceSetData>, KotlinCompilation>> {
|
||||||
|
|
||||||
|
val sourceSetsMap = HashMap<String, DataNode<GradleSourceSetData>>()
|
||||||
|
for (dataNode in ExternalSystemApiUtil.findAll(ideModule, GradleSourceSetData.KEY)) {
|
||||||
|
if (dataNode.kotlinSourceSet != null) {
|
||||||
|
sourceSetsMap[dataNode.data.id] = dataNode
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sequence {
|
||||||
|
for (target in mppModel.targets) {
|
||||||
|
for (compilation in target.compilations) {
|
||||||
|
val moduleId = getKotlinModuleId(gradleModule, compilation, resolverCtx)
|
||||||
|
val moduleDataNode = sourceSetsMap[moduleId] ?: continue
|
||||||
|
yield(moduleDataNode to compilation)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
+30
@@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2021 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.mpp
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.idea.configuration.KotlinMPPGradleProjectResolver
|
||||||
|
import org.jetbrains.kotlin.idea.configuration.utils.fullName
|
||||||
|
import org.jetbrains.kotlin.idea.configuration.utils.getKotlinModuleId
|
||||||
|
|
||||||
|
internal fun KotlinMPPGradleProjectResolver.Companion.populateModuleDependenciesByCompilations(
|
||||||
|
context: PopulateModuleDependenciesContext
|
||||||
|
): Unit = with(context) {
|
||||||
|
getCompilations(gradleModule, mppModel, ideModule, resolverCtx)
|
||||||
|
.filterNot { (_, compilation) -> delegateToAndroidPlugin(compilation) }
|
||||||
|
.filter { (_, compilation) -> processedModuleIds.add(getKotlinModuleId(gradleModule, compilation, resolverCtx)) }
|
||||||
|
.forEach { (dataNode, compilation) ->
|
||||||
|
buildDependencies(
|
||||||
|
resolverCtx, sourceSetMap, artifactsMap, dataNode, getDependencies(compilation), ideProject
|
||||||
|
)
|
||||||
|
for (sourceSet in compilation.declaredSourceSets) {
|
||||||
|
if (sourceSet.fullName() == compilation.fullName()) continue
|
||||||
|
val targetDataNode = getSiblingKotlinModuleData(sourceSet, gradleModule, ideModule, resolverCtx) ?: continue
|
||||||
|
addDependency(dataNode, targetDataNode, sourceSet.isTestModule)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
+234
@@ -0,0 +1,234 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2021 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.mpp
|
||||||
|
|
||||||
|
import com.google.common.graph.Graph
|
||||||
|
import com.intellij.openapi.externalSystem.model.DataNode
|
||||||
|
import org.jetbrains.annotations.NonNls
|
||||||
|
import org.jetbrains.kotlin.gradle.*
|
||||||
|
import org.jetbrains.kotlin.idea.configuration.KotlinMPPGradleProjectResolver
|
||||||
|
import org.jetbrains.kotlin.idea.configuration.KotlinMPPGradleProjectResolver.Companion.CompilationWithDependencies
|
||||||
|
import org.jetbrains.kotlin.idea.configuration.klib.KotlinNativeLibraryNameUtil
|
||||||
|
import org.jetbrains.kotlin.idea.configuration.kotlinAndroidSourceSets
|
||||||
|
import org.jetbrains.kotlin.idea.configuration.kotlinSourceSet
|
||||||
|
import org.jetbrains.kotlin.idea.configuration.utils.createSourceSetVisibilityGraph
|
||||||
|
import org.jetbrains.kotlin.idea.configuration.utils.fullName
|
||||||
|
import org.jetbrains.kotlin.idea.configuration.utils.getKotlinModuleId
|
||||||
|
import org.jetbrains.kotlin.idea.configuration.utils.transitiveClosure
|
||||||
|
import org.jetbrains.plugins.gradle.model.ExternalDependency
|
||||||
|
import org.jetbrains.plugins.gradle.model.data.GradleSourceSetData
|
||||||
|
|
||||||
|
internal fun KotlinMPPGradleProjectResolver.Companion.populateModuleDependenciesBySourceSetVisibilityGraph(
|
||||||
|
context: PopulateModuleDependenciesContext
|
||||||
|
): Unit = with(context) {
|
||||||
|
val sourceSetVisibilityGraph = createSourceSetVisibilityGraph(mppModel).transitiveClosure
|
||||||
|
for (sourceSet in sourceSetVisibilityGraph.nodes()) {
|
||||||
|
populateSourceSetInfos(context, sourceSetVisibilityGraph, sourceSet)
|
||||||
|
if (delegateToAndroidPlugin(sourceSet)) continue
|
||||||
|
|
||||||
|
|
||||||
|
val visibleSourceSets = sourceSetVisibilityGraph.successors(sourceSet)
|
||||||
|
val fromDataNode = getSiblingKotlinModuleData(sourceSet, gradleModule, ideModule, resolverCtx)?.cast<GradleSourceSetData>()
|
||||||
|
?: return
|
||||||
|
|
||||||
|
|
||||||
|
/* Add dependencies from current sourceSet to all visible source sets (dependsOn, test to production, ...)*/
|
||||||
|
for (visibleSourceSet in visibleSourceSets) {
|
||||||
|
val toDataNode = getSiblingKotlinModuleData(visibleSourceSet, gradleModule, ideModule, resolverCtx) ?: continue
|
||||||
|
addDependency(fromDataNode, toDataNode, visibleSourceSet.isTestModule)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!processedModuleIds.add(getKotlinModuleId(gradleModule, sourceSet, resolverCtx))) continue
|
||||||
|
val settings = dependencyPopulationSettings(mppModel, sourceSet)
|
||||||
|
val directDependencies = getDependencies(sourceSet).toSet()
|
||||||
|
val dependenciesFromVisibleSourceSets = getDependenciesFromVisibleSourceSets(settings, visibleSourceSets)
|
||||||
|
val dependenciesFromNativePropagation = getPropagatedNativeDependencies(settings, sourceSet)
|
||||||
|
val dependenciesFromPlatformPropagation = getPropagatedPlatformDependencies(sourceSet)
|
||||||
|
|
||||||
|
val dependencies = dependenciesPreprocessor(
|
||||||
|
directDependencies + dependenciesFromVisibleSourceSets +
|
||||||
|
dependenciesFromNativePropagation + dependenciesFromPlatformPropagation
|
||||||
|
)
|
||||||
|
|
||||||
|
buildDependencies(resolverCtx, sourceSetMap, artifactsMap, fromDataNode, dependencies, ideProject)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private data class DependencyPopulationSettings(
|
||||||
|
val forceNativeDependencyPropagation: Boolean,
|
||||||
|
val excludeInheritedNativeDependencies: Boolean
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun dependencyPopulationSettings(mppModel: KotlinMPPGradleModel, sourceSet: KotlinSourceSet): DependencyPopulationSettings {
|
||||||
|
val forceNativeDependencyPropagation: Boolean
|
||||||
|
val excludeInheritedNativeDependencies: Boolean
|
||||||
|
if (mppModel.extraFeatures.isHMPPEnabled && sourceSet.actualPlatforms.singleOrNull() == KotlinPlatform.NATIVE) {
|
||||||
|
forceNativeDependencyPropagation = mppModel.extraFeatures.isNativeDependencyPropagationEnabled
|
||||||
|
excludeInheritedNativeDependencies = !forceNativeDependencyPropagation
|
||||||
|
} else {
|
||||||
|
forceNativeDependencyPropagation = false
|
||||||
|
excludeInheritedNativeDependencies = false
|
||||||
|
}
|
||||||
|
return DependencyPopulationSettings(
|
||||||
|
forceNativeDependencyPropagation = forceNativeDependencyPropagation,
|
||||||
|
excludeInheritedNativeDependencies = excludeInheritedNativeDependencies
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun PopulateModuleDependenciesContext.getDependenciesFromVisibleSourceSets(
|
||||||
|
settings: DependencyPopulationSettings,
|
||||||
|
visibleSourceSets: Set<KotlinSourceSet>
|
||||||
|
): Set<KotlinDependency> {
|
||||||
|
val inheritedDependencies = visibleSourceSets
|
||||||
|
.flatMap { visibleSourceSet -> getDependencies(visibleSourceSet) }
|
||||||
|
|
||||||
|
return if (settings.excludeInheritedNativeDependencies) {
|
||||||
|
inheritedDependencies.filter { !it.name.startsWith(KotlinNativeLibraryNameUtil.KOTLIN_NATIVE_LIBRARY_PREFIX_PLUS_SPACE) }
|
||||||
|
} else {
|
||||||
|
inheritedDependencies
|
||||||
|
}.toSet()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun PopulateModuleDependenciesContext.getPropagatedNativeDependencies(
|
||||||
|
settings: DependencyPopulationSettings,
|
||||||
|
sourceSet: KotlinSourceSet
|
||||||
|
): Set<KotlinDependency> {
|
||||||
|
if (!settings.forceNativeDependencyPropagation) {
|
||||||
|
return emptySet()
|
||||||
|
}
|
||||||
|
|
||||||
|
return getPropagatedNativeDependencies(getCompilationsWithDependencies(sourceSet)).toSet()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We can't really commonize native platform libraries yet.
|
||||||
|
* But APIs for different targets may be very similar.
|
||||||
|
* E.g. ios_arm64 and ios_x64 have almost identical platform libraries
|
||||||
|
* We handle these special cases and resolve common sources for such
|
||||||
|
* targets against libraries of one of them. E.g. common sources for
|
||||||
|
* ios_x64 and ios_arm64 will be resolved against ios_arm64 libraries.
|
||||||
|
* Currently such special casing is available for Apple platforms
|
||||||
|
* (iOS, watchOS and tvOS) and native Android (ARM, X86).
|
||||||
|
* TODO: Do we need to support user's interop libraries too?
|
||||||
|
*/
|
||||||
|
private fun getPropagatedNativeDependencies(compilations: List<CompilationWithDependencies>): List<ExternalDependency> {
|
||||||
|
if (compilations.size <= 1) {
|
||||||
|
return emptyList()
|
||||||
|
}
|
||||||
|
|
||||||
|
val copyFrom = when {
|
||||||
|
compilations.all { it.isAppleCompilation } ->
|
||||||
|
compilations.selectFirstAvailableTarget(
|
||||||
|
"watchos_arm64", "watchos_arm32", "watchos_x86",
|
||||||
|
"ios_arm64", "ios_arm32", "ios_x64",
|
||||||
|
"tvos_arm64", "tvos_x64"
|
||||||
|
)
|
||||||
|
compilations.all { it.konanTarget?.startsWith("android") == true } ->
|
||||||
|
compilations.selectFirstAvailableTarget(
|
||||||
|
"android_arm64", "android_arm32", "android_x64", "android_x86"
|
||||||
|
)
|
||||||
|
else -> return emptyList()
|
||||||
|
}
|
||||||
|
|
||||||
|
return copyFrom.dependencyNames.mapNotNull { (name, dependency) ->
|
||||||
|
when {
|
||||||
|
!name.startsWith(KotlinNativeLibraryNameUtil.KOTLIN_NATIVE_LIBRARY_PREFIX_PLUS_SPACE) -> null // Support only default platform libs for now.
|
||||||
|
compilations.all { it.dependencyNames.containsKey(name) } -> dependency
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val CompilationWithDependencies.isAppleCompilation: Boolean
|
||||||
|
get() = konanTarget?.let {
|
||||||
|
it.startsWith("ios") || it.startsWith("watchos") || it.startsWith("tvos")
|
||||||
|
} ?: false
|
||||||
|
|
||||||
|
private fun Iterable<CompilationWithDependencies>.selectFirstAvailableTarget(
|
||||||
|
@NonNls vararg targetsByPriority: String
|
||||||
|
): CompilationWithDependencies {
|
||||||
|
for (target in targetsByPriority) {
|
||||||
|
val result = firstOrNull { it.konanTarget == target }
|
||||||
|
if (result != null) {
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return first()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun PopulateModuleDependenciesContext.getPropagatedPlatformDependencies(
|
||||||
|
sourceSet: KotlinSourceSet
|
||||||
|
): Set<KotlinDependency> {
|
||||||
|
if (!mppModel.extraFeatures.isHMPPEnabled) {
|
||||||
|
return emptySet()
|
||||||
|
}
|
||||||
|
|
||||||
|
return getPropagatedPlatformDependencies(mppModel, sourceSet)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Source sets sharing code between JVM and Android are the only intermediate source sets that
|
||||||
|
* can effectively consume a dependency's platform artifact.
|
||||||
|
* When a library only offers a JVM variant, then Android and JVM consume this variant of the library.
|
||||||
|
*
|
||||||
|
* This will be replaced later on by [KT-43450](https://youtrack.jetbrains.com/issue/KT-43450)
|
||||||
|
*
|
||||||
|
* @return all dependencies being present across given JVM and Android compilations that this [sourceSet] can also participates in.
|
||||||
|
*/
|
||||||
|
private fun getPropagatedPlatformDependencies(
|
||||||
|
mppModel: KotlinMPPGradleModel,
|
||||||
|
sourceSet: KotlinSourceSet,
|
||||||
|
): Set<ExternalDependency> {
|
||||||
|
if (
|
||||||
|
sourceSet.actualPlatforms.platforms.sorted() == listOf(KotlinPlatform.JVM, KotlinPlatform.ANDROID).sorted()
|
||||||
|
) {
|
||||||
|
return mppModel.targets
|
||||||
|
.filter { target -> target.platform == KotlinPlatform.JVM || target.platform == KotlinPlatform.ANDROID }
|
||||||
|
.flatMap { target -> target.compilations }
|
||||||
|
.filter { compilation -> compilation.dependsOnSourceSet(mppModel, sourceSet) }
|
||||||
|
.map { targetCompilations -> targetCompilations.dependencies.mapNotNull(mppModel.dependencyMap::get).toSet() }
|
||||||
|
.reduceOrNull { acc, dependencies -> acc.intersect(dependencies) }.orEmpty()
|
||||||
|
}
|
||||||
|
|
||||||
|
return emptySet()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// TODO: Move this maybe to another semantic part of KotlinMPPGradleProjectResolver?
|
||||||
|
private fun KotlinMPPGradleProjectResolver.Companion.populateSourceSetInfos(
|
||||||
|
context: PopulateModuleDependenciesContext,
|
||||||
|
closedSourceSetGraph: Graph<KotlinSourceSet>,
|
||||||
|
sourceSet: KotlinSourceSet
|
||||||
|
) = with(context) {
|
||||||
|
val isAndroid = delegateToAndroidPlugin(sourceSet)
|
||||||
|
val fromDataNode = if (isAndroid) ideModule
|
||||||
|
else getSiblingKotlinModuleData(sourceSet, gradleModule, ideModule, resolverCtx) ?: return
|
||||||
|
|
||||||
|
val dependeeSourceSets = closedSourceSetGraph.successors(sourceSet)
|
||||||
|
val sourceSetInfos = if (isAndroid) {
|
||||||
|
ideModule.kotlinAndroidSourceSets?.filter {
|
||||||
|
(it.kotlinModule as? KotlinCompilation)?.declaredSourceSets?.contains(sourceSet) ?: false
|
||||||
|
} ?: emptyList()
|
||||||
|
} else {
|
||||||
|
listOfNotNull(fromDataNode.kotlinSourceSet)
|
||||||
|
}
|
||||||
|
for (sourceSetInfo in sourceSetInfos) {
|
||||||
|
if (sourceSetInfo.kotlinModule is KotlinCompilation) {
|
||||||
|
val selfName = sourceSetInfo.kotlinModule.fullName()
|
||||||
|
sourceSetInfo.addSourceSets(dependeeSourceSets, selfName, gradleModule, resolverCtx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <reified T : Any> DataNode<*>.cast(): DataNode<T> {
|
||||||
|
if (data !is T) {
|
||||||
|
throw ClassCastException("DataNode<${data.javaClass.canonicalName}> cannot be cast to DataNode<${T::class.java.canonicalName}>")
|
||||||
|
}
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
return this as DataNode<T>
|
||||||
|
}
|
||||||
+22
@@ -0,0 +1,22 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2021 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.utils
|
||||||
|
|
||||||
|
import org.gradle.tooling.model.idea.IdeaModule
|
||||||
|
import org.jetbrains.kotlin.gradle.KotlinCompilation
|
||||||
|
import org.jetbrains.kotlin.gradle.KotlinModule
|
||||||
|
import org.jetbrains.kotlin.gradle.compilationFullName
|
||||||
|
import org.jetbrains.kotlin.idea.configuration.KotlinMPPGradleProjectResolver
|
||||||
|
import org.jetbrains.plugins.gradle.service.project.ProjectResolverContext
|
||||||
|
|
||||||
|
internal fun KotlinModule.fullName(simpleName: String = name) = when (this) {
|
||||||
|
is KotlinCompilation -> compilationFullName(simpleName, disambiguationClassifier)
|
||||||
|
else -> simpleName
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun KotlinMPPGradleProjectResolver.Companion.getKotlinModuleId(
|
||||||
|
gradleModule: IdeaModule, kotlinModule: KotlinModule, resolverCtx: ProjectResolverContext
|
||||||
|
) = getGradleModuleQualifiedName(resolverCtx, gradleModule, kotlinModule.fullName())
|
||||||
+89
@@ -0,0 +1,89 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2021 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
@file:Suppress("UnstableApiUsage")
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.idea.configuration.utils
|
||||||
|
|
||||||
|
import com.google.common.graph.*
|
||||||
|
import org.jetbrains.kotlin.gradle.KotlinMPPGradleModel
|
||||||
|
import org.jetbrains.kotlin.gradle.KotlinPlatform
|
||||||
|
import org.jetbrains.kotlin.gradle.KotlinSourceSet
|
||||||
|
|
||||||
|
internal fun createSourceSetVisibilityGraph(model: KotlinMPPGradleModel): ImmutableGraph<KotlinSourceSet> {
|
||||||
|
val graph = createSourceSetDependsOnGraph(model)
|
||||||
|
graph.putInferredTestToProductionEdges()
|
||||||
|
return graph.immutable
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun createSourceSetDependsOnGraph(model: KotlinMPPGradleModel): MutableGraph<KotlinSourceSet> {
|
||||||
|
return createSourceSetDependsOnGraph(model.sourceSetsByName)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun createSourceSetDependsOnGraph(
|
||||||
|
sourceSetsByName: Map<String, KotlinSourceSet>
|
||||||
|
): MutableGraph<KotlinSourceSet> {
|
||||||
|
val graph = GraphBuilder.directed().build<KotlinSourceSet>()
|
||||||
|
val sourceSets = sourceSetsByName.values.toSet()
|
||||||
|
|
||||||
|
for (sourceSet in sourceSets) {
|
||||||
|
graph.addNode(sourceSet)
|
||||||
|
val dependsOnSourceSets = getFixedDependsOnSourceSets(sourceSetsByName, sourceSet)
|
||||||
|
for (dependsOnSourceSet in dependsOnSourceSets) {
|
||||||
|
graph.addNode(dependsOnSourceSet)
|
||||||
|
graph.putEdge(sourceSet, dependsOnSourceSet)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return graph
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun MutableGraph<KotlinSourceSet>.putInferredTestToProductionEdges() {
|
||||||
|
val sourceSets = this.nodes()
|
||||||
|
for (sourceSet in sourceSets) {
|
||||||
|
if (sourceSet.isTestModule) {
|
||||||
|
@OptIn(UnsafeTestSourceSetHeuristicApi::class)
|
||||||
|
val predictedMainSourceSetName = predictedProductionSourceSetName(sourceSet.name)
|
||||||
|
val predictedMainSourceSet = sourceSets.firstOrNull { it.name == predictedMainSourceSetName } ?: continue
|
||||||
|
putEdge(sourceSet, predictedMainSourceSet)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getFixedDependsOnSourceSets(
|
||||||
|
sourceSetsByName: Map<String, KotlinSourceSet>, sourceSet: KotlinSourceSet
|
||||||
|
): Set<KotlinSourceSet> {
|
||||||
|
/*
|
||||||
|
Workaround for older Kotlin Gradle Plugin versions that did not explicitly declare a dependsOn relation
|
||||||
|
from a Kotlin source set to "commonMain"
|
||||||
|
(Can probably be dropped in Kotlin 1.5)
|
||||||
|
*/
|
||||||
|
val implicitDependsOnEdgeForAndroid = if (
|
||||||
|
sourceSet.actualPlatforms.contains(KotlinPlatform.ANDROID) && sourceSet.declaredDependsOnSourceSets.isEmpty()
|
||||||
|
) {
|
||||||
|
val commonSourceSetName = if (sourceSet.isTestModule) KotlinSourceSet.COMMON_TEST_SOURCE_SET_NAME
|
||||||
|
else KotlinSourceSet.COMMON_MAIN_SOURCE_SET_NAME
|
||||||
|
listOfNotNull(sourceSetsByName[commonSourceSetName])
|
||||||
|
} else emptyList()
|
||||||
|
|
||||||
|
return sourceSet.declaredDependsOnSourceSets.map(sourceSetsByName::getValue)
|
||||||
|
.plus(implicitDependsOnEdgeForAndroid)
|
||||||
|
/*
|
||||||
|
Gracefully filter out source sets that declare a dependency on themselves.
|
||||||
|
This also fixes KTIJ-1025
|
||||||
|
*/
|
||||||
|
.filter { dependencySourceSet -> dependencySourceSet != sourceSet }
|
||||||
|
.toSet()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see Graphs.transitiveClosure
|
||||||
|
*/
|
||||||
|
internal val <T> Graph<T>.transitiveClosure: Graph<T> get() = Graphs.transitiveClosure(this)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see ImmutableGraph.copyOf
|
||||||
|
*/
|
||||||
|
internal val <T> Graph<T>.immutable: ImmutableGraph<T> get() = ImmutableGraph.copyOf(this)
|
||||||
+42
@@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2021 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.utils
|
||||||
|
|
||||||
|
// TODO: Replace heuristic with proper import!
|
||||||
|
@RequiresOptIn(level = RequiresOptIn.Level.ERROR)
|
||||||
|
annotation class UnsafeTestSourceSetHeuristicApi
|
||||||
|
|
||||||
|
|
||||||
|
@UnsafeTestSourceSetHeuristicApi
|
||||||
|
internal fun isProbablyTestSourceSet(name: String): Boolean {
|
||||||
|
return name.endsWith("Test") || name == "test"
|
||||||
|
}
|
||||||
|
|
||||||
|
@UnsafeTestSourceSetHeuristicApi
|
||||||
|
internal fun isProbablyProductionSourceSet(name: String): Boolean {
|
||||||
|
return !isProbablyTestSourceSet(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
@UnsafeTestSourceSetHeuristicApi
|
||||||
|
internal fun predictedProductionSourceSetName(testSourceSetName: String): String {
|
||||||
|
/*
|
||||||
|
This implementation uses a lot of implicit knowledge and should be replaced.
|
||||||
|
This implicit knowledge is/was used at other places as well that should also
|
||||||
|
use an explicit API once available.
|
||||||
|
|
||||||
|
See:
|
||||||
|
https://github.com/JetBrains/intellij-community/blob/c05e8d6de8d1c690eb99c2fff8629c0de373c48f/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/CommonGradleProjectResolverExtension.java#L153
|
||||||
|
https://github.com/JetBrains/intellij-kotlin/blob/fe6ee9dfb42ad1cdd9e55449e2481125f1631133/gradle/gradle-idea/src/org/jetbrains/kotlin/idea/configuration/KotlinMPPGradleProjectResolver.kt#L424
|
||||||
|
https://github.com/JetBrains/intellij-kotlin/blob/fe6ee9dfb42ad1cdd9e55449e2481125f1631133/gradle/gradle-idea/src/org/jetbrains/kotlin/idea/configuration/KotlinMPPGradleProjectResolver.kt#L627
|
||||||
|
*/
|
||||||
|
if (testSourceSetName.endsWith("Test")) {
|
||||||
|
return testSourceSetName.removeSuffix("Test") + "Main"
|
||||||
|
}
|
||||||
|
if (testSourceSetName == "test") {
|
||||||
|
return "main"
|
||||||
|
}
|
||||||
|
return testSourceSetName + "Main"
|
||||||
|
}
|
||||||
+167
@@ -0,0 +1,167 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2021 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.utils
|
||||||
|
|
||||||
|
import com.google.common.graph.EndpointPair
|
||||||
|
import com.google.common.graph.EndpointPair.ordered
|
||||||
|
import com.google.common.graph.Graph
|
||||||
|
import com.google.common.graph.GraphBuilder
|
||||||
|
import org.jetbrains.kotlin.gradle.*
|
||||||
|
import org.jetbrains.kotlin.gradle.KotlinSourceSet.Companion.COMMON_MAIN_SOURCE_SET_NAME
|
||||||
|
import org.jetbrains.kotlin.gradle.KotlinSourceSet.Companion.COMMON_TEST_SOURCE_SET_NAME
|
||||||
|
import org.junit.Test
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
|
class KotlinSourceSetGraphUtilTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `simple layout`() {
|
||||||
|
val sourceSetsByName = mapOf(
|
||||||
|
createKotlinSourceSetPair(COMMON_MAIN_SOURCE_SET_NAME),
|
||||||
|
createKotlinSourceSetPair(COMMON_TEST_SOURCE_SET_NAME),
|
||||||
|
createKotlinSourceSetPair("jvmMain", setOf(COMMON_MAIN_SOURCE_SET_NAME)),
|
||||||
|
createKotlinSourceSetPair("jvmTest", setOf(COMMON_TEST_SOURCE_SET_NAME))
|
||||||
|
)
|
||||||
|
val dependsOnGraph = createSourceSetDependsOnGraph(sourceSetsByName)
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
listOf(
|
||||||
|
ordered("jvmMain", COMMON_MAIN_SOURCE_SET_NAME),
|
||||||
|
ordered("jvmTest", COMMON_TEST_SOURCE_SET_NAME)
|
||||||
|
).sorted(),
|
||||||
|
dependsOnGraph.nameEdges().sorted()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `hierarchical layout`() {
|
||||||
|
val sourceSetsByName = mapOf(
|
||||||
|
createKotlinSourceSetPair(COMMON_MAIN_SOURCE_SET_NAME),
|
||||||
|
createKotlinSourceSetPair(COMMON_TEST_SOURCE_SET_NAME),
|
||||||
|
|
||||||
|
createKotlinSourceSetPair("jvmAndJsMain", setOf(COMMON_MAIN_SOURCE_SET_NAME)),
|
||||||
|
createKotlinSourceSetPair("jvmAndJsTest", setOf(COMMON_TEST_SOURCE_SET_NAME)),
|
||||||
|
|
||||||
|
createKotlinSourceSetPair("jvmMain", setOf("jvmAndJsMain")),
|
||||||
|
createKotlinSourceSetPair("jvmTest", setOf("jvmAndJsTest")),
|
||||||
|
|
||||||
|
createKotlinSourceSetPair("jsMain", setOf("jvmAndJsMain")),
|
||||||
|
createKotlinSourceSetPair("jsTest", setOf("jvmAndJsTest")),
|
||||||
|
)
|
||||||
|
|
||||||
|
val dependsOnGraph = createSourceSetDependsOnGraph(sourceSetsByName)
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
listOf(
|
||||||
|
ordered("jvmMain", "jvmAndJsMain"),
|
||||||
|
ordered("jvmTest", "jvmAndJsTest"),
|
||||||
|
ordered("jsMain", "jvmAndJsMain"),
|
||||||
|
ordered("jsTest", "jvmAndJsTest"),
|
||||||
|
ordered("jvmAndJsMain", COMMON_MAIN_SOURCE_SET_NAME),
|
||||||
|
ordered("jvmAndJsTest", COMMON_TEST_SOURCE_SET_NAME)
|
||||||
|
).sorted(),
|
||||||
|
dependsOnGraph.nameEdges().sorted()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `source set depending on multiple other source sets`() {
|
||||||
|
val sourceSetsByName = mapOf(
|
||||||
|
createKotlinSourceSetPair("common1"),
|
||||||
|
createKotlinSourceSetPair("common2"),
|
||||||
|
createKotlinSourceSetPair("consumerA", setOf("common1", "common2")),
|
||||||
|
createKotlinSourceSetPair("consumerB", setOf("common1", "consumerA"))
|
||||||
|
)
|
||||||
|
|
||||||
|
val dependsOnGraph = createSourceSetDependsOnGraph(sourceSetsByName)
|
||||||
|
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
listOf(
|
||||||
|
ordered("consumerA", "common1"),
|
||||||
|
ordered("consumerA", "common2"),
|
||||||
|
ordered("consumerB", "common1"),
|
||||||
|
ordered("consumerB", "consumerA")
|
||||||
|
).sorted(),
|
||||||
|
dependsOnGraph.nameEdges().sorted()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `infer default test to production edges`() {
|
||||||
|
val sourceSetsByName = mapOf(
|
||||||
|
createKotlinSourceSetPair(COMMON_MAIN_SOURCE_SET_NAME),
|
||||||
|
createKotlinSourceSetPair(COMMON_TEST_SOURCE_SET_NAME, isTestModule = true),
|
||||||
|
createKotlinSourceSetPair("main"),
|
||||||
|
createKotlinSourceSetPair("test", isTestModule = true),
|
||||||
|
createKotlinSourceSetPair("abcMain"),
|
||||||
|
createKotlinSourceSetPair("abcTest", isTestModule = true)
|
||||||
|
)
|
||||||
|
|
||||||
|
val graph = GraphBuilder.directed().build<KotlinSourceSet>()
|
||||||
|
sourceSetsByName.values.forEach { sourceSet -> graph.addNode(sourceSet) }
|
||||||
|
graph.putInferredTestToProductionEdges()
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
listOf(
|
||||||
|
ordered(COMMON_TEST_SOURCE_SET_NAME, COMMON_MAIN_SOURCE_SET_NAME),
|
||||||
|
ordered("test", "main"),
|
||||||
|
ordered("abcTest", "abcMain")
|
||||||
|
).sorted(),
|
||||||
|
graph.nameEdges().sorted()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `depends on graph will automatically infer missing dependsOn edges for Android source sets`() {
|
||||||
|
val sourceSetsByName = mapOf(
|
||||||
|
createKotlinSourceSetPair(COMMON_MAIN_SOURCE_SET_NAME),
|
||||||
|
createKotlinSourceSetPair(COMMON_TEST_SOURCE_SET_NAME, isTestModule = true),
|
||||||
|
createKotlinSourceSetPair("androidMain", platforms = setOf(KotlinPlatform.ANDROID)),
|
||||||
|
createKotlinSourceSetPair("androidTest", platforms = setOf(KotlinPlatform.ANDROID), isTestModule = true)
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
listOf(
|
||||||
|
ordered("androidMain", COMMON_MAIN_SOURCE_SET_NAME),
|
||||||
|
ordered("androidTest", COMMON_TEST_SOURCE_SET_NAME)
|
||||||
|
).sorted(),
|
||||||
|
createSourceSetDependsOnGraph(sourceSetsByName).nameEdges().sorted()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createKotlinSourceSetPair(
|
||||||
|
name: String,
|
||||||
|
declaredDependsOnSourceSets: Set<String> = emptySet(),
|
||||||
|
allDependsOnSourceSets: Set<String> = declaredDependsOnSourceSets,
|
||||||
|
platforms: Set<KotlinPlatform> = emptySet(),
|
||||||
|
isTestModule: Boolean = false,
|
||||||
|
): Pair<String, KotlinSourceSet> = name to KotlinSourceSetImpl(
|
||||||
|
name = name,
|
||||||
|
languageSettings = KotlinLanguageSettingsImpl(
|
||||||
|
languageVersion = null,
|
||||||
|
apiVersion = null,
|
||||||
|
isProgressiveMode = false,
|
||||||
|
enabledLanguageFeatures = emptySet(),
|
||||||
|
experimentalAnnotationsInUse = emptySet(),
|
||||||
|
compilerPluginArguments = emptyArray(),
|
||||||
|
compilerPluginClasspath = emptySet(),
|
||||||
|
freeCompilerArgs = emptyArray()
|
||||||
|
),
|
||||||
|
sourceDirs = emptySet(),
|
||||||
|
resourceDirs = emptySet(),
|
||||||
|
dependencies = emptyArray(),
|
||||||
|
declaredDependsOnSourceSets = declaredDependsOnSourceSets,
|
||||||
|
allDependsOnSourceSets = allDependsOnSourceSets,
|
||||||
|
defaultActualPlatforms = KotlinPlatformContainerImpl().apply { pushPlatforms(platforms) },
|
||||||
|
defaultIsTestModule = isTestModule
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun Graph<KotlinSourceSet>.nameEdges() = edges()
|
||||||
|
.map { edge -> ordered(edge.source().name, edge.target().name) }
|
||||||
|
|
||||||
|
private fun Iterable<EndpointPair<String>>.sorted() = this.sortedBy { it.source() + " -> " + it.target() }
|
||||||
+21
@@ -0,0 +1,21 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2021 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.utils
|
||||||
|
|
||||||
|
import org.junit.Test
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
|
@OptIn(UnsafeTestSourceSetHeuristicApi::class)
|
||||||
|
class TestSourceSetUtilsTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `test predicted production source set name for various examples`() {
|
||||||
|
assertEquals("commonMain", predictedProductionSourceSetName("commonTest"))
|
||||||
|
assertEquals("main", predictedProductionSourceSetName("test"))
|
||||||
|
assertEquals("abcMain", predictedProductionSourceSetName("abc"))
|
||||||
|
assertEquals("abctestMain", predictedProductionSourceSetName("abctest"))
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -12,11 +12,17 @@ dependencies {
|
|||||||
|
|
||||||
compileOnly(intellijPluginDep("gradle"))
|
compileOnly(intellijPluginDep("gradle"))
|
||||||
compileOnly(intellijDep()) { includeJars("slf4j-api-1.7.25") }
|
compileOnly(intellijDep()) { includeJars("slf4j-api-1.7.25") }
|
||||||
|
|
||||||
|
testImplementation(commonDep("junit:junit"))
|
||||||
|
testImplementation(projectTests(":compiler:tests-common"))
|
||||||
|
testCompileOnly(projectTests(":idea:idea-test-framework"))
|
||||||
|
testCompileOnly(intellijDep())
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sourceSets {
|
sourceSets {
|
||||||
"main" { projectDefault() }
|
"main" { projectDefault() }
|
||||||
"test" {}
|
"test" { projectDefault() }
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.withType<org.jetbrains.kotlin.gradle.dsl.KotlinCompile<*>> {
|
tasks.withType<org.jetbrains.kotlin.gradle.dsl.KotlinCompile<*>> {
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2021 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.gradle
|
||||||
|
|
||||||
|
@ExperimentalGradleToolingApi
|
||||||
|
fun KotlinMPPGradleModel.getCompilations(sourceSet: KotlinSourceSet): Set<KotlinCompilation> {
|
||||||
|
return targets.flatMap { target -> target.compilations }
|
||||||
|
.filter { compilation -> compilationDependsOnSourceSet(compilation, sourceSet) }
|
||||||
|
.toSet()
|
||||||
|
}
|
||||||
|
|
||||||
|
@ExperimentalGradleToolingApi
|
||||||
|
fun KotlinMPPGradleModel.compilationDependsOnSourceSet(
|
||||||
|
compilation: KotlinCompilation, sourceSet: KotlinSourceSet
|
||||||
|
): Boolean {
|
||||||
|
return compilation.declaredSourceSets.any { sourceSetInCompilation ->
|
||||||
|
sourceSetInCompilation == sourceSet || sourceSetInCompilation.isDependsOn(this, sourceSet)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -16,30 +16,25 @@ class KotlinSourceSetProto(
|
|||||||
private val dependencies: () -> Array<KotlinDependencyId>,
|
private val dependencies: () -> Array<KotlinDependencyId>,
|
||||||
val dependsOnSourceSets: Set<String>
|
val dependsOnSourceSets: Set<String>
|
||||||
) {
|
) {
|
||||||
|
|
||||||
fun buildKotlinSourceSetImpl(
|
fun buildKotlinSourceSetImpl(
|
||||||
doBuildDependencies: Boolean,
|
doBuildDependencies: Boolean,
|
||||||
allSourceSetsProtosByNames: Map<String, KotlinSourceSetProto>,
|
allSourceSetsProtosByNames: Map<String, KotlinSourceSetProto>,
|
||||||
dependsOnCache: HashMap<String, Set<String>>
|
|
||||||
) = KotlinSourceSetImpl(
|
) = KotlinSourceSetImpl(
|
||||||
name,
|
name = name,
|
||||||
languageSettings,
|
languageSettings = languageSettings,
|
||||||
sourceDirs,
|
sourceDirs = sourceDirs,
|
||||||
resourceDirs,
|
resourceDirs = resourceDirs,
|
||||||
if (doBuildDependencies) dependencies.invoke() else emptyArray(),
|
dependencies = if (doBuildDependencies) dependencies.invoke() else emptyArray(),
|
||||||
calculateDependsOnClosure(this, allSourceSetsProtosByNames, dependsOnCache)
|
declaredDependsOnSourceSets = dependsOnSourceSets,
|
||||||
|
allDependsOnSourceSets = allDependsOnSourceSets(allSourceSetsProtosByNames)
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private fun calculateDependsOnClosure(
|
fun KotlinSourceSetProto.allDependsOnSourceSets(sourceSetsByName: Map<String, KotlinSourceSetProto>): Set<String> {
|
||||||
currentSourceSetProto: KotlinSourceSetProto,
|
return mutableSetOf<String>().apply {
|
||||||
sourceSetsMap: Map<String, KotlinSourceSetProto>,
|
addAll(dependsOnSourceSets)
|
||||||
cache: MutableMap<String, Set<String>>
|
dependsOnSourceSets.map(sourceSetsByName::getValue).forEach { dependsOnSourceSet ->
|
||||||
): Set<String> {
|
addAll(dependsOnSourceSet.allDependsOnSourceSets(sourceSetsByName))
|
||||||
return cache.computeIfAbsent(currentSourceSetProto.name) {
|
|
||||||
currentSourceSetProto.dependsOnSourceSets.flatMap { name ->
|
|
||||||
val nextSourceSet = sourceSetsMap[name] ?: error("Source set $name is not found in map $sourceSetsMap")
|
|
||||||
calculateDependsOnClosure(nextSourceSet, sourceSetsMap, cache).union(setOf(name))
|
|
||||||
}.toSet()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -50,29 +45,41 @@ class KotlinSourceSetImpl(
|
|||||||
override val sourceDirs: Set<File>,
|
override val sourceDirs: Set<File>,
|
||||||
override val resourceDirs: Set<File>,
|
override val resourceDirs: Set<File>,
|
||||||
override val dependencies: Array<KotlinDependencyId>,
|
override val dependencies: Array<KotlinDependencyId>,
|
||||||
override val dependsOnSourceSets: Set<String>,
|
override val declaredDependsOnSourceSets: Set<String>,
|
||||||
val defaultPlatform: KotlinPlatformContainerImpl = KotlinPlatformContainerImpl(),
|
@Suppress("OverridingDeprecatedMember")
|
||||||
|
override val allDependsOnSourceSets: Set<String>,
|
||||||
|
defaultActualPlatforms: KotlinPlatformContainerImpl = KotlinPlatformContainerImpl(),
|
||||||
|
defaultIsTestModule: Boolean = false
|
||||||
) : KotlinSourceSet {
|
) : KotlinSourceSet {
|
||||||
|
|
||||||
constructor(kotlinSourceSet: KotlinSourceSet, cloningCache: MutableMap<Any, Any>) : this(
|
@Suppress("DEPRECATION")
|
||||||
kotlinSourceSet.name,
|
constructor(kotlinSourceSet: KotlinSourceSet) : this(
|
||||||
KotlinLanguageSettingsImpl(kotlinSourceSet.languageSettings),
|
name = kotlinSourceSet.name,
|
||||||
HashSet(kotlinSourceSet.sourceDirs),
|
languageSettings = KotlinLanguageSettingsImpl(kotlinSourceSet.languageSettings),
|
||||||
HashSet(kotlinSourceSet.resourceDirs),
|
sourceDirs = HashSet(kotlinSourceSet.sourceDirs),
|
||||||
kotlinSourceSet.dependencies,
|
resourceDirs = HashSet(kotlinSourceSet.resourceDirs),
|
||||||
HashSet(kotlinSourceSet.dependsOnSourceSets),
|
dependencies = kotlinSourceSet.dependencies.clone(),
|
||||||
KotlinPlatformContainerImpl(kotlinSourceSet.actualPlatforms)
|
declaredDependsOnSourceSets = HashSet(kotlinSourceSet.declaredDependsOnSourceSets),
|
||||||
|
allDependsOnSourceSets = HashSet(kotlinSourceSet.allDependsOnSourceSets),
|
||||||
|
defaultActualPlatforms = KotlinPlatformContainerImpl(kotlinSourceSet.actualPlatforms)
|
||||||
) {
|
) {
|
||||||
this.isTestModule = kotlinSourceSet.isTestModule
|
this.isTestModule = kotlinSourceSet.isTestModule
|
||||||
}
|
}
|
||||||
|
|
||||||
override var actualPlatforms: KotlinPlatformContainer = defaultPlatform
|
override var actualPlatforms: KotlinPlatformContainer = defaultActualPlatforms
|
||||||
internal set
|
internal set
|
||||||
|
|
||||||
override var isTestModule: Boolean = false
|
override var isTestModule: Boolean = defaultIsTestModule
|
||||||
internal set
|
internal set
|
||||||
|
|
||||||
override fun toString() = name
|
override fun toString() = name
|
||||||
|
|
||||||
|
init {
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
|
require(allDependsOnSourceSets.containsAll(declaredDependsOnSourceSets)) {
|
||||||
|
"Inconsistent source set dependencies: 'allDependsOnSourceSets' is expected to contain all 'declaredDependsOnSourceSets'"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
data class KotlinLanguageSettingsImpl(
|
data class KotlinLanguageSettingsImpl(
|
||||||
@@ -128,7 +135,7 @@ data class KotlinNativeCompilationExtensionsImpl(
|
|||||||
data class KotlinCompilationImpl(
|
data class KotlinCompilationImpl(
|
||||||
override val name: String,
|
override val name: String,
|
||||||
override val allSourceSets: Collection<KotlinSourceSet>,
|
override val allSourceSets: Collection<KotlinSourceSet>,
|
||||||
override val defaultSourceSets: Collection<KotlinSourceSet>,
|
override val declaredSourceSets: Collection<KotlinSourceSet>,
|
||||||
override val dependencies: Array<KotlinDependencyId>,
|
override val dependencies: Array<KotlinDependencyId>,
|
||||||
override val output: KotlinCompilationOutput,
|
override val output: KotlinCompilationOutput,
|
||||||
override val arguments: KotlinCompilationArguments,
|
override val arguments: KotlinCompilationArguments,
|
||||||
@@ -139,15 +146,15 @@ data class KotlinCompilationImpl(
|
|||||||
|
|
||||||
// create deep copy
|
// create deep copy
|
||||||
constructor(kotlinCompilation: KotlinCompilation, cloningCache: MutableMap<Any, Any>) : this(
|
constructor(kotlinCompilation: KotlinCompilation, cloningCache: MutableMap<Any, Any>) : this(
|
||||||
kotlinCompilation.name,
|
name = kotlinCompilation.name,
|
||||||
cloneSourceSetsWithCaching(kotlinCompilation.allSourceSets, cloningCache),
|
declaredSourceSets = cloneSourceSetsWithCaching(kotlinCompilation.declaredSourceSets, cloningCache),
|
||||||
cloneSourceSetsWithCaching(kotlinCompilation.defaultSourceSets, cloningCache),
|
allSourceSets = cloneSourceSetsWithCaching(kotlinCompilation.allSourceSets, cloningCache),
|
||||||
kotlinCompilation.dependencies,
|
dependencies = kotlinCompilation.dependencies,
|
||||||
KotlinCompilationOutputImpl(kotlinCompilation.output),
|
output = KotlinCompilationOutputImpl(kotlinCompilation.output),
|
||||||
KotlinCompilationArgumentsImpl(kotlinCompilation.arguments),
|
arguments = KotlinCompilationArgumentsImpl(kotlinCompilation.arguments),
|
||||||
kotlinCompilation.dependencyClasspath,
|
dependencyClasspath = kotlinCompilation.dependencyClasspath,
|
||||||
KotlinTaskPropertiesImpl(kotlinCompilation.kotlinTaskProperties),
|
kotlinTaskProperties = KotlinTaskPropertiesImpl(kotlinCompilation.kotlinTaskProperties),
|
||||||
kotlinCompilation.nativeExtensions?.let(::KotlinNativeCompilationExtensionsImpl)
|
nativeExtensions = kotlinCompilation.nativeExtensions?.let(::KotlinNativeCompilationExtensionsImpl)
|
||||||
) {
|
) {
|
||||||
disambiguationClassifier = kotlinCompilation.disambiguationClassifier
|
disambiguationClassifier = kotlinCompilation.disambiguationClassifier
|
||||||
platform = kotlinCompilation.platform
|
platform = kotlinCompilation.platform
|
||||||
@@ -158,7 +165,7 @@ data class KotlinCompilationImpl(
|
|||||||
override lateinit var platform: KotlinPlatform
|
override lateinit var platform: KotlinPlatform
|
||||||
internal set
|
internal set
|
||||||
|
|
||||||
|
// TODO: Logic like this is duplicated *and different*
|
||||||
override val isTestModule: Boolean
|
override val isTestModule: Boolean
|
||||||
get() = name == KotlinCompilation.TEST_COMPILATION_NAME
|
get() = name == KotlinCompilation.TEST_COMPILATION_NAME
|
||||||
|| platform == KotlinPlatform.ANDROID && name.contains("Test")
|
|| platform == KotlinPlatform.ANDROID && name.contains("Test")
|
||||||
@@ -171,7 +178,7 @@ data class KotlinCompilationImpl(
|
|||||||
cloningCache: MutableMap<Any, Any>
|
cloningCache: MutableMap<Any, Any>
|
||||||
): List<KotlinSourceSet> =
|
): List<KotlinSourceSet> =
|
||||||
sourceSets.map { initialSourceSet ->
|
sourceSets.map { initialSourceSet ->
|
||||||
(cloningCache[initialSourceSet] as? KotlinSourceSet) ?: KotlinSourceSetImpl(initialSourceSet, cloningCache).also {
|
(cloningCache[initialSourceSet] as? KotlinSourceSet) ?: KotlinSourceSetImpl(initialSourceSet).also {
|
||||||
cloningCache[initialSourceSet] = it
|
cloningCache[initialSourceSet] = it
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -250,7 +257,7 @@ data class ExtraFeaturesImpl(
|
|||||||
) : ExtraFeatures
|
) : ExtraFeatures
|
||||||
|
|
||||||
data class KotlinMPPGradleModelImpl(
|
data class KotlinMPPGradleModelImpl(
|
||||||
override val sourceSets: Map<String, KotlinSourceSet>,
|
override val sourceSetsByName: Map<String, KotlinSourceSet>,
|
||||||
override val targets: Collection<KotlinTarget>,
|
override val targets: Collection<KotlinTarget>,
|
||||||
override val extraFeatures: ExtraFeatures,
|
override val extraFeatures: ExtraFeatures,
|
||||||
override val kotlinNativeHome: String,
|
override val kotlinNativeHome: String,
|
||||||
@@ -259,11 +266,9 @@ data class KotlinMPPGradleModelImpl(
|
|||||||
) : KotlinMPPGradleModel {
|
) : KotlinMPPGradleModel {
|
||||||
|
|
||||||
constructor(mppModel: KotlinMPPGradleModel, cloningCache: MutableMap<Any, Any>) : this(
|
constructor(mppModel: KotlinMPPGradleModel, cloningCache: MutableMap<Any, Any>) : this(
|
||||||
mppModel.sourceSets.mapValues { initialSourceSet ->
|
mppModel.sourceSetsByName.mapValues { initialSourceSet ->
|
||||||
(cloningCache[initialSourceSet] as? KotlinSourceSet) ?: KotlinSourceSetImpl(
|
(cloningCache[initialSourceSet] as? KotlinSourceSet) ?: KotlinSourceSetImpl(initialSourceSet.value)
|
||||||
initialSourceSet.value,
|
.also { cloningCache[initialSourceSet] = it }
|
||||||
cloningCache
|
|
||||||
).also { cloningCache[initialSourceSet] = it }
|
|
||||||
},
|
},
|
||||||
mppModel.targets.map { initialTarget ->
|
mppModel.targets.map { initialTarget ->
|
||||||
(cloningCache[initialTarget] as? KotlinTarget) ?: KotlinTargetImpl(initialTarget, cloningCache).also {
|
(cloningCache[initialTarget] as? KotlinTarget) ?: KotlinTargetImpl(initialTarget, cloningCache).also {
|
||||||
@@ -289,20 +294,20 @@ class KotlinPlatformContainerImpl() : KotlinPlatformContainer {
|
|||||||
get() = myPlatforms != null
|
get() = myPlatforms != null
|
||||||
|
|
||||||
constructor(platform: KotlinPlatformContainer) : this() {
|
constructor(platform: KotlinPlatformContainer) : this() {
|
||||||
myPlatforms = HashSet<KotlinPlatform>(platform.platforms)
|
myPlatforms = HashSet(platform.platforms)
|
||||||
}
|
}
|
||||||
|
|
||||||
override val platforms: Collection<KotlinPlatform>
|
override val platforms: Set<KotlinPlatform>
|
||||||
get() = myPlatforms ?: defaultCommonPlatform
|
get() = myPlatforms ?: defaultCommonPlatform
|
||||||
|
|
||||||
override fun supports(simplePlatform: KotlinPlatform): Boolean = platforms.contains(simplePlatform)
|
override fun supports(simplePlatform: KotlinPlatform): Boolean = platforms.contains(simplePlatform)
|
||||||
|
|
||||||
override fun addSimplePlatforms(platforms: Collection<KotlinPlatform>) {
|
override fun pushPlatforms(platforms: Iterable<KotlinPlatform>) {
|
||||||
(myPlatforms ?: HashSet<KotlinPlatform>().apply { myPlatforms = this }).let {
|
myPlatforms = (myPlatforms ?: LinkedHashSet()).apply {
|
||||||
it.addAll(platforms)
|
addAll(platforms)
|
||||||
if (it.contains(KotlinPlatform.COMMON)) {
|
if (contains(KotlinPlatform.COMMON)) {
|
||||||
it.clear()
|
clear()
|
||||||
it.addAll(defaultCommonPlatform)
|
addAll(defaultCommonPlatform)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,307 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2021 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.gradle
|
||||||
|
|
||||||
|
import org.junit.Test
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
import kotlin.test.assertFalse
|
||||||
|
import kotlin.test.assertTrue
|
||||||
|
|
||||||
|
@OptIn(ExperimentalGradleToolingApi::class)
|
||||||
|
class KotlinMppGradleModelExtensionsTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun resolveDeclaredDependsOnSourceSets() {
|
||||||
|
val commonMain = createKotlinSourceSet("commonMain")
|
||||||
|
val appleMain = createKotlinSourceSet("appleMain", declaredDependsOnSourceSets = setOf("commonMain"))
|
||||||
|
val macosMain = createKotlinSourceSet("macosMain", declaredDependsOnSourceSets = setOf("appleMain"))
|
||||||
|
val iosMain = createKotlinSourceSet("iosMain", declaredDependsOnSourceSets = setOf("appleMain", "commonMain"))
|
||||||
|
|
||||||
|
val model = createKotlinMPPGradleModel(
|
||||||
|
sourceSets = setOf(commonMain, appleMain, macosMain, iosMain)
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
emptySet(), model.resolveDeclaredDependsOnSourceSets(commonMain),
|
||||||
|
"Expected no declared dependency source sets for commonMain"
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
setOf(commonMain), model.resolveDeclaredDependsOnSourceSets(appleMain),
|
||||||
|
"Expected only declared dependency for 'appleMain'"
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
setOf(appleMain, commonMain), model.resolveDeclaredDependsOnSourceSets(iosMain),
|
||||||
|
"Expected only declared dependency for 'iosMain'"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `resolveDeclaredDependsOnSourceSets is graceful for missing source sets`() {
|
||||||
|
val commonMain = createKotlinSourceSet("commonMain")
|
||||||
|
val macosMain = createKotlinSourceSet("macosMain", declaredDependsOnSourceSets = setOf("commonMain", "missing"))
|
||||||
|
val model = createKotlinMPPGradleModel(sourceSets = setOf(commonMain, macosMain))
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
setOf(commonMain), model.resolveDeclaredDependsOnSourceSets(macosMain),
|
||||||
|
"Expected declaredDependencySourceSets to ignore missing dependency source set"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun resolveAllDependsOnSourceSets() {
|
||||||
|
val commonMain = createKotlinSourceSet("commonMain")
|
||||||
|
val appleMain = createKotlinSourceSet("appleMain", declaredDependsOnSourceSets = setOf("commonMain"))
|
||||||
|
val x64Main = createKotlinSourceSet("x64Main", declaredDependsOnSourceSets = setOf("commonMain"))
|
||||||
|
val macosMain = createKotlinSourceSet("macosMain", declaredDependsOnSourceSets = setOf("appleMain"))
|
||||||
|
val macosX64Main = createKotlinSourceSet("macosX64Main", declaredDependsOnSourceSets = setOf("appleMain", "x64Main"))
|
||||||
|
val macosArm64Main = createKotlinSourceSet("macosArm64Main", declaredDependsOnSourceSets = setOf("appleMain"))
|
||||||
|
|
||||||
|
val model = createKotlinMPPGradleModel(sourceSets = setOf(commonMain, appleMain, x64Main, macosMain, macosX64Main, macosArm64Main))
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
setOf(appleMain, x64Main, commonMain),
|
||||||
|
model.resolveAllDependsOnSourceSets(macosX64Main),
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
setOf(appleMain, x64Main, commonMain).sortedBy { it.name },
|
||||||
|
model.resolveAllDependsOnSourceSets(macosX64Main).sortedBy { it.name }.toList(),
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
setOf(appleMain, commonMain),
|
||||||
|
model.resolveAllDependsOnSourceSets(macosArm64Main).toSet(),
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
setOf(commonMain),
|
||||||
|
model.resolveAllDependsOnSourceSets(appleMain).toSet(),
|
||||||
|
"Expected only 'commonMain' for 'appleMain'"
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
emptySet(), model.resolveAllDependsOnSourceSets(commonMain).toSet(),
|
||||||
|
"Expected empty set for 'commonMain'"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `resolving source sets with self references or loops`() {
|
||||||
|
val a = createKotlinSourceSet("a", declaredDependsOnSourceSets = setOf(""))
|
||||||
|
val b = createKotlinSourceSet("b", declaredDependsOnSourceSets = setOf("a", "c")) // loop d -> c -> b -> c
|
||||||
|
val c = createKotlinSourceSet("c", declaredDependsOnSourceSets = setOf("b", "c")) // self reference c -> c
|
||||||
|
val d = createKotlinSourceSet("d", declaredDependsOnSourceSets = setOf("c"))
|
||||||
|
|
||||||
|
val model = createKotlinMPPGradleModel(sourceSets = setOf(a, b, c, d))
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
setOf(a, b, c).sortedBy { it.name },
|
||||||
|
model.resolveAllDependsOnSourceSets(d).sortedBy { it.name },
|
||||||
|
"Expected dependency loop to be handled gracefully"
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
setOf(a, b, c).sortedBy { it.name },
|
||||||
|
model.resolveAllDependsOnSourceSets(c).sortedBy { it.name },
|
||||||
|
"Expected self dependency to be resolved for 'resolveAllDependsOnSourceSets'"
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
setOf(b, c).sortedBy { it.name },
|
||||||
|
model.resolveDeclaredDependsOnSourceSets(c).sortedBy { it.name },
|
||||||
|
"Expected self dependency to be resolved by 'resolveDeclaredDependsOnSourceSets'"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun isDependsOn() {
|
||||||
|
val commonMain = createKotlinSourceSet("commonMain")
|
||||||
|
val appleMain = createKotlinSourceSet("appleMain", declaredDependsOnSourceSets = setOf("commonMain"))
|
||||||
|
val x64Main = createKotlinSourceSet("x64Main", declaredDependsOnSourceSets = setOf("commonMain"))
|
||||||
|
val macosX64Main = createKotlinSourceSet("macosX64Main", declaredDependsOnSourceSets = setOf("appleMain", "x64Main"))
|
||||||
|
val macosArm64Main = createKotlinSourceSet("macosArm64Main", declaredDependsOnSourceSets = setOf("appleMain"))
|
||||||
|
|
||||||
|
|
||||||
|
val model = createKotlinMPPGradleModel(sourceSets = setOf(commonMain, appleMain, x64Main, macosX64Main))
|
||||||
|
|
||||||
|
assertTrue(
|
||||||
|
model.isDependsOn(from = appleMain, to = commonMain),
|
||||||
|
"Expected isDependsOn from appleMain to commonMain"
|
||||||
|
)
|
||||||
|
|
||||||
|
assertTrue(
|
||||||
|
model.isDependsOn(from = x64Main, to = commonMain),
|
||||||
|
"Expected isDependsOn from x64Main to commonMain"
|
||||||
|
)
|
||||||
|
|
||||||
|
assertTrue(
|
||||||
|
model.isDependsOn(from = macosX64Main, to = commonMain),
|
||||||
|
"Expected isDependsOn from macosX64Main to commonMain"
|
||||||
|
)
|
||||||
|
|
||||||
|
assertTrue(
|
||||||
|
model.isDependsOn(from = macosX64Main, to = appleMain),
|
||||||
|
"Expected isDependsOn from macosX64Main to appleMain"
|
||||||
|
)
|
||||||
|
|
||||||
|
assertTrue(
|
||||||
|
model.isDependsOn(from = macosX64Main, to = commonMain),
|
||||||
|
"Expected isDependsOn from macosX64Main to commonMain"
|
||||||
|
)
|
||||||
|
|
||||||
|
assertTrue(
|
||||||
|
model.isDependsOn(from = macosX64Main, to = appleMain),
|
||||||
|
"Expected isDependsOn from macosX64Main to appleMain"
|
||||||
|
)
|
||||||
|
|
||||||
|
assertTrue(
|
||||||
|
model.isDependsOn(from = macosX64Main, to = x64Main),
|
||||||
|
"Expected isDependsOn from macosX64Main to x64Main"
|
||||||
|
)
|
||||||
|
|
||||||
|
assertTrue(
|
||||||
|
model.isDependsOn(from = macosArm64Main, to = commonMain),
|
||||||
|
"Expected isDependsOn from macosArm64Main to commonMain"
|
||||||
|
)
|
||||||
|
|
||||||
|
assertTrue(
|
||||||
|
model.isDependsOn(from = macosArm64Main, to = appleMain),
|
||||||
|
"Expected isDependsOn from macosArm64Main to appleMain"
|
||||||
|
)
|
||||||
|
|
||||||
|
assertFalse(
|
||||||
|
model.isDependsOn(from = macosArm64Main, to = x64Main),
|
||||||
|
"Expected false isDependsOn from macosArm64 to x64Main"
|
||||||
|
)
|
||||||
|
|
||||||
|
for (sourceSet in model.sourceSetsByName.values) {
|
||||||
|
assertFalse(
|
||||||
|
model.isDependsOn(from = commonMain, to = sourceSet),
|
||||||
|
"Expected false isDependsOn from commonMain to ${sourceSet.name}"
|
||||||
|
)
|
||||||
|
|
||||||
|
assertFalse(
|
||||||
|
model.isDependsOn(from = sourceSet, to = sourceSet),
|
||||||
|
"Expected false isDependsOn for same source set"
|
||||||
|
)
|
||||||
|
|
||||||
|
assertFalse(
|
||||||
|
sourceSet.isDependsOn(model, sourceSet),
|
||||||
|
"Expected false isDependsOn for same source set"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun compilationDependsOnSourceSet() {
|
||||||
|
val commonMain = createKotlinSourceSet("commonMain")
|
||||||
|
val appleMain = createKotlinSourceSet("appleMain", declaredDependsOnSourceSets = setOf("commonMain"))
|
||||||
|
val macosMain = createKotlinSourceSet("macosMain", declaredDependsOnSourceSets = setOf("appleMain"))
|
||||||
|
val iosMain = createKotlinSourceSet("iosMain", declaredDependsOnSourceSets = setOf("appleMain"))
|
||||||
|
|
||||||
|
val metadataCompilation = createKotlinCompilation(defaultSourceSets = setOf(commonMain))
|
||||||
|
val macosMainCompilation = createKotlinCompilation(defaultSourceSets = setOf(macosMain))
|
||||||
|
val iosMainCompilation = createKotlinCompilation(defaultSourceSets = setOf(iosMain))
|
||||||
|
|
||||||
|
val model = createKotlinMPPGradleModel(sourceSets = setOf(commonMain, appleMain, macosMain, iosMain))
|
||||||
|
|
||||||
|
assertTrue(
|
||||||
|
model.compilationDependsOnSourceSet(iosMainCompilation, iosMain),
|
||||||
|
"Expected iosMainCompilation depending on iosMain"
|
||||||
|
)
|
||||||
|
|
||||||
|
assertTrue(
|
||||||
|
model.compilationDependsOnSourceSet(iosMainCompilation, appleMain),
|
||||||
|
"Expected iosMainCompilation depending on appleMain"
|
||||||
|
)
|
||||||
|
|
||||||
|
assertTrue(
|
||||||
|
model.compilationDependsOnSourceSet(iosMainCompilation, commonMain),
|
||||||
|
"Expected iosMainCompilation depending on commonMain"
|
||||||
|
)
|
||||||
|
|
||||||
|
assertFalse(
|
||||||
|
model.compilationDependsOnSourceSet(iosMainCompilation, macosMain),
|
||||||
|
"Expected iosMainCompilation *not* depending on macosMain"
|
||||||
|
)
|
||||||
|
|
||||||
|
assertTrue(
|
||||||
|
model.compilationDependsOnSourceSet(macosMainCompilation, macosMain),
|
||||||
|
"Expected macosMainCompilation depending on macosMain"
|
||||||
|
)
|
||||||
|
|
||||||
|
assertTrue(
|
||||||
|
model.compilationDependsOnSourceSet(macosMainCompilation, appleMain),
|
||||||
|
"Expected macosMainCompilation depending on appleMain"
|
||||||
|
)
|
||||||
|
|
||||||
|
assertTrue(
|
||||||
|
model.compilationDependsOnSourceSet(macosMainCompilation, commonMain),
|
||||||
|
"Expected macosMainCompilation depending on commonMain"
|
||||||
|
)
|
||||||
|
|
||||||
|
assertFalse(
|
||||||
|
model.compilationDependsOnSourceSet(macosMainCompilation, iosMain),
|
||||||
|
"Expected macosMainCompilation *not* depending on iosMain"
|
||||||
|
)
|
||||||
|
|
||||||
|
assertTrue(
|
||||||
|
model.compilationDependsOnSourceSet(metadataCompilation, commonMain),
|
||||||
|
"Expected metadataCompilation depending on commonMain"
|
||||||
|
)
|
||||||
|
|
||||||
|
assertFalse(
|
||||||
|
model.compilationDependsOnSourceSet(metadataCompilation, appleMain),
|
||||||
|
"Expected metadataCompilation *not* depending on appleMain"
|
||||||
|
)
|
||||||
|
|
||||||
|
assertFalse(
|
||||||
|
model.compilationDependsOnSourceSet(metadataCompilation, macosMain),
|
||||||
|
"Expected metadataCompilation *not* depending on macosMain"
|
||||||
|
)
|
||||||
|
|
||||||
|
assertFalse(
|
||||||
|
model.compilationDependsOnSourceSet(metadataCompilation, iosMain),
|
||||||
|
"Expected metadataCompilation *not* depending on iosMain"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun getCompilations() {
|
||||||
|
val commonMain = createKotlinSourceSet("commonMain")
|
||||||
|
val appleMain = createKotlinSourceSet("appleMain", declaredDependsOnSourceSets = setOf("commonMain"))
|
||||||
|
val macosMain = createKotlinSourceSet("macosMain", declaredDependsOnSourceSets = setOf("appleMain"))
|
||||||
|
|
||||||
|
val metadataCompilation = createKotlinCompilation(defaultSourceSets = setOf(commonMain))
|
||||||
|
val macosMainCompilation = createKotlinCompilation(defaultSourceSets = setOf(macosMain))
|
||||||
|
|
||||||
|
val metadataTarget = createKotlinTarget("metadata", compilations = setOf(metadataCompilation))
|
||||||
|
val macosTarget = createKotlinTarget("macos", compilations = setOf(macosMainCompilation))
|
||||||
|
|
||||||
|
val model = createKotlinMPPGradleModel(
|
||||||
|
sourceSets = setOf(commonMain, appleMain, macosMain),
|
||||||
|
targets = setOf(metadataTarget, macosTarget)
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
setOf(metadataCompilation, macosMainCompilation),
|
||||||
|
model.getCompilations(commonMain),
|
||||||
|
"Expected correct compilations for commonMain"
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
setOf(macosMainCompilation), model.getCompilations(appleMain),
|
||||||
|
"Expected correct compilations for appleMain"
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
setOf(macosMainCompilation), model.getCompilations(macosMain),
|
||||||
|
"Expected correct compilations for macosMain"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,124 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2021 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.gradle
|
||||||
|
|
||||||
|
internal fun createKotlinMPPGradleModel(
|
||||||
|
dependencyMap: Map<KotlinDependencyId, KotlinDependency> = emptyMap(),
|
||||||
|
sourceSets: Set<KotlinSourceSet> = emptySet(),
|
||||||
|
targets: Iterable<KotlinTarget> = emptyList(),
|
||||||
|
extraFeatures: ExtraFeatures = createExtraFeatures(),
|
||||||
|
kotlinNativeHome: String = ""
|
||||||
|
|
||||||
|
): KotlinMPPGradleModelImpl {
|
||||||
|
return KotlinMPPGradleModelImpl(
|
||||||
|
dependencyMap = dependencyMap,
|
||||||
|
sourceSetsByName = sourceSets.associateBy { it.name },
|
||||||
|
targets = targets.toList(),
|
||||||
|
extraFeatures = extraFeatures,
|
||||||
|
kotlinNativeHome = kotlinNativeHome
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun createExtraFeatures(
|
||||||
|
coroutinesState: String? = null,
|
||||||
|
isHmppEnabled: Boolean = false,
|
||||||
|
isNativeDependencyPropagationEnabled: Boolean = false
|
||||||
|
): ExtraFeaturesImpl {
|
||||||
|
return ExtraFeaturesImpl(
|
||||||
|
coroutinesState = coroutinesState,
|
||||||
|
isHMPPEnabled = isHmppEnabled,
|
||||||
|
isNativeDependencyPropagationEnabled = isNativeDependencyPropagationEnabled
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun createKotlinSourceSet(
|
||||||
|
name: String,
|
||||||
|
declaredDependsOnSourceSets: Set<String> = emptySet(),
|
||||||
|
allDependsOnSourceSets: Set<String> = declaredDependsOnSourceSets,
|
||||||
|
platforms: Set<KotlinPlatform> = emptySet(),
|
||||||
|
): KotlinSourceSetImpl = KotlinSourceSetImpl(
|
||||||
|
name = name,
|
||||||
|
languageSettings = KotlinLanguageSettingsImpl(
|
||||||
|
languageVersion = null,
|
||||||
|
apiVersion = null,
|
||||||
|
isProgressiveMode = false,
|
||||||
|
enabledLanguageFeatures = emptySet(),
|
||||||
|
experimentalAnnotationsInUse = emptySet(),
|
||||||
|
compilerPluginArguments = emptyArray(),
|
||||||
|
compilerPluginClasspath = emptySet(),
|
||||||
|
freeCompilerArgs = emptyArray()
|
||||||
|
),
|
||||||
|
sourceDirs = emptySet(),
|
||||||
|
resourceDirs = emptySet(),
|
||||||
|
dependencies = emptyArray(),
|
||||||
|
declaredDependsOnSourceSets = declaredDependsOnSourceSets,
|
||||||
|
allDependsOnSourceSets = allDependsOnSourceSets,
|
||||||
|
defaultActualPlatforms = KotlinPlatformContainerImpl().apply { pushPlatforms(platforms) },
|
||||||
|
)
|
||||||
|
|
||||||
|
internal fun createKotlinCompilation(
|
||||||
|
name: String = "main",
|
||||||
|
defaultSourceSets: Set<KotlinSourceSet> = emptySet(),
|
||||||
|
allSourceSets: Set<KotlinSourceSet> = emptySet(),
|
||||||
|
dependencies: Iterable<KotlinDependencyId> = emptyList(),
|
||||||
|
output: KotlinCompilationOutput = createKotlinCompilationOutput(),
|
||||||
|
arguments: KotlinCompilationArguments = createKotlinCompilationArguments(),
|
||||||
|
dependencyClasspath: Iterable<String> = emptyList(),
|
||||||
|
kotlinTaskProperties: KotlinTaskProperties = createKotlinTaskProperties(),
|
||||||
|
nativeExtensions: KotlinNativeCompilationExtensions? = null
|
||||||
|
|
||||||
|
): KotlinCompilationImpl {
|
||||||
|
return KotlinCompilationImpl(
|
||||||
|
name = name,
|
||||||
|
declaredSourceSets = defaultSourceSets,
|
||||||
|
allSourceSets = allSourceSets,
|
||||||
|
dependencies = dependencies.toList().toTypedArray(),
|
||||||
|
output = output,
|
||||||
|
arguments = arguments,
|
||||||
|
dependencyClasspath = dependencyClasspath.toList().toTypedArray(),
|
||||||
|
kotlinTaskProperties = kotlinTaskProperties,
|
||||||
|
nativeExtensions = nativeExtensions
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun createKotlinCompilationOutput(): KotlinCompilationOutputImpl {
|
||||||
|
return KotlinCompilationOutputImpl(
|
||||||
|
classesDirs = emptySet(),
|
||||||
|
effectiveClassesDir = null,
|
||||||
|
resourcesDir = null
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun createKotlinCompilationArguments(): KotlinCompilationArgumentsImpl {
|
||||||
|
return KotlinCompilationArgumentsImpl(
|
||||||
|
defaultArguments = emptyArray(),
|
||||||
|
currentArguments = emptyArray()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun createKotlinTaskProperties(): KotlinTaskPropertiesImpl {
|
||||||
|
return KotlinTaskPropertiesImpl(
|
||||||
|
null, null, null, null
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun createKotlinTarget(
|
||||||
|
name: String,
|
||||||
|
platform: KotlinPlatform = KotlinPlatform.COMMON,
|
||||||
|
compilations: Iterable<KotlinCompilation> = emptyList()
|
||||||
|
): KotlinTargetImpl {
|
||||||
|
return KotlinTargetImpl(
|
||||||
|
name = name,
|
||||||
|
presetName = null,
|
||||||
|
disambiguationClassifier = null,
|
||||||
|
platform = platform,
|
||||||
|
compilations = compilations.toList(),
|
||||||
|
testRunTasks = emptyList(),
|
||||||
|
nativeMainRunTasks = emptyList(),
|
||||||
|
jar = null,
|
||||||
|
konanArtifacts = emptyList()
|
||||||
|
)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user