[Commonizer] More fine-grained control of commonized module dependencies

- Reduce usage of 'isUnderStandardKotlinPackages' check in commonizer source code
- Rely on common module dependencies supplied via commonizer Parameters which not only
  Kotlin standard library but may also include common fragments of other libraries
This commit is contained in:
Dmitriy Dolovov
2020-11-26 17:19:03 +03:00
parent 9d749feb64
commit b0ff3e7e5e
23 changed files with 479 additions and 470 deletions
@@ -16,16 +16,13 @@ class Parameters(
val targetProviders: List<TargetProvider> get() = _targetProviders.values.toList() val targetProviders: List<TargetProvider> get() = _targetProviders.values.toList()
// only for test purposes // common module dependencies (ex: Kotlin stdlib)
internal var extendedLookupForBuiltInsClassifiers: Boolean = false var dependeeModulesProvider: ModulesProvider? = null
set(value) { set(value) {
check(!field || value) check(field == null)
field = value field = value
} }
// only for test purposes
internal var commonModulesProvider: ModulesProvider? = null
fun addTarget(targetProvider: TargetProvider): Parameters { fun addTarget(targetProvider: TargetProvider): Parameters {
require(targetProvider.target !in _targetProviders) { "Target ${targetProvider.target} is already added" } require(targetProvider.target !in _targetProviders) { "Target ${targetProvider.target} is already added" }
_targetProviders[targetProvider.target] = targetProvider _targetProviders[targetProvider.target] = targetProvider
@@ -14,7 +14,8 @@ class TargetProvider(
val target: InputTarget, val target: InputTarget,
val builtInsClass: Class<out KotlinBuiltIns>, val builtInsClass: Class<out KotlinBuiltIns>,
val builtInsProvider: BuiltInsProvider, val builtInsProvider: BuiltInsProvider,
val modulesProvider: ModulesProvider val modulesProvider: ModulesProvider,
val dependeeModulesProvider: ModulesProvider?
) )
interface BuiltInsProvider { interface BuiltInsProvider {
@@ -40,5 +41,5 @@ interface ModulesProvider {
) )
fun loadModuleInfos(): Map<String, ModuleInfo> fun loadModuleInfos(): Map<String, ModuleInfo>
fun loadModules(): Map<String, ModuleDescriptor> fun loadModules(dependencies: Collection<ModuleDescriptor>): Map<String, ModuleDescriptor>
} }
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.descriptors.commonizer.builder
import gnu.trove.THashMap import gnu.trove.THashMap
import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.commonizer.Parameters import org.jetbrains.kotlin.descriptors.commonizer.Parameters
import org.jetbrains.kotlin.descriptors.commonizer.Target import org.jetbrains.kotlin.descriptors.commonizer.Target
@@ -133,68 +134,84 @@ class TargetDeclarationsBuilderComponents(
val storageManager: StorageManager, val storageManager: StorageManager,
val target: Target, val target: Target,
val builtIns: KotlinBuiltIns, val builtIns: KotlinBuiltIns,
val lazyModulesLookupTable: NotNullLazyValue<MutableMap<String, ModuleDescriptor?>>, val lazyClassifierLookupTable: NotNullLazyValue<LazyClassifierLookupTable>,
val isCommon: Boolean,
val index: Int, val index: Int,
private val cache: DeclarationsBuilderCache private val cache: DeclarationsBuilderCache
) { ) {
// only for test purposes
internal var extendedLookupForBuiltInsClassifiers: Boolean = false
// N.B. this function may create new classifiers for types from Kotlin/Native forward declarations packages // N.B. this function may create new classifiers for types from Kotlin/Native forward declarations packages
fun findClassOrTypeAlias(classId: ClassId): ClassifierDescriptorWithTypeParameters { fun findClassOrTypeAlias(classifierId: ClassId): ClassifierDescriptorWithTypeParameters {
return when { return if (classifierId.packageFqName.isUnderKotlinNativeSyntheticPackages) {
classId.packageFqName.isUnderStandardKotlinPackages -> { // that's a synthetic Kotlin/Native classifier that was exported as forward declaration in one or more modules,
// look up for classifier in built-ins module: // but did not match any existing class or typealias
val builtInsModule = builtIns.builtInsModule cache.getOrPutForwardDeclarationsModule(index) {
// N.B. forward declarations module is created only on demand
// TODO: this works fine for Native as far as built-ins module contains full Native stdlib, but this is not enough for JVM and JS createKotlinNativeForwardDeclarationsModule(
val classifier = builtInsModule.resolveClassOrTypeAlias(classId) storageManager = storageManager,
if (classifier != null) builtIns = builtIns
return classifier )
}.resolveClassOrTypeAlias(classifierId)
if (extendedLookupForBuiltInsClassifiers) { ?: error("Classifier ${classifierId.asString()} not found for $target")
return findOriginalClassOrTypeAlias(classId) } else {
?: error("Classifier ${classId.asString()} not found neither in built-ins module $builtInsModule nor in original modules for $target") cache.getCachedClassifier(classifierId, index) // first, look up in created descriptors cache
} ?: lazyClassifierLookupTable().resolveClassOrTypeAlias(classifierId) // then, attempt to load the original classifier
?: error("Classifier ${classifierId.asString()} not found for $target")
error("Classifier ${classId.asString()} not found in built-ins module $builtInsModule for $target")
}
classId.packageFqName.isUnderKotlinNativeSyntheticPackages -> {
// that's a synthetic Kotlin/Native classifier that was exported as forward declaration in one or more modules,
// but did not match any existing class or typealias
cache.getOrPutForwardDeclarationsModule(index) {
// N.B. forward declarations module is created only on demand
createKotlinNativeForwardDeclarationsModule(
storageManager = storageManager,
builtIns = builtIns
)
}.resolveClassOrTypeAlias(classId)
?: error("Classifier ${classId.asString()} not found for $target")
}
else -> {
cache.getCachedClassifier(classId, index) // first, look up in created descriptors cache
?: findOriginalClassOrTypeAlias(classId) // then, attempt to load the original classifier
?: error("Classifier ${classId.asString()} not found for $target")
}
} }
} }
}
private fun findOriginalClassOrTypeAlias(classId: ClassId): ClassifierDescriptorWithTypeParameters? { class LazyClassifierLookupTable(lazyModules: Map<String, List<ModuleDescriptor>>) {
if (classId.packageFqName.isRoot) private val table = THashMap<String, List<ModuleDescriptor>>()
return null private val allModules: Collection<ModuleDescriptor>
// first, guess containing module and look up in it init {
val classifier = lazyModulesLookupTable() // add "module:" prefix for each key representing a module name, not a package name
.guessModuleByPackageFqName(classId.packageFqName) lazyModules.forEach { (moduleName, modules) -> table[MODULE_NAME_PREFIX + moduleName.toLowerCase()] = modules }
?.resolveClassOrTypeAlias(classId) allModules = lazyModules.values.flatten()
}
// if failed, then look up though all modules fun resolveClassOrTypeAlias(classifierId: ClassId): ClassifierDescriptorWithTypeParameters? {
return classifier if (table.isEmpty) return null
?: lazyModulesLookupTable().values
.asSequence() val packageFqName = classifierId.packageFqName
.mapNotNull { it?.resolveClassOrTypeAlias(classId) } if (packageFqName.isRoot) return null
.firstOrNull()
val packageFqNameRaw = packageFqName.asString()
table[packageFqNameRaw]?.let { modules ->
for (module in modules)
return module.resolveClassOrTypeAlias(classifierId) ?: continue
}
val packageFqNameFragments = packageFqNameRaw.split('.')
val moduleNameForLookup = when (packageFqNameFragments[0]) {
"kotlin" -> "kotlin"
"platform" -> if (packageFqNameFragments.size == 2) packageFqNameFragments[1].toLowerCase() else null
else -> null
}
// try to find the classifier by guessing its container module
if (moduleNameForLookup != null) {
table[MODULE_NAME_PREFIX + moduleNameForLookup]?.let { modules ->
for (module in modules) {
val classifier = module.resolveClassOrTypeAlias(classifierId) ?: continue
table[packageFqNameRaw] = modules // cache to speed-up the further look-ups
return classifier
}
}
}
// last resort: brute force
for (module in allModules) {
val classifier = module.resolveClassOrTypeAlias(classifierId) ?: continue
table[packageFqNameRaw] = listOf(module) // cache to speed-up the further look-ups
return classifier
}
table[packageFqNameRaw] = null // cache to speed-up the further look-ups
return null
}
companion object {
private const val MODULE_NAME_PREFIX = "module:"
} }
} }
@@ -204,6 +221,10 @@ fun CirRootNode.createGlobalBuilderComponents(
): GlobalDeclarationsBuilderComponents { ): GlobalDeclarationsBuilderComponents {
val cache = DeclarationsBuilderCache(dimension) val cache = DeclarationsBuilderCache(dimension)
val lazyCommonDependeeModules = storageManager.createLazyValue {
parameters.dependeeModulesProvider?.loadModules(emptyList()).orEmpty()
}
val targetContexts = (0 until dimension).map { index -> val targetContexts = (0 until dimension).map { index ->
val isCommon = index == indexOfCommon val isCommon = index == indexOfCommon
@@ -216,24 +237,38 @@ fun CirRootNode.createGlobalBuilderComponents(
} }
val lazyModulesLookupTable = storageManager.createLazyValue { val lazyModulesLookupTable = storageManager.createLazyValue {
val source = if (isCommon) val result = mutableMapOf<String, MutableList<ModuleDescriptor>>()
parameters.commonModulesProvider?.loadModules() ?: emptyMap()
else val commonDependeeModules: Map<String, ModuleDescriptor> = lazyCommonDependeeModules()
parameters.targetProviders[index].modulesProvider.loadModules()
THashMap(source) if (!isCommon) {
with(parameters.targetProviders[index]) {
val targetDependeeModules: Map<String, ModuleDescriptor> =
dependeeModulesProvider?.loadModules(commonDependeeModules.values).orEmpty()
val targetModules: Map<String, ModuleDescriptor> =
modulesProvider.loadModules(targetDependeeModules.values + commonDependeeModules.values)
targetModules.forEach { (moduleName, module) -> result.getOrPut(moduleName) { mutableListOf() } += module }
targetDependeeModules.forEach { (moduleName, module) -> result.getOrPut(moduleName) { mutableListOf() } += module }
}
}
commonDependeeModules.forEach { (moduleName, module) -> result.getOrPut(moduleName) { mutableListOf() } += module }
result.getOrPut(StandardNames.BUILT_INS_PACKAGE_FQ_NAME.asString()) { mutableListOf() } += builtIns.builtInsModule
LazyClassifierLookupTable(result)
} }
TargetDeclarationsBuilderComponents( TargetDeclarationsBuilderComponents(
storageManager = storageManager, storageManager = storageManager,
target = root.target, target = root.target,
builtIns = builtIns, builtIns = builtIns,
lazyModulesLookupTable = lazyModulesLookupTable, lazyClassifierLookupTable = lazyModulesLookupTable,
isCommon = isCommon,
index = index, index = index,
cache = cache cache = cache
).also { )
it.extendedLookupForBuiltInsClassifiers = parameters.extendedLookupForBuiltInsClassifiers
}
} }
return GlobalDeclarationsBuilderComponents(storageManager, targetContexts, cache, parameters.statsCollector) return GlobalDeclarationsBuilderComponents(storageManager, targetContexts, cache, parameters.statsCollector)
@@ -55,13 +55,13 @@ class NativeDistributionCommonizer(
clockMark.reset() clockMark.reset()
// 1. load libraries // 1. load libraries
val librariesByTargets = loadLibraries() val allLibraries = loadLibraries()
// 2. run commonization // 2. run commonization
val result = commonize(librariesByTargets) val result = commonize(allLibraries)
// 3. write new libraries // 3. write new libraries
saveModules(librariesByTargets, result) saveModules(allLibraries, result)
logTotal() logTotal()
} }
@@ -86,29 +86,29 @@ class NativeDistributionCommonizer(
private fun logTotal() = logger.log("TOTAL: ${clockMark.elapsedSinceStart()}") private fun logTotal() = logger.log("TOTAL: ${clockMark.elapsedSinceStart()}")
private fun loadLibraries(): Map<InputTarget, NativeDistributionLibraries> { private fun loadLibraries(): AllNativeLibraries {
val stdlibPath = repository.resolve(konanCommonLibraryPath(KONAN_STDLIB_NAME)) val stdlibPath = repository.resolve(konanCommonLibraryPath(KONAN_STDLIB_NAME))
val stdlib = loadLibrary(stdlibPath) val stdlib = NativeLibrary(loadLibrary(stdlibPath))
val result = targets.associate { target -> val librariesByTargets = targets.associate { target ->
val leafTarget = InputTarget(target.name, target) val leafTarget = InputTarget(target.name, target)
val platformLibs = leafTarget.platformLibrariesSource val platformLibs = leafTarget.platformLibrariesSource
.takeIf { it.isDirectory } .takeIf { it.isDirectory }
?.listFiles() ?.listFiles()
?.takeIf { it.isNotEmpty() } ?.takeIf { it.isNotEmpty() }
?.map { loadLibrary(it) } ?.map { NativeLibrary(loadLibrary(it)) }
.orEmpty() .orEmpty()
if (platformLibs.isEmpty()) if (platformLibs.isEmpty())
logger.warning("No platform libraries found for target $target. This target will be excluded from commonization.") logger.warning("No platform libraries found for target $target. This target will be excluded from commonization.")
leafTarget to NativeDistributionLibraries(stdlib, platformLibs) leafTarget to NativeLibrariesToCommonize(platformLibs)
} }
logProgress("Read lazy (uninitialized) libraries") logProgress("Read lazy (uninitialized) libraries")
return result return AllNativeLibraries(stdlib, librariesByTargets)
} }
private fun loadLibrary(location: File): KotlinLibrary { private fun loadLibrary(location: File): KotlinLibrary {
@@ -136,7 +136,7 @@ class NativeDistributionCommonizer(
return library return library
} }
private fun commonize(librariesByTargets: Map<InputTarget, NativeDistributionLibraries>): Result { private fun commonize(allLibraries: AllNativeLibraries): Result {
val statsCollector = when (statsType) { val statsCollector = when (statsType) {
RAW -> RawStatsCollector(targets, FileStatsOutput(destination, "raw")) RAW -> RawStatsCollector(targets, FileStatsOutput(destination, "raw"))
AGGREGATED -> AggregatedStatsCollector(targets, FileStatsOutput(destination, "aggregated")) AGGREGATED -> AggregatedStatsCollector(targets, FileStatsOutput(destination, "aggregated"))
@@ -144,20 +144,23 @@ class NativeDistributionCommonizer(
} }
statsCollector.use { statsCollector.use {
val parameters = Parameters(statsCollector, ::logProgress).apply { val parameters = Parameters(statsCollector, ::logProgress).apply {
librariesByTargets.forEach { (target, libraries) -> val storageManager = LockBasedStorageManager("Commonized modules")
if (libraries.platformLibs.isEmpty()) return@forEach
val provider = NativeDistributionModulesProvider( val stdlibProvider = NativeDistributionStdlibProvider(storageManager, allLibraries.stdlib)
storageManager = LockBasedStorageManager("Target $target"), dependeeModulesProvider = stdlibProvider
libraries = libraries
) allLibraries.librariesByTargets.forEach { (target, librariesToCommonize) ->
if (librariesToCommonize.libraries.isEmpty()) return@forEach
val modulesProvider = NativeDistributionModulesProvider(storageManager, librariesToCommonize)
addTarget( addTarget(
TargetProvider( TargetProvider(
target = target, target = target,
builtInsClass = KonanBuiltIns::class.java, builtInsClass = KonanBuiltIns::class.java,
builtInsProvider = provider, builtInsProvider = stdlibProvider,
modulesProvider = provider modulesProvider = modulesProvider,
dependeeModulesProvider = null // stdlib is already set as common dependency
) )
) )
} }
@@ -167,10 +170,7 @@ class NativeDistributionCommonizer(
} }
} }
private fun saveModules( private fun saveModules(originalLibraries: AllNativeLibraries, result: Result) {
originalLibrariesByTargets: Map<InputTarget, NativeDistributionLibraries>,
result: Result
) {
// optimization: stdlib and endorsed libraries effectively remain the same across all Kotlin/Native targets, // optimization: stdlib and endorsed libraries effectively remain the same across all Kotlin/Native targets,
// so they can be just copied to the new destination without running serializer // so they can be just copied to the new destination without running serializer
copyCommonStandardLibraries() copyCommonStandardLibraries()
@@ -180,8 +180,8 @@ class NativeDistributionCommonizer(
// It may happen that all targets to be commonized (or at least all but one target) miss platform libraries. // It may happen that all targets to be commonized (or at least all but one target) miss platform libraries.
// In such case commonizer will do nothing and return a special result value 'NothingToCommonize'. // In such case commonizer will do nothing and return a special result value 'NothingToCommonize'.
// So, let's just copy platform libraries from the target where they are to the new destination. // So, let's just copy platform libraries from the target where they are to the new destination.
originalLibrariesByTargets.forEach { (target, libraries) -> originalLibraries.librariesByTargets.forEach { (target, librariesToCommonize) ->
copyTargetAsIs(target, libraries.platformLibs.size) copyTargetAsIs(target, librariesToCommonize.libraries.size)
} }
} }
@@ -194,11 +194,11 @@ class NativeDistributionCommonizer(
) )
// 'targetsToCopy' are some targets with empty set of platform libraries // 'targetsToCopy' are some targets with empty set of platform libraries
val targetsToCopy = originalLibrariesByTargets.keys - result.leafTargets val targetsToCopy = originalLibraries.librariesByTargets.keys - result.leafTargets
if (targetsToCopy.isNotEmpty()) { if (targetsToCopy.isNotEmpty()) {
targetsToCopy.forEach { target -> targetsToCopy.forEach { target ->
val libraries = originalLibrariesByTargets.getValue(target) val librariesToCommonize = originalLibraries.librariesByTargets.getValue(target)
copyTargetAsIs(target, libraries.platformLibs.size) copyTargetAsIs(target, librariesToCommonize.libraries.size)
} }
} }
@@ -214,11 +214,11 @@ class NativeDistributionCommonizer(
val starredTarget: String? val starredTarget: String?
when (target) { when (target) {
is InputTarget -> { is InputTarget -> {
manifestProvider = originalLibrariesByTargets.getValue(target) manifestProvider = originalLibraries.librariesByTargets.getValue(target)
starredTarget = target.name starredTarget = target.name
} }
is OutputTarget -> { is OutputTarget -> {
manifestProvider = CommonNativeManifestDataProvider(originalLibrariesByTargets.values) manifestProvider = CommonNativeManifestDataProvider(originalLibraries.librariesByTargets.values)
starredTarget = null starredTarget = null
} }
} }
@@ -5,38 +5,26 @@
package org.jetbrains.kotlin.descriptors.commonizer.konan package org.jetbrains.kotlin.descriptors.commonizer.konan
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl
import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.commonizer.BuiltInsProvider
import org.jetbrains.kotlin.descriptors.commonizer.ModulesProvider import org.jetbrains.kotlin.descriptors.commonizer.ModulesProvider
import org.jetbrains.kotlin.descriptors.commonizer.ModulesProvider.CInteropModuleAttributes import org.jetbrains.kotlin.descriptors.commonizer.ModulesProvider.CInteropModuleAttributes
import org.jetbrains.kotlin.descriptors.commonizer.ModulesProvider.ModuleInfo import org.jetbrains.kotlin.descriptors.commonizer.ModulesProvider.ModuleInfo
import org.jetbrains.kotlin.descriptors.commonizer.utils.NativeFactories import org.jetbrains.kotlin.descriptors.commonizer.utils.NativeFactories
import org.jetbrains.kotlin.descriptors.commonizer.utils.createKotlinNativeForwardDeclarationsModule import org.jetbrains.kotlin.descriptors.commonizer.utils.createKotlinNativeForwardDeclarationsModule
import org.jetbrains.kotlin.descriptors.commonizer.utils.strip
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
import org.jetbrains.kotlin.incremental.components.LookupTracker import org.jetbrains.kotlin.incremental.components.LookupTracker
import org.jetbrains.kotlin.konan.library.KONAN_STDLIB_NAME
import org.jetbrains.kotlin.storage.StorageManager import org.jetbrains.kotlin.storage.StorageManager
import org.jetbrains.kotlin.utils.addIfNotNull
import java.io.File import java.io.File
internal class NativeDistributionModulesProvider( internal class NativeDistributionModulesProvider(
private val storageManager: StorageManager, private val storageManager: StorageManager,
private val libraries: NativeDistributionLibraries private val librariesToCommonize: NativeLibrariesToCommonize
) : BuiltInsProvider, ModulesProvider { ) : ModulesProvider {
override fun loadBuiltIns(): KotlinBuiltIns {
val stdlib = NativeFactories.DefaultDeserializedDescriptorFactory.createDescriptorAndNewBuiltIns(
library = libraries.stdlib.library,
languageVersionSettings = LanguageVersionSettingsImpl.DEFAULT,
storageManager = storageManager,
packageAccessHandler = null
)
stdlib.setDependencies(listOf(stdlib))
return stdlib.builtIns
}
override fun loadModuleInfos(): Map<String, ModuleInfo> { override fun loadModuleInfos(): Map<String, ModuleInfo> {
return libraries.platformLibs.associate { library -> return librariesToCommonize.libraries.associate { library ->
val manifestData = library.manifestData val manifestData = library.manifestData
val name = manifestData.uniqueName val name = manifestData.uniqueName
@@ -54,11 +42,18 @@ internal class NativeDistributionModulesProvider(
} }
} }
override fun loadModules(): Map<String, ModuleDescriptor> { override fun loadModules(dependencies: Collection<ModuleDescriptor>): Map<String, ModuleDescriptor> {
val builtIns = loadBuiltIns() check(dependencies.isNotEmpty()) { "At least Kotlin/Native stdlib should be provided" }
val stdlib = builtIns.builtInsModule
val platformModulesMap = libraries.platformLibs.associate { library -> val dependenciesMap = mutableMapOf<String, MutableList<ModuleDescriptorImpl>>()
dependencies.forEach { dependency ->
val name = dependency.name.strip()
dependenciesMap.getOrPut(name) { mutableListOf() } += dependency as ModuleDescriptorImpl
}
val builtIns = dependencies.first().builtIns
val platformModulesMap = librariesToCommonize.libraries.associate { library ->
val name = library.manifestData.uniqueName val name = library.manifestData.uniqueName
val module = NativeFactories.DefaultDeserializedDescriptorFactory.createDescriptorOptionalBuiltIns( val module = NativeFactories.DefaultDeserializedDescriptorFactory.createDescriptorOptionalBuiltIns(
library = library.library, library = library.library,
@@ -78,11 +73,17 @@ internal class NativeDistributionModulesProvider(
) )
platformModulesMap.forEach { (name, module) -> platformModulesMap.forEach { (name, module) ->
val dependencies = libraries.getManifest(name) val moduleDependencies = mutableListOf<ModuleDescriptorImpl>()
.dependencies moduleDependencies += module
.map { if (it == KONAN_STDLIB_NAME) stdlib else platformModulesMap.getValue(it) }
module.setDependencies(listOf(module) + dependencies + forwardDeclarations) librariesToCommonize.getManifest(name).dependencies.forEach {
moduleDependencies.addIfNotNull(platformModulesMap[it])
moduleDependencies += dependenciesMap[it].orEmpty()
}
moduleDependencies += forwardDeclarations
module.setDependencies(moduleDependencies)
} }
return platformModulesMap return platformModulesMap
@@ -0,0 +1,46 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.descriptors.commonizer.konan
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.commonizer.BuiltInsProvider
import org.jetbrains.kotlin.descriptors.commonizer.ModulesProvider
import org.jetbrains.kotlin.descriptors.commonizer.ModulesProvider.ModuleInfo
import org.jetbrains.kotlin.descriptors.commonizer.utils.NativeFactories
import org.jetbrains.kotlin.konan.library.KONAN_STDLIB_NAME
import org.jetbrains.kotlin.storage.StorageManager
import java.io.File
internal class NativeDistributionStdlibProvider(
private val storageManager: StorageManager,
private val stdlib: NativeLibrary
) : BuiltInsProvider, ModulesProvider {
private val moduleInfo = ModuleInfo(
name = KONAN_STDLIB_NAME,
originalLocation = File(stdlib.library.libraryFile.absolutePath),
cInteropAttributes = null
)
override fun loadBuiltIns(): KotlinBuiltIns = loadStdlibModule().builtIns
override fun loadModuleInfos(): Map<String, ModuleInfo> = mapOf(KONAN_STDLIB_NAME to moduleInfo)
override fun loadModules(dependencies: Collection<ModuleDescriptor>): Map<String, ModuleDescriptor> {
check(dependencies.isEmpty())
return mapOf(KONAN_STDLIB_NAME to loadStdlibModule())
}
private fun loadStdlibModule() =
NativeFactories.DefaultDeserializedDescriptorFactory.createDescriptorAndNewBuiltIns(
library = stdlib.library,
languageVersionSettings = LanguageVersionSettingsImpl.DEFAULT,
storageManager = storageManager,
packageAccessHandler = null
).apply {
setDependencies(listOf(this))
}
}
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.descriptors.commonizer.konan package org.jetbrains.kotlin.descriptors.commonizer.konan
import gnu.trove.THashMap import gnu.trove.THashMap
import org.jetbrains.kotlin.descriptors.commonizer.InputTarget
import org.jetbrains.kotlin.library.KotlinLibrary import org.jetbrains.kotlin.library.KotlinLibrary
internal interface NativeManifestDataProvider { internal interface NativeManifestDataProvider {
@@ -13,33 +14,34 @@ internal interface NativeManifestDataProvider {
} }
/** /**
* A separate Kotlin/Native library from the distribution. * A separate Kotlin/Native library.
*/ */
internal class NativeDistributionLibrary( internal class NativeLibrary(
val library: KotlinLibrary val library: KotlinLibrary
) { ) {
val manifestData = NativeSensitiveManifestData.readFrom(library) val manifestData = NativeSensitiveManifestData.readFrom(library)
} }
/** /**
* A collection of Kotlin/Native libraries for a certain Native target + stdlib from the distribution. * A collection of Kotlin/Native libraries for a certain Native target.
*/ */
internal class NativeDistributionLibraries( internal class NativeLibrariesToCommonize(val libraries: List<NativeLibrary>) : NativeManifestDataProvider {
val stdlib: NativeDistributionLibrary,
val platformLibs: List<NativeDistributionLibrary>
) : NativeManifestDataProvider {
constructor(stdlib: KotlinLibrary, platformLibs: List<KotlinLibrary>) : this(
NativeDistributionLibrary(stdlib),
platformLibs.map(::NativeDistributionLibrary)
)
private val manifestIndex: Map<String, NativeSensitiveManifestData> = buildManifestIndex() private val manifestIndex: Map<String, NativeSensitiveManifestData> = buildManifestIndex()
override fun getManifest(libraryName: String) = manifestIndex.getValue(libraryName) override fun getManifest(libraryName: String) = manifestIndex.getValue(libraryName)
companion object {
fun create(libraries: List<KotlinLibrary>) = NativeLibrariesToCommonize(libraries.map(::NativeLibrary))
}
} }
internal class AllNativeLibraries(
val stdlib: NativeLibrary,
val librariesByTargets: Map<InputTarget, NativeLibrariesToCommonize>
)
internal class CommonNativeManifestDataProvider( internal class CommonNativeManifestDataProvider(
libraryGroups: Collection<NativeDistributionLibraries> libraryGroups: Collection<NativeLibrariesToCommonize>
) : NativeManifestDataProvider { ) : NativeManifestDataProvider {
private val manifestIndex: Map<String, NativeSensitiveManifestData> private val manifestIndex: Map<String, NativeSensitiveManifestData>
@@ -66,5 +68,5 @@ internal class CommonNativeManifestDataProvider(
override fun getManifest(libraryName: String) = manifestIndex.getValue(libraryName) override fun getManifest(libraryName: String) = manifestIndex.getValue(libraryName)
} }
private fun NativeDistributionLibraries.buildManifestIndex(): MutableMap<String, NativeSensitiveManifestData> = private fun NativeLibrariesToCommonize.buildManifestIndex(): MutableMap<String, NativeSensitiveManifestData> =
(platformLibs + stdlib).map { it.manifestData }.associateByTo(THashMap()) { it.uniqueName } libraries.map { it.manifestData }.associateByTo(THashMap()) { it.uniqueName }
@@ -59,14 +59,26 @@ class CirTreeMerger(
private val size = parameters.targetProviders.size private val size = parameters.targetProviders.size
fun merge(): CirTreeMergeResult { fun merge(): CirTreeMergeResult {
val result = processRoot()
System.gc()
return result
}
private fun processRoot(): CirTreeMergeResult {
val rootNode: CirRootNode = buildRootNode(storageManager, size) val rootNode: CirRootNode = buildRootNode(storageManager, size)
// remember any exported forward declarations from common fragments of dependee modules
parameters.dependeeModulesProvider?.loadModuleInfos()?.values?.forEach(::processCInteropModuleAttributes)
// load common dependencies
val dependeeModules = parameters.dependeeModulesProvider?.loadModules(emptyList())?.values.orEmpty()
val allModuleInfos: List<Map<String, ModuleInfo>> = parameters.targetProviders.map { it.modulesProvider.loadModuleInfos() } val allModuleInfos: List<Map<String, ModuleInfo>> = parameters.targetProviders.map { it.modulesProvider.loadModuleInfos() }
val commonModuleNames = allModuleInfos.map { it.keys }.reduce { a, b -> a intersect b } val commonModuleNames = allModuleInfos.map { it.keys }.reduce { a, b -> a intersect b }
parameters.targetProviders.forEachIndexed { targetIndex, targetProvider -> parameters.targetProviders.forEachIndexed { targetIndex, targetProvider ->
val commonModuleInfos = allModuleInfos[targetIndex].filterKeys { it in commonModuleNames } val commonModuleInfos = allModuleInfos[targetIndex].filterKeys { it in commonModuleNames }
processTarget(rootNode, targetIndex, targetProvider, commonModuleInfos) processTarget(rootNode, targetIndex, targetProvider, commonModuleInfos, dependeeModules)
parameters.progressLogger?.invoke("Loaded declarations for [${targetProvider.target.name}]") parameters.progressLogger?.invoke("Loaded declarations for [${targetProvider.target.name}]")
System.gc() System.gc()
} }
@@ -87,7 +99,8 @@ class CirTreeMerger(
rootNode: CirRootNode, rootNode: CirRootNode,
targetIndex: Int, targetIndex: Int,
targetProvider: TargetProvider, targetProvider: TargetProvider,
commonModuleInfos: Map<String, ModuleInfo> commonModuleInfos: Map<String, ModuleInfo>,
dependeeModules: Collection<ModuleDescriptor>
) { ) {
rootNode.targetDeclarations[targetIndex] = CirRootFactory.create( rootNode.targetDeclarations[targetIndex] = CirRootFactory.create(
targetProvider.target, targetProvider.target,
@@ -95,7 +108,10 @@ class CirTreeMerger(
targetProvider.builtInsProvider targetProvider.builtInsProvider
) )
val moduleDescriptors: Map<String, ModuleDescriptor> = targetProvider.modulesProvider.loadModules() val targetDependeeModules = targetProvider.dependeeModulesProvider?.loadModules(dependeeModules)?.values.orEmpty()
val allDependeeModules = targetDependeeModules + dependeeModules
val moduleDescriptors: Map<String, ModuleDescriptor> = targetProvider.modulesProvider.loadModules(allDependeeModules)
val modules: MutableMap<Name, CirModuleNode> = rootNode.modules val modules: MutableMap<Name, CirModuleNode> = rootNode.modules
moduleDescriptors.forEach { (name, moduleDescriptor) -> moduleDescriptors.forEach { (name, moduleDescriptor) ->
@@ -110,16 +126,7 @@ class CirTreeMerger(
moduleInfo: ModuleInfo, moduleInfo: ModuleInfo,
moduleDescriptor: ModuleDescriptor moduleDescriptor: ModuleDescriptor
) { ) {
moduleInfo.cInteropAttributes?.let { cInteropAttributes -> processCInteropModuleAttributes(moduleInfo)
val exportForwardDeclarations = cInteropAttributes.exportForwardDeclarations.takeIf { it.isNotEmpty() } ?: return@let
val mainPackageFqName = FqName(cInteropAttributes.mainPackageFqName).intern()
exportForwardDeclarations.forEach { classFqName ->
// Class has synthetic package FQ name (cnames/objcnames). Need to transfer it to the main package.
val className = Name.identifier(classFqName.substringAfterLast('.')).intern()
cache.addExportedForwardDeclaration(internedClassId(mainPackageFqName, className))
}
}
val moduleName: Name = moduleDescriptor.name.intern() val moduleName: Name = moduleDescriptor.name.intern()
val moduleNode: CirModuleNode = modules.getOrPut(moduleName) { val moduleNode: CirModuleNode = modules.getOrPut(moduleName) {
@@ -258,4 +265,16 @@ class CirTreeMerger(
} }
typeAliasNode.targetDeclarations[targetIndex] = CirTypeAliasFactory.create(typeAliasDescriptor) typeAliasNode.targetDeclarations[targetIndex] = CirTypeAliasFactory.create(typeAliasDescriptor)
} }
private fun processCInteropModuleAttributes(moduleInfo: ModuleInfo) {
val cInteropAttributes = moduleInfo.cInteropAttributes ?: return
val exportForwardDeclarations = cInteropAttributes.exportForwardDeclarations.takeIf { it.isNotEmpty() } ?: return
val mainPackageFqName = FqName(cInteropAttributes.mainPackageFqName).intern()
exportForwardDeclarations.forEach { classFqName ->
// Class has synthetic package FQ name (cnames/objcnames). Need to transfer it to the main package.
val className = Name.identifier(classFqName.substringAfterLast('.')).intern()
cache.addExportedForwardDeclaration(internedClassId(mainPackageFqName, className))
}
}
} }
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.descriptors.commonizer.mergedtree package org.jetbrains.kotlin.descriptors.commonizer.mergedtree
import org.jetbrains.kotlin.backend.common.serialization.metadata.impl.ClassifierAliasingPackageFragmentDescriptor
import org.jetbrains.kotlin.backend.common.serialization.metadata.impl.ExportedForwardDeclarationsPackageFragmentDescriptor import org.jetbrains.kotlin.backend.common.serialization.metadata.impl.ExportedForwardDeclarationsPackageFragmentDescriptor
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.commonizer.utils.* import org.jetbrains.kotlin.descriptors.commonizer.utils.*
@@ -69,12 +70,9 @@ internal fun ModuleDescriptor.collectNonEmptyPackageMemberScopes(collector: (FqN
val packageFragmentProvider = this.packageFragmentProvider val packageFragmentProvider = this.packageFragmentProvider
fun recurse(packageFqName: FqName) { fun recurse(packageFqName: FqName) {
if (packageFqName.isUnderStandardKotlinPackages || packageFqName.isUnderKotlinNativeSyntheticPackages)
return
val ownPackageFragments = packageFragmentProvider.packageFragments(packageFqName) val ownPackageFragments = packageFragmentProvider.packageFragments(packageFqName)
val ownPackageMemberScopes = ownPackageFragments.asSequence() val ownPackageMemberScopes = ownPackageFragments.asSequence()
.filter { it !is ExportedForwardDeclarationsPackageFragmentDescriptor } .filter { it !is ExportedForwardDeclarationsPackageFragmentDescriptor && it !is ClassifierAliasingPackageFragmentDescriptor }
.map { it.getMemberScope() } .map { it.getMemberScope() }
.filter { it != MemberScope.Empty } .filter { it != MemberScope.Empty }
.toList(ownPackageFragments.size) .toList(ownPackageFragments.size)
@@ -10,18 +10,17 @@ import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.serialization.konan.impl.ForwardDeclarationsFqNames import org.jetbrains.kotlin.serialization.konan.impl.ForwardDeclarationsFqNames
internal val DEPRECATED_ANNOTATION_FQN: FqName = FqName(Deprecated::class.java.name).intern() internal val DEPRECATED_ANNOTATION_FQN: FqName = FqName(Deprecated::class.java.name).intern()
internal val DEPRECATED_ANNOTATION_CID: ClassId = internedClassId(DEPRECATED_ANNOTATION_FQN) internal val DEPRECATED_ANNOTATION_CID: ClassId = internedClassId(DEPRECATED_ANNOTATION_FQN)
internal val STANDARD_KOTLIN_PACKAGE_FQNS: List<FqName> = listOf( private val STANDARD_KOTLIN_PACKAGES = listOf(
StandardNames.BUILT_INS_PACKAGE_FQ_NAME.intern(), StandardNames.BUILT_INS_PACKAGE_FQ_NAME.asString(),
FqName("kotlinx").intern() "kotlinx"
) )
private val STANDARD_KOTLIN_PACKAGES = STANDARD_KOTLIN_PACKAGE_FQNS.map { it.asString() }
private val KOTLIN_NATIVE_SYNTHETIC_PACKAGES = ForwardDeclarationsFqNames.syntheticPackages private val KOTLIN_NATIVE_SYNTHETIC_PACKAGES = ForwardDeclarationsFqNames.syntheticPackages
.map { fqName -> .map { fqName ->
check(!fqName.isRoot) check(!fqName.isRoot)
@@ -37,6 +36,9 @@ private val OBJC_INTEROP_CALLABLE_ANNOTATIONS = listOf(
"ObjCFactory" "ObjCFactory"
) )
internal fun Name.strip(): String =
asString().removeSurrounding("<", ">")
internal val FqName.isUnderStandardKotlinPackages: Boolean internal val FqName.isUnderStandardKotlinPackages: Boolean
get() = hasAnyPrefix(STANDARD_KOTLIN_PACKAGES) get() = hasAnyPrefix(STANDARD_KOTLIN_PACKAGES)
@@ -5,25 +5,20 @@
package org.jetbrains.kotlin.descriptors.commonizer.utils package org.jetbrains.kotlin.descriptors.commonizer.utils
import org.jetbrains.kotlin.backend.common.serialization.metadata.impl.ExportedForwardDeclarationsPackageFragmentDescriptor
import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.builtins.konan.KonanBuiltIns import org.jetbrains.kotlin.builtins.konan.KonanBuiltIns
import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.ClassifierDescriptorWithTypeParameters
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
import org.jetbrains.kotlin.descriptors.packageFragments
import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.konan.util.KlibMetadataFactories import org.jetbrains.kotlin.konan.util.KlibMetadataFactories
import org.jetbrains.kotlin.library.metadata.NativeTypeTransformer import org.jetbrains.kotlin.library.metadata.NativeTypeTransformer
import org.jetbrains.kotlin.library.metadata.NullFlexibleTypeDeserializer import org.jetbrains.kotlin.library.metadata.NullFlexibleTypeDeserializer
import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.scopes.MemberScope
import org.jetbrains.kotlin.serialization.konan.impl.KlibResolvedModuleDescriptorsFactoryImpl import org.jetbrains.kotlin.serialization.konan.impl.KlibResolvedModuleDescriptorsFactoryImpl
import org.jetbrains.kotlin.storage.StorageManager import org.jetbrains.kotlin.storage.StorageManager
internal val ModuleDescriptor.packageFragmentProvider internal val ModuleDescriptor.packageFragmentProvider: PackageFragmentProvider
get() = (this as ModuleDescriptorImpl).packageFragmentProviderForModuleContentWithoutDependencies get() = (this as ModuleDescriptorImpl).packageFragmentProviderForModuleContentWithoutDependencies
internal fun createKotlinNativeForwardDeclarationsModule( internal fun createKotlinNativeForwardDeclarationsModule(
@@ -42,73 +37,30 @@ internal fun ModuleDescriptor.resolveClassOrTypeAlias(classId: ClassId): Classif
if (relativeClassName.isRoot) if (relativeClassName.isRoot)
return null return null
var memberScope: MemberScope = getPackage(classId.packageFqName).memberScope return packageFragmentProvider.packageFragments(classId.packageFqName).asSequence().mapNotNull { packageFragment ->
var memberScope = packageFragment.getMemberScope()
val classifierName = if ('.' in relativeClassName.asString()) { val classifierName = if ('.' in relativeClassName.asString()) {
// resolve member scope of the nested class // resolve member scope of the nested class
relativeClassName.pathSegments().reduce { first, second -> relativeClassName.pathSegments().reduce { first, second ->
memberScope = (memberScope.getContributedClassifier( memberScope = (memberScope.getContributedClassifier(
first, first,
NoLookupLocation.FOR_ALREADY_TRACKED NoLookupLocation.FOR_ALREADY_TRACKED
) as? ClassDescriptor)?.unsubstitutedMemberScope ?: return null ) as? ClassDescriptor)?.unsubstitutedMemberScope ?: return@mapNotNull null
second second
}
} else {
relativeClassName.shortName()
} }
} else {
relativeClassName.shortName()
}
return memberScope.getContributedClassifier( memberScope.getContributedClassifier(
classifierName, classifierName,
NoLookupLocation.FOR_ALREADY_TRACKED NoLookupLocation.FOR_ALREADY_TRACKED
) as? ClassifierDescriptorWithTypeParameters ) as? ClassifierDescriptorWithTypeParameters
}.firstOrNull()
} }
internal fun MutableMap<String, ModuleDescriptor?>.guessModuleByPackageFqName(packageFqName: FqName): ModuleDescriptor? { internal const val MODULE_NAME_PREFIX = "module:"
if (isEmpty()) return null
val packageFqNameRaw = packageFqName.asString()
if (containsKey(packageFqNameRaw)) {
return this[packageFqNameRaw] // might return null if this is a previously cached result
}
fun guessByEnding(): ModuleDescriptor? {
return entries
.firstOrNull { (name, _) -> name.endsWith(packageFqNameRaw, ignoreCase = true) }
?.value
}
fun guessBySmartEnding(): ModuleDescriptor? {
val packageFqNameFragments = packageFqNameRaw.split('.')
if (packageFqNameFragments.size < 2) return null
return entries.firstOrNull { (name, _) ->
var startIndex = 0
for (fragment in packageFqNameFragments) {
val index = name.indexOf(fragment, startIndex = startIndex, ignoreCase = true)
if (index < startIndex)
return@firstOrNull false
else
startIndex = index + fragment.length
}
true
}?.value
}
val candidate = guessByEnding() ?: guessBySmartEnding()
this[packageFqNameRaw] = candidate // cache to speed-up the further look-ups
return candidate
}
internal val ModuleDescriptor.hasSomethingUnderStandardKotlinPackages: Boolean
get() {
val packageFragmentProvider = packageFragmentProvider
return STANDARD_KOTLIN_PACKAGE_FQNS.any { fqName ->
packageFragmentProvider.packageFragments(fqName).any { packageFragment ->
packageFragment !is ExportedForwardDeclarationsPackageFragmentDescriptor
&& packageFragment.getMemberScope() != MemberScope.Empty
}
}
}
internal val NativeFactories = KlibMetadataFactories(::KonanBuiltIns, NullFlexibleTypeDeserializer, NativeTypeTransformer()) internal val NativeFactories = KlibMetadataFactories(::KonanBuiltIns, NullFlexibleTypeDeserializer, NativeTypeTransformer())
@@ -1,12 +0,0 @@
// this is to avoid missing Kotlin/Native stdlib
package kotlinx.cinterop
// fake classes with the default constructor and no member scope
abstract class CStructVar
class CPointer<T>
@Suppress("FINAL_UPPER_BOUND") class UByteVarOf<T : UByte>
class UByte
// fake typealiases
typealias CArrayPointer<T> = CPointer<T>
typealias UByteVar = UByteVarOf<UByte>
@@ -1,12 +0,0 @@
// this is to avoid missing Kotlin/Native stdlib
package kotlinx.cinterop
// fake classes with the default constructor and no member scope
abstract class CStructVar
class CPointer<T>
@Suppress("FINAL_UPPER_BOUND") class UByteVarOf<T : UByte>
class UByte
// fake typealiases
typealias CArrayPointer<T> = CPointer<T>
typealias UByteVar = UByteVarOf<UByte>
@@ -1,12 +0,0 @@
// this is to avoid missing Kotlin/Native stdlib
package kotlinx.cinterop
// fake classes with the default constructor and no member scope
abstract class CStructVar
class CPointer<T>
@Suppress("FINAL_UPPER_BOUND") class UByteVarOf<T : UByte>
class UByte
// fake typealiases
typealias CArrayPointer<T> = CPointer<T>
typealias UByteVar = UByteVarOf<UByte>
@@ -1,12 +0,0 @@
// this is to avoid missing Kotlin/Native stdlib
package kotlinx.cinterop
// fake classes with the default constructor and no member scope
abstract class CStructVar
class CPointer<T>
@Suppress("FINAL_UPPER_BOUND") class UByteVarOf<T : UByte>
class UByte
// fake typealiases
typealias CArrayPointer<T> = CPointer<T>
typealias UByteVar = UByteVarOf<UByte>
@@ -1,6 +0,0 @@
// this is to avoid missing Kotlin/Native stdlib
package kotlinx.cinterop
@Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER)
@Retention(AnnotationRetention.BINARY)
annotation class ObjCMethod() // fake annotation class without properties
@@ -1,6 +0,0 @@
// this is to avoid missing Kotlin/Native stdlib
package kotlinx.cinterop
@Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER)
@Retention(AnnotationRetention.BINARY)
annotation class ObjCMethod() // fake annotation class without properties
@@ -1,6 +0,0 @@
// this is to avoid missing Kotlin/Native stdlib
package kotlinx.cinterop
@Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER)
@Retention(AnnotationRetention.BINARY)
annotation class ObjCMethod() // fake annotation class without properties
@@ -17,7 +17,7 @@ import org.jetbrains.kotlin.config.CommonConfigurationKeys
import org.jetbrains.kotlin.config.CompilerConfiguration import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.config.languageVersionSettings import org.jetbrains.kotlin.config.languageVersionSettings
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.commonizer.SourceModuleRoot.Companion.COMMON_TARGET_NAME import org.jetbrains.kotlin.descriptors.commonizer.SourceModuleRoot.Companion.SHARED_TARGET_NAME
import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ClassCollector import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ClassCollector
import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.FunctionCollector import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.FunctionCollector
import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.collectMembers import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.collectMembers
@@ -30,10 +30,8 @@ import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.platform.CommonPlatforms import org.jetbrains.kotlin.platform.CommonPlatforms
import org.jetbrains.kotlin.platform.TargetPlatform
import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtPsiFactory import org.jetbrains.kotlin.psi.KtPsiFactory
import org.jetbrains.kotlin.resolve.PlatformDependentAnalyzerServices
import org.jetbrains.kotlin.resolve.scopes.MemberScope import org.jetbrains.kotlin.resolve.scopes.MemberScope
import org.jetbrains.kotlin.test.KotlinTestUtils.* import org.jetbrains.kotlin.test.KotlinTestUtils.*
import org.jetbrains.kotlin.test.testFramework.KtUsefulTestCase import org.jetbrains.kotlin.test.testFramework.KtUsefulTestCase
@@ -70,10 +68,10 @@ abstract class AbstractCommonizationFromSourcesTest : KtUsefulTestCase() {
val result: Result = runCommonization(analyzedModules.toCommonizationParameters()) val result: Result = runCommonization(analyzedModules.toCommonizationParameters())
assertCommonizationPerformed(result) assertCommonizationPerformed(result)
val sharedTarget: OutputTarget = analyzedModules.commonizedCommonModule.target val sharedTarget: OutputTarget = analyzedModules.sharedTarget
assertEquals(sharedTarget, result.sharedTarget) assertEquals(sharedTarget, result.sharedTarget)
val sharedModuleAsExpected: ModuleDescriptor = analyzedModules.commonizedCommonModule.module val sharedModuleAsExpected: ModuleDescriptor = analyzedModules.commonizedModules.getValue(sharedTarget)
val sharedModuleByCommonizer: ModuleDescriptor = val sharedModuleByCommonizer: ModuleDescriptor =
(result.modulesByTargets.getValue(sharedTarget).single() as ModuleResult.Commonized).module (result.modulesByTargets.getValue(sharedTarget).single() as ModuleResult.Commonized).module
@@ -81,11 +79,11 @@ abstract class AbstractCommonizationFromSourcesTest : KtUsefulTestCase() {
assertValidModule(sharedModuleByCommonizer) assertValidModule(sharedModuleByCommonizer)
assertModulesAreEqual(sharedModuleAsExpected, sharedModuleByCommonizer, "\"$sharedTarget\" target") assertModulesAreEqual(sharedModuleAsExpected, sharedModuleByCommonizer, "\"$sharedTarget\" target")
val leafTargets: Set<InputTarget> = analyzedModules.commonizedPlatformModules.keys val leafTargets: Set<InputTarget> = analyzedModules.leafTargets
assertEquals(leafTargets, result.leafTargets) assertEquals(leafTargets, result.leafTargets)
for (leafTarget in leafTargets) { for (leafTarget in leafTargets) {
val leafTargetModuleAsExpected: ModuleDescriptor = analyzedModules.commonizedPlatformModules.getValue(leafTarget).module val leafTargetModuleAsExpected: ModuleDescriptor = analyzedModules.commonizedModules.getValue(leafTarget)
val leafTargetModuleByCommonizer: ModuleDescriptor = val leafTargetModuleByCommonizer: ModuleDescriptor =
(result.modulesByTargets.getValue(leafTarget).single() as ModuleResult.Commonized).module (result.modulesByTargets.getValue(leafTarget).single() as ModuleResult.Commonized).module
@@ -98,117 +96,196 @@ abstract class AbstractCommonizationFromSourcesTest : KtUsefulTestCase() {
private data class SourceModuleRoot( private data class SourceModuleRoot(
val targetName: String, val targetName: String,
val root: File val location: File
) { ) {
init { init {
assertIsDirectory(root) assertIsDirectory(location)
} }
companion object { companion object {
fun load(directory: File): SourceModuleRoot = SourceModuleRoot( fun load(directory: File): SourceModuleRoot = SourceModuleRoot(
targetName = directory.name, targetName = directory.name,
root = directory location = directory
) )
const val COMMON_TARGET_NAME = "common" const val SHARED_TARGET_NAME = "common"
} }
} }
private class SourceModuleRoots( private class SourceModuleRoots(
val originalPlatformRoots: Map<String, SourceModuleRoot>, val originalRoots: Map<InputTarget, SourceModuleRoot>,
val commonizedPlatformRoots: Map<String, SourceModuleRoot>, val commonizedRoots: Map<Target, SourceModuleRoot>,
val commonizedCommonRoot: SourceModuleRoot val dependeeRoots: Map<Target, SourceModuleRoot>
) { ) {
val leafTargets: Set<InputTarget> = originalRoots.keys
val sharedTarget: OutputTarget
init { init {
check(originalPlatformRoots.isNotEmpty()) check(leafTargets.size >= 2)
check(COMMON_TARGET_NAME !in originalPlatformRoots) check(leafTargets.none { it.name == SHARED_TARGET_NAME })
check(originalPlatformRoots.keys == commonizedPlatformRoots.keys)
check(commonizedCommonRoot.targetName == COMMON_TARGET_NAME) val sharedTargets = commonizedRoots.keys.filterIsInstance<OutputTarget>()
check(sharedTargets.size == 1)
sharedTarget = sharedTargets.single()
check(sharedTarget.targets == leafTargets)
val allTargets = leafTargets + sharedTarget
check(commonizedRoots.keys == allTargets)
check(allTargets.containsAll(dependeeRoots.keys))
} }
companion object { companion object {
fun load(dataDir: File): SourceModuleRoots = try { fun load(dataDir: File): SourceModuleRoots = try {
val originalRoots = listRoots(dataDir, ORIGINAL_ROOTS_DIR) val originalRoots = listRoots(dataDir, ORIGINAL_ROOTS_DIR).mapKeys { InputTarget(it.key) }
val commonizedRoots = listRoots(dataDir, COMMONIZED_ROOTS_DIR)
SourceModuleRoots( val leafTargets = originalRoots.keys
originalPlatformRoots = originalRoots, val sharedTarget = OutputTarget(leafTargets)
commonizedPlatformRoots = commonizedRoots - COMMON_TARGET_NAME,
commonizedCommonRoot = commonizedRoots.getValue(COMMON_TARGET_NAME) fun getTarget(targetName: String): Target =
) if (targetName == SHARED_TARGET_NAME) sharedTarget else leafTargets.first { it.name == targetName }
val commonizedRoots = listRoots(dataDir, COMMONIZED_ROOTS_DIR).mapKeys { getTarget(it.key) }
val dependeeRoots = listRoots(dataDir, DEPENDEE_ROOTS_DIR).mapKeys { getTarget(it.key) }
SourceModuleRoots(originalRoots, commonizedRoots, dependeeRoots)
} catch (e: Exception) { } catch (e: Exception) {
fail("Source module misconfiguration in $dataDir", cause = e) fail("Source module misconfiguration in $dataDir", cause = e)
} }
private const val ORIGINAL_ROOTS_DIR = "original" private const val ORIGINAL_ROOTS_DIR = "original"
private const val COMMONIZED_ROOTS_DIR = "commonized" private const val COMMONIZED_ROOTS_DIR = "commonized"
private const val DEPENDEE_ROOTS_DIR = "dependee"
private fun listRoots(dataDir: File, rootsDirName: String): Map<String, SourceModuleRoot> = private fun listRoots(dataDir: File, rootsDirName: String): Map<String, SourceModuleRoot> =
dataDir.resolve(rootsDirName).listFiles()?.toSet().orEmpty().map(SourceModuleRoot::load).associateBy { it.targetName } dataDir.resolve(rootsDirName).listFiles()?.toSet().orEmpty().map(SourceModuleRoot::load).associateBy { it.targetName }
} }
} }
private class AnalyzedModule<T : Target>( private class AnalyzedModuleDependencies(
val target: T, val regularDependencies: Map<Target, List<ModuleDescriptor>>,
val module: ModuleDescriptor val expectByDependencies: List<ModuleDescriptor>
) { ) {
companion object { fun withExpectByDependency(dependency: ModuleDescriptor) =
fun <T : Target> create( AnalyzedModuleDependencies(
target: T, regularDependencies = regularDependencies,
sourceModuleRoot: SourceModuleRoot, expectByDependencies = expectByDependencies + dependency
commonSourceModuleRoot: SourceModuleRoot? = null, )
parentDisposable: Disposable
): AnalyzedModule<T> {
val moduleName: String = sourceModuleRoot.root.parentFile.parentFile.name
check(Name.isValidIdentifier(moduleName))
return AnalyzedModule( companion object {
target = target, val EMPTY = AnalyzedModuleDependencies(emptyMap(), emptyList())
module = analyze(
moduleName = moduleName, fun create(regularDependencies: Map<Target, ModuleDescriptor>, expectByDependencies: List<ModuleDescriptor>) =
moduleRoot = sourceModuleRoot.root, AnalyzedModuleDependencies(regularDependencies.mapValues { listOf(it.value) }, expectByDependencies)
commonModuleRoot = commonSourceModuleRoot?.root, }
parentDisposable = parentDisposable }
private class AnalyzedModules(
val originalModules: Map<Target, ModuleDescriptor>,
val commonizedModules: Map<Target, ModuleDescriptor>,
val dependeeModules: Map<Target, ModuleDescriptor>
) {
val leafTargets: Set<InputTarget>
val sharedTarget: OutputTarget
init {
originalModules.keys.let { targets ->
check(targets.isNotEmpty())
leafTargets = targets.filterIsInstance<InputTarget>().toSet()
check(targets.size == leafTargets.size)
}
sharedTarget = OutputTarget(leafTargets)
val allTargets = leafTargets + sharedTarget
check(commonizedModules.keys == allTargets)
check(allTargets.containsAll(dependeeModules.keys))
}
fun toCommonizationParameters(): Parameters {
val parameters = Parameters()
leafTargets.forEach { leafTarget ->
val originalModule = originalModules.getValue(leafTarget)
parameters.addTarget(
TargetProvider(
target = leafTarget,
builtInsClass = originalModule.builtIns::class.java,
builtInsProvider = MockBuiltInsProvider(originalModule.builtIns),
modulesProvider = MockModulesProvider(originalModule),
dependeeModulesProvider = dependeeModules[leafTarget]?.let(::MockModulesProvider)
) )
) )
} }
private fun analyze( parameters.dependeeModulesProvider = dependeeModules[sharedTarget]?.let(::MockModulesProvider)
moduleName: String,
moduleRoot: File,
commonModuleRoot: File?,
parentDisposable: Disposable
): ModuleDescriptor {
val commonModule: ModuleDescriptor? = if (commonModuleRoot != null) {
analyzeModule(
moduleName = "common" + moduleName.capitalize(),
moduleRoot = commonModuleRoot,
dependencyContainer = null, // common module does not have any specific dependencies
parentDisposable = parentDisposable
)
} else null
val module: ModuleDescriptor = analyzeModule( return parameters
moduleName = moduleName, }
moduleRoot = moduleRoot,
dependencyContainer = commonModule?.let(::CommonizedCommonDependenciesContainer), // platform module has dependencies to common module companion object {
parentDisposable = parentDisposable fun create(
sourceModuleRoots: SourceModuleRoots,
parentDisposable: Disposable
): AnalyzedModules = with(sourceModuleRoots) {
// first, build the modules that are are the dependencies for "original" and "commonized" modules
val dependeeModules =
createModules(sharedTarget, dependeeRoots, AnalyzedModuleDependencies.EMPTY, parentDisposable, isDependeeModule = true)
val dependencies = AnalyzedModuleDependencies.create(
regularDependencies = dependeeModules,
expectByDependencies = listOfNotNull(dependeeModules[sharedTarget])
) )
if (commonModule != null) { // then, build "original" and "commonized" modules
check(commonModule in module.expectedByModules) val originalModules = createModules(sharedTarget, originalRoots, dependencies, parentDisposable)
check(commonModule in module.allDependencyModules) val commonizedModules = createModules(sharedTarget, commonizedRoots, dependencies, parentDisposable)
return AnalyzedModules(originalModules, commonizedModules, dependeeModules)
}
private fun createModules(
sharedTarget: OutputTarget,
moduleRoots: Map<out Target, SourceModuleRoot>,
dependencies: AnalyzedModuleDependencies,
parentDisposable: Disposable,
isDependeeModule: Boolean = false
): Map<Target, ModuleDescriptor> {
val result = mutableMapOf<Target, ModuleDescriptor>()
var dependenciesForOthers = dependencies
// first, process the common module
moduleRoots[sharedTarget]?.let { moduleRoot ->
val commonModule = createModule(sharedTarget, sharedTarget, moduleRoot, dependencies, parentDisposable, isDependeeModule)
result[sharedTarget] = commonModule
dependenciesForOthers = dependencies.withExpectByDependency(commonModule)
} }
return module // then, all platform modules
moduleRoots.filterKeys { it != sharedTarget }.forEach { (leafTarget, moduleRoot) ->
result[leafTarget] =
createModule(sharedTarget, leafTarget, moduleRoot, dependenciesForOthers, parentDisposable, isDependeeModule)
}
return result
} }
private fun analyzeModule( private fun createModule(
moduleName: String, sharedTarget: OutputTarget,
moduleRoot: File, currentTarget: Target,
dependencyContainer: CommonDependenciesContainer?, moduleRoot: SourceModuleRoot,
parentDisposable: Disposable dependencies: AnalyzedModuleDependencies,
parentDisposable: Disposable,
isDependeeModule: Boolean
): ModuleDescriptor { ): ModuleDescriptor {
val moduleName: String = moduleRoot.location.parentFile.parentFile.name.let {
if (isDependeeModule) "dependee-$it" else it
}
check(Name.isValidIdentifier(moduleName))
val configuration: CompilerConfiguration = newConfiguration() val configuration: CompilerConfiguration = newConfiguration()
configuration.put(CommonConfigurationKeys.MODULE_NAME, moduleName) configuration.put(CommonConfigurationKeys.MODULE_NAME, moduleName)
@@ -220,7 +297,7 @@ private class AnalyzedModule<T : Target>(
val psiFactory = KtPsiFactory(environment.project) val psiFactory = KtPsiFactory(environment.project)
val psiFiles: List<KtFile> = moduleRoot.walkTopDown() val psiFiles: List<KtFile> = moduleRoot.location.walkTopDown()
.filter { it.isFile } .filter { it.isFile }
.map { psiFactory.createFile(it.name, doLoadFile(it)) } .map { psiFactory.createFile(it.name, doLoadFile(it)) }
.toList() .toList()
@@ -231,105 +308,68 @@ private class AnalyzedModule<T : Target>(
dependOnBuiltIns = true, dependOnBuiltIns = true,
languageVersionSettings = environment.configuration.languageVersionSettings, languageVersionSettings = environment.configuration.languageVersionSettings,
targetPlatform = CommonPlatforms.defaultCommonPlatform, targetPlatform = CommonPlatforms.defaultCommonPlatform,
dependenciesContainer = dependencyContainer dependenciesContainer = DependenciesContainerImpl(sharedTarget, currentTarget, dependencies)
) { content -> ) { content ->
environment.createPackagePartProvider(content.moduleContentScope) environment.createPackagePartProvider(content.moduleContentScope)
}.moduleDescriptor }.moduleDescriptor
module.accept(PatchingTestDescriptorVisitor, Unit) if (!isDependeeModule)
module.accept(PatchingTestDescriptorVisitor, Unit)
return module return module
} }
} }
} }
private class AnalyzedModules( private class DependenciesContainerImpl(
val originalPlatformModules: Map<InputTarget, AnalyzedModule<InputTarget>>, sharedTarget: OutputTarget,
val commonizedPlatformModules: Map<InputTarget, AnalyzedModule<InputTarget>>, currentTarget: Target,
val commonizedCommonModule: AnalyzedModule<OutputTarget> dependencies: AnalyzedModuleDependencies
) { ) : CommonDependenciesContainer {
private val moduleInfoToModule = mutableMapOf<ModuleInfo, ModuleDescriptor>()
private val expectByModuleInfos = mutableListOf<ModuleInfo>()
private val regularModuleInfos = mutableListOf<ModuleInfo>()
init { init {
check(originalPlatformModules.isNotEmpty()) if (currentTarget != sharedTarget) {
check(originalPlatformModules.keys == commonizedPlatformModules.keys) dependencies.expectByDependencies.forEach { expectByDependency ->
} val moduleInfo = ModuleInfoImpl(expectByDependency, emptyList())
moduleInfoToModule[moduleInfo] = expectByDependency
fun toCommonizationParameters(): Parameters { expectByModuleInfos += moduleInfo
val parameters = originalPlatformModules.mapValues { it.value.module }.toCommonizationParameters() }
parameters.commonModulesProvider = MockModulesProvider(commonizedCommonModule.module)
return parameters
}
companion object {
fun create(
sourceModuleRoots: SourceModuleRoots,
parentDisposable: Disposable
): AnalyzedModules {
val originalPlatformModules: Map<InputTarget, AnalyzedModule<InputTarget>> = createInputTargetModules(
sourceModuleRoots = sourceModuleRoots.originalPlatformRoots,
parentDisposable = parentDisposable
)
val commonizedCommonModule: AnalyzedModule<OutputTarget> = AnalyzedModule.create(
target = OutputTarget(originalPlatformModules.keys),
sourceModuleRoot = sourceModuleRoots.commonizedCommonRoot,
parentDisposable = parentDisposable
)
val commonizedPlatformModules: Map<InputTarget, AnalyzedModule<InputTarget>> = createInputTargetModules(
sourceModuleRoots = sourceModuleRoots.commonizedPlatformRoots,
commonSourceModuleRoot = sourceModuleRoots.commonizedCommonRoot,
parentDisposable = parentDisposable
)
return AnalyzedModules(
originalPlatformModules = originalPlatformModules,
commonizedPlatformModules = commonizedPlatformModules,
commonizedCommonModule = commonizedCommonModule
)
} }
private fun createInputTargetModules( dependencies.regularDependencies[currentTarget]?.forEach { regularDependency ->
sourceModuleRoots: Map<String, SourceModuleRoot>, val moduleInfo = ModuleInfoImpl(regularDependency, expectByModuleInfos)
commonSourceModuleRoot: SourceModuleRoot? = null, moduleInfoToModule[moduleInfo] = regularDependency
parentDisposable: Disposable regularModuleInfos += moduleInfo
): Map<InputTarget, AnalyzedModule<InputTarget>> = sourceModuleRoots.map { (targetName, sourceModuleRoot) -> }
AnalyzedModule.create(
target = InputTarget(targetName),
sourceModuleRoot = sourceModuleRoot,
commonSourceModuleRoot = commonSourceModuleRoot,
parentDisposable = parentDisposable
)
}.associateBy { it.target }
}
}
private class CommonizedCommonDependenciesContainer( regularModuleInfos += expectByModuleInfos
private val commonModule: ModuleDescriptor
) : CommonDependenciesContainer {
private val commonModuleInfo = object : ModuleInfo {
override val name: Name get() = commonModule.name
override fun dependencies(): List<ModuleInfo> = listOf(this)
override fun dependencyOnBuiltIns(): ModuleInfo.DependencyOnBuiltIns = ModuleInfo.DependencyOnBuiltIns.LAST
override val platform: TargetPlatform get() = CommonPlatforms.defaultCommonPlatform
override val analyzerServices: PlatformDependentAnalyzerServices get() = CommonPlatformAnalyzerServices
} }
override val moduleInfos: List<ModuleInfo> get() = listOf(commonModuleInfo) private inner class ModuleInfoImpl(
private val module: ModuleDescriptor,
private val regularDependencies: List<ModuleInfo>
) : ModuleInfo {
override val name get() = module.name
override fun moduleDescriptorForModuleInfo(moduleInfo: ModuleInfo): ModuleDescriptor { override fun dependencies() = listOf(this) + regularDependencies
if (moduleInfo !== commonModuleInfo) override fun dependencyOnBuiltIns() = ModuleInfo.DependencyOnBuiltIns.LAST
error("Unknown module info $moduleInfo")
return commonModule override val platform get() = CommonPlatforms.defaultCommonPlatform
override val analyzerServices get() = CommonPlatformAnalyzerServices
} }
override val moduleInfos: List<ModuleInfo> get() = regularModuleInfos
override val friendModuleInfos: List<ModuleInfo> get() = emptyList()
override val refinesModuleInfos: List<ModuleInfo> get() = expectByModuleInfos
override fun moduleDescriptorForModuleInfo(moduleInfo: ModuleInfo) =
moduleInfoToModule[moduleInfo] ?: error("Unknown module info $moduleInfo")
override fun registerDependencyForAllModules(moduleInfo: ModuleInfo, descriptorForModule: ModuleDescriptorImpl) = Unit override fun registerDependencyForAllModules(moduleInfo: ModuleInfo, descriptorForModule: ModuleDescriptorImpl) = Unit
override fun packageFragmentProviderForModuleInfo(moduleInfo: ModuleInfo): PackageFragmentProvider? = null override fun packageFragmentProviderForModuleInfo(moduleInfo: ModuleInfo): PackageFragmentProvider? = null
override val friendModuleInfos: List<ModuleInfo> get() = emptyList()
override val refinesModuleInfos: List<ModuleInfo> get() = listOf(commonModuleInfo)
} }
private object PatchingTestDescriptorVisitor : DeclarationDescriptorVisitorEmptyBodies<Unit, Unit>() { private object PatchingTestDescriptorVisitor : DeclarationDescriptorVisitorEmptyBodies<Unit, Unit>() {
@@ -368,21 +408,3 @@ private object PatchingTestDescriptorVisitor : DeclarationDescriptorVisitorEmpty
} }
} }
} }
private fun Map<InputTarget, ModuleDescriptor>.toCommonizationParameters(): Parameters = Parameters().also { parameters ->
forEach { (target, moduleDescriptor) ->
if (!parameters.extendedLookupForBuiltInsClassifiers) {
if (moduleDescriptor.hasSomethingUnderStandardKotlinPackages)
parameters.extendedLookupForBuiltInsClassifiers = true
}
parameters.addTarget(
TargetProvider(
target = target,
builtInsClass = moduleDescriptor.builtIns::class.java,
builtInsProvider = MockBuiltInsProvider(moduleDescriptor.builtIns),
modulesProvider = MockModulesProvider(moduleDescriptor)
)
)
}
}
@@ -67,7 +67,8 @@ class CommonizerFacadeTest {
target = InputTarget(targetName), target = InputTarget(targetName),
builtInsClass = DefaultBuiltIns::class.java, builtInsClass = DefaultBuiltIns::class.java,
builtInsProvider = BuiltInsProvider.defaultBuiltInsProvider, builtInsProvider = BuiltInsProvider.defaultBuiltInsProvider,
modulesProvider = MockModulesProvider(moduleNames) modulesProvider = MockModulesProvider(moduleNames),
dependeeModulesProvider = null
) )
) )
} }
@@ -46,8 +46,7 @@ internal fun mockClassType(
storageManager = LockBasedStorageManager.NO_LOCKS, storageManager = LockBasedStorageManager.NO_LOCKS,
target = InputTarget("Arbitrary target"), target = InputTarget("Arbitrary target"),
builtIns = DefaultBuiltIns.Instance, builtIns = DefaultBuiltIns.Instance,
lazyModulesLookupTable = LockBasedStorageManager.NO_LOCKS.createLazyValue { mutableMapOf() }, lazyClassifierLookupTable = LockBasedStorageManager.NO_LOCKS.createLazyValue { LazyClassifierLookupTable(emptyMap()) },
isCommon = false,
index = 0, index = 0,
cache = DeclarationsBuilderCache(1) cache = DeclarationsBuilderCache(1)
) )
@@ -173,7 +172,7 @@ internal class MockModulesProvider : ModulesProvider {
} }
override fun loadModuleInfos() = moduleInfos override fun loadModuleInfos() = moduleInfos
override fun loadModules() = modules override fun loadModules(dependencies: Collection<ModuleDescriptor>): Map<String, ModuleDescriptor> = modules
private fun fakeModuleInfo(name: String) = ModuleInfo(name, File("/tmp/commonizer/mocks/$name"), null) private fun fakeModuleInfo(name: String) = ModuleInfo(name, File("/tmp/commonizer/mocks/$name"), null)
} }