[Tests] Support KLIB metadata for stdlib in test compile utility
Create dependency provider able to resolve code from .knm metadata files to simplify migration from the legacy kotlin-stdlib-common artifact. KTIJ-28668 KTI-1457
This commit is contained in:
committed by
Space Team
parent
bfb1ef14f5
commit
ae664d37ae
+2
-1
@@ -146,6 +146,7 @@ class CommonResolverForModuleFactory(
|
||||
targetEnvironment: TargetEnvironment,
|
||||
capabilities: Map<ModuleCapability<*>, Any?> = emptyMap(),
|
||||
dependenciesContainer: CommonDependenciesContainer? = null,
|
||||
explicitProjectContext: ProjectContext? = null,
|
||||
metadataPartProviderFactory: (ModuleContent<ModuleInfo>) -> MetadataPartProvider
|
||||
): AnalysisResult {
|
||||
val moduleInfo = SourceModuleInfo(
|
||||
@@ -173,7 +174,7 @@ class CommonResolverForModuleFactory(
|
||||
dependenciesContainer
|
||||
)
|
||||
|
||||
val projectContext = ProjectContext(project, "metadata serializer")
|
||||
val projectContext = explicitProjectContext ?: ProjectContext(project, "metadata serializer")
|
||||
|
||||
val resolver = ResolverForSingleModuleProject<ModuleInfo>(
|
||||
"sources for metadata serializer",
|
||||
|
||||
@@ -6,6 +6,9 @@
|
||||
package org.jetbrains.kotlin.test
|
||||
|
||||
import com.intellij.openapi.util.Disposer
|
||||
import org.jetbrains.kotlin.analyzer.ModuleInfo
|
||||
import org.jetbrains.kotlin.analyzer.common.CommonDependenciesContainer
|
||||
import org.jetbrains.kotlin.analyzer.common.CommonPlatformAnalyzerServices
|
||||
import org.jetbrains.kotlin.analyzer.common.CommonResolverForModuleFactory
|
||||
import org.jetbrains.kotlin.backend.common.serialization.metadata.KlibMetadataMonolithicSerializer
|
||||
import org.jetbrains.kotlin.builtins.DefaultBuiltIns
|
||||
@@ -21,24 +24,29 @@ import org.jetbrains.kotlin.codegen.forTestCompile.ForTestCompileRuntime
|
||||
import org.jetbrains.kotlin.config.CommonConfigurationKeys
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl
|
||||
import org.jetbrains.kotlin.config.languageVersionSettings
|
||||
import org.jetbrains.kotlin.context.ProjectContext
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PackageFragmentProvider
|
||||
import org.jetbrains.kotlin.descriptors.impl.CompositePackageFragmentProvider
|
||||
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
|
||||
import org.jetbrains.kotlin.library.KLIB_FILE_EXTENSION
|
||||
import org.jetbrains.kotlin.library.KotlinLibraryVersioning
|
||||
import org.jetbrains.kotlin.library.ToolingSingleFileKlibResolveStrategy
|
||||
import org.jetbrains.kotlin.incremental.components.LookupTracker
|
||||
import org.jetbrains.kotlin.ir.backend.js.moduleName
|
||||
import org.jetbrains.kotlin.library.*
|
||||
import org.jetbrains.kotlin.library.impl.BuiltInsPlatform
|
||||
import org.jetbrains.kotlin.library.impl.KotlinLibraryLayoutForWriter
|
||||
import org.jetbrains.kotlin.library.impl.KotlinLibraryWriterImpl
|
||||
import org.jetbrains.kotlin.library.metadata.KlibMetadataFactories
|
||||
import org.jetbrains.kotlin.library.metadata.KlibMetadataVersion
|
||||
import org.jetbrains.kotlin.library.metadata.NullFlexibleTypeDeserializer
|
||||
import org.jetbrains.kotlin.library.resolveSingleFileKlib
|
||||
import org.jetbrains.kotlin.library.metadata.*
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.platform.CommonPlatforms
|
||||
import org.jetbrains.kotlin.platform.TargetPlatform
|
||||
import org.jetbrains.kotlin.resolve.CompilerDeserializationConfiguration
|
||||
import org.jetbrains.kotlin.resolve.CompilerEnvironment
|
||||
import org.jetbrains.kotlin.resolve.PlatformDependentAnalyzerServices
|
||||
import org.jetbrains.kotlin.storage.LockBasedStorageManager
|
||||
import org.jetbrains.kotlin.util.DummyLogger
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
import java.nio.file.Path
|
||||
import org.jetbrains.kotlin.konan.file.File as KFile
|
||||
|
||||
object KlibTestUtil {
|
||||
@@ -53,6 +61,7 @@ object KlibTestUtil {
|
||||
configuration.put(CommonConfigurationKeys.MODULE_NAME, libraryName)
|
||||
configuration.addKotlinSourceRoots(sourceFiles.map { it.absolutePath })
|
||||
val stdlibFile = ForTestCompileRuntime.stdlibCommonForTests()
|
||||
// support for the legacy version of kotlin-stdlib-common (JAR with .kotlin_metadata)
|
||||
configuration.addJvmClasspathRoot(stdlibFile)
|
||||
|
||||
val rootDisposable = Disposer.newDisposable("Disposable for ${KlibTestUtil::class.simpleName}.compileCommonSourcesToKlib")
|
||||
@@ -63,6 +72,8 @@ object KlibTestUtil {
|
||||
extensionConfigs = EnvironmentConfigFiles.METADATA_CONFIG_FILES
|
||||
)
|
||||
|
||||
val projectContext = ProjectContext(environment.project, "Compile common sources to KLIB metadata")
|
||||
|
||||
val analyzer = AnalyzerWithCompilerReport(
|
||||
configuration.getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY),
|
||||
configuration.languageVersionSettings,
|
||||
@@ -77,6 +88,9 @@ object KlibTestUtil {
|
||||
environment.configuration.languageVersionSettings,
|
||||
CommonPlatforms.defaultCommonPlatform,
|
||||
CompilerEnvironment,
|
||||
explicitProjectContext = projectContext,
|
||||
// support for the KLIB version of kotlin-stdlib-common (KLIB with .knm metadata)
|
||||
dependenciesContainer = createDependencyContainerForStdlibIfKlib(stdlibFile.toPath(), environment, projectContext),
|
||||
) { content ->
|
||||
environment.createPackagePartProvider(content.moduleContentScope)
|
||||
}
|
||||
@@ -153,3 +167,96 @@ object KlibTestUtil {
|
||||
return module
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a dependency container that includes common stdlib, if the passed file path points to a metadata KLIB in the supported format.
|
||||
* Note that [resolveSingleFileKlib] is sensitive to the library layout and to the file extension.
|
||||
* In the case of a custom klib layout or file extension other than .klib, the library won't be resolved even if it contains .knm files.
|
||||
* For the current kotlin-stdlib-common.jar it will always return null, the purpose of the function is to simplify future migration.
|
||||
* It's been checked that the dependency container for a library with the supported layout is functional.
|
||||
* See KTI-1457.
|
||||
*/
|
||||
private fun createDependencyContainerForStdlibIfKlib(
|
||||
stdlibFilePath: Path,
|
||||
environment: KotlinCoreEnvironment,
|
||||
projectContext: ProjectContext,
|
||||
): CommonDependenciesContainerImpl? {
|
||||
val stdlibKlib = resolveSingleFileKlib(KFile(stdlibFilePath), strategy = ToolingSingleFileKlibResolveStrategy).also {
|
||||
try {
|
||||
it.moduleName // trigger an exception in case of unsupported file/layout
|
||||
} catch (e: IOException) {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
val stdlibModuleDescriptor = createAndInitializeKlibBasedStdlibCommonDescriptor(stdlibKlib, environment, projectContext)
|
||||
return CommonDependenciesContainerImpl(listOf(stdlibModuleDescriptor))
|
||||
}
|
||||
|
||||
private fun createAndInitializeKlibBasedStdlibCommonDescriptor(
|
||||
stdlibKlib: KotlinLibrary,
|
||||
environment: KotlinCoreEnvironment,
|
||||
projectContext: ProjectContext,
|
||||
): ModuleDescriptor {
|
||||
val stdlibCommonDescriptor = ModuleDescriptorImpl(
|
||||
Name.special("<stdlib-common>"),
|
||||
projectContext.storageManager, DefaultBuiltIns.Instance, CommonPlatforms.defaultCommonPlatform
|
||||
).also {
|
||||
it.setDependencies(it)
|
||||
}
|
||||
|
||||
val metadataModuleDescriptorFactory: KlibMetadataModuleDescriptorFactory = KlibMetadataFactories(
|
||||
{ DefaultBuiltIns.Instance },
|
||||
NullFlexibleTypeDeserializer,
|
||||
).DefaultDeserializedDescriptorFactory
|
||||
|
||||
val klibPackageFragmentProvider = metadataModuleDescriptorFactory.createPackageFragmentProvider(
|
||||
library = stdlibKlib,
|
||||
packageAccessHandler = null,
|
||||
packageFragmentNames = parseModuleHeader(stdlibKlib.moduleHeaderData).packageFragmentNameList,
|
||||
storageManager = projectContext.storageManager,
|
||||
moduleDescriptor = stdlibCommonDescriptor,
|
||||
configuration = CompilerDeserializationConfiguration(environment.configuration.languageVersionSettings),
|
||||
compositePackageFragmentAddend = null,
|
||||
lookupTracker = LookupTracker.DO_NOTHING,
|
||||
)
|
||||
|
||||
stdlibCommonDescriptor.initialize(
|
||||
CompositePackageFragmentProvider(
|
||||
listOf(
|
||||
klibPackageFragmentProvider,
|
||||
DefaultBuiltIns.Instance.builtInsModule.packageFragmentProvider,
|
||||
),
|
||||
"Test provider for .knm metadata and built-in declarations of kotlin-stdlib-common"
|
||||
)
|
||||
)
|
||||
|
||||
return stdlibCommonDescriptor
|
||||
}
|
||||
|
||||
private class CommonDependenciesContainerImpl(dependencies: Collection<ModuleDescriptor>) : CommonDependenciesContainer {
|
||||
private class ModuleInfoImpl(val module: ModuleDescriptor) : ModuleInfo {
|
||||
override val name: Name get() = module.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
|
||||
}
|
||||
|
||||
private val moduleDescriptorByModuleInfo: Map<ModuleInfo, ModuleDescriptor> = dependencies.associateBy(::ModuleInfoImpl)
|
||||
|
||||
override val moduleInfos: List<ModuleInfo> get() = moduleDescriptorByModuleInfo.keys.toList()
|
||||
|
||||
override fun moduleDescriptorForModuleInfo(moduleInfo: ModuleInfo): ModuleDescriptor {
|
||||
return moduleDescriptorByModuleInfo[moduleInfo]
|
||||
?: error("Unknown module info $moduleInfo")
|
||||
}
|
||||
|
||||
override fun registerDependencyForAllModules(moduleInfo: ModuleInfo, descriptorForModule: ModuleDescriptorImpl) = Unit
|
||||
override fun packageFragmentProviderForModuleInfo(moduleInfo: ModuleInfo): PackageFragmentProvider? = null
|
||||
|
||||
override val friendModuleInfos: List<ModuleInfo> get() = emptyList()
|
||||
override val refinesModuleInfos: List<ModuleInfo> get() = emptyList()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user