Remove dependency of module 'cli' on 'builtins-serializer'
This breaks the circular dependency between them
This commit is contained in:
@@ -33,7 +33,6 @@ import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
import org.jetbrains.kotlin.config.Services
|
||||
import org.jetbrains.kotlin.config.addKotlinSourceRoot
|
||||
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||
import org.jetbrains.kotlin.serialization.MetadataSerializer
|
||||
import java.io.File
|
||||
|
||||
class K2MetadataCompiler : CLICompiler<K2MetadataCompilerArguments>() {
|
||||
|
||||
@@ -0,0 +1,204 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.cli.metadata
|
||||
|
||||
import org.jetbrains.kotlin.analyzer.AnalysisResult
|
||||
import org.jetbrains.kotlin.analyzer.common.DefaultAnalyzerFacade
|
||||
import org.jetbrains.kotlin.builtins.BuiltInsBinaryVersion
|
||||
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
|
||||
import org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport
|
||||
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.JvmPackagePartProvider
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
||||
import org.jetbrains.kotlin.codegen.JvmCodegenUtil
|
||||
import org.jetbrains.kotlin.codegen.serializeToByteArray
|
||||
import org.jetbrains.kotlin.config.CommonConfigurationKeys
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.load.kotlin.PackagePartClassUtils
|
||||
import org.jetbrains.kotlin.load.kotlin.PackageParts
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
|
||||
import org.jetbrains.kotlin.serialization.DescriptorSerializer
|
||||
import org.jetbrains.kotlin.serialization.KotlinSerializerExtensionBase
|
||||
import org.jetbrains.kotlin.serialization.ProtoBuf
|
||||
import org.jetbrains.kotlin.serialization.deserialization.MetadataPackageFragment.Companion.DOT_METADATA_FILE_EXTENSION
|
||||
import org.jetbrains.kotlin.serialization.jvm.JvmPackageTable
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.io.DataOutputStream
|
||||
import java.io.File
|
||||
|
||||
open class MetadataSerializer(private val dependOnOldBuiltIns: Boolean) {
|
||||
protected var totalSize = 0
|
||||
protected var totalFiles = 0
|
||||
|
||||
fun serialize(environment: KotlinCoreEnvironment) {
|
||||
val configuration = environment.configuration
|
||||
val messageCollector = configuration.getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY)
|
||||
val files = environment.getSourceFiles()
|
||||
val moduleName = Name.special("<${configuration.getNotNull(CommonConfigurationKeys.MODULE_NAME)}>")
|
||||
|
||||
val destDir = configuration.get(CLIConfigurationKeys.METADATA_DESTINATION_DIRECTORY) ?: run {
|
||||
messageCollector.report(CompilerMessageSeverity.ERROR, "Specify destination via -d")
|
||||
return
|
||||
}
|
||||
|
||||
val analyzer = AnalyzerWithCompilerReport(messageCollector)
|
||||
analyzer.analyzeAndReport(files, object : AnalyzerWithCompilerReport.Analyzer {
|
||||
override fun analyze(): AnalysisResult = DefaultAnalyzerFacade.analyzeFiles(files, moduleName, dependOnOldBuiltIns) {
|
||||
_, content -> JvmPackagePartProvider(environment, content.moduleContentScope)
|
||||
}
|
||||
})
|
||||
|
||||
if (analyzer.hasErrors()) return
|
||||
|
||||
val (bindingContext, moduleDescriptor) = analyzer.analysisResult
|
||||
|
||||
performSerialization(files, bindingContext, moduleDescriptor, destDir)
|
||||
}
|
||||
|
||||
protected open fun performSerialization(
|
||||
files: Collection<KtFile>, bindingContext: BindingContext, module: ModuleDescriptor, destDir: File
|
||||
) {
|
||||
val packageTable = hashMapOf<FqName, PackageParts>()
|
||||
|
||||
for (file in files) {
|
||||
val packageFqName = file.packageFqName
|
||||
val members = arrayListOf<DeclarationDescriptor>()
|
||||
for (declaration in file.declarations) {
|
||||
declaration.accept(object : KtVisitorVoid() {
|
||||
override fun visitNamedFunction(function: KtNamedFunction) {
|
||||
members.add(bindingContext.get(BindingContext.FUNCTION, function)
|
||||
?: error("No descriptor found for function ${function.fqName}"))
|
||||
}
|
||||
|
||||
override fun visitProperty(property: KtProperty) {
|
||||
members.add(bindingContext.get(BindingContext.VARIABLE, property)
|
||||
?: error("No descriptor found for property ${property.fqName}"))
|
||||
}
|
||||
|
||||
override fun visitTypeAlias(typeAlias: KtTypeAlias) {
|
||||
members.add(bindingContext.get(BindingContext.TYPE_ALIAS, typeAlias)
|
||||
?: error("No descriptor found for type alias ${typeAlias.fqName}"))
|
||||
}
|
||||
|
||||
override fun visitClassOrObject(classOrObject: KtClassOrObject) {
|
||||
val classDescriptor = bindingContext.get(BindingContext.CLASS, classOrObject)
|
||||
?: error("No descriptor found for class ${classOrObject.fqName}")
|
||||
val destFile = File(destDir, getClassFilePath(ClassId(packageFqName, classDescriptor.name)))
|
||||
PackageSerializer(listOf(classDescriptor), emptyList(), packageFqName, destFile).run()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (members.isNotEmpty()) {
|
||||
val destFile = File(destDir, getPackageFilePath(packageFqName, file.name))
|
||||
PackageSerializer(emptyList(), members, packageFqName, destFile).run()
|
||||
|
||||
packageTable.getOrPut(packageFqName) {
|
||||
PackageParts(packageFqName.asString())
|
||||
}.addMetadataPart(destFile.nameWithoutExtension)
|
||||
}
|
||||
}
|
||||
|
||||
val kotlinModuleFile = File(destDir, JvmCodegenUtil.getMappingFileName(JvmCodegenUtil.getModuleName(module)))
|
||||
val packageTableBytes = JvmPackageTable.PackageTable.newBuilder().apply {
|
||||
for (table in packageTable.values) {
|
||||
table.addTo(this)
|
||||
}
|
||||
}.serializeToByteArray()
|
||||
|
||||
kotlinModuleFile.parentFile.mkdirs()
|
||||
kotlinModuleFile.writeBytes(packageTableBytes)
|
||||
}
|
||||
|
||||
protected open fun createSerializerExtension(): KotlinSerializerExtensionBase = MetadataSerializerExtension()
|
||||
|
||||
private fun getPackageFilePath(packageFqName: FqName, fileName: String): String =
|
||||
packageFqName.asString().replace('.', '/') + "/" +
|
||||
PackagePartClassUtils.getFilePartShortName(fileName) + DOT_METADATA_FILE_EXTENSION
|
||||
|
||||
private fun getClassFilePath(classId: ClassId): String =
|
||||
classId.asSingleFqName().asString().replace('.', '/') + DOT_METADATA_FILE_EXTENSION
|
||||
|
||||
protected inner class PackageSerializer(
|
||||
private val classes: Collection<DeclarationDescriptor>,
|
||||
private val members: Collection<DeclarationDescriptor>,
|
||||
private val packageFqName: FqName,
|
||||
private val destFile: File
|
||||
) {
|
||||
private val proto = ProtoBuf.PackageFragment.newBuilder()
|
||||
private val extension = createSerializerExtension()
|
||||
|
||||
fun run() {
|
||||
serializeClasses(classes)
|
||||
serializeMembers(members)
|
||||
serializeStringTable()
|
||||
serializeBuiltInsFile()
|
||||
}
|
||||
|
||||
private fun serializeClass(classDescriptor: ClassDescriptor) {
|
||||
val classProto = DescriptorSerializer.createTopLevel(extension).classProto(classDescriptor).build()
|
||||
proto.addClass_(classProto)
|
||||
|
||||
serializeClasses(classDescriptor.unsubstitutedInnerClassesScope.getContributedDescriptors(DescriptorKindFilter.CLASSIFIERS))
|
||||
}
|
||||
|
||||
private fun serializeClasses(classes: Collection<DeclarationDescriptor>) {
|
||||
for (descriptor in DescriptorSerializer.sort(classes)) {
|
||||
if (descriptor is ClassDescriptor && descriptor.kind != ClassKind.ENUM_ENTRY) {
|
||||
serializeClass(descriptor)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun serializeMembers(members: Collection<DeclarationDescriptor>) {
|
||||
proto.`package` = DescriptorSerializer.createTopLevel(extension).packagePartProto(packageFqName, members).build()
|
||||
}
|
||||
|
||||
private fun serializeStringTable() {
|
||||
val (strings, qualifiedNames) = extension.stringTable.buildProto()
|
||||
proto.strings = strings
|
||||
proto.qualifiedNames = qualifiedNames
|
||||
}
|
||||
|
||||
private fun serializeBuiltInsFile() {
|
||||
val stream = ByteArrayOutputStream()
|
||||
with(DataOutputStream(stream)) {
|
||||
val version = BuiltInsBinaryVersion.INSTANCE.toArray()
|
||||
writeInt(version.size)
|
||||
version.forEach { writeInt(it) }
|
||||
}
|
||||
proto.build().writeTo(stream)
|
||||
write(stream)
|
||||
}
|
||||
|
||||
private fun write(stream: ByteArrayOutputStream) {
|
||||
totalSize += stream.size()
|
||||
totalFiles++
|
||||
assert(!destFile.isDirectory) { "Cannot write because output destination is a directory: $destFile" }
|
||||
destFile.parentFile.mkdirs()
|
||||
destFile.writeBytes(stream.toByteArray())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.cli.metadata
|
||||
|
||||
import org.jetbrains.kotlin.builtins.BuiltInSerializerProtocol
|
||||
import org.jetbrains.kotlin.serialization.KotlinSerializerExtensionBase
|
||||
|
||||
class MetadataSerializerExtension : KotlinSerializerExtensionBase(BuiltInSerializerProtocol) {
|
||||
override fun shouldUseTypeTable(): Boolean = true
|
||||
}
|
||||
Reference in New Issue
Block a user