diff --git a/jps/jps-plugin/src/org/jetbrains/kotlin/jps/build/KotlinChunk.kt b/jps/jps-plugin/src/org/jetbrains/kotlin/jps/build/KotlinChunk.kt index bfea0d372ec..ba26d010214 100644 --- a/jps/jps-plugin/src/org/jetbrains/kotlin/jps/build/KotlinChunk.kt +++ b/jps/jps-plugin/src/org/jetbrains/kotlin/jps/build/KotlinChunk.kt @@ -6,9 +6,11 @@ package org.jetbrains.kotlin.jps.build import org.jetbrains.jps.incremental.ModuleBuildTarget +import org.jetbrains.jps.model.java.JpsJavaClasspathKind +import org.jetbrains.jps.model.java.JpsJavaExtensionService +import org.jetbrains.jps.model.module.JpsModuleDependency import org.jetbrains.kotlin.config.ApiVersion import org.jetbrains.kotlin.config.LanguageVersion -import org.jetbrains.kotlin.config.VersionView import org.jetbrains.kotlin.jps.incremental.CacheStatus import org.jetbrains.kotlin.jps.incremental.JpsIncrementalCache import org.jetbrains.kotlin.jps.incremental.getKotlinCache @@ -24,16 +26,73 @@ import kotlin.io.path.writeText class KotlinChunk internal constructor(val context: KotlinCompileContext, val targets: List>) { val containsTests = targets.any { it.isTests } - lateinit var dependencies: List - // Should be initialized only in KotlinChunk.calculateChunkDependencies - internal set + private var areChunkDependenciesCalculated: Boolean = false - lateinit var dependent: List - // Should be initialized only in KotlinChunk.calculateChunkDependencies - internal set + /** + * Dependencies of all "modules" inside the chunk collected into single [List]. + * (Any of those dependencies may target "modules" outside current chunk) + * + * It would be more correct to say [KotlinModuleBuildTarget] instead of "module" + * but word "module" makes it easier to understand this doc + */ + private val _dependencies: MutableList = mutableListOf() + val dependencies: List + get() = _dependencies.takeIf { areChunkDependenciesCalculated } ?: error("Chunk dependencies are not calculated yet") - // used only during dependency calculation - internal var _dependent: MutableSet? = mutableSetOf() + /** + * Dependents of all "modules" inside the chunk collected into single [List]. + * (Any of those dependants may target "modules" outside current chunk) + * + * It would be more correct to say [KotlinModuleBuildTarget] instead of "module" + * but word "module" makes it easier to understand this doc + */ + private val _dependents: MutableList = mutableListOf() + val dependents: List + get() = _dependents.takeIf { areChunkDependenciesCalculated } ?: error("Chunk dependents are not calculated yet") + + companion object { + fun calculateChunkDependencies( + chunks: List, + byJpsModuleBuildTarget: MutableMap> + ) { + chunks.forEach { chunk -> + check(!chunk.areChunkDependenciesCalculated) { "Chunk dependencies should be calculated only once" } + chunk.areChunkDependenciesCalculated = true + } + chunks.forEach { chunk -> + chunk._dependencies.addAll( + chunk.targets.asSequence() + .flatMap { calculateTargetDependencies(it, byJpsModuleBuildTarget) } + .distinct() // TODO does this "distinct" really needed? + .toList() + ) + + chunk._dependencies.forEach { dependency -> + dependency.target.chunk._dependents.add(dependency) + } + } + } + + private fun calculateTargetDependencies( + srcTarget: KotlinModuleBuildTarget<*>, + byJpsModuleBuildTarget: MutableMap> + ): List { + val compileClasspathKind = JpsJavaClasspathKind.compile(srcTarget.isTests) + + val jpsJavaExtensionService = JpsJavaExtensionService.getInstance() + return srcTarget.module.dependenciesList.dependencies.asSequence() + .filterIsInstance() + .mapNotNull { dep -> + val extension = jpsJavaExtensionService.getDependencyExtension(dep) + ?.takeIf { it.scope.isIncludedIn(compileClasspathKind) } + ?: return@mapNotNull null + dep.module + ?.let { byJpsModuleBuildTarget[ModuleBuildTarget(it, srcTarget.isTests)] } + ?.let { KotlinModuleBuildTarget.Dependency(srcTarget, it, extension.isExported) } + } + .toList() + } + } val representativeTarget get() = targets.first() @@ -109,7 +168,7 @@ class KotlinChunk internal constructor(val context: KotlinCompileContext, val ta } fun collectDependentChunksRecursivelyExportedOnly(result: MutableSet = mutableSetOf()) { - dependent.forEach { + dependents.forEach { if (result.add(it.src.chunk)) { if (it.exported) { it.src.chunk.collectDependentChunksRecursivelyExportedOnly(result) diff --git a/jps/jps-plugin/src/org/jetbrains/kotlin/jps/targets/KotlinTargetsIndex.kt b/jps/jps-plugin/src/org/jetbrains/kotlin/jps/targets/KotlinTargetsIndex.kt index abd9ab1457b..ae9c62d1bed 100644 --- a/jps/jps-plugin/src/org/jetbrains/kotlin/jps/targets/KotlinTargetsIndex.kt +++ b/jps/jps-plugin/src/org/jetbrains/kotlin/jps/targets/KotlinTargetsIndex.kt @@ -54,7 +54,7 @@ internal class KotlinTargetsIndexBuilder internal constructor( } } - calculateChunkDependencies() + KotlinChunk.calculateChunkDependencies(chunks, byJpsModuleBuildTarget) } KotlinBuilder.LOG.info("KotlinTargetsIndex created in $time ms") @@ -66,43 +66,6 @@ internal class KotlinTargetsIndexBuilder internal constructor( ) } - private fun calculateChunkDependencies() { - chunks.forEach { chunk -> - val dependencies = mutableSetOf() - - chunk.targets.forEach { - dependencies.addAll(calculateTargetDependencies(it)) - } - - chunk.dependencies = dependencies.toList() - chunk.dependencies.forEach { dependency -> - dependency.target.chunk._dependent!!.add(dependency) - } - } - - chunks.forEach { - it.dependent = it._dependent!!.toList() - it._dependent = null - } - } - - private fun calculateTargetDependencies(srcTarget: KotlinModuleBuildTarget<*>): List { - val compileClasspathKind = JpsJavaClasspathKind.compile(srcTarget.isTests) - - val jpsJavaExtensionService = JpsJavaExtensionService.getInstance() - return srcTarget.module.dependenciesList.dependencies.asSequence() - .filterIsInstance() - .mapNotNull { dep -> - val extension = jpsJavaExtensionService.getDependencyExtension(dep) - ?.takeIf { it.scope.isIncludedIn(compileClasspathKind) } - ?: return@mapNotNull null - dep.module - ?.let { byJpsModuleBuildTarget[ModuleBuildTarget(it, srcTarget.isTests)] } - ?.let { KotlinModuleBuildTarget.Dependency(srcTarget, it, extension.isExported) } - } - .toList() - } - private fun ensureLoaded(target: ModuleBuildTarget): KotlinModuleBuildTarget<*> { return byJpsModuleBuildTarget.computeIfAbsent(target) { val platform = target.module.platform?.idePlatformKind ?: DefaultIdeTargetPlatformKindProvider.defaultPlatform.idePlatformKind