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 GenerationState state;
|
||||||
private final ClassBuilderFactory builderFactory;
|
private final ClassBuilderFactory builderFactory;
|
||||||
private final Map<FqName, PackageCodegen> package2codegen = new HashMap<FqName, PackageCodegen>();
|
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 final Map<String, OutAndSourceFileList> generators = new LinkedHashMap<String, OutAndSourceFileList>();
|
||||||
|
|
||||||
private boolean isDone = false;
|
private boolean isDone = false;
|
||||||
@@ -189,7 +190,7 @@ public class ClassFileFactory implements OutputFileCollection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@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!";
|
assert !isDone : "Already done!";
|
||||||
PackageCodegen codegen = package2codegen.get(facadeFqName);
|
PackageCodegen codegen = package2codegen.get(facadeFqName);
|
||||||
if (codegen == null) {
|
if (codegen == null) {
|
||||||
@@ -200,6 +201,17 @@ public class ClassFileFactory implements OutputFileCollection {
|
|||||||
return codegen;
|
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
|
@NotNull
|
||||||
private static List<File> toIoFilesIgnoringNonPhysical(@NotNull Collection<? extends PsiFile> psiFiles) {
|
private static List<File> toIoFilesIgnoringNonPhysical(@NotNull Collection<? extends PsiFile> psiFiles) {
|
||||||
List<File> result = Lists.newArrayList();
|
List<File> result = Lists.newArrayList();
|
||||||
|
|||||||
@@ -20,6 +20,8 @@ import com.google.common.collect.Sets;
|
|||||||
import com.intellij.util.containers.MultiMap;
|
import com.intellij.util.containers.MultiMap;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.kotlin.codegen.state.GenerationState;
|
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.progress.ProgressIndicatorAndCompilationCanceledStatus;
|
||||||
import org.jetbrains.kotlin.name.FqName;
|
import org.jetbrains.kotlin.name.FqName;
|
||||||
import org.jetbrains.kotlin.psi.JetFile;
|
import org.jetbrains.kotlin.psi.JetFile;
|
||||||
@@ -62,15 +64,31 @@ public class KotlinCodegenFacade {
|
|||||||
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled();
|
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled();
|
||||||
|
|
||||||
MultiMap<FqName, JetFile> packageFqNameToFiles = new MultiMap<FqName, JetFile>();
|
MultiMap<FqName, JetFile> packageFqNameToFiles = new MultiMap<FqName, JetFile>();
|
||||||
|
MultiMap<FqName, JetFile> multifileClassFqNameToFiles = new MultiMap<FqName, JetFile>();
|
||||||
|
|
||||||
for (JetFile file : state.getFiles()) {
|
for (JetFile file : state.getFiles()) {
|
||||||
if (file == null) throw new IllegalArgumentException("A null file given for compilation");
|
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());
|
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();
|
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();
|
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled();
|
||||||
@@ -79,13 +97,23 @@ public class KotlinCodegenFacade {
|
|||||||
|
|
||||||
public static void generatePackage(
|
public static void generatePackage(
|
||||||
@NotNull GenerationState state,
|
@NotNull GenerationState state,
|
||||||
@NotNull FqName fqName,
|
@NotNull FqName packageFqName,
|
||||||
@NotNull Collection<JetFile> jetFiles,
|
@NotNull Collection<JetFile> jetFiles,
|
||||||
@NotNull CompilationErrorHandler errorHandler
|
@NotNull CompilationErrorHandler errorHandler
|
||||||
) {
|
) {
|
||||||
PackageCodegen codegen = state.getFactory().forPackage(fqName, jetFiles);
|
PackageCodegen codegen = state.getFactory().forPackage(packageFqName, jetFiles);
|
||||||
codegen.generate(errorHandler);
|
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() {}
|
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.DeclarationDescriptor;
|
||||||
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor;
|
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor;
|
||||||
import org.jetbrains.kotlin.diagnostics.DiagnosticUtils;
|
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.JvmAbi;
|
||||||
import org.jetbrains.kotlin.load.java.JvmAnnotationNames;
|
import org.jetbrains.kotlin.load.java.JvmAnnotationNames;
|
||||||
import org.jetbrains.kotlin.load.kotlin.PackagePartClassUtils;
|
import org.jetbrains.kotlin.load.kotlin.PackagePartClassUtils;
|
||||||
@@ -335,7 +336,6 @@ public class PackageCodegen {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (!generatePackagePart || !state.getGenerateDeclaredClassFilter().shouldGeneratePackagePart(file)) return null;
|
if (!generatePackagePart || !state.getGenerateDeclaredClassFilter().shouldGeneratePackagePart(file)) return null;
|
||||||
|
|
||||||
String name = packagePartType.getInternalName();
|
String name = packagePartType.getInternalName();
|
||||||
|
|||||||
@@ -189,6 +189,24 @@ public abstract class CodegenContext<T extends DeclarationDescriptor> {
|
|||||||
return new PackageFacadeContext(descriptor, this, delegateTo);
|
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
|
@NotNull
|
||||||
public ClassContext intoClass(ClassDescriptor descriptor, OwnerKind kind, GenerationState state) {
|
public ClassContext intoClass(ClassDescriptor descriptor, OwnerKind kind, GenerationState state) {
|
||||||
return new ClassContext(state.getTypeMapper(), descriptor, kind, this, null);
|
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,
|
public val generateDeclaredClassFilter: GenerationState.GenerateClassFilter = GenerationState.GenerateClassFilter.GENERATE_ALL,
|
||||||
disableInline: Boolean = false,
|
disableInline: Boolean = false,
|
||||||
disableOptimization: Boolean = false,
|
disableOptimization: Boolean = false,
|
||||||
|
public val packageFacadesAsMultifileClasses: Boolean = false,
|
||||||
public val diagnostics: DiagnosticSink = DiagnosticSink.DO_NOTHING,
|
public val diagnostics: DiagnosticSink = DiagnosticSink.DO_NOTHING,
|
||||||
public val packagesWithObsoleteParts: Collection<FqName> = emptySet(),
|
public val packagesWithObsoleteParts: Collection<FqName> = emptySet(),
|
||||||
// for PackageCodegen in incremental compilation mode
|
// for PackageCodegen in incremental compilation mode
|
||||||
|
|||||||
+3
@@ -69,6 +69,9 @@ public class K2JVMCompilerArguments extends CommonCompilerArguments {
|
|||||||
@Argument(value = "Xno-optimize", description = "Disable optimizations")
|
@Argument(value = "Xno-optimize", description = "Disable optimizations")
|
||||||
public boolean noOptimize;
|
public boolean noOptimize;
|
||||||
|
|
||||||
|
@Argument(value = "Xmultifile-package-facades", description = "Compile package facade classes as multifile classes")
|
||||||
|
public boolean packageFacadesAsMultifileClasses;
|
||||||
|
|
||||||
@Argument(value = "Xreport-perf", description = "Report detailed performance statistics")
|
@Argument(value = "Xreport-perf", description = "Report detailed performance statistics")
|
||||||
public boolean reportPerf;
|
public boolean reportPerf;
|
||||||
|
|
||||||
|
|||||||
@@ -272,6 +272,7 @@ public open class K2JVMCompiler : CLICompiler<K2JVMCompilerArguments>() {
|
|||||||
configuration.put(JVMConfigurationKeys.DISABLE_PARAM_ASSERTIONS, arguments.noParamAssertions)
|
configuration.put(JVMConfigurationKeys.DISABLE_PARAM_ASSERTIONS, arguments.noParamAssertions)
|
||||||
configuration.put(JVMConfigurationKeys.DISABLE_INLINE, arguments.noInline)
|
configuration.put(JVMConfigurationKeys.DISABLE_INLINE, arguments.noInline)
|
||||||
configuration.put(JVMConfigurationKeys.DISABLE_OPTIMIZATION, arguments.noOptimize)
|
configuration.put(JVMConfigurationKeys.DISABLE_OPTIMIZATION, arguments.noOptimize)
|
||||||
|
configuration.put(JVMConfigurationKeys.PACKAGE_FACADES_AS_MULTIFILE_CLASSES, arguments.packageFacadesAsMultifileClasses);
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getClasspath(paths: KotlinPaths, arguments: K2JVMCompilerArguments): List<File> {
|
private fun getClasspath(paths: KotlinPaths, arguments: K2JVMCompilerArguments): List<File> {
|
||||||
|
|||||||
+1
@@ -392,6 +392,7 @@ public class KotlinToJVMBytecodeCompiler {
|
|||||||
GenerationState.GenerateClassFilter.GENERATE_ALL,
|
GenerationState.GenerateClassFilter.GENERATE_ALL,
|
||||||
configuration.get(JVMConfigurationKeys.DISABLE_INLINE, false),
|
configuration.get(JVMConfigurationKeys.DISABLE_INLINE, false),
|
||||||
configuration.get(JVMConfigurationKeys.DISABLE_OPTIMIZATION, false),
|
configuration.get(JVMConfigurationKeys.DISABLE_OPTIMIZATION, false),
|
||||||
|
configuration.get(JVMConfigurationKeys.PACKAGE_FACADES_AS_MULTIFILE_CLASSES, false),
|
||||||
diagnosticHolder,
|
diagnosticHolder,
|
||||||
packagesWithObsoleteParts,
|
packagesWithObsoleteParts,
|
||||||
targetId,
|
targetId,
|
||||||
|
|||||||
@@ -42,6 +42,8 @@ public class JVMConfigurationKeys {
|
|||||||
CompilerConfigurationKey.create("disable inline");
|
CompilerConfigurationKey.create("disable inline");
|
||||||
public static final CompilerConfigurationKey<Boolean> DISABLE_OPTIMIZATION =
|
public static final CompilerConfigurationKey<Boolean> DISABLE_OPTIMIZATION =
|
||||||
CompilerConfigurationKey.create("disable optimization");
|
CompilerConfigurationKey.create("disable optimization");
|
||||||
|
public static final CompilerConfigurationKey<Boolean> PACKAGE_FACADES_AS_MULTIFILE_CLASSES =
|
||||||
|
CompilerConfigurationKey.create("compile package facades as multifile classes");
|
||||||
|
|
||||||
public static final CompilerConfigurationKey<IncrementalCompilationComponents> INCREMENTAL_COMPILATION_COMPONENTS =
|
public static final CompilerConfigurationKey<IncrementalCompilationComponents> INCREMENTAL_COMPILATION_COMPONENTS =
|
||||||
CompilerConfigurationKey.create("incremental cache provider");
|
CompilerConfigurationKey.create("incremental cache provider");
|
||||||
|
|||||||
@@ -22,30 +22,23 @@ import org.jetbrains.kotlin.psi.JetFile
|
|||||||
public interface JvmFileClassInfo {
|
public interface JvmFileClassInfo {
|
||||||
public val fileClassFqName: FqName
|
public val fileClassFqName: FqName
|
||||||
public val facadeClassFqName: FqName
|
public val facadeClassFqName: FqName
|
||||||
public val kind: Kind
|
public val isWithJvmName: Boolean
|
||||||
|
public val isMultifileClass: Boolean
|
||||||
public enum class Kind {
|
|
||||||
FILE_CLASS,
|
|
||||||
MULTIFILE_CLASS_PART
|
|
||||||
;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class JvmFileFacadeInfo(
|
public class JvmSimpleFileClassInfo(
|
||||||
override val fileClassFqName: FqName
|
override val fileClassFqName: FqName,
|
||||||
|
override val isWithJvmName: Boolean
|
||||||
) : JvmFileClassInfo {
|
) : JvmFileClassInfo {
|
||||||
override val facadeClassFqName: FqName
|
override val facadeClassFqName: FqName get() = fileClassFqName
|
||||||
get() = fileClassFqName
|
override val isMultifileClass: Boolean get() = false
|
||||||
override val kind: JvmFileClassInfo.Kind
|
|
||||||
get() = JvmFileClassInfo.Kind.FILE_CLASS
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class JvmMultifileFacadePartInfo(
|
public class JvmMultifileClassPartInfo(
|
||||||
override val fileClassFqName: FqName,
|
override val fileClassFqName: FqName,
|
||||||
override val facadeClassFqName: FqName
|
override val facadeClassFqName: FqName
|
||||||
) : JvmFileClassInfo {
|
) : JvmFileClassInfo {
|
||||||
override val kind: JvmFileClassInfo.Kind
|
override val isWithJvmName: Boolean get() = true
|
||||||
get() = JvmFileClassInfo.Kind.MULTIFILE_CLASS_PART
|
override val isMultifileClass: Boolean get() = true
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,7 +30,8 @@ public object JvmFileClassUtil {
|
|||||||
public val JVM_NAME: FqName = FqName("kotlin.jvm.JvmName")
|
public val JVM_NAME: FqName = FqName("kotlin.jvm.JvmName")
|
||||||
public val JVM_NAME_SHORT: String = JVM_NAME.shortName().asString()
|
public val JVM_NAME_SHORT: String = JVM_NAME.shortName().asString()
|
||||||
|
|
||||||
// TODO @JvmMultifileClass
|
public val JVM_MULTIFILE_CLASS: FqName = FqName("kotlin.jvm.JvmMultifileClass")
|
||||||
|
public val JVM_MULTIFILE_CLASS_SHORT = JVM_MULTIFILE_CLASS.shortName().asString()
|
||||||
|
|
||||||
public @jvmStatic fun getFileClassInfo(file: JetFile, jvmFileClassAnnotations: ParsedJmvFileClassAnnotations?): JvmFileClassInfo =
|
public @jvmStatic fun getFileClassInfo(file: JetFile, jvmFileClassAnnotations: ParsedJmvFileClassAnnotations?): JvmFileClassInfo =
|
||||||
if (jvmFileClassAnnotations != null)
|
if (jvmFileClassAnnotations != null)
|
||||||
@@ -40,13 +41,13 @@ public object JvmFileClassUtil {
|
|||||||
|
|
||||||
public @jvmStatic fun getFileClassInfoForAnnotation(file: JetFile, jvmFileClassAnnotations: ParsedJmvFileClassAnnotations): JvmFileClassInfo =
|
public @jvmStatic fun getFileClassInfoForAnnotation(file: JetFile, jvmFileClassAnnotations: ParsedJmvFileClassAnnotations): JvmFileClassInfo =
|
||||||
if (jvmFileClassAnnotations.multipleFiles)
|
if (jvmFileClassAnnotations.multipleFiles)
|
||||||
JvmMultifileFacadePartInfo(getHiddenPartFqName(file, jvmFileClassAnnotations),
|
JvmMultifileClassPartInfo(getHiddenPartFqName(file, jvmFileClassAnnotations),
|
||||||
getFacadeFqName(file, jvmFileClassAnnotations))
|
getFacadeFqName(file, jvmFileClassAnnotations))
|
||||||
else
|
else
|
||||||
JvmFileFacadeInfo(getFacadeFqName(file, jvmFileClassAnnotations))
|
JvmSimpleFileClassInfo(getFacadeFqName(file, jvmFileClassAnnotations), true)
|
||||||
|
|
||||||
public @jvmStatic fun getDefaultFileClassInfo(file: JetFile): JvmFileClassInfo =
|
public @jvmStatic fun getDefaultFileClassInfo(file: JetFile): JvmFileClassInfo =
|
||||||
JvmFileFacadeInfo(PackagePartClassUtils.getPackagePartFqName(file.packageFqName, file.name))
|
JvmSimpleFileClassInfo(PackagePartClassUtils.getPackagePartFqName(file.packageFqName, file.name), false)
|
||||||
|
|
||||||
public @jvmStatic fun getFacadeFqName(file: JetFile, jvmFileClassAnnotations: ParsedJmvFileClassAnnotations): FqName =
|
public @jvmStatic fun getFacadeFqName(file: JetFile, jvmFileClassAnnotations: ParsedJmvFileClassAnnotations): FqName =
|
||||||
file.packageFqName.child(Name.identifier(jvmFileClassAnnotations.name))
|
file.packageFqName.child(Name.identifier(jvmFileClassAnnotations.name))
|
||||||
@@ -59,31 +60,35 @@ public object JvmFileClassUtil {
|
|||||||
|
|
||||||
public @jvmStatic fun parseJvmFileClass(annotations: Annotations): ParsedJmvFileClassAnnotations? {
|
public @jvmStatic fun parseJvmFileClass(annotations: Annotations): ParsedJmvFileClassAnnotations? {
|
||||||
val jvmName = annotations.findAnnotation(JVM_NAME)
|
val jvmName = annotations.findAnnotation(JVM_NAME)
|
||||||
// TODO @JvmMultifileClass
|
val jvmMultifileClass = annotations.findAnnotation(JVM_MULTIFILE_CLASS)
|
||||||
return if (jvmName != null) parseJvmFileClass(jvmName) else null
|
return jvmName?.let {
|
||||||
|
parseJvmFileClass(it, jvmMultifileClass)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public @jvmStatic fun parseJvmFileClass(jvmName: AnnotationDescriptor): ParsedJmvFileClassAnnotations {
|
public @jvmStatic fun parseJvmFileClass(jvmName: AnnotationDescriptor, jvmMultifileClass: AnnotationDescriptor?): ParsedJmvFileClassAnnotations {
|
||||||
val name = jvmName.allValueArguments.values().firstOrNull()?.let { (it as? StringValue)?.value }
|
val name = jvmName.allValueArguments.values().firstOrNull()?.let { (it as? StringValue)?.value }
|
||||||
return ParsedJmvFileClassAnnotations(name!!, false)
|
val isMultifileClassPart = jvmMultifileClass != null
|
||||||
|
return ParsedJmvFileClassAnnotations(name!!, isMultifileClassPart)
|
||||||
}
|
}
|
||||||
|
|
||||||
public @jvmStatic fun getFileClassInfoNoResolve(file: JetFile): JvmFileClassInfo =
|
public @jvmStatic fun getFileClassInfoNoResolve(file: JetFile): JvmFileClassInfo =
|
||||||
getFileClassInfo(file, parseJvmNameOnFileNoResolve(file))
|
getFileClassInfo(file, parseJvmNameOnFileNoResolve(file))
|
||||||
|
|
||||||
public @jvmStatic fun parseJvmNameOnFileNoResolve(file: JetFile): ParsedJmvFileClassAnnotations? =
|
public @jvmStatic fun parseJvmNameOnFileNoResolve(file: JetFile): ParsedJmvFileClassAnnotations? =
|
||||||
findJvmNameOnFileNoResolve(file)?.let { parseJvmNameOnFileNoResolve(it) }
|
findAnnotationEntryOnFileNoResolve(file, JVM_NAME_SHORT)?.let { annotationEntry ->
|
||||||
|
val nameExpr = annotationEntry.valueArguments.firstOrNull()?.getArgumentExpression() ?: return null
|
||||||
public @jvmStatic fun findJvmNameOnFileNoResolve(file: JetFile): JetAnnotationEntry? =
|
val name = getLiteralStringFromRestrictedConstExpression(nameExpr)
|
||||||
file.fileAnnotationList?.annotationEntries?.firstOrNull {
|
val isMultifileClassPart = findAnnotationEntryOnFileNoResolve(file, JVM_MULTIFILE_CLASS_SHORT) != null
|
||||||
it.calleeExpression?.constructorReferenceExpression?.getReferencedName() == JVM_NAME_SHORT
|
name?.let {
|
||||||
|
ParsedJmvFileClassAnnotations(it, isMultifileClassPart)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public @jvmStatic fun parseJvmNameOnFileNoResolve(annotationEntry: JetAnnotationEntry): ParsedJmvFileClassAnnotations? {
|
public @jvmStatic fun findAnnotationEntryOnFileNoResolve(file: JetFile, shortName: String): JetAnnotationEntry? =
|
||||||
val nameExpr = annotationEntry.valueArguments.firstOrNull()?.getArgumentExpression() ?: return null
|
file.fileAnnotationList?.annotationEntries?.firstOrNull {
|
||||||
val name = getLiteralStringFromRestrictedConstExpression(nameExpr)
|
it.calleeExpression?.constructorReferenceExpression?.getReferencedName() == shortName
|
||||||
return name?.let { ParsedJmvFileClassAnnotations(it, false) }
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private @jvmStatic fun getLiteralStringFromRestrictedConstExpression(argumentExpression: JetExpression?): String? {
|
private @jvmStatic fun getLiteralStringFromRestrictedConstExpression(argumentExpression: JetExpression?): String? {
|
||||||
val stringTemplate = argumentExpression as? JetStringTemplateExpression ?: return null
|
val stringTemplate = argumentExpression as? JetStringTemplateExpression ?: return null
|
||||||
|
|||||||
+10
-1
@@ -25,6 +25,7 @@ import org.jetbrains.kotlin.psi.JetClassOrObject
|
|||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKind.*
|
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKind.*
|
||||||
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
|
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
|
||||||
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
|
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
|
||||||
|
|
||||||
public enum class MemberKind { FIELD, METHOD }
|
public enum class MemberKind { FIELD, METHOD }
|
||||||
@@ -39,13 +40,16 @@ public enum class JvmDeclarationOriginKind {
|
|||||||
DELEGATION_TO_TRAIT_IMPL,
|
DELEGATION_TO_TRAIT_IMPL,
|
||||||
DELEGATION,
|
DELEGATION,
|
||||||
BRIDGE,
|
BRIDGE,
|
||||||
|
MULTIFILE_CLASS,
|
||||||
|
MULTIFILE_CLASS_PART,
|
||||||
SYNTHETIC // this means that there's no proper descriptor for this jvm declaration
|
SYNTHETIC // this means that there's no proper descriptor for this jvm declaration
|
||||||
}
|
}
|
||||||
|
|
||||||
public class JvmDeclarationOrigin(
|
public class JvmDeclarationOrigin(
|
||||||
public val originKind: JvmDeclarationOriginKind,
|
public val originKind: JvmDeclarationOriginKind,
|
||||||
public val element: PsiElement?,
|
public val element: PsiElement?,
|
||||||
public val descriptor: DeclarationDescriptor?
|
public val descriptor: DeclarationDescriptor?,
|
||||||
|
public val multifileClassFqName: FqName? = null
|
||||||
) {
|
) {
|
||||||
companion object {
|
companion object {
|
||||||
public val NO_ORIGIN: JvmDeclarationOrigin = JvmDeclarationOrigin(OTHER, null, null)
|
public val NO_ORIGIN: JvmDeclarationOrigin = JvmDeclarationOrigin(OTHER, null, null)
|
||||||
@@ -67,6 +71,11 @@ public fun Bridge(descriptor: DeclarationDescriptor, element: PsiElement? = Desc
|
|||||||
public fun PackageFacade(descriptor: PackageFragmentDescriptor): JvmDeclarationOrigin = JvmDeclarationOrigin(PACKAGE_FACADE, null, descriptor)
|
public fun PackageFacade(descriptor: PackageFragmentDescriptor): JvmDeclarationOrigin = JvmDeclarationOrigin(PACKAGE_FACADE, null, descriptor)
|
||||||
public fun PackagePart(file: JetFile, descriptor: PackageFragmentDescriptor): JvmDeclarationOrigin = JvmDeclarationOrigin(PACKAGE_PART, file, descriptor)
|
public fun PackagePart(file: JetFile, descriptor: PackageFragmentDescriptor): JvmDeclarationOrigin = JvmDeclarationOrigin(PACKAGE_PART, file, descriptor)
|
||||||
|
|
||||||
|
public fun MultifileClass(descriptor: PackageFragmentDescriptor, multifileClassFqName: FqName): JvmDeclarationOrigin =
|
||||||
|
JvmDeclarationOrigin(MULTIFILE_CLASS, null, descriptor, multifileClassFqName)
|
||||||
|
public fun MultifileClassPart(file: JetFile, descriptor: PackageFragmentDescriptor, multifileClassFqName: FqName): JvmDeclarationOrigin =
|
||||||
|
JvmDeclarationOrigin(MULTIFILE_CLASS_PART, file, descriptor, multifileClassFqName)
|
||||||
|
|
||||||
public fun TraitImpl(element: JetClassOrObject, descriptor: ClassDescriptor): JvmDeclarationOrigin = JvmDeclarationOrigin(TRAIT_IMPL, element, descriptor)
|
public fun TraitImpl(element: JetClassOrObject, descriptor: ClassDescriptor): JvmDeclarationOrigin = JvmDeclarationOrigin(TRAIT_IMPL, element, descriptor)
|
||||||
public fun DelegationToTraitImpl(element: PsiElement?, descriptor: FunctionDescriptor): JvmDeclarationOrigin =
|
public fun DelegationToTraitImpl(element: PsiElement?, descriptor: FunctionDescriptor): JvmDeclarationOrigin =
|
||||||
JvmDeclarationOrigin(DELEGATION_TO_TRAIT_IMPL, element, descriptor)
|
JvmDeclarationOrigin(DELEGATION_TO_TRAIT_IMPL, element, descriptor)
|
||||||
|
|||||||
+2
-1
@@ -214,7 +214,7 @@ public class KotlinJavaFileStubProvider<T extends WithFileStubAndExtraDiagnostic
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void generate(@NotNull GenerationState state, @NotNull Collection<JetFile> files) {
|
public void generate(@NotNull GenerationState state, @NotNull Collection<JetFile> files) {
|
||||||
PackageCodegen codegen = state.getFactory().forFacade(facadeFqName, files);
|
PackageCodegen codegen = state.getFactory().forFacadeLightClass(facadeFqName, files);
|
||||||
codegen.generate(CompilationErrorHandler.THROW_EXCEPTION);
|
codegen.generate(CompilationErrorHandler.THROW_EXCEPTION);
|
||||||
state.getFactory().asList();
|
state.getFactory().asList();
|
||||||
}
|
}
|
||||||
@@ -415,6 +415,7 @@ public class KotlinJavaFileStubProvider<T extends WithFileStubAndExtraDiagnostic
|
|||||||
/*generateClassFilter=*/stubGenerationStrategy.getGenerateClassFilter(),
|
/*generateClassFilter=*/stubGenerationStrategy.getGenerateClassFilter(),
|
||||||
/*disableInline=*/false,
|
/*disableInline=*/false,
|
||||||
/*disableOptimization=*/false,
|
/*disableOptimization=*/false,
|
||||||
|
/*packageFacadesAsMultifileClasses=*/false,
|
||||||
forExtraDiagnostics
|
forExtraDiagnostics
|
||||||
);
|
);
|
||||||
KotlinCodegenFacade.prepareForCompilation(state);
|
KotlinCodegenFacade.prepareForCompilation(state);
|
||||||
|
|||||||
@@ -67,6 +67,7 @@ public class CodegenTestUtil {
|
|||||||
GenerationState.GenerateClassFilter.GENERATE_ALL,
|
GenerationState.GenerateClassFilter.GENERATE_ALL,
|
||||||
configuration.get(JVMConfigurationKeys.DISABLE_INLINE, false),
|
configuration.get(JVMConfigurationKeys.DISABLE_INLINE, false),
|
||||||
configuration.get(JVMConfigurationKeys.DISABLE_OPTIMIZATION, false),
|
configuration.get(JVMConfigurationKeys.DISABLE_OPTIMIZATION, false),
|
||||||
|
configuration.get(JVMConfigurationKeys.PACKAGE_FACADES_AS_MULTIFILE_CLASSES, false),
|
||||||
forExtraDiagnostics
|
forExtraDiagnostics
|
||||||
);
|
);
|
||||||
KotlinCodegenFacade.compileCorrectFiles(state, CompilationErrorHandler.THROW_EXCEPTION);
|
KotlinCodegenFacade.compileCorrectFiles(state, CompilationErrorHandler.THROW_EXCEPTION);
|
||||||
|
|||||||
@@ -31,6 +31,8 @@ public final class JvmAnnotationNames {
|
|||||||
public static final FqName KOTLIN_CLASS = KotlinClass.CLASS_NAME.getFqNameForClassNameWithoutDollars();
|
public static final FqName KOTLIN_CLASS = KotlinClass.CLASS_NAME.getFqNameForClassNameWithoutDollars();
|
||||||
public static final FqName KOTLIN_PACKAGE = new FqName("kotlin.jvm.internal.KotlinPackage");
|
public static final FqName KOTLIN_PACKAGE = new FqName("kotlin.jvm.internal.KotlinPackage");
|
||||||
public static final FqName KOTLIN_FILE_FACADE = new FqName("kotlin.jvm.internal.KotlinFileFacade");
|
public static final FqName KOTLIN_FILE_FACADE = new FqName("kotlin.jvm.internal.KotlinFileFacade");
|
||||||
|
public static final FqName KOTLIN_MULTIFILE_CLASS = new FqName("kotlin.jvm.internal.KotlinMultifileClass");
|
||||||
|
public static final FqName KOTLIN_MULTIFILE_CLASS_PART = new FqName("kotlin.jvm.internal.KotlinMultifileClassPart");
|
||||||
public static final FqName KOTLIN_CALLABLE = new FqName("kotlin.jvm.internal.KotlinCallable");
|
public static final FqName KOTLIN_CALLABLE = new FqName("kotlin.jvm.internal.KotlinCallable");
|
||||||
|
|
||||||
public static final FqName KOTLIN_SIGNATURE = new FqName("kotlin.jvm.KotlinSignature");
|
public static final FqName KOTLIN_SIGNATURE = new FqName("kotlin.jvm.KotlinSignature");
|
||||||
@@ -38,6 +40,8 @@ public final class JvmAnnotationNames {
|
|||||||
|
|
||||||
public static final String ABI_VERSION_FIELD_NAME = "abiVersion";
|
public static final String ABI_VERSION_FIELD_NAME = "abiVersion";
|
||||||
public static final String KIND_FIELD_NAME = "kind";
|
public static final String KIND_FIELD_NAME = "kind";
|
||||||
|
public static final String FILE_PART_CLASS_NAMES_FIELD_NAME = "filePartClassNames";
|
||||||
|
public static final String MULTIFILE_CLASS_NAME_FIELD_NAME = "multifileClassName";
|
||||||
public static final String DATA_FIELD_NAME = "data";
|
public static final String DATA_FIELD_NAME = "data";
|
||||||
public static final Name DEFAULT_ANNOTATION_MEMBER_NAME = Name.identifier("value");
|
public static final Name DEFAULT_ANNOTATION_MEMBER_NAME = Name.identifier("value");
|
||||||
public static final Name TARGET_ANNOTATION_MEMBER_NAME = Name.identifier("allowedTargets");
|
public static final Name TARGET_ANNOTATION_MEMBER_NAME = Name.identifier("allowedTargets");
|
||||||
|
|||||||
+7
-1
@@ -25,7 +25,9 @@ public class KotlinClassHeader(
|
|||||||
public val version: Int,
|
public val version: Int,
|
||||||
public val annotationData: Array<String>?,
|
public val annotationData: Array<String>?,
|
||||||
public val classKind: KotlinClass.Kind?,
|
public val classKind: KotlinClass.Kind?,
|
||||||
public val syntheticClassKind: KotlinSyntheticClass.Kind?
|
public val syntheticClassKind: KotlinSyntheticClass.Kind?,
|
||||||
|
public val filePartClassNames: Array<String>?,
|
||||||
|
public val multifileClassName: String?
|
||||||
) {
|
) {
|
||||||
public val isCompatibleAbiVersion: Boolean get() = AbiVersionUtil.isAbiVersionCompatible(version)
|
public val isCompatibleAbiVersion: Boolean get() = AbiVersionUtil.isAbiVersionCompatible(version)
|
||||||
|
|
||||||
@@ -33,6 +35,8 @@ public class KotlinClassHeader(
|
|||||||
CLASS,
|
CLASS,
|
||||||
PACKAGE_FACADE,
|
PACKAGE_FACADE,
|
||||||
FILE_FACADE,
|
FILE_FACADE,
|
||||||
|
MULTIFILE_CLASS,
|
||||||
|
MULTIFILE_CLASS_PART,
|
||||||
SYNTHETIC_CLASS
|
SYNTHETIC_CLASS
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,4 +50,6 @@ public class KotlinClassHeader(
|
|||||||
public fun KotlinClassHeader.isCompatibleClassKind(): Boolean = isCompatibleAbiVersion && kind == KotlinClassHeader.Kind.CLASS
|
public fun KotlinClassHeader.isCompatibleClassKind(): Boolean = isCompatibleAbiVersion && kind == KotlinClassHeader.Kind.CLASS
|
||||||
public fun KotlinClassHeader.isCompatiblePackageFacadeKind(): Boolean = isCompatibleAbiVersion && kind == KotlinClassHeader.Kind.PACKAGE_FACADE
|
public fun KotlinClassHeader.isCompatiblePackageFacadeKind(): Boolean = isCompatibleAbiVersion && kind == KotlinClassHeader.Kind.PACKAGE_FACADE
|
||||||
public fun KotlinClassHeader.isCompatibleFileFacadeKind(): Boolean = isCompatibleAbiVersion && kind == KotlinClassHeader.Kind.FILE_FACADE
|
public fun KotlinClassHeader.isCompatibleFileFacadeKind(): Boolean = isCompatibleAbiVersion && kind == KotlinClassHeader.Kind.FILE_FACADE
|
||||||
|
public fun KotlinClassHeader.isCompatibleMultifileClassKind(): Boolean = isCompatibleAbiVersion && kind == KotlinClassHeader.Kind.MULTIFILE_CLASS
|
||||||
|
public fun KotlinClassHeader.isCompatibleMultifileClassPartKind(): Boolean = isCompatibleAbiVersion && kind == KotlinClassHeader.Kind.MULTIFILE_CLASS_PART
|
||||||
public fun KotlinClassHeader.isCompatibleSyntheticClassKind(): Boolean = isCompatibleAbiVersion && kind == KotlinClassHeader.Kind.SYNTHETIC_CLASS
|
public fun KotlinClassHeader.isCompatibleSyntheticClassKind(): Boolean = isCompatibleAbiVersion && kind == KotlinClassHeader.Kind.SYNTHETIC_CLASS
|
||||||
|
|||||||
+73
-24
@@ -37,11 +37,12 @@ public class ReadKotlinClassHeaderAnnotationVisitor implements AnnotationVisitor
|
|||||||
private static final Map<JvmClassName, KotlinClassHeader.Kind> HEADER_KINDS = new HashMap<JvmClassName, KotlinClassHeader.Kind>();
|
private static final Map<JvmClassName, KotlinClassHeader.Kind> HEADER_KINDS = new HashMap<JvmClassName, KotlinClassHeader.Kind>();
|
||||||
private static final Map<JvmClassName, KotlinClassHeader.Kind> OLD_DEPRECATED_ANNOTATIONS_KINDS = new HashMap<JvmClassName, KotlinClassHeader.Kind>();
|
private static final Map<JvmClassName, KotlinClassHeader.Kind> OLD_DEPRECATED_ANNOTATIONS_KINDS = new HashMap<JvmClassName, KotlinClassHeader.Kind>();
|
||||||
|
|
||||||
private int version = AbiVersionUtil.INVALID_VERSION;
|
|
||||||
static {
|
static {
|
||||||
HEADER_KINDS.put(KotlinClass.CLASS_NAME, CLASS);
|
HEADER_KINDS.put(KotlinClass.CLASS_NAME, CLASS);
|
||||||
HEADER_KINDS.put(JvmClassName.byFqNameWithoutInnerClasses(KOTLIN_PACKAGE), PACKAGE_FACADE);
|
HEADER_KINDS.put(JvmClassName.byFqNameWithoutInnerClasses(KOTLIN_PACKAGE), PACKAGE_FACADE);
|
||||||
HEADER_KINDS.put(JvmClassName.byFqNameWithoutInnerClasses(KOTLIN_FILE_FACADE), FILE_FACADE);
|
HEADER_KINDS.put(JvmClassName.byFqNameWithoutInnerClasses(KOTLIN_FILE_FACADE), FILE_FACADE);
|
||||||
|
HEADER_KINDS.put(JvmClassName.byFqNameWithoutInnerClasses(KOTLIN_MULTIFILE_CLASS), MULTIFILE_CLASS);
|
||||||
|
HEADER_KINDS.put(JvmClassName.byFqNameWithoutInnerClasses(KOTLIN_MULTIFILE_CLASS_PART), MULTIFILE_CLASS_PART);
|
||||||
HEADER_KINDS.put(KotlinSyntheticClass.CLASS_NAME, SYNTHETIC_CLASS);
|
HEADER_KINDS.put(KotlinSyntheticClass.CLASS_NAME, SYNTHETIC_CLASS);
|
||||||
|
|
||||||
initOldAnnotations();
|
initOldAnnotations();
|
||||||
@@ -58,6 +59,9 @@ public class ReadKotlinClassHeaderAnnotationVisitor implements AnnotationVisitor
|
|||||||
OLD_DEPRECATED_ANNOTATIONS_KINDS.put(JvmClassName.byFqNameWithoutInnerClasses(OLD_KOTLIN_TRAIT_IMPL), SYNTHETIC_CLASS);
|
OLD_DEPRECATED_ANNOTATIONS_KINDS.put(JvmClassName.byFqNameWithoutInnerClasses(OLD_KOTLIN_TRAIT_IMPL), SYNTHETIC_CLASS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int version = AbiVersionUtil.INVALID_VERSION;
|
||||||
|
private String multifileClassName = null;
|
||||||
|
private String[] filePartClassNames = null;
|
||||||
private String[] annotationData = null;
|
private String[] annotationData = null;
|
||||||
private KotlinClassHeader.Kind headerKind = null;
|
private KotlinClassHeader.Kind headerKind = null;
|
||||||
private KotlinClass.Kind classKind = null;
|
private KotlinClass.Kind classKind = null;
|
||||||
@@ -75,16 +79,24 @@ public class ReadKotlinClassHeaderAnnotationVisitor implements AnnotationVisitor
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!AbiVersionUtil.isAbiVersionCompatible(version)) {
|
if (!AbiVersionUtil.isAbiVersionCompatible(version)) {
|
||||||
return new KotlinClassHeader(headerKind, version, null, classKind, syntheticClassKind);
|
return new KotlinClassHeader(headerKind, version, null, classKind, syntheticClassKind, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((headerKind == CLASS || headerKind == PACKAGE_FACADE || headerKind == FILE_FACADE) && annotationData == null) {
|
if (shouldHaveData() && annotationData == null) {
|
||||||
// This means that the annotation is found and its ABI version is compatible, but there's no "data" string array in it.
|
// This means that the annotation is found and its ABI version is compatible, but there's no "data" string array in it.
|
||||||
// We tell the outside world that there's really no annotation at all
|
// We tell the outside world that there's really no annotation at all
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new KotlinClassHeader(headerKind, version, annotationData, classKind, syntheticClassKind);
|
return new KotlinClassHeader(headerKind, version, annotationData, classKind, syntheticClassKind, filePartClassNames, multifileClassName);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean shouldHaveData() {
|
||||||
|
return headerKind == CLASS ||
|
||||||
|
headerKind == PACKAGE_FACADE ||
|
||||||
|
headerKind == FILE_FACADE ||
|
||||||
|
headerKind == MULTIFILE_CLASS ||
|
||||||
|
headerKind == MULTIFILE_CLASS_PART;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@@ -136,15 +148,38 @@ public class ReadKotlinClassHeaderAnnotationVisitor implements AnnotationVisitor
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(@Nullable Name name, @Nullable Object value) {
|
public void visit(@Nullable Name name, @Nullable Object value) {
|
||||||
if (name != null && name.asString().equals(ABI_VERSION_FIELD_NAME)) {
|
if (name != null) {
|
||||||
version = value instanceof Integer ? (Integer) value : AbiVersionUtil.INVALID_VERSION;
|
if (name.asString().equals(ABI_VERSION_FIELD_NAME)) {
|
||||||
|
version = value instanceof Integer ? (Integer) value : AbiVersionUtil.INVALID_VERSION;
|
||||||
|
}
|
||||||
|
else if (name.asString().equals(MULTIFILE_CLASS_NAME_FIELD_NAME)) {
|
||||||
|
multifileClassName = value instanceof String ? (String) value : null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Nullable
|
@Nullable
|
||||||
public AnnotationArrayArgumentVisitor visitArray(@NotNull Name name) {
|
public AnnotationArrayArgumentVisitor visitArray(@NotNull Name name) {
|
||||||
return name.asString().equals(DATA_FIELD_NAME) ? stringArrayVisitor() : null;
|
if (name.asString().equals(DATA_FIELD_NAME)) {
|
||||||
|
return dataArrayVisitor();
|
||||||
|
}
|
||||||
|
else if (name.asString().equals(FILE_PART_CLASS_NAMES_FIELD_NAME)) {
|
||||||
|
return filePartClassNamesVisitor();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private AnnotationArrayArgumentVisitor filePartClassNamesVisitor() {
|
||||||
|
return new CollectStringArrayAnnotationVisitor() {
|
||||||
|
@Override
|
||||||
|
protected void visitEnd(String[] data) {
|
||||||
|
filePartClassNames = data;
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -158,24 +193,11 @@ public class ReadKotlinClassHeaderAnnotationVisitor implements AnnotationVisitor
|
|||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private AnnotationArrayArgumentVisitor stringArrayVisitor() {
|
private AnnotationArrayArgumentVisitor dataArrayVisitor() {
|
||||||
final List<String> strings = new ArrayList<String>(1);
|
return new CollectStringArrayAnnotationVisitor() {
|
||||||
return new AnnotationArrayArgumentVisitor() {
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(@Nullable Object value) {
|
protected void visitEnd(String[] data) {
|
||||||
if (value instanceof String) {
|
annotationData = data;
|
||||||
strings.add((String) value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visitEnum(@NotNull ClassId enumClassId, @NotNull Name enumEntryName) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visitEnd() {
|
|
||||||
//noinspection SSBasedInspection
|
|
||||||
annotationData = strings.toArray(new String[strings.size()]);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -183,6 +205,33 @@ public class ReadKotlinClassHeaderAnnotationVisitor implements AnnotationVisitor
|
|||||||
@Override
|
@Override
|
||||||
public void visitEnd() {
|
public void visitEnd() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private abstract class CollectStringArrayAnnotationVisitor implements AnnotationArrayArgumentVisitor {
|
||||||
|
private final List<String> strings;
|
||||||
|
|
||||||
|
public CollectStringArrayAnnotationVisitor() {
|
||||||
|
this.strings = new ArrayList<String>();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(@Nullable Object value) {
|
||||||
|
if (value instanceof String) {
|
||||||
|
strings.add((String) value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitEnum(@NotNull ClassId enumClassId, @NotNull Name enumEntryName) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitEnd() {
|
||||||
|
//noinspection SSBasedInspection
|
||||||
|
visitEnd(strings.toArray(new String[strings.size()]));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract void visitEnd(String[] data);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ClassHeaderReader extends HeaderAnnotationArgumentVisitor {
|
private class ClassHeaderReader extends HeaderAnnotationArgumentVisitor {
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* 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 kotlin.jvm.internal;
|
||||||
|
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
public @interface KotlinMultifileClass {
|
||||||
|
int abiVersion();
|
||||||
|
|
||||||
|
String[] filePartClassNames();
|
||||||
|
String[] data();
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* 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 kotlin.jvm.internal;
|
||||||
|
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
public @interface KotlinMultifileClassPart {
|
||||||
|
int abiVersion();
|
||||||
|
|
||||||
|
String multifileClassName();
|
||||||
|
String[] data();
|
||||||
|
}
|
||||||
@@ -70,7 +70,8 @@ public fun isKotlinInternalCompiledFile(file: VirtualFile): Boolean {
|
|||||||
}
|
}
|
||||||
val header = KotlinBinaryClassCache.getKotlinBinaryClass(file)?.getClassHeader() ?: return false
|
val header = KotlinBinaryClassCache.getKotlinBinaryClass(file)?.getClassHeader() ?: return false
|
||||||
return (header.kind == KotlinClassHeader.Kind.SYNTHETIC_CLASS && header.syntheticClassKind != KotlinSyntheticClass.Kind.PACKAGE_PART) ||
|
return (header.kind == KotlinClassHeader.Kind.SYNTHETIC_CLASS && header.syntheticClassKind != KotlinSyntheticClass.Kind.PACKAGE_PART) ||
|
||||||
(header.kind == KotlinClassHeader.Kind.CLASS && header.classKind != null && header.classKind != KotlinClass.Kind.CLASS)
|
(header.kind == KotlinClassHeader.Kind.CLASS && header.classKind != null && header.classKind != KotlinClass.Kind.CLASS) ||
|
||||||
|
(header.kind == KotlinClassHeader.Kind.MULTIFILE_CLASS_PART)
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun isKotlinJavaScriptInternalCompiledFile(file: VirtualFile): Boolean =
|
public fun isKotlinJavaScriptInternalCompiledFile(file: VirtualFile): Boolean =
|
||||||
|
|||||||
+1
-1
@@ -83,7 +83,7 @@ private fun ClsStubBuilderContext.child(typeParameterList: List<ProtoBuf.TypePar
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun ClsStubBuilderContext.child(nameResolver: NameResolver): ClsStubBuilderContext {
|
internal fun ClsStubBuilderContext.child(nameResolver: NameResolver): ClsStubBuilderContext {
|
||||||
return ClsStubBuilderContext(
|
return ClsStubBuilderContext(
|
||||||
this.components,
|
this.components,
|
||||||
nameResolver,
|
nameResolver,
|
||||||
|
|||||||
+29
-5
@@ -28,11 +28,10 @@ import org.jetbrains.kotlin.idea.decompiler.textBuilder.DirectoryBasedDataFinder
|
|||||||
import org.jetbrains.kotlin.idea.decompiler.textBuilder.LoggingErrorReporter
|
import org.jetbrains.kotlin.idea.decompiler.textBuilder.LoggingErrorReporter
|
||||||
import org.jetbrains.kotlin.load.java.JvmAnnotationNames
|
import org.jetbrains.kotlin.load.java.JvmAnnotationNames
|
||||||
import org.jetbrains.kotlin.load.kotlin.KotlinBinaryClassCache
|
import org.jetbrains.kotlin.load.kotlin.KotlinBinaryClassCache
|
||||||
import org.jetbrains.kotlin.load.kotlin.header.isCompatibleClassKind
|
import org.jetbrains.kotlin.load.kotlin.header.*
|
||||||
import org.jetbrains.kotlin.load.kotlin.header.isCompatibleFileFacadeKind
|
import org.jetbrains.kotlin.name.ClassId
|
||||||
import org.jetbrains.kotlin.load.kotlin.header.isCompatiblePackageFacadeKind
|
|
||||||
import org.jetbrains.kotlin.load.kotlin.header.isCompatibleSyntheticClassKind
|
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.psi.JetFile
|
import org.jetbrains.kotlin.psi.JetFile
|
||||||
import org.jetbrains.kotlin.serialization.jvm.JvmProtoBufUtil
|
import org.jetbrains.kotlin.serialization.jvm.JvmProtoBufUtil
|
||||||
|
|
||||||
@@ -81,10 +80,35 @@ public open class KotlinClsStubBuilder : ClsStubBuilder() {
|
|||||||
val context = components.createContext(packageData.getNameResolver(), packageFqName)
|
val context = components.createContext(packageData.getNameResolver(), packageFqName)
|
||||||
createFileFacadeStub(packageData.getPackageProto(), classId.asSingleFqName(), context)
|
createFileFacadeStub(packageData.getPackageProto(), classId.asSingleFqName(), context)
|
||||||
}
|
}
|
||||||
|
header.isCompatibleMultifileClassKind() -> {
|
||||||
|
val packageData = JvmProtoBufUtil.readPackageDataFrom(annotationData)
|
||||||
|
val context = components.createContext(packageData.nameResolver, packageFqName)
|
||||||
|
val partHeaders = readMultifileClassPartHeaders(file, header, packageFqName)
|
||||||
|
partHeaders?.let {
|
||||||
|
createMultifileClassStub(it, classId.asSingleFqName(), context)
|
||||||
|
}
|
||||||
|
}
|
||||||
else -> throw IllegalStateException("Should have processed " + file.getPath() + " with header $header")
|
else -> throw IllegalStateException("Should have processed " + file.getPath() + " with header $header")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun readMultifileClassPartHeaders(file: VirtualFile, header: KotlinClassHeader, packageFqName: FqName): List<KotlinClassHeader>? {
|
||||||
|
val result = arrayListOf<KotlinClassHeader>()
|
||||||
|
val partsFinder = DirectoryBasedClassFinder(file.parent!!, packageFqName)
|
||||||
|
val partNames = header.filePartClassNames
|
||||||
|
if (partNames != null) {
|
||||||
|
for (partName in partNames) {
|
||||||
|
val partClass = partsFinder.findKotlinClass(ClassId.topLevel(packageFqName.child(Name.identifier(partName))))
|
||||||
|
if (partClass == null) {
|
||||||
|
LOG.error("Missing part class: $packageFqName.$partName")
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
result.add(partClass.classHeader)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
private fun createStubBuilderComponents(file: VirtualFile, packageFqName: FqName): ClsStubBuilderComponents {
|
private fun createStubBuilderComponents(file: VirtualFile, packageFqName: FqName): ClsStubBuilderComponents {
|
||||||
val classFinder = DirectoryBasedClassFinder(file.getParent()!!, packageFqName)
|
val classFinder = DirectoryBasedClassFinder(file.getParent()!!, packageFqName)
|
||||||
val classDataFinder = DirectoryBasedDataFinder(classFinder, LOG)
|
val classDataFinder = DirectoryBasedDataFinder(classFinder, LOG)
|
||||||
@@ -93,6 +117,6 @@ public open class KotlinClsStubBuilder : ClsStubBuilder() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val LOG = Logger.getInstance(javaClass<KotlinClsStubBuilder>())
|
val LOG = Logger.getInstance(KotlinClsStubBuilder::class.java)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+21
-1
@@ -20,9 +20,9 @@ import com.intellij.psi.PsiElement
|
|||||||
import com.intellij.psi.stubs.StubElement
|
import com.intellij.psi.stubs.StubElement
|
||||||
import com.intellij.util.io.StringRef
|
import com.intellij.util.io.StringRef
|
||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
|
|
||||||
import org.jetbrains.kotlin.lexer.JetModifierKeywordToken
|
import org.jetbrains.kotlin.lexer.JetModifierKeywordToken
|
||||||
import org.jetbrains.kotlin.lexer.JetTokens
|
import org.jetbrains.kotlin.lexer.JetTokens
|
||||||
|
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader
|
||||||
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.name.Name
|
||||||
@@ -35,6 +35,7 @@ import org.jetbrains.kotlin.serialization.ProtoBuf
|
|||||||
import org.jetbrains.kotlin.serialization.ProtoBuf.Callable.CallableKind
|
import org.jetbrains.kotlin.serialization.ProtoBuf.Callable.CallableKind
|
||||||
import org.jetbrains.kotlin.serialization.deserialization.AnnotatedCallableKind
|
import org.jetbrains.kotlin.serialization.deserialization.AnnotatedCallableKind
|
||||||
import org.jetbrains.kotlin.serialization.deserialization.ProtoContainer
|
import org.jetbrains.kotlin.serialization.deserialization.ProtoContainer
|
||||||
|
import org.jetbrains.kotlin.serialization.jvm.JvmProtoBufUtil
|
||||||
|
|
||||||
fun createTopLevelClassStub(classId: ClassId, classProto: ProtoBuf.Class, context: ClsStubBuilderContext): KotlinFileStubImpl {
|
fun createTopLevelClassStub(classId: ClassId, classProto: ProtoBuf.Class, context: ClsStubBuilderContext): KotlinFileStubImpl {
|
||||||
val fileStub = createFileStub(classId.getPackageFqName())
|
val fileStub = createFileStub(classId.getPackageFqName())
|
||||||
@@ -71,6 +72,25 @@ fun createFileFacadeStub(
|
|||||||
return fileStub
|
return fileStub
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun createMultifileClassStub(
|
||||||
|
partHeaders: List<KotlinClassHeader>,
|
||||||
|
facadeFqName: FqName,
|
||||||
|
c: ClsStubBuilderContext
|
||||||
|
): KotlinFileStubImpl {
|
||||||
|
val packageFqName = facadeFqName.parent()
|
||||||
|
val fileStub = KotlinFileStubImpl.forFileFacadeStub(facadeFqName, packageFqName.isRoot)
|
||||||
|
setupFileStub(fileStub, packageFqName)
|
||||||
|
val multifileClassContainer = ProtoContainer(null, facadeFqName.parent())
|
||||||
|
for (partHeader in partHeaders) {
|
||||||
|
val partData = JvmProtoBufUtil.readPackageDataFrom(partHeader.annotationData!!)
|
||||||
|
val partContext = c.child(partData.nameResolver)
|
||||||
|
for (partMember in partData.packageProto.memberList) {
|
||||||
|
createCallableStub(fileStub, partMember, partContext, multifileClassContainer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fileStub
|
||||||
|
}
|
||||||
|
|
||||||
fun createIncompatibleAbiVersionFileStub() = createFileStub(FqName.ROOT)
|
fun createIncompatibleAbiVersionFileStub() = createFileStub(FqName.ROOT)
|
||||||
|
|
||||||
fun createFileStub(packageFqName: FqName): KotlinFileStubImpl {
|
fun createFileStub(packageFqName: FqName): KotlinFileStubImpl {
|
||||||
|
|||||||
@@ -239,6 +239,7 @@ public class KotlinBytecodeToolWindow extends JPanel implements Disposable {
|
|||||||
generateClassFilter,
|
generateClassFilter,
|
||||||
!enableInline,
|
!enableInline,
|
||||||
!enableOptimization,
|
!enableOptimization,
|
||||||
|
/*packageFacadesAsMultifileClasses=*/false,
|
||||||
sink);
|
sink);
|
||||||
KotlinCodegenFacade.compileCorrectFiles(state, CompilationErrorHandler.THROW_EXCEPTION);
|
KotlinCodegenFacade.compileCorrectFiles(state, CompilationErrorHandler.THROW_EXCEPTION);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,6 +50,14 @@ public annotation class JvmStatic
|
|||||||
@MustBeDocumented
|
@MustBeDocumented
|
||||||
public annotation class JvmName(public val name: String)
|
public annotation class JvmName(public val name: String)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instructs the Kotlin compiler to generate a multifile class with this file as one o
|
||||||
|
*/
|
||||||
|
target(AnnotationTarget.FILE)
|
||||||
|
@Retention(AnnotationRetention.RUNTIME)
|
||||||
|
@MustBeDocumented
|
||||||
|
public annotation class JvmMultifileClass
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Instructs the Kotlin compiler to generate a public backing field for this property.
|
* Instructs the Kotlin compiler to generate a public backing field for this property.
|
||||||
*/
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user