MultifileClassCodegen
- initial implementation - new Kotlin file kinds + stub builder
This commit is contained in:
@@ -50,6 +50,7 @@ public class ClassFileFactory implements OutputFileCollection {
|
||||
private final GenerationState state;
|
||||
private final ClassBuilderFactory builderFactory;
|
||||
private final Map<FqName, PackageCodegen> package2codegen = new HashMap<FqName, PackageCodegen>();
|
||||
private final Map<FqName, MultifileClassCodegen> multifileClass2codegen = new HashMap<FqName, MultifileClassCodegen>();
|
||||
private final Map<String, OutAndSourceFileList> generators = new LinkedHashMap<String, OutAndSourceFileList>();
|
||||
|
||||
private boolean isDone = false;
|
||||
@@ -189,7 +190,7 @@ public class ClassFileFactory implements OutputFileCollection {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public PackageCodegen forFacade(@NotNull FqName facadeFqName, @NotNull Collection<JetFile> files) {
|
||||
public PackageCodegen forFacadeLightClass(@NotNull FqName facadeFqName, @NotNull Collection<JetFile> files) {
|
||||
assert !isDone : "Already done!";
|
||||
PackageCodegen codegen = package2codegen.get(facadeFqName);
|
||||
if (codegen == null) {
|
||||
@@ -200,6 +201,17 @@ public class ClassFileFactory implements OutputFileCollection {
|
||||
return codegen;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public MultifileClassCodegen forMultifileClass(@NotNull FqName facadeFqName, @NotNull Collection<JetFile> files) {
|
||||
assert !isDone : "Already done!";
|
||||
MultifileClassCodegen codegen = multifileClass2codegen.get(facadeFqName);
|
||||
if (codegen == null) {
|
||||
codegen = new MultifileClassCodegen(state, files, facadeFqName);
|
||||
multifileClass2codegen.put(facadeFqName, codegen);
|
||||
}
|
||||
return codegen;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static List<File> toIoFilesIgnoringNonPhysical(@NotNull Collection<? extends PsiFile> psiFiles) {
|
||||
List<File> result = Lists.newArrayList();
|
||||
|
||||
@@ -20,6 +20,8 @@ import com.google.common.collect.Sets;
|
||||
import com.intellij.util.containers.MultiMap;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState;
|
||||
import org.jetbrains.kotlin.fileClasses.JvmFileClassInfo;
|
||||
import org.jetbrains.kotlin.load.kotlin.PackageClassUtils;
|
||||
import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus;
|
||||
import org.jetbrains.kotlin.name.FqName;
|
||||
import org.jetbrains.kotlin.psi.JetFile;
|
||||
@@ -62,15 +64,31 @@ public class KotlinCodegenFacade {
|
||||
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled();
|
||||
|
||||
MultiMap<FqName, JetFile> packageFqNameToFiles = new MultiMap<FqName, JetFile>();
|
||||
MultiMap<FqName, JetFile> multifileClassFqNameToFiles = new MultiMap<FqName, JetFile>();
|
||||
|
||||
for (JetFile file : state.getFiles()) {
|
||||
if (file == null) throw new IllegalArgumentException("A null file given for compilation");
|
||||
packageFqNameToFiles.putValue(file.getPackageFqName(), file);
|
||||
JvmFileClassInfo fileClassInfo = state.getFileClassesProvider().getFileClassInfo(file);
|
||||
if (fileClassInfo.getIsMultifileClass()) {
|
||||
multifileClassFqNameToFiles.putValue(fileClassInfo.getFacadeClassFqName(), file);
|
||||
}
|
||||
else if (state.getPackageFacadesAsMultifileClasses()) {
|
||||
multifileClassFqNameToFiles.putValue(PackageClassUtils.getPackageClassFqName(file.getPackageFqName()), file);
|
||||
}
|
||||
else {
|
||||
packageFqNameToFiles.putValue(file.getPackageFqName(), file);
|
||||
}
|
||||
}
|
||||
|
||||
Set<FqName> packagesWithObsoleteParts = new HashSet<FqName>(state.getPackagesWithObsoleteParts());
|
||||
for (FqName fqName : Sets.union(packagesWithObsoleteParts, packageFqNameToFiles.keySet())) {
|
||||
for (FqName packageFqName : Sets.union(packagesWithObsoleteParts, packageFqNameToFiles.keySet())) {
|
||||
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled();
|
||||
generatePackage(state, fqName, packageFqNameToFiles.get(fqName), errorHandler);
|
||||
generatePackage(state, packageFqName, packageFqNameToFiles.get(packageFqName), errorHandler);
|
||||
}
|
||||
|
||||
for (FqName multifileClassFqName : multifileClassFqNameToFiles.keySet()) {
|
||||
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled();
|
||||
generateMultifileClass(state, multifileClassFqName, multifileClassFqNameToFiles.get(multifileClassFqName), errorHandler);
|
||||
}
|
||||
|
||||
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled();
|
||||
@@ -79,13 +97,23 @@ public class KotlinCodegenFacade {
|
||||
|
||||
public static void generatePackage(
|
||||
@NotNull GenerationState state,
|
||||
@NotNull FqName fqName,
|
||||
@NotNull FqName packageFqName,
|
||||
@NotNull Collection<JetFile> jetFiles,
|
||||
@NotNull CompilationErrorHandler errorHandler
|
||||
) {
|
||||
PackageCodegen codegen = state.getFactory().forPackage(fqName, jetFiles);
|
||||
PackageCodegen codegen = state.getFactory().forPackage(packageFqName, jetFiles);
|
||||
codegen.generate(errorHandler);
|
||||
}
|
||||
|
||||
private static void generateMultifileClass(
|
||||
@NotNull GenerationState state,
|
||||
@NotNull FqName multifileClassFqName,
|
||||
@NotNull Collection<JetFile> files,
|
||||
@NotNull CompilationErrorHandler handler
|
||||
) {
|
||||
MultifileClassCodegen codegen = state.getFactory().forMultifileClass(multifileClassFqName, files);
|
||||
codegen.generate(handler);
|
||||
}
|
||||
|
||||
private KotlinCodegenFacade() {}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,272 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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.codegen
|
||||
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.progress.ProcessCanceledException
|
||||
import com.intellij.util.ArrayUtil
|
||||
import com.intellij.util.SmartList
|
||||
import com.intellij.util.containers.ContainerUtil
|
||||
import org.jetbrains.kotlin.codegen.context.CodegenContext
|
||||
import org.jetbrains.kotlin.codegen.context.FieldOwnerContext
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||
import org.jetbrains.kotlin.config.IncrementalCompilation
|
||||
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticUtils
|
||||
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||
import org.jetbrains.kotlin.load.java.JvmAnnotationNames
|
||||
import org.jetbrains.kotlin.load.kotlin.incremental.IncrementalPackageFragmentProvider
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.MemberComparator
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.MultifileClass
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.MultifileClassPart
|
||||
import org.jetbrains.kotlin.serialization.DescriptorSerializer
|
||||
import org.jetbrains.kotlin.serialization.PackageData
|
||||
import org.jetbrains.kotlin.serialization.SerializationUtil
|
||||
import org.jetbrains.kotlin.serialization.deserialization.NameResolver
|
||||
import org.jetbrains.kotlin.serialization.jvm.BitEncoding
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import java.util.*
|
||||
|
||||
|
||||
public class MultifileClassCodegen(
|
||||
private val state: GenerationState,
|
||||
private val files: Collection<JetFile>,
|
||||
private val facadeFqName: FqName
|
||||
) {
|
||||
private val facadeClassType = AsmUtil.asmTypeByFqNameWithoutInnerClasses(facadeFqName)
|
||||
|
||||
private val packageFragment = getOnlyPackageFragment(facadeFqName.parent(), files, state.bindingContext)
|
||||
|
||||
private val compiledPackageFragment = getCompiledPackageFragment(facadeFqName.parent(), state)
|
||||
|
||||
// TODO incremental compilation support
|
||||
// TODO previouslyCompiledCallables
|
||||
// We can do this (probably without 'compiledPackageFragment') after modifications to part codegen.
|
||||
|
||||
private val classBuilder = ClassBuilderOnDemand {
|
||||
val filesWithTopLevelCallables = files.filter { hasTopLevelCallables(it) }
|
||||
val sourceFile = filesWithTopLevelCallables.firstOrNull()
|
||||
val actualPackageFragment = packageFragment ?:
|
||||
compiledPackageFragment ?:
|
||||
throw AssertionError("No package fragment for multifile facade $facadeFqName; files: $files")
|
||||
val declarationOrigin = MultifileClass(actualPackageFragment, facadeFqName)
|
||||
val classBuilder = state.factory.newVisitor(declarationOrigin, facadeClassType, filesWithTopLevelCallables)
|
||||
|
||||
classBuilder.defineClass(sourceFile, Opcodes.V1_6, FACADE_CLASS_ATTRIBUTES,
|
||||
facadeClassType.internalName,
|
||||
null, "java/lang/Object", ArrayUtil.EMPTY_STRING_ARRAY)
|
||||
sourceFile?.let { classBuilder.visitSource(it.name, null) }
|
||||
classBuilder
|
||||
}
|
||||
|
||||
private fun hasTopLevelCallables(file: JetFile) =
|
||||
file.declarations.any { it is JetNamedFunction || it is JetProperty }
|
||||
|
||||
public fun generate(errorHandler: CompilationErrorHandler) {
|
||||
val bindings = ArrayList<JvmSerializationBindings>(files.size() + 1)
|
||||
val generateCallableMemberTasks = HashMap<CallableMemberDescriptor, () -> Unit>()
|
||||
val partFqNames = arrayListOf<FqName>()
|
||||
|
||||
for (file in files) {
|
||||
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled()
|
||||
try {
|
||||
val partClassBuilder = generatePart(file, generateCallableMemberTasks, partFqNames)
|
||||
if (partClassBuilder != null) {
|
||||
bindings.add(partClassBuilder.serializationBindings)
|
||||
}
|
||||
}
|
||||
catch (e: ProcessCanceledException) {
|
||||
throw e
|
||||
}
|
||||
catch (e: Throwable) {
|
||||
val vFile = file.virtualFile
|
||||
errorHandler.reportException(e, if (vFile == null) "no file" else vFile.url)
|
||||
DiagnosticUtils.throwIfRunningOnServer(e)
|
||||
if (ApplicationManager.getApplication().isInternal) {
|
||||
//noinspection CallToPrintStackTrace
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// generateDelegationsToPreviouslyCompiled(generateCallableMemberTasks)
|
||||
|
||||
if (!generateCallableMemberTasks.isEmpty()) {
|
||||
generateMultifileFacadeClass(generateCallableMemberTasks, bindings, partFqNames)
|
||||
}
|
||||
}
|
||||
|
||||
private fun generateMultifileFacadeClass(
|
||||
tasks: Map<CallableMemberDescriptor, () -> Unit>,
|
||||
bindings: MutableList<JvmSerializationBindings>,
|
||||
partFqNames: List<FqName>
|
||||
) {
|
||||
MemberCodegen.generateModuleNameField(state, classBuilder)
|
||||
|
||||
for (member in tasks.keySet().sortedWith(MemberComparator.INSTANCE)) {
|
||||
tasks[member]!!()
|
||||
}
|
||||
|
||||
bindings.add(classBuilder.serializationBindings)
|
||||
writeKotlinMultifileFacadeAnnotationIfNeeded(JvmSerializationBindings.union(bindings), partFqNames)
|
||||
}
|
||||
|
||||
public fun generateClassOrObject(classOrObject: JetClassOrObject) {
|
||||
val file = classOrObject.getContainingJetFile()
|
||||
val packagePartType = state.fileClassesProvider.getFileClassType(file)
|
||||
val context = CodegenContext.STATIC.intoPackagePart(packageFragment!!, packagePartType)
|
||||
MemberCodegen.genClassOrObject(context, classOrObject, state, null)
|
||||
}
|
||||
|
||||
private fun generatePart(
|
||||
file: JetFile,
|
||||
generateCallableMemberTasks: MutableMap<CallableMemberDescriptor, () -> Unit>,
|
||||
partFqNames: MutableList<FqName>
|
||||
): ClassBuilder? {
|
||||
val packageFragment = this.packageFragment ?:
|
||||
throw AssertionError("File part $file of $facadeFqName: no package fragment")
|
||||
|
||||
var generatePart = false
|
||||
val partClassInfo = state.fileClassesProvider.getFileClassInfo(file)
|
||||
val partType = AsmUtil.asmTypeByFqNameWithoutInnerClasses(partClassInfo.fileClassFqName)
|
||||
val partContext = CodegenContext.STATIC.intoMultifileClassPart(packageFragment, facadeClassType, partType)
|
||||
|
||||
for (declaration in file.declarations) {
|
||||
if (declaration is JetProperty || declaration is JetNamedFunction) {
|
||||
generatePart = true
|
||||
}
|
||||
else if (declaration is JetClassOrObject) {
|
||||
if (state.generateDeclaredClassFilter.shouldGenerateClass(declaration)) {
|
||||
generateClassOrObject(declaration)
|
||||
}
|
||||
}
|
||||
else if (declaration is JetScript) {
|
||||
|
||||
// SCRIPT: generate script code, should be separate execution branch
|
||||
if (state.generateDeclaredClassFilter.shouldGenerateScript(declaration)) {
|
||||
ScriptCodegen.createScriptCodegen(declaration, state, partContext).generate()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!generatePart || !state.generateDeclaredClassFilter.shouldGeneratePackagePart(file)) return null
|
||||
|
||||
partFqNames.add(partClassInfo.fileClassFqName)
|
||||
|
||||
// val name = partType.internalName
|
||||
// packageParts.parts.add(name.substring(name.lastIndexOf('/') + 1))
|
||||
|
||||
val builder = state.factory.newVisitor(MultifileClassPart(file, packageFragment, facadeFqName), partType, file)
|
||||
|
||||
MultifileClassPartCodegen(builder, file, partType, facadeFqName, partContext, state).generate()
|
||||
|
||||
val facadeContext = CodegenContext.STATIC.intoMultifileClass(packageFragment, facadeClassType, partType)
|
||||
val memberCodegen = createCodegenForPartOfMultifileFacade(facadeContext)
|
||||
for (declaration in file.declarations) {
|
||||
if (declaration is JetNamedFunction || declaration is JetProperty) {
|
||||
val descriptor = state.bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, declaration)
|
||||
assert(descriptor is CallableMemberDescriptor) { "Expected callable member, was " + descriptor + " for " + declaration.text }
|
||||
generateCallableMemberTasks.put(descriptor as CallableMemberDescriptor,
|
||||
{ memberCodegen.genFunctionOrProperty(declaration) })
|
||||
}
|
||||
}
|
||||
|
||||
return builder
|
||||
}
|
||||
|
||||
private fun writeKotlinMultifileFacadeAnnotationIfNeeded(bindings: JvmSerializationBindings, partFqNames: List<FqName>) {
|
||||
if (state.classBuilderMode != ClassBuilderMode.FULL) return
|
||||
if (files.any { it.isScript }) return
|
||||
|
||||
val serializer = DescriptorSerializer.createTopLevel(JvmSerializerExtension(bindings, state.typeMapper))
|
||||
|
||||
val packageFragments = arrayListOf<PackageFragmentDescriptor>()
|
||||
ContainerUtil.addIfNotNull(packageFragments, packageFragment)
|
||||
ContainerUtil.addIfNotNull(packageFragments, compiledPackageFragment)
|
||||
val facadeProto = serializer.packageProto(packageFragments, /* skip= */ { true }).build()
|
||||
|
||||
val strings = serializer.stringTable
|
||||
val nameResolver = NameResolver(strings.serializeSimpleNames(), strings.serializeQualifiedNames())
|
||||
val facadeData = PackageData(nameResolver, facadeProto)
|
||||
|
||||
val av = classBuilder.newAnnotation(AsmUtil.asmDescByFqNameWithoutInnerClasses(JvmAnnotationNames.KOTLIN_MULTIFILE_CLASS), true)
|
||||
av.visit(JvmAnnotationNames.ABI_VERSION_FIELD_NAME, JvmAbi.VERSION)
|
||||
|
||||
val shortNames = partFqNames.map { it.shortName().asString() }.sorted()
|
||||
val filePartClassNamesArray = av.visitArray(JvmAnnotationNames.FILE_PART_CLASS_NAMES_FIELD_NAME)
|
||||
for (shortName in shortNames) {
|
||||
filePartClassNamesArray.visit(null, shortName)
|
||||
}
|
||||
filePartClassNamesArray.visitEnd()
|
||||
|
||||
val dataArray = av.visitArray(JvmAnnotationNames.DATA_FIELD_NAME)
|
||||
for (string in BitEncoding.encodeBytes(SerializationUtil.serializePackageData(facadeData))) {
|
||||
dataArray.visit(null, string)
|
||||
}
|
||||
dataArray.visitEnd()
|
||||
|
||||
av.visitEnd()
|
||||
}
|
||||
|
||||
private fun createCodegenForPartOfMultifileFacade(facadeContext: FieldOwnerContext<DeclarationDescriptor>): MemberCodegen<JetFile> =
|
||||
object : MemberCodegen<JetFile>(state, null, facadeContext, null, classBuilder) {
|
||||
override fun generateDeclaration() = throw UnsupportedOperationException()
|
||||
override fun generateBody() = throw UnsupportedOperationException()
|
||||
override fun generateKotlinAnnotation() = throw UnsupportedOperationException()
|
||||
}
|
||||
|
||||
public fun done() {
|
||||
classBuilder.done()
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val FACADE_CLASS_ATTRIBUTES = Opcodes.ACC_PUBLIC or Opcodes.ACC_FINAL
|
||||
|
||||
private fun getOnlyPackageFragment(packageFqName: FqName, files: Collection<JetFile>, bindingContext: BindingContext): PackageFragmentDescriptor? {
|
||||
val fragments = SmartList<PackageFragmentDescriptor>()
|
||||
for (file in files) {
|
||||
val fragment = bindingContext.get(BindingContext.FILE_TO_PACKAGE_FRAGMENT, file)
|
||||
assert(fragment != null) { "package fragment is null for " + file + "\n" + file.text }
|
||||
|
||||
assert(packageFqName == fragment!!.fqName) { "expected package fq name: " + packageFqName + ", actual: " + fragment.fqName }
|
||||
|
||||
if (!fragments.contains(fragment)) {
|
||||
fragments.add(fragment)
|
||||
}
|
||||
}
|
||||
if (fragments.size() > 1) {
|
||||
throw IllegalStateException("More than one package fragment, files: $files | fragments: $fragments")
|
||||
}
|
||||
return fragments.firstOrNull()
|
||||
}
|
||||
|
||||
private fun getCompiledPackageFragment(packageFqName: FqName, state: GenerationState): PackageFragmentDescriptor? =
|
||||
if (!IncrementalCompilation.ENABLED) null
|
||||
else state.module.getPackage(packageFqName).fragments.firstOrNull { fragment ->
|
||||
fragment is IncrementalPackageFragmentProvider.IncrementalPackageFragment &&
|
||||
fragment.moduleId == state.moduleId
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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.codegen
|
||||
|
||||
import com.intellij.util.ArrayUtil
|
||||
import org.jetbrains.kotlin.codegen.context.FieldOwnerContext
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||
import org.jetbrains.kotlin.load.java.JvmAnnotationNames
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.psi.JetFile
|
||||
import org.jetbrains.kotlin.psi.JetNamedFunction
|
||||
import org.jetbrains.kotlin.psi.JetProperty
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.serialization.DescriptorSerializer
|
||||
import org.jetbrains.kotlin.serialization.PackageData
|
||||
import org.jetbrains.kotlin.serialization.SerializationUtil
|
||||
import org.jetbrains.kotlin.serialization.deserialization.NameResolver
|
||||
import org.jetbrains.kotlin.serialization.jvm.BitEncoding
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import java.util.*
|
||||
|
||||
|
||||
public class MultifileClassPartCodegen(
|
||||
v: ClassBuilder,
|
||||
file: JetFile,
|
||||
private val filePartType: Type,
|
||||
private val multifileClassFqName: FqName,
|
||||
partContext: FieldOwnerContext<*>,
|
||||
state: GenerationState
|
||||
) : MemberCodegen<JetFile>(state, null, partContext, file, v){
|
||||
override fun generateDeclaration() {
|
||||
v.defineClass(element, Opcodes.V1_6,
|
||||
Opcodes.ACC_SYNTHETIC,
|
||||
filePartType.internalName,
|
||||
null,
|
||||
"java/lang/Object",
|
||||
ArrayUtil.EMPTY_STRING_ARRAY)
|
||||
v.visitSource(element.name, null)
|
||||
|
||||
generatePropertyMetadataArrayFieldIfNeeded(filePartType)
|
||||
}
|
||||
|
||||
override fun generateBody() {
|
||||
for (declaration in element.declarations) {
|
||||
if (declaration is JetNamedFunction || declaration is JetProperty) {
|
||||
genFunctionOrProperty(declaration);
|
||||
}
|
||||
}
|
||||
|
||||
if (state.classBuilderMode == ClassBuilderMode.FULL) {
|
||||
generateInitializers({ createOrGetClInitCodegen(); });
|
||||
}
|
||||
}
|
||||
|
||||
override fun generateKotlinAnnotation() {
|
||||
if (state.classBuilderMode != ClassBuilderMode.FULL) {
|
||||
return
|
||||
}
|
||||
|
||||
val members = ArrayList<DeclarationDescriptor>()
|
||||
for (declaration in element.declarations) {
|
||||
when (declaration) {
|
||||
is JetNamedFunction -> {
|
||||
val functionDescriptor = bindingContext.get(BindingContext.FUNCTION, declaration)
|
||||
members.add(functionDescriptor ?: throw AssertionError("Function ${declaration.name} is not bound in ${element.name}"))
|
||||
}
|
||||
is JetProperty -> {
|
||||
val property = bindingContext.get(BindingContext.VARIABLE, declaration)
|
||||
members.add(property ?: throw AssertionError("Property ${declaration.name} is not bound in ${element.name}"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val bindings = v.serializationBindings
|
||||
|
||||
val serializer = DescriptorSerializer.createTopLevel(JvmSerializerExtension(bindings, state.typeMapper))
|
||||
val packageProto = serializer.packagePartProto(members).build()
|
||||
|
||||
if (packageProto.memberCount == 0) return
|
||||
|
||||
val strings = serializer.stringTable
|
||||
val nameResolver = NameResolver(strings.serializeSimpleNames(), strings.serializeQualifiedNames())
|
||||
val data = PackageData(nameResolver, packageProto)
|
||||
|
||||
val av = v.newAnnotation(AsmUtil.asmDescByFqNameWithoutInnerClasses(JvmAnnotationNames.KOTLIN_MULTIFILE_CLASS_PART), true)
|
||||
av.visit(JvmAnnotationNames.ABI_VERSION_FIELD_NAME, JvmAbi.VERSION)
|
||||
av.visit(JvmAnnotationNames.MULTIFILE_CLASS_NAME_FIELD_NAME, multifileClassFqName.shortName().asString())
|
||||
val dataArray = av.visitArray(JvmAnnotationNames.DATA_FIELD_NAME)
|
||||
for (string in BitEncoding.encodeBytes(SerializationUtil.serializePackageData(data))) {
|
||||
dataArray.visit(null, string)
|
||||
}
|
||||
dataArray.visitEnd()
|
||||
av.visitEnd()
|
||||
}
|
||||
}
|
||||
@@ -39,6 +39,7 @@ import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor;
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticUtils;
|
||||
import org.jetbrains.kotlin.fileClasses.JvmFileClassInfo;
|
||||
import org.jetbrains.kotlin.load.java.JvmAbi;
|
||||
import org.jetbrains.kotlin.load.java.JvmAnnotationNames;
|
||||
import org.jetbrains.kotlin.load.kotlin.PackagePartClassUtils;
|
||||
@@ -335,7 +336,6 @@ public class PackageCodegen {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!generatePackagePart || !state.getGenerateDeclaredClassFilter().shouldGeneratePackagePart(file)) return null;
|
||||
|
||||
String name = packagePartType.getInternalName();
|
||||
|
||||
@@ -189,6 +189,24 @@ public abstract class CodegenContext<T extends DeclarationDescriptor> {
|
||||
return new PackageFacadeContext(descriptor, this, delegateTo);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public FieldOwnerContext<PackageFragmentDescriptor> intoMultifileClassPart(
|
||||
@NotNull PackageFragmentDescriptor descriptor,
|
||||
@NotNull Type multifileClassType,
|
||||
@NotNull Type filePartType
|
||||
) {
|
||||
return new MultifileClassPartContext(descriptor, this, multifileClassType, filePartType);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public FieldOwnerContext<PackageFragmentDescriptor> intoMultifileClass(
|
||||
@NotNull PackageFragmentDescriptor descriptor,
|
||||
@NotNull Type multifileClassType,
|
||||
@NotNull Type filePartType
|
||||
) {
|
||||
return new MultifileClassContext(descriptor, this, multifileClassType, filePartType);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public ClassContext intoClass(ClassDescriptor descriptor, OwnerKind kind, GenerationState state) {
|
||||
return new ClassContext(state.getTypeMapper(), descriptor, kind, this, null);
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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.codegen.context;
|
||||
|
||||
import org.jetbrains.kotlin.codegen.OwnerKind;
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor;
|
||||
import org.jetbrains.org.objectweb.asm.Type;
|
||||
|
||||
public class MultifileClassContext extends FieldOwnerContext<PackageFragmentDescriptor> {
|
||||
private final Type multifileClassType;
|
||||
private final Type filePartType;
|
||||
|
||||
public MultifileClassContext(
|
||||
PackageFragmentDescriptor descriptor,
|
||||
CodegenContext parent,
|
||||
Type multifileClassType,
|
||||
Type filePartType
|
||||
) {
|
||||
super(descriptor, OwnerKind.PACKAGE, parent, null, null, null);
|
||||
this.multifileClassType = multifileClassType;
|
||||
this.filePartType = filePartType;
|
||||
}
|
||||
|
||||
public Type getMultifileClassType() {
|
||||
return multifileClassType;
|
||||
}
|
||||
|
||||
public Type getFilePartType() {
|
||||
return filePartType;
|
||||
}
|
||||
}
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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.codegen.context;
|
||||
|
||||
import org.jetbrains.kotlin.codegen.OwnerKind;
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor;
|
||||
import org.jetbrains.org.objectweb.asm.Type;
|
||||
|
||||
public class MultifileClassPartContext extends FieldOwnerContext<PackageFragmentDescriptor> {
|
||||
private final Type multifileClassType;
|
||||
private final Type filePartType;
|
||||
|
||||
public MultifileClassPartContext(
|
||||
PackageFragmentDescriptor descriptor,
|
||||
CodegenContext parent,
|
||||
Type multifileClassType,
|
||||
Type filePartType
|
||||
) {
|
||||
super(descriptor, OwnerKind.PACKAGE, parent, null, null, null);
|
||||
this.multifileClassType = multifileClassType;
|
||||
this.filePartType = filePartType;
|
||||
}
|
||||
|
||||
public Type getMultifileClassType() {
|
||||
return multifileClassType;
|
||||
}
|
||||
|
||||
public Type getFilePartType() {
|
||||
return filePartType;
|
||||
}
|
||||
}
|
||||
@@ -52,6 +52,7 @@ public class GenerationState jvmOverloads constructor(
|
||||
public val generateDeclaredClassFilter: GenerationState.GenerateClassFilter = GenerationState.GenerateClassFilter.GENERATE_ALL,
|
||||
disableInline: Boolean = false,
|
||||
disableOptimization: Boolean = false,
|
||||
public val packageFacadesAsMultifileClasses: Boolean = false,
|
||||
public val diagnostics: DiagnosticSink = DiagnosticSink.DO_NOTHING,
|
||||
public val packagesWithObsoleteParts: Collection<FqName> = emptySet(),
|
||||
// for PackageCodegen in incremental compilation mode
|
||||
|
||||
Reference in New Issue
Block a user