Support friend internal visibility in K2Metadata compiler (KT-37264)

Add and handle the friend paths and refines paths compiler arguments;
Reuse klib dependency module descriptors in the resolver for project;

Issue #KT-37264
This commit is contained in:
Sergey Igushkin
2020-03-05 23:11:49 +03:00
parent 04c924a119
commit 3858c8e1f8
7 changed files with 86 additions and 8 deletions
@@ -65,10 +65,14 @@ class CommonResolverForModuleFactory(
override val name: Name,
override val capabilities: Map<ModuleDescriptor.Capability<*>, Any?>,
private val dependencies: Iterable<ModuleInfo>,
override val expectedBy: List<ModuleInfo>,
private val modulesWhoseInternalsAreVisible: Collection<ModuleInfo>,
private val dependOnOldBuiltIns: Boolean
) : ModuleInfo {
override fun dependencies() = listOf(this, *dependencies.toList().toTypedArray() )
override fun modulesWhoseInternalsAreVisible(): Collection<ModuleInfo> = modulesWhoseInternalsAreVisible
override fun dependencyOnBuiltIns(): ModuleInfo.DependencyOnBuiltIns =
if (dependOnOldBuiltIns) ModuleInfo.DependencyOnBuiltIns.LAST else ModuleInfo.DependencyOnBuiltIns.NONE
@@ -123,6 +127,8 @@ class CommonResolverForModuleFactory(
moduleName,
capabilities,
dependenciesContainer?.moduleInfos?.toList().orEmpty(),
dependenciesContainer?.refinesModuleInfos.orEmpty(),
dependenciesContainer?.friendModuleInfos.orEmpty(),
dependOnBuiltIns
)
val project = files.firstOrNull()?.project ?: throw AssertionError("No files to analyze")
@@ -150,7 +156,8 @@ class CommonResolverForModuleFactory(
GlobalSearchScope.allScope(project),
languageVersionSettings = multiplatformLanguageSettings,
syntheticFiles = files,
dependencyModules = dependenciesContainer?.moduleInfos ?: emptyList()
knownDependencyModuleDescriptors = dependenciesContainer?.moduleInfos
?.associateWith(dependenciesContainer::moduleDescriptorForModuleInfo).orEmpty()
)
val moduleDescriptor = resolver.descriptorForModule(moduleInfo)
@@ -167,7 +174,11 @@ class CommonResolverForModuleFactory(
interface CommonDependenciesContainer {
val moduleInfos: List<ModuleInfo>
fun moduleDescriptorForModuleInfo(moduleInfo: ModuleInfo): ModuleDescriptor
fun packageFragmentProviderForModuleInfo(moduleInfo: ModuleInfo): PackageFragmentProvider?
val friendModuleInfos: List<ModuleInfo>
val refinesModuleInfos: List<ModuleInfo>
}
private fun createContainerToResolveCommonCode(
@@ -40,4 +40,18 @@ class K2MetadataCompilerArguments : CommonCompilerArguments() {
description = "Enable in JPS"
)
var enabledInJps: Boolean by FreezableVar(false)
@Argument(
value = "-Xfriend-paths",
valueDescription = "<path>",
description = "Paths to output directories for friend modules (whose internals should be visible)"
)
var friendPaths: Array<String>? by FreezableVar(null)
@Argument(
value = "-Xrefines-paths",
valueDescription = "<path>",
description = "Paths to output directories for refined modules (whose expects this module can actualize)"
)
var refinesPaths: Array<String>? by FreezableVar(null)
}
@@ -0,0 +1,13 @@
/*
* 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.cli.jvm.config
import org.jetbrains.kotlin.config.CompilerConfigurationKey
object K2MetadataConfigurationKeys {
val FRIEND_PATHS = CompilerConfigurationKey.create<List<String>>("friend module paths")
val REFINES_PATHS = CompilerConfigurationKey.create<List<String>>("refined module paths")
}
@@ -25,6 +25,7 @@ import org.jetbrains.kotlin.cli.common.messages.MessageUtil
import org.jetbrains.kotlin.cli.common.messages.OutputMessageUtil
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
import org.jetbrains.kotlin.cli.jvm.config.K2MetadataConfigurationKeys
import org.jetbrains.kotlin.cli.jvm.config.addJvmClasspathRoots
import org.jetbrains.kotlin.cli.jvm.plugins.PluginCliParser
import org.jetbrains.kotlin.codegen.CompilationException
@@ -73,6 +74,10 @@ class K2MetadataCompiler : CLICompiler<K2MetadataCompilerArguments>() {
configuration.put(CLIConfigurationKeys.ALLOW_KOTLIN_PACKAGE, arguments.allowKotlinPackage)
configuration.putIfNotNull(K2MetadataConfigurationKeys.FRIEND_PATHS, arguments.friendPaths?.toList())
configuration.putIfNotNull(K2MetadataConfigurationKeys.REFINES_PATHS, arguments.refinesPaths?.toList())
val destination = arguments.destination
if (destination != null) {
if (destination.endsWith(".jar")) {
@@ -5,7 +5,7 @@
package org.jetbrains.kotlin.cli.metadata
import org.jetbrains.kotlin.analyzer.ModuleInfo
import org.jetbrains.kotlin.analyzer.*
import org.jetbrains.kotlin.analyzer.common.CommonDependenciesContainer
import org.jetbrains.kotlin.analyzer.common.CommonPlatformAnalyzerServices
import org.jetbrains.kotlin.backend.common.serialization.metadata.KlibMetadataMonolithicSerializer
@@ -15,6 +15,7 @@ import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
import org.jetbrains.kotlin.cli.jvm.config.JvmClasspathRoot
import org.jetbrains.kotlin.cli.jvm.config.JvmContentRoot
import org.jetbrains.kotlin.cli.jvm.config.K2MetadataConfigurationKeys
import org.jetbrains.kotlin.config.CommonConfigurationKeys
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.config.KotlinCompilerVersion
@@ -112,6 +113,9 @@ private class KlibMetadataDependencyContainer(
klibFiles.map { resolveSingleFileKlib(org.jetbrains.kotlin.konan.file.File(it.absolutePath)) }
}
private val friendPaths = configuration.get(K2MetadataConfigurationKeys.FRIEND_PATHS).orEmpty().toSet()
private val refinesPaths = configuration.get(K2MetadataConfigurationKeys.REFINES_PATHS).orEmpty().toSet()
private val builtIns
get() = DefaultBuiltIns.Instance
@@ -147,7 +151,7 @@ private class KlibMetadataDependencyContainer(
}
}
override val moduleInfos: List<ModuleInfo> = mutableListOf<KlibModuleInfo>().apply {
private val moduleInfosImpl: List<KlibModuleInfo> = mutableListOf<KlibModuleInfo>().apply {
addAll(
moduleDescriptorsForKotlinLibraries.map { (kotlinLibrary, moduleDescriptor) ->
KlibModuleInfo(moduleDescriptor.name, kotlinLibrary, this@apply)
@@ -155,6 +159,28 @@ private class KlibMetadataDependencyContainer(
)
}
override val moduleInfos: List<ModuleInfo> get() = moduleInfosImpl
override val friendModuleInfos: List<ModuleInfo> = moduleInfosImpl.filter {
it.kotlinLibrary.libraryFile.absolutePath in friendPaths
}
override val refinesModuleInfos: List<ModuleInfo> = moduleInfosImpl.filter {
it.kotlinLibrary.libraryFile.absolutePath in refinesPaths
}
override fun moduleDescriptorForModuleInfo(moduleInfo: ModuleInfo): ModuleDescriptor {
if (moduleInfo !in moduleInfos)
error("Unknown module info $moduleInfo")
moduleInfo as KlibModuleInfo
// Ensure that the package fragment provider has been created and the module descriptor has been
// initialized with the package fragment provider:
packageFragmentProviderForModuleInfo(moduleInfo)
return moduleDescriptorsForKotlinLibraries.getValue(moduleInfo.kotlinLibrary)
}
override fun packageFragmentProviderForModuleInfo(
moduleInfo: ModuleInfo
): PackageFragmentProvider? {
@@ -19,12 +19,12 @@ abstract class AbstractResolverForProject<M : ModuleInfo>(
private val debugName: String,
protected val projectContext: ProjectContext,
modules: Collection<M>,
private val fallbackModificationTracker: ModificationTracker? = null,
protected val fallbackModificationTracker: ModificationTracker? = null,
private val delegateResolver: ResolverForProject<M> = EmptyResolverForProject(),
private val packageOracleFactory: PackageOracleFactory = PackageOracleFactory.OptimisticFactory
) : ResolverForProject<M>() {
private class ModuleData(
protected class ModuleData(
val moduleDescriptor: ModuleDescriptorImpl,
val modificationTracker: ModificationTracker?
) {
@@ -37,7 +37,7 @@ abstract class AbstractResolverForProject<M : ModuleInfo>(
}
// Protected by ("projectContext.storageManager.lock")
private val descriptorByModule = mutableMapOf<M, ModuleData>()
protected val descriptorByModule = mutableMapOf<M, ModuleData>()
// Protected by ("projectContext.storageManager.lock")
private val moduleInfoByDescriptor = mutableMapOf<ModuleDescriptorImpl, M>()
@@ -26,17 +26,26 @@ class ResolverForSingleModuleProject<M : ModuleInfo>(
private val languageVersionSettings: LanguageVersionSettings = LanguageVersionSettingsImpl.DEFAULT,
private val syntheticFiles: Collection<KtFile> = emptyList(),
private val sdkDependency: M? = null,
dependencyModules: Iterable<M> = emptyList()
knownDependencyModuleDescriptors: Map<M, ModuleDescriptor> = emptyMap()
) : AbstractResolverForProject<M>(
debugName,
projectContext,
listOf(module) + dependencyModules,
listOf(module) + knownDependencyModuleDescriptors.keys,
null,
EmptyResolverForProject(),
PackageOracleFactory.OptimisticFactory
) {
override fun sdkDependency(module: M): M? = sdkDependency
init {
knownDependencyModuleDescriptors.forEach { (module, descriptor) ->
descriptorByModule[module] = ModuleData(
descriptor as ModuleDescriptorImpl,
(module as? TrackableModuleInfo)?.createModificationTracker() ?: fallbackModificationTracker
)
}
}
override fun modulesContent(module: M): ModuleContent<M> = when (module) {
this.module -> ModuleContent(module, syntheticFiles, searchScope)
else -> ModuleContent(module, emptyList(), searchScope)