From 3dfe9951efe4f972ea7efb75dc6dd3bca01dc071 Mon Sep 17 00:00:00 2001 From: Dmitry Petrov Date: Wed, 23 Sep 2015 17:10:42 +0300 Subject: [PATCH] Incremental compilation support for multifile classes. --- .../org/jetbrains/kotlin/codegen/AsmUtil.java | 11 ++ .../kotlin/codegen/FunctionCodegen.java | 2 +- .../kotlin/codegen/KotlinCodegenFacade.java | 16 +-- .../kotlin/codegen/MultifileClassCodegen.kt | 115 ++++++++++++++--- .../kotlin/codegen/PackageCodegen.java | 53 ++++++-- .../kotlin/codegen/PropertyCodegen.java | 2 +- .../codegen/context/CodegenContext.java | 4 +- .../codegen/context/PackageFacadeContext.java | 16 +++ .../kotlin/codegen/inline/InlineCodegen.java | 6 +- .../kotlin/codegen/state/GenerationState.kt | 1 + .../kotlin/codegen/state/JetTypeMapper.java | 48 +++++-- .../compiler/KotlinToJVMBytecodeCompiler.java | 11 ++ .../IncrementalPackageFragmentProvider.kt | 31 +++++ .../components/IncrementalCache.kt | 6 + .../kotlinr/RemoteIncrementalCacheServer.kt | 6 + .../jetbrains/kotlin/rmi/CompileService.kt | 9 ++ .../service/RemoteIncrementalCacheClient.kt | 6 + ...eClassInlineFunctionAccessingProperty.A.kt | 6 + ...eClassInlineFunctionAccessingProperty.B.kt | 4 + ...mpileKotlinAgainstKotlinTestGenerated.java | 6 + .../jps/incremental/IncrementalCacheImpl.kt | 121 +++++++++++++++--- .../build/IncrementalJpsTestGenerated.java | 48 +++++++ .../classFilesComparison.kt | 6 +- .../pureKotlin/multifileClassFileAdded/a.kt | 4 + .../multifileClassFileAdded/b.kt.new | 4 + .../multifileClassFileAdded/build.log | 23 ++++ .../pureKotlin/multifileClassFileChanged/a.kt | 4 + .../pureKotlin/multifileClassFileChanged/b.kt | 4 + .../multifileClassFileChanged/b.kt.new | 4 + .../multifileClassFileChanged/build.log | 9 ++ .../a.kt | 4 + .../b.kt | 4 + .../b.kt.new | 4 + .../build.log | 18 +++ .../multifileClassInlineFunction/build.log | 8 ++ .../multifileClassInlineFunction/inline.kt | 7 + .../inlineOther.kt | 7 + .../multifileClassInlineFunction/usage.kt | 6 + .../multifileClassInlineFunction/usage.kt.new | 6 + .../build.log | 8 ++ .../inline.kt | 9 ++ .../inlineOther.kt | 9 ++ .../usage.kt | 6 + .../usage.kt.new | 6 + .../pureKotlin/multifileClassRecreated/a.kt | 4 + .../multifileClassRecreated/a.kt.delete.1 | 1 + .../multifileClassRecreated/b.kt.new.2 | 4 + .../multifileClassRecreated/build.log | 13 ++ .../multifileClassRecreatedAfterRenaming/a.kt | 4 + .../a.kt.new.1 | 4 + .../b.kt.new.2 | 4 + .../build.log | 23 ++++ .../pureKotlin/multifileClassRemoved/a.kt | 4 + .../multifileClassRemoved/a.kt.delete | 0 .../pureKotlin/multifileClassRemoved/b.kt | 4 + .../multifileClassRemoved/b.kt.delete | 0 .../multifileClassRemoved/build.log | 11 ++ 57 files changed, 689 insertions(+), 75 deletions(-) create mode 100644 compiler/testData/compileKotlinAgainstKotlin/MultifileClassInlineFunctionAccessingProperty.A.kt create mode 100644 compiler/testData/compileKotlinAgainstKotlin/MultifileClassInlineFunctionAccessingProperty.B.kt create mode 100644 jps-plugin/testData/incremental/pureKotlin/multifileClassFileAdded/a.kt create mode 100644 jps-plugin/testData/incremental/pureKotlin/multifileClassFileAdded/b.kt.new create mode 100644 jps-plugin/testData/incremental/pureKotlin/multifileClassFileAdded/build.log create mode 100644 jps-plugin/testData/incremental/pureKotlin/multifileClassFileChanged/a.kt create mode 100644 jps-plugin/testData/incremental/pureKotlin/multifileClassFileChanged/b.kt create mode 100644 jps-plugin/testData/incremental/pureKotlin/multifileClassFileChanged/b.kt.new create mode 100644 jps-plugin/testData/incremental/pureKotlin/multifileClassFileChanged/build.log create mode 100644 jps-plugin/testData/incremental/pureKotlin/multifileClassFileMovedToAnotherMultifileClass/a.kt create mode 100644 jps-plugin/testData/incremental/pureKotlin/multifileClassFileMovedToAnotherMultifileClass/b.kt create mode 100644 jps-plugin/testData/incremental/pureKotlin/multifileClassFileMovedToAnotherMultifileClass/b.kt.new create mode 100644 jps-plugin/testData/incremental/pureKotlin/multifileClassFileMovedToAnotherMultifileClass/build.log create mode 100644 jps-plugin/testData/incremental/pureKotlin/multifileClassInlineFunction/build.log create mode 100644 jps-plugin/testData/incremental/pureKotlin/multifileClassInlineFunction/inline.kt create mode 100644 jps-plugin/testData/incremental/pureKotlin/multifileClassInlineFunction/inlineOther.kt create mode 100644 jps-plugin/testData/incremental/pureKotlin/multifileClassInlineFunction/usage.kt create mode 100644 jps-plugin/testData/incremental/pureKotlin/multifileClassInlineFunction/usage.kt.new create mode 100644 jps-plugin/testData/incremental/pureKotlin/multifileClassInlineFunctionAccessingField/build.log create mode 100644 jps-plugin/testData/incremental/pureKotlin/multifileClassInlineFunctionAccessingField/inline.kt create mode 100644 jps-plugin/testData/incremental/pureKotlin/multifileClassInlineFunctionAccessingField/inlineOther.kt create mode 100644 jps-plugin/testData/incremental/pureKotlin/multifileClassInlineFunctionAccessingField/usage.kt create mode 100644 jps-plugin/testData/incremental/pureKotlin/multifileClassInlineFunctionAccessingField/usage.kt.new create mode 100644 jps-plugin/testData/incremental/pureKotlin/multifileClassRecreated/a.kt create mode 100644 jps-plugin/testData/incremental/pureKotlin/multifileClassRecreated/a.kt.delete.1 create mode 100644 jps-plugin/testData/incremental/pureKotlin/multifileClassRecreated/b.kt.new.2 create mode 100644 jps-plugin/testData/incremental/pureKotlin/multifileClassRecreated/build.log create mode 100644 jps-plugin/testData/incremental/pureKotlin/multifileClassRecreatedAfterRenaming/a.kt create mode 100644 jps-plugin/testData/incremental/pureKotlin/multifileClassRecreatedAfterRenaming/a.kt.new.1 create mode 100644 jps-plugin/testData/incremental/pureKotlin/multifileClassRecreatedAfterRenaming/b.kt.new.2 create mode 100644 jps-plugin/testData/incremental/pureKotlin/multifileClassRecreatedAfterRenaming/build.log create mode 100644 jps-plugin/testData/incremental/pureKotlin/multifileClassRemoved/a.kt create mode 100644 jps-plugin/testData/incremental/pureKotlin/multifileClassRemoved/a.kt.delete create mode 100644 jps-plugin/testData/incremental/pureKotlin/multifileClassRemoved/b.kt create mode 100644 jps-plugin/testData/incremental/pureKotlin/multifileClassRemoved/b.kt.delete create mode 100644 jps-plugin/testData/incremental/pureKotlin/multifileClassRemoved/build.log diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/AsmUtil.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/AsmUtil.java index 3113ef5a0b7..1f51e9a1fa4 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/AsmUtil.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/AsmUtil.java @@ -887,6 +887,17 @@ public class AsmUtil { return JvmClassName.byFqNameWithoutInnerClasses(fqName).getInternalName(); } + @NotNull + public static String getSimpleInternalName(@NotNull String internalName) { + int lastSlash = internalName.lastIndexOf('/'); + if (lastSlash >= 0) { + return internalName.substring(lastSlash + 1); + } + else { + return internalName; + } + } + public static void putJavaLangClassInstance(@NotNull InstructionAdapter v, @NotNull Type type) { if (isPrimitive(type)) { v.getstatic(boxType(type).getInternalName(), "TYPE", "Ljava/lang/Class;"); diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java index e28af2172c7..036e0c85a9f 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java @@ -239,7 +239,7 @@ public class FunctionCodegen { private void writePackageFacadeMethodAnnotationsIfNeeded(MethodVisitor mv) { if (owner instanceof PackageFacadeContext) { PackageFacadeContext packageFacadeContext = (PackageFacadeContext) owner; - Type delegateToClassType = packageFacadeContext.getDelegateToClassType(); + Type delegateToClassType = packageFacadeContext.getPublicFacadeType(); if (delegateToClassType != null) { String className = delegateToClassType.getClassName(); AnnotationVisitor diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/KotlinCodegenFacade.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/KotlinCodegenFacade.java index 12581188c87..ae8e8ce461b 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/KotlinCodegenFacade.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/KotlinCodegenFacade.java @@ -17,6 +17,7 @@ package org.jetbrains.kotlin.codegen; import com.google.common.collect.Sets; +import com.intellij.util.containers.HashMap; import com.intellij.util.containers.MultiMap; import org.jetbrains.annotations.NotNull; import org.jetbrains.kotlin.codegen.state.GenerationState; @@ -29,9 +30,7 @@ import org.jetbrains.kotlin.psi.JetScript; import org.jetbrains.kotlin.resolve.ScriptNameUtil; import org.jetbrains.org.objectweb.asm.Type; -import java.util.Collection; -import java.util.HashSet; -import java.util.Set; +import java.util.*; import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.registerClassNameForScript; @@ -85,17 +84,18 @@ public class KotlinCodegenFacade { } } + Set obsoleteMultifileClasses = new HashSet(state.getObsoleteMultifileClasses()); + for (FqName multifileClassFqName : Sets.union(filesInMultifileClasses.keySet(), obsoleteMultifileClasses)) { + ProgressIndicatorAndCompilationCanceledStatus.checkCanceled(); + generateMultifileClass(state, multifileClassFqName, filesInMultifileClasses.get(multifileClassFqName), errorHandler); + } + Set packagesWithObsoleteParts = new HashSet(state.getPackagesWithObsoleteParts()); for (FqName packageFqName : Sets.union(packagesWithObsoleteParts, filesInPackageClasses.keySet())) { ProgressIndicatorAndCompilationCanceledStatus.checkCanceled(); generatePackage(state, packageFqName, filesInPackageClasses.get(packageFqName), errorHandler); } - for (FqName multifileClassFqName : filesInMultifileClasses.keySet()) { - ProgressIndicatorAndCompilationCanceledStatus.checkCanceled(); - generateMultifileClass(state, multifileClassFqName, filesInMultifileClasses.get(multifileClassFqName), errorHandler); - } - ProgressIndicatorAndCompilationCanceledStatus.checkCanceled(); state.getFactory().done(); } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/MultifileClassCodegen.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/MultifileClassCodegen.kt index 3ca1588051a..37936dfb0db 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/MultifileClassCodegen.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/MultifileClassCodegen.kt @@ -21,11 +21,14 @@ import com.intellij.openapi.progress.ProcessCanceledException import com.intellij.util.ArrayUtil import com.intellij.util.SmartList import org.jetbrains.kotlin.codegen.context.FieldOwnerContext +import org.jetbrains.kotlin.codegen.context.MethodContext 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.fileClasses.JvmFileClassUtil import org.jetbrains.kotlin.fileClasses.getFileClassType import org.jetbrains.kotlin.load.java.JvmAbi import org.jetbrains.kotlin.load.java.JvmAnnotationNames @@ -37,9 +40,18 @@ import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.MemberComparator import org.jetbrains.kotlin.resolve.jvm.AsmTypes +import org.jetbrains.kotlin.resolve.jvm.JvmClassName import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin import org.jetbrains.kotlin.resolve.jvm.diagnostics.MultifileClass import org.jetbrains.kotlin.resolve.jvm.diagnostics.MultifileClassPart +import org.jetbrains.kotlin.resolve.jvm.diagnostics.OtherOrigin +import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature +import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter +import org.jetbrains.kotlin.resolve.scopes.JetScope +import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedCallableMemberDescriptor +import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedPropertyDescriptor +import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedSimpleFunctionDescriptor +import org.jetbrains.org.objectweb.asm.MethodVisitor import org.jetbrains.org.objectweb.asm.Opcodes import org.jetbrains.org.objectweb.asm.Type import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter @@ -55,14 +67,19 @@ public class MultifileClassCodegen( private val packageFragment = getOnlyPackageFragment(facadeFqName.parent(), files, state.bindingContext) - private val compiledPackageFragment = getCompiledPackageFragment(facadeFqName.parent(), state) + private val compiledPackageFragment = getCompiledPackageFragment(facadeFqName, state) + + private val previouslyCompiledCallables = + if (compiledPackageFragment == null) + emptyList() + else + getDeserializedCallables(compiledPackageFragment) + + private fun getDeserializedCallables(compiledPackageFragment: PackageFragmentDescriptor) = + compiledPackageFragment.getMemberScope().getDescriptors(DescriptorKindFilter.CALLABLES, JetScope.ALL_NAME_FILTER).filterIsInstance() public val packageParts = PackageParts(facadeFqName.parent().asString()) - // TODO incremental compilation support - // TODO previouslyCompiledCallables - // We can do this (probably without 'compiledPackageFragment') after modifications to part codegen. - private val classBuilder = ClassBuilderOnDemand { val originFile = files.firstOrNull() val actualPackageFragment = packageFragment ?: @@ -72,7 +89,9 @@ public class MultifileClassCodegen( val classBuilder = state.factory.newVisitor(declarationOrigin, facadeClassType, files) val filesWithCallables = files.filter { it.declarations.any { it is JetNamedFunction || it is JetProperty } } - val singleSourceFile = filesWithCallables.singleOrNull() + + val singleSourceFile = if (previouslyCompiledCallables.isNotEmpty()) null else filesWithCallables.singleOrNull() + classBuilder.defineClass(singleSourceFile, Opcodes.V1_6, FACADE_CLASS_ATTRIBUTES, facadeClassType.internalName, null, "java/lang/Object", ArrayUtil.EMPTY_STRING_ARRAY) @@ -86,6 +105,20 @@ public class MultifileClassCodegen( val generateCallableMemberTasks = HashMap Unit>() val partFqNames = arrayListOf() + generateCodeForSourceFiles(errorHandler, generateCallableMemberTasks, partFqNames) + + generateDelegatesToPreviouslyCompiledParts(generateCallableMemberTasks, partFqNames) + + if (!generateCallableMemberTasks.isEmpty()) { + generateMultifileFacadeClass(generateCallableMemberTasks, partFqNames) + } + } + + private fun generateCodeForSourceFiles( + errorHandler: CompilationErrorHandler, + generateCallableMemberTasks: MutableMap Unit>, + partFqNames: MutableList + ) { for (file in files) { ProgressIndicatorAndCompilationCanceledStatus.checkCanceled() try { @@ -104,12 +137,6 @@ public class MultifileClassCodegen( } } } - -// generateDelegationsToPreviouslyCompiled(generateCallableMemberTasks) - - if (!generateCallableMemberTasks.isEmpty()) { - generateMultifileFacadeClass(generateCallableMemberTasks, partFqNames) - } } private fun generateMultifileFacadeClass( @@ -187,6 +214,55 @@ public class MultifileClassCodegen( } } + private fun generateDelegatesToPreviouslyCompiledParts( + generateCallableMemberTasks: MutableMap Unit>, + partFqNames: MutableList + ) { + if (compiledPackageFragment == null) return + + partFqNames.addAll(compiledPackageFragment.partsNames.map { JvmClassName.byInternalName(it).fqNameForClassNameWithoutDollars }) + + for (callable in previouslyCompiledCallables) { + val partFqName = JvmFileClassUtil.getPartFqNameForDeserializedCallable(callable) + val partType = AsmUtil.asmTypeByFqNameWithoutInnerClasses(partFqName) + + generateCallableMemberTasks[callable] = { generateDelegateToCompiledMember(callable, compiledPackageFragment, partType) } + } + } + + private fun generateDelegateToCompiledMember( + member: CallableMemberDescriptor, + compiledPackageFragment: PackageFragmentDescriptor, + partType: Type + ) { + val context = state.rootContext.intoMultifileClass(compiledPackageFragment, facadeClassType, partType) + + val memberCodegen = createCodegenForPartOfMultifileFacade(context) + + when (member) { + is DeserializedSimpleFunctionDescriptor -> { + memberCodegen.functionCodegen.generateMethod(OtherOrigin(member), member, DelegateToCompiledMemberGenerationStrategy) + + memberCodegen.functionCodegen.generateDefaultIfNeeded( + context.intoFunction(member), member, OwnerKind.PACKAGE, DefaultParameterValueLoader.DEFAULT, null) + + memberCodegen.functionCodegen.generateOverloadsWithDefaultValues(null, member, member) + } + is DeserializedPropertyDescriptor -> { + memberCodegen.propertyCodegen.generateInPackageFacade(member) + } + else -> { + throw IllegalStateException("Unexpected member: " + member) + } + } + } + + object DelegateToCompiledMemberGenerationStrategy : FunctionGenerationStrategy() { + override fun generateBody(mv: MethodVisitor, frameMap: FrameMap, signature: JvmMethodSignature, context: MethodContext, parentCodegen: MemberCodegen<*>) { + throw IllegalStateException("shouldn't be called") + } + } + private fun generateKotlinPackageReflectionField() { val mv = classBuilder.newMethod(JvmDeclarationOrigin.NO_ORIGIN, Opcodes.ACC_STATIC, "", "()V", null, null) val method = AsmUtil.method("createKotlinPackage", @@ -246,12 +322,19 @@ public class MultifileClassCodegen( return fragments.firstOrNull() } - private fun getCompiledPackageFragment(packageFqName: FqName, state: GenerationState): PackageFragmentDescriptor? = - if (!IncrementalCompilation.isEnabled()) null - else state.module.getPackage(packageFqName).fragments.firstOrNull { fragment -> + private fun getCompiledPackageFragment(facadeFqName: FqName, state: GenerationState): + IncrementalPackageFragmentProvider.IncrementalPackageFragment.IncrementalMultifileClassPackageFragment? { + if (!IncrementalCompilation.isEnabled()) return null + + val packageFqName = facadeFqName.parent() + + val incrementalPackageFragment = state.module.getPackage(packageFqName).fragments.firstOrNull { fragment -> fragment is IncrementalPackageFragmentProvider.IncrementalPackageFragment && fragment.target == state.targetId - } + } as IncrementalPackageFragmentProvider.IncrementalPackageFragment? + + return incrementalPackageFragment?.getPackageFragmentForMultifileClass(facadeFqName) + } } } \ No newline at end of file diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/PackageCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/PackageCodegen.java index bd57e5e672c..4f5afd88a4d 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/PackageCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/PackageCodegen.java @@ -42,6 +42,7 @@ import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor; import org.jetbrains.kotlin.diagnostics.DiagnosticUtils; import org.jetbrains.kotlin.fileClasses.FileClassesPackage; import org.jetbrains.kotlin.fileClasses.JvmFileClassInfo; +import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil; import org.jetbrains.kotlin.load.java.JvmAbi; import org.jetbrains.kotlin.load.java.JvmAnnotationNames; import org.jetbrains.kotlin.load.kotlin.PackagePartClassUtils; @@ -52,6 +53,7 @@ import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStat import org.jetbrains.kotlin.psi.*; import org.jetbrains.kotlin.resolve.BindingContext; import org.jetbrains.kotlin.resolve.MemberComparator; +import org.jetbrains.kotlin.resolve.jvm.JvmClassName; import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature; import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter; import org.jetbrains.kotlin.resolve.scopes.JetScope; @@ -83,7 +85,7 @@ public class PackageCodegen { private final Collection files; private final Type packageClassType; private final PackageFragmentDescriptor packageFragment; - private final PackageFragmentDescriptor compiledPackageFragment; + private final IncrementalPackageFragmentProvider.IncrementalPackageFragment compiledPackageFragment; private final List previouslyCompiledCallables; private final PackageParts packageParts; @@ -141,7 +143,7 @@ public class PackageCodegen { } @Nullable - private PackageFragmentDescriptor getCompiledPackageFragment(@NotNull FqName fqName) { + private IncrementalPackageFragmentProvider.IncrementalPackageFragment getCompiledPackageFragment(@NotNull FqName fqName) { if (!IncrementalCompilation.isEnabled()) { return null; } @@ -150,7 +152,7 @@ public class PackageCodegen { for (PackageFragmentDescriptor fragment : state.getModule().getPackage(fqName).getFragments()) { if (fragment instanceof IncrementalPackageFragmentProvider.IncrementalPackageFragment && ((IncrementalPackageFragmentProvider.IncrementalPackageFragment) fragment).getTarget().equals(state.getTargetId())) { - return fragment; + return (IncrementalPackageFragmentProvider.IncrementalPackageFragment) fragment; } } return null; @@ -172,13 +174,12 @@ public class PackageCodegen { private void generateDelegationsToPreviouslyCompiled(@NotNull @Mutable Map generateCallableMemberTasks) { for (final DeserializedCallableMemberDescriptor member : previouslyCompiledCallables) { + final FqName delegateToFqName = JvmFileClassUtil.getPartFqNameForDeserializedCallable(member); + generateCallableMemberTasks.put(member, new Runnable() { @Override public void run() { - FieldOwnerContext context = state.getRootContext().intoPackageFacade( - AsmUtil.asmTypeByFqNameWithoutInnerClasses(PackagePartClassUtils.getPackagePartFqName(member)), - compiledPackageFragment - ); + FieldOwnerContext context = getPackageFacadeContextForPreviouslyCompiled(delegateToFqName); MemberCodegen memberCodegen = createCodegenForPartOfPackageFacade(context); @@ -216,6 +217,24 @@ public class PackageCodegen { } } + @NotNull + private FieldOwnerContext getPackageFacadeContextForPreviouslyCompiled(@NotNull FqName delegateToFqName) { + Type delegateToType = AsmUtil.asmTypeByFqNameWithoutInnerClasses(delegateToFqName); + String partInternalName = JvmClassName.byFqNameWithoutInnerClasses(delegateToFqName).getInternalName(); + String facadeInternalName = compiledPackageFragment.getMultifileFacade(partInternalName); + + Type publicFacadeType; + if (facadeInternalName != null) { + FqName facadeFqName = JvmClassName.byInternalName(facadeInternalName).getFqNameForClassNameWithoutDollars(); + publicFacadeType = AsmUtil.asmTypeByFqNameWithoutInnerClasses(facadeFqName); + } + else { + publicFacadeType = delegateToType; + } + + return state.getRootContext().intoPackageFacade(delegateToType, compiledPackageFragment, publicFacadeType); + } + public void generate(@NotNull CompilationErrorHandler errorHandler) { List bindings = new ArrayList(files.size() + 1); @@ -302,12 +321,17 @@ public class PackageCodegen { } @Nullable - private ClassBuilder generateFile(@NotNull JetFile file, @NotNull Map generateCallableMemberTasks) { + private ClassBuilder generateFile( + @NotNull JetFile file, + @NotNull Map generateCallableMemberTasks + ) { JvmFileClassInfo fileClassInfo = state.getFileClassesProvider().getFileClassInfo(file); - if (fileClassInfo.getTEMP_isMultifileClass()) { - Type fileFacadeType = AsmUtil.asmTypeByFqNameWithoutInnerClasses(fileClassInfo.getFacadeClassFqName()); - addDelegateToFileClassMemberTasks(file, generateCallableMemberTasks, fileFacadeType); + if (fileClassInfo.getIsMultifileClass()) { + FqName partClassFqName = fileClassInfo.getFileClassFqName(); + Type delegateToType = AsmUtil.asmTypeByFqNameWithoutInnerClasses(partClassFqName); + Type publicFacadeType = AsmUtil.asmTypeByFqNameWithoutInnerClasses(fileClassInfo.getFacadeClassFqName()); + addDelegateToFileClassMemberTasks(file, generateCallableMemberTasks, delegateToType, publicFacadeType); return null; } @@ -345,7 +369,7 @@ public class PackageCodegen { new PackagePartCodegen(builder, file, fileClassType, packagePartContext, state).generate(); - addDelegateToFileClassMemberTasks(file, generateCallableMemberTasks, fileClassType); + addDelegateToFileClassMemberTasks(file, generateCallableMemberTasks, fileClassType, fileClassType); return builder; } @@ -353,9 +377,10 @@ public class PackageCodegen { private void addDelegateToFileClassMemberTasks( @NotNull JetFile file, @NotNull Map generateCallableMemberTasks, - @NotNull Type fileClassType + @NotNull Type fileClassType, + @NotNull Type publicFacadeType ) { - FieldOwnerContext packageFacade = state.getRootContext().intoPackageFacade(fileClassType, packageFragment); + FieldOwnerContext packageFacade = state.getRootContext().intoPackageFacade(fileClassType, packageFragment, publicFacadeType); final MemberCodegen memberCodegen = createCodegenForPartOfPackageFacade(packageFacade); for (final JetDeclaration declaration : file.getDeclarations()) { diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/PropertyCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/PropertyCodegen.java index 771ed01af42..a9e21daeacd 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/PropertyCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/PropertyCodegen.java @@ -97,7 +97,7 @@ public class PropertyCodegen { } public void generateInPackageFacade(@NotNull DeserializedPropertyDescriptor deserializedProperty) { - assert context instanceof PackageFacadeContext : "should be called only for generating package facade: " + context; + assert context instanceof DelegatingFacadeContext : "should be called only for generating facade: " + context; gen(null, deserializedProperty, null, null); } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/context/CodegenContext.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/context/CodegenContext.java index 486074fd360..229d89882a2 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/context/CodegenContext.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/context/CodegenContext.java @@ -185,8 +185,8 @@ public abstract class CodegenContext { } @NotNull - public FieldOwnerContext intoPackageFacade(@NotNull Type delegateTo, @NotNull PackageFragmentDescriptor descriptor) { - return new PackageFacadeContext(descriptor, this, delegateTo); + public FieldOwnerContext intoPackageFacade(@NotNull Type delegateTo, @NotNull PackageFragmentDescriptor descriptor, @NotNull Type publicFacadeType) { + return new PackageFacadeContext(descriptor, this, delegateTo, publicFacadeType); } @NotNull diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/context/PackageFacadeContext.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/context/PackageFacadeContext.java index 1e72102d88f..fd6cfca81e5 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/context/PackageFacadeContext.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/context/PackageFacadeContext.java @@ -22,13 +22,25 @@ import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor; import org.jetbrains.org.objectweb.asm.Type; public class PackageFacadeContext extends PackageContext implements DelegatingFacadeContext { + private final Type publicFacadeType; public PackageFacadeContext( @NotNull PackageFragmentDescriptor contextDescriptor, @NotNull CodegenContext parent, @NotNull Type packagePartType + ) { + this(contextDescriptor, parent, packagePartType, packagePartType); + } + + public PackageFacadeContext( + @NotNull PackageFragmentDescriptor contextDescriptor, + @NotNull CodegenContext parent, + @NotNull Type packagePartType, + @NotNull Type publicFacadeType ) { super(contextDescriptor, parent, packagePartType); + + this.publicFacadeType = publicFacadeType; } @Override @@ -36,4 +48,8 @@ public class PackageFacadeContext extends PackageContext implements DelegatingFa public Type getDelegateToClassType() { return getPackagePartType(); } + + public Type getPublicFacadeType() { + return publicFacadeType; + } } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.java index 8f850e8aee0..7a5e6469216 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.java @@ -231,10 +231,10 @@ public class InlineCodegen extends CallGenerator { SMAP smap; if (callDefault) { - Type ownerType = typeMapper.mapOwner(functionDescriptor); + Type implementationOwner = typeMapper.mapImplementationOwner(functionDescriptor); FakeMemberCodegen parentCodegen = new FakeMemberCodegen(codegen.getParentCodegen(), inliningFunction, (FieldOwnerContext) methodContext.getParentContext(), - ownerType.getInternalName()); + implementationOwner.getInternalName()); FunctionCodegen.generateDefaultImplBody( methodContext, functionDescriptor, maxCalcAdapter, DefaultParameterValueLoader.DEFAULT, inliningFunction, parentCodegen @@ -343,7 +343,7 @@ public class InlineCodegen extends CallGenerator { new FakeMemberCodegen(codegen.getParentCodegen(), expression, (FieldOwnerContext) context.getParentContext(), isLambda ? codegen.getParentCodegen().getClassName() - : typeMapper.mapOwner(descriptor).getInternalName()); + : typeMapper.mapImplementationOwner(descriptor).getInternalName()); FunctionGenerationStrategy strategy = expression instanceof JetCallableReferenceExpression ? diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/GenerationState.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/GenerationState.kt index c53a2eff481..2ea186a2a00 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/GenerationState.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/GenerationState.kt @@ -54,6 +54,7 @@ public class GenerationState @JvmOverloads constructor( public val packageFacadesAsMultifileClasses: Boolean = false, public val diagnostics: DiagnosticSink = DiagnosticSink.DO_NOTHING, public val packagesWithObsoleteParts: Collection = emptySet(), + public val obsoleteMultifileClasses: Collection = emptySet(), // for PackageCodegen in incremental compilation mode public val targetId: TargetId? = null, moduleName: String? = null, diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/JetTypeMapper.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/JetTypeMapper.java index f90c9392299..3d5d9b08bb7 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/JetTypeMapper.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/JetTypeMapper.java @@ -38,6 +38,7 @@ import org.jetbrains.kotlin.load.java.descriptors.JavaCallableMemberDescriptor; import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor; import org.jetbrains.kotlin.load.java.lazy.descriptors.LazyJavaPackageScope; import org.jetbrains.kotlin.load.kotlin.PackageClassUtils; +import org.jetbrains.kotlin.load.kotlin.incremental.IncrementalPackageFragmentProvider; import org.jetbrains.kotlin.name.*; import org.jetbrains.kotlin.platform.JavaToKotlinClassMap; import org.jetbrains.kotlin.psi.JetExpression; @@ -136,13 +137,23 @@ public class JetTypeMapper { @NotNull public Type mapOwner(@NotNull DeclarationDescriptor descriptor) { + return mapOwner(descriptor, false); + } + + @NotNull + public Type mapImplementationOwner(@NotNull DeclarationDescriptor descriptor) { + return mapOwner(descriptor, true); + } + + @NotNull + private Type mapOwner(@NotNull DeclarationDescriptor descriptor, boolean isImplementation) { if (isLocalFunction(descriptor)) { return asmTypeForAnonymousClass(bindingContext, (FunctionDescriptor) descriptor); } DeclarationDescriptor container = descriptor.getContainingDeclaration(); if (container instanceof PackageFragmentDescriptor) { - return Type.getObjectType(internalNameForPackage((CallableMemberDescriptor) descriptor)); + return Type.getObjectType(internalNameForPackageMemberOwner((CallableMemberDescriptor) descriptor, isImplementation)); } else if (container instanceof ClassDescriptor) { return mapClass((ClassDescriptor) container); @@ -156,11 +167,11 @@ public class JetTypeMapper { } @NotNull - private String internalNameForPackage(@NotNull CallableMemberDescriptor descriptor) { + private String internalNameForPackageMemberOwner(@NotNull CallableMemberDescriptor descriptor, boolean isImplementation) { JetFile file = DescriptorToSourceUtils.getContainingFile(descriptor); if (file != null) { Visibility visibility = descriptor.getVisibility(); - if (descriptor instanceof PropertyDescriptor || Visibilities.isPrivate(visibility)) { + if (isImplementation || descriptor instanceof PropertyDescriptor || Visibilities.isPrivate(visibility)) { return FileClassesPackage.getFileClassInternalName(fileClassesProvider, file); } else { @@ -171,7 +182,7 @@ public class JetTypeMapper { CallableMemberDescriptor directMember = getDirectMember(descriptor); if (directMember instanceof DeserializedCallableMemberDescriptor) { - String facadeFqName = getPackageMemberOwnerInternalName((DeserializedCallableMemberDescriptor) directMember); + String facadeFqName = getPackageMemberOwnerInternalName((DeserializedCallableMemberDescriptor) directMember, isImplementation); if (facadeFqName != null) return facadeFqName; } @@ -180,7 +191,7 @@ public class JetTypeMapper { } @Nullable - private static String getPackageMemberOwnerInternalName(@NotNull DeserializedCallableMemberDescriptor descriptor) { + private static String getPackageMemberOwnerInternalName(@NotNull DeserializedCallableMemberDescriptor descriptor, boolean isImplementation) { // XXX This method (and getPackageMemberOwnerShortName) is a dirty hack // introduced to make stdlib work with package facades built as multifile facades for M13. // We need some safe, concise way to identify multifile facade and multifile part @@ -193,7 +204,7 @@ public class JetTypeMapper { assert containingDeclaration instanceof PackageFragmentDescriptor : "Not a top-level member: " + descriptor; PackageFragmentDescriptor packageFragmentDescriptor = (PackageFragmentDescriptor) containingDeclaration; - String facadeShortName = getPackageMemberOwnerShortName(descriptor); + String facadeShortName = getPackageMemberOwnerShortName(descriptor, isImplementation); if (facadeShortName == null) { return null; } @@ -203,27 +214,40 @@ public class JetTypeMapper { } @Nullable - private static String getPackageMemberOwnerShortName(@NotNull DeserializedCallableMemberDescriptor descriptor) { + private static String getPackageMemberOwnerShortName(@NotNull DeserializedCallableMemberDescriptor descriptor, boolean isImplementation) { // XXX Dirty hack; see getPackageMemberOwnerInternalName above for more details. DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration(); if (containingDeclaration instanceof PackageFragmentDescriptor) { + Name implClassName = JvmFileClassUtil.getImplClassName(descriptor); + if (isImplementation) { + return implClassName.asString(); + } + PackageFragmentDescriptor packageFragmentDescriptor = (PackageFragmentDescriptor) containingDeclaration; JetScope scope = packageFragmentDescriptor.getMemberScope(); if (scope instanceof AbstractScopeAdapter) { scope = ((AbstractScopeAdapter) scope).getActualScope(); } if (scope instanceof LazyJavaPackageScope) { - Name implClassName = JvmFileClassUtil.getImplClassName(descriptor); return ((LazyJavaPackageScope) scope).getFacadeSimpleNameForPartSimpleName(implClassName.asString()); } else if (packageFragmentDescriptor instanceof BuiltinsPackageFragment) { return PackageClassUtils.getPackageClassFqName(packageFragmentDescriptor.getFqName()).shortName().asString(); } + else if (packageFragmentDescriptor instanceof IncrementalPackageFragmentProvider.IncrementalPackageFragment) { + IncrementalPackageFragmentProvider.IncrementalPackageFragment incrementalPackageFragment = + (IncrementalPackageFragmentProvider.IncrementalPackageFragment) packageFragmentDescriptor; + String implClassInternalName = internalNameByFqNameWithoutInnerClasses( + packageFragmentDescriptor.getFqName().child(implClassName)); + String facadeClassInternalName = incrementalPackageFragment.getMultifileFacade(implClassInternalName); + if (facadeClassInternalName == null) { + return implClassName.asString(); + } + else { + return getSimpleInternalName(facadeClassInternalName); + } + } else { - // Incremental compilation ends up here. We do not have multifile classes support in incremental so far, - // so "use implementation class name" looks like a safe assumption for this case. - // However, this should be fixed; see getPackageMemberOwnerInternalName above for more details. - Name implClassName = JvmFileClassUtil.getImplClassName(descriptor); return implClassName.asString(); } } diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinToJVMBytecodeCompiler.java b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinToJVMBytecodeCompiler.java index f9e64ce43e6..50b904edf64 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinToJVMBytecodeCompiler.java +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinToJVMBytecodeCompiler.java @@ -60,6 +60,8 @@ import org.jetbrains.kotlin.resolve.BindingTraceContext; import org.jetbrains.kotlin.resolve.ScriptNameUtil; import org.jetbrains.kotlin.resolve.jvm.JvmClassName; import org.jetbrains.kotlin.resolve.jvm.TopDownAnalyzerFacadeForJVM; +import org.jetbrains.kotlin.serialization.PackageData; +import org.jetbrains.kotlin.serialization.jvm.JvmProtoBufUtil; import org.jetbrains.kotlin.util.PerformanceCounter; import org.jetbrains.kotlin.utils.KotlinPaths; @@ -368,18 +370,26 @@ public class KotlinToJVMBytecodeCompiler { IncrementalCompilationComponents incrementalCompilationComponents = configuration.get(JVMConfigurationKeys.INCREMENTAL_COMPILATION_COMPONENTS); Collection packagesWithObsoleteParts; + List obsoleteMultifileClasses; TargetId targetId = null; if (module == null || incrementalCompilationComponents == null) { packagesWithObsoleteParts = Collections.emptySet(); + obsoleteMultifileClasses = Collections.emptyList(); } else { targetId = ModulesPackage.TargetId(module); IncrementalCache incrementalCache = incrementalCompilationComponents.getIncrementalCache(targetId); + packagesWithObsoleteParts = new HashSet(); for (String internalName : incrementalCache.getObsoletePackageParts()) { packagesWithObsoleteParts.add(JvmClassName.byInternalName(internalName).getPackageFqName()); } + + obsoleteMultifileClasses = new ArrayList(); + for (String obsoleteFacadeInternalName : incrementalCache.getObsoleteMultifileClasses()) { + obsoleteMultifileClasses.add(JvmClassName.byInternalName(obsoleteFacadeInternalName).getFqNameForClassNameWithoutDollars()); + } } BindingTraceContext diagnosticHolder = new BindingTraceContext(); GenerationState generationState = new GenerationState( @@ -396,6 +406,7 @@ public class KotlinToJVMBytecodeCompiler { configuration.get(JVMConfigurationKeys.PACKAGE_FACADES_AS_MULTIFILE_CLASSES, false), diagnosticHolder, packagesWithObsoleteParts, + obsoleteMultifileClasses, targetId, moduleName, outputDirectory, diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/load/kotlin/incremental/IncrementalPackageFragmentProvider.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/load/kotlin/incremental/IncrementalPackageFragmentProvider.kt index bf015c5bf9e..d5aaa00e51d 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/load/kotlin/incremental/IncrementalPackageFragmentProvider.kt +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/load/kotlin/incremental/IncrementalPackageFragmentProvider.kt @@ -22,6 +22,7 @@ import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor import org.jetbrains.kotlin.descriptors.PackageFragmentProvider import org.jetbrains.kotlin.descriptors.impl.PackageFragmentDescriptorImpl +import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil import org.jetbrains.kotlin.load.kotlin.ModuleMapping import org.jetbrains.kotlin.load.kotlin.PackagePartClassUtils import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCache @@ -35,6 +36,7 @@ import org.jetbrains.kotlin.resolve.scopes.JetScope import org.jetbrains.kotlin.serialization.PackageData import org.jetbrains.kotlin.serialization.ProtoBuf import org.jetbrains.kotlin.serialization.deserialization.DeserializationComponents +import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedCallableMemberDescriptor import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedPackageMemberScope import org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf import org.jetbrains.kotlin.serialization.jvm.JvmProtoBufUtil @@ -135,8 +137,37 @@ public class IncrementalPackageFragmentProvider( } } + public fun getPackageFragmentForMultifileClass(multifileClassFqName: FqName): IncrementalMultifileClassPackageFragment? { + val facadeInternalName = JvmClassName.byFqNameWithoutInnerClasses(multifileClassFqName).internalName + val partsNames = incrementalCache.getStableMultifileFacadeParts(facadeInternalName) ?: return null + return IncrementalMultifileClassPackageFragment(multifileClassFqName, partsNames) + } + + public fun getMultifileFacade(partInternalName: String): String? { + return incrementalCache.getMultifileFacade(partInternalName) + } + override fun getMemberScope(): JetScope = memberScope() + public inner class IncrementalMultifileClassPackageFragment( + val multifileClassFqName: FqName, + val partsNames: Collection + ) : PackageFragmentDescriptorImpl(moduleDescriptor, multifileClassFqName.parent()) { + val memberScope = storageManager.createLazyValue { + val partsData = partsNames.map { incrementalCache.getPackagePartData(it) }.filterNotNull() + if (partsData.isEmpty()) + JetScope.Empty + else { + val scopes = partsData.map { IncrementalPackageScope(JvmProtoBufUtil.readPackageDataFrom(it)) } + ChainedScope(this, + "Member scope for incremental compilation: union of multifile class parts data for $multifileClassFqName", + *scopes.toTypedArray()) + } + } + + override fun getMemberScope(): JetScope = memberScope() + } + private inner class IncrementalPackageScope(val packageData: PackageData) : DeserializedPackageMemberScope( this@IncrementalPackageFragment, packageData.packageProto, packageData.nameResolver, deserializationComponents, { listOf() } diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/load/kotlin/incremental/components/IncrementalCache.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/load/kotlin/incremental/components/IncrementalCache.kt index f0ebcd5d323..26720db5d8c 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/load/kotlin/incremental/components/IncrementalCache.kt +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/load/kotlin/incremental/components/IncrementalCache.kt @@ -23,6 +23,12 @@ data class JvmPackagePartProto(val data: ByteArray, val strings: Array) public interface IncrementalCache { public fun getObsoletePackageParts(): Collection + public fun getObsoleteMultifileClasses(): Collection + + public fun getStableMultifileFacadeParts(facadeInternalName: String): Collection? + + public fun getMultifileFacade(partInternalName: String): String? + public fun getPackagePartData(fqName: String): JvmPackagePartProto? public fun getModuleMappingData(): ByteArray? diff --git a/compiler/rmi/kotlinr/src/org/jetbrains/kotlin/rmi/kotlinr/RemoteIncrementalCacheServer.kt b/compiler/rmi/kotlinr/src/org/jetbrains/kotlin/rmi/kotlinr/RemoteIncrementalCacheServer.kt index 30dc0f1a96f..9401733e765 100644 --- a/compiler/rmi/kotlinr/src/org/jetbrains/kotlin/rmi/kotlinr/RemoteIncrementalCacheServer.kt +++ b/compiler/rmi/kotlinr/src/org/jetbrains/kotlin/rmi/kotlinr/RemoteIncrementalCacheServer.kt @@ -31,6 +31,12 @@ public class RemoteIncrementalCacheServer(val cache: IncrementalCache, port: Int override fun getObsoletePackageParts(): Collection = cache.getObsoletePackageParts() + override fun getObsoleteMultifileClassFacades(): Collection = cache.getObsoleteMultifileClasses() + + override fun getMultifileFacadeParts(internalName: String): Collection? = cache.getStableMultifileFacadeParts(internalName) + + override fun getMultifileFacade(partInternalName: String): String? = cache.getMultifileFacade(partInternalName) + override fun getPackagePartData(fqName: String): JvmPackagePartProto? = cache.getPackagePartData(fqName) override fun getModuleMappingData(): ByteArray? = cache.getModuleMappingData() diff --git a/compiler/rmi/rmi-interface/src/org/jetbrains/kotlin/rmi/CompileService.kt b/compiler/rmi/rmi-interface/src/org/jetbrains/kotlin/rmi/CompileService.kt index 922168ce1b7..d4d27db8b8e 100644 --- a/compiler/rmi/rmi-interface/src/org/jetbrains/kotlin/rmi/CompileService.kt +++ b/compiler/rmi/rmi-interface/src/org/jetbrains/kotlin/rmi/CompileService.kt @@ -34,6 +34,12 @@ public interface CompileService : Remote { @Throws(RemoteException::class) public fun getObsoletePackageParts(): Collection + @Throws(RemoteException::class) + public fun getObsoleteMultifileClassFacades(): Collection + + @Throws(RemoteException::class) + public fun getMultifileFacade(partInternalName: String): String? + @Throws(RemoteException::class) public fun getPackagePartData(fqName: String): JvmPackagePartProto? @@ -48,6 +54,9 @@ public interface CompileService : Remote { @Throws(RemoteException::class) public fun close() + + @Throws(RemoteException::class) + public fun getMultifileFacadeParts(internalName: String): Collection? } public interface RemoteLookupTracker : Remote { diff --git a/compiler/rmi/rmi-server/src/org/jetbrains/kotlin/rmi/service/RemoteIncrementalCacheClient.kt b/compiler/rmi/rmi-server/src/org/jetbrains/kotlin/rmi/service/RemoteIncrementalCacheClient.kt index 13a68de84d5..5eeffd7bbb7 100644 --- a/compiler/rmi/rmi-server/src/org/jetbrains/kotlin/rmi/service/RemoteIncrementalCacheClient.kt +++ b/compiler/rmi/rmi-server/src/org/jetbrains/kotlin/rmi/service/RemoteIncrementalCacheClient.kt @@ -21,8 +21,14 @@ import org.jetbrains.kotlin.load.kotlin.incremental.components.JvmPackagePartPro import org.jetbrains.kotlin.rmi.CompileService public class RemoteIncrementalCacheClient(val cache: CompileService.RemoteIncrementalCache): IncrementalCache { + override fun getObsoleteMultifileClasses(): Collection = cache.getObsoleteMultifileClassFacades() + + override fun getStableMultifileFacadeParts(facadeInternalName: String): Collection? = cache.getMultifileFacadeParts(facadeInternalName) + override fun getObsoletePackageParts(): Collection = cache.getObsoletePackageParts() + override fun getMultifileFacade(partInternalName: String): String? = cache.getMultifileFacade(partInternalName) + override fun getPackagePartData(fqName: String): JvmPackagePartProto? = cache.getPackagePartData(fqName) override fun getModuleMappingData(): ByteArray? = cache.getModuleMappingData() diff --git a/compiler/testData/compileKotlinAgainstKotlin/MultifileClassInlineFunctionAccessingProperty.A.kt b/compiler/testData/compileKotlinAgainstKotlin/MultifileClassInlineFunctionAccessingProperty.A.kt new file mode 100644 index 00000000000..85a2e78cec4 --- /dev/null +++ b/compiler/testData/compileKotlinAgainstKotlin/MultifileClassInlineFunctionAccessingProperty.A.kt @@ -0,0 +1,6 @@ +@file:[JvmName("Test") JvmMultifileClass] + +val property = "K" + +inline fun K(body: () -> String): String = + body() + property diff --git a/compiler/testData/compileKotlinAgainstKotlin/MultifileClassInlineFunctionAccessingProperty.B.kt b/compiler/testData/compileKotlinAgainstKotlin/MultifileClassInlineFunctionAccessingProperty.B.kt new file mode 100644 index 00000000000..7dcc8a09a07 --- /dev/null +++ b/compiler/testData/compileKotlinAgainstKotlin/MultifileClassInlineFunctionAccessingProperty.B.kt @@ -0,0 +1,4 @@ +fun main(args: Array) { + val ok = K { "O" } + if (ok != "OK") throw java.lang.AssertionError("Expected: OK, actual: $ok") +} \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstKotlinTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstKotlinTestGenerated.java index 756c525b8da..36b65fa7137 100644 --- a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstKotlinTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstKotlinTestGenerated.java @@ -113,6 +113,12 @@ public class CompileKotlinAgainstKotlinTestGenerated extends AbstractCompileKotl doTest(fileName); } + @TestMetadata("MultifileClassInlineFunctionAccessingProperty.A.kt") + public void testMultifileClassInlineFunctionAccessingProperty() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/compileKotlinAgainstKotlin/MultifileClassInlineFunctionAccessingProperty.A.kt"); + doTest(fileName); + } + @TestMetadata("NestedClass.A.kt") public void testNestedClass() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/compileKotlinAgainstKotlin/NestedClass.A.kt"); diff --git a/jps-plugin/src/org/jetbrains/kotlin/jps/incremental/IncrementalCacheImpl.kt b/jps-plugin/src/org/jetbrains/kotlin/jps/incremental/IncrementalCacheImpl.kt index b9f97d84ddc..6b64149885a 100644 --- a/jps-plugin/src/org/jetbrains/kotlin/jps/incremental/IncrementalCacheImpl.kt +++ b/jps-plugin/src/org/jetbrains/kotlin/jps/incremental/IncrementalCacheImpl.kt @@ -17,10 +17,7 @@ package org.jetbrains.kotlin.jps.incremental import com.intellij.openapi.util.io.FileUtil -import com.intellij.util.io.BooleanDataDescriptor -import com.intellij.util.io.DataExternalizer -import com.intellij.util.io.IOUtil -import com.intellij.util.io.KeyDescriptor +import com.intellij.util.io.* import gnu.trove.THashSet import org.jetbrains.annotations.TestOnly import org.jetbrains.jps.builders.BuildTarget @@ -35,12 +32,12 @@ import org.jetbrains.kotlin.jps.build.KotlinBuilder import org.jetbrains.kotlin.jps.incremental.storage.BasicMap import org.jetbrains.kotlin.jps.incremental.storage.BasicStringMap import org.jetbrains.kotlin.load.java.JvmAnnotationNames +import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinaryClass import org.jetbrains.kotlin.load.kotlin.ModuleMapping import org.jetbrains.kotlin.load.kotlin.PackageClassUtils -import org.jetbrains.kotlin.load.kotlin.header.isCompatibleClassKind -import org.jetbrains.kotlin.load.kotlin.header.isCompatibleFileFacadeKind -import org.jetbrains.kotlin.load.kotlin.header.isCompatiblePackageFacadeKind +import org.jetbrains.kotlin.load.kotlin.header.* import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCache +import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.load.kotlin.incremental.components.JvmPackagePartProto import org.jetbrains.kotlin.resolve.jvm.JvmClassName import org.jetbrains.kotlin.resolve.jvm.JvmClassName.byInternalName @@ -68,14 +65,17 @@ public class IncrementalCacheImpl( companion object { val CACHE_EXTENSION = "tab" - private val PROTO_MAP = "proto" - private val CONSTANTS_MAP = "constants" - private val INLINE_FUNCTIONS = "inline-functions" - private val PACKAGE_PARTS = "package-parts" - private val SOURCE_TO_CLASSES = "source-to-classes" - private val DIRTY_OUTPUT_CLASSES = "dirty-output-classes" - private val DIRTY_INLINE_FUNCTIONS = "dirty-inline-functions" - private val INLINED_TO = "inlined-to" + val PROTO_MAP = "proto" + val CONSTANTS_MAP = "constants" + val INLINE_FUNCTIONS = "inline-functions" + val PACKAGE_PARTS = "package-parts" + val MULTIFILE_CLASS_FACADES = "multifile-class-facades" + val MULTIFILE_CLASS_PARTS = "multifile-class-parts" + val SOURCE_TO_CLASSES = "source-to-classes" + val CLASS_TO_SOURCES = "class-to-sources" + val DIRTY_OUTPUT_CLASSES = "dirty-output-classes" + val DIRTY_INLINE_FUNCTIONS = "dirty-inline-functions" + val INLINED_TO = "inlined-to" private val MODULE_MAPPING_FILE_NAME = "." + ModuleMapping.MAPPING_FILE_EXT } @@ -95,6 +95,8 @@ public class IncrementalCacheImpl( private val constantsMap = registerMap(ConstantsMap(CONSTANTS_MAP.storageFile)) private val inlineFunctionsMap = registerMap(InlineFunctionsMap(INLINE_FUNCTIONS.storageFile)) private val packagePartMap = registerMap(PackagePartMap(PACKAGE_PARTS.storageFile)) + private val multifileClassFacadeMap = registerMap(MultifileClassFacadeMap(MULTIFILE_CLASS_FACADES.storageFile)) + private val multifileClassPartMap = registerMap(MultifileClassPartMap(MULTIFILE_CLASS_PARTS.storageFile)) private val sourceToClassesMap = registerMap(SourceToClassesMap(SOURCE_TO_CLASSES.storageFile)) private val dirtyOutputClassesMap = registerMap(DirtyOutputClassesMap(DIRTY_OUTPUT_CLASSES.storageFile)) // TODO: can be removed? @@ -196,6 +198,24 @@ public class IncrementalCacheImpl( constantsMap.process(kotlinClass) + inlineFunctionsMap.process(kotlinClass) } + header.isCompatibleMultifileClassKind() -> { + val partNames = getFullNamesOfMultifileClassParts(kotlinClass) + multifileClassFacadeMap.add(className, partNames) + + // TODO NO_CHANGES? (delegates only, see package facade) + constantsMap.process(kotlinClass) + + inlineFunctionsMap.process(kotlinClass) + } + header.isCompatibleMultifileClassPartKind() -> { + assert(sourceFiles.size() == 1) { "Multifile class part from several source files: $sourceFiles" } + packagePartMap.addPackagePart(className) + val facadeClassName = getInternalNameOfTopLevelClassInTheSamePackage(kotlinClass, header.multifileClassName!!) + multifileClassPartMap.add(className.internalName, facadeClassName) + + protoMap.process(kotlinClass, isPackage = true) + + constantsMap.process(kotlinClass) + + inlineFunctionsMap.process(kotlinClass) + } header.isCompatibleClassKind() && JvmAnnotationNames.KotlinClass.Kind.CLASS == header.classKind -> protoMap.process(kotlinClass, isPackage = false) + constantsMap.process(kotlinClass) + @@ -236,6 +256,8 @@ public class IncrementalCacheImpl( dirtyClasses.forEach { protoMap.remove(it) packagePartMap.remove(it) + multifileClassFacadeMap.remove(it) + multifileClassPartMap.remove(it) constantsMap.remove(it) inlineFunctionsMap.remove(it) } @@ -256,6 +278,25 @@ public class IncrementalCacheImpl( } } + override fun getObsoleteMultifileClasses(): Collection { + val obsoleteMultifileClasses = linkedSetOf() + for (dirtyClass in dirtyOutputClassesMap.getDirtyOutputClasses()) { + val dirtyFacade = multifileClassPartMap.getFacadeName(dirtyClass) ?: continue + obsoleteMultifileClasses.add(dirtyFacade) + } + KotlinBuilder.LOG.debug("Obsolete multifile class facades: $obsoleteMultifileClasses") + return obsoleteMultifileClasses + } + + override fun getStableMultifileFacadeParts(facadeInternalName: String): Collection? { + val partNames = multifileClassFacadeMap.getMultifileClassParts(facadeInternalName) ?: return null + return partNames.filter { !dirtyOutputClassesMap.isDirty(it) } + } + + override fun getMultifileFacade(partInternalName: String): String? { + return multifileClassPartMap.getFacadeName(partInternalName) + } + override fun getModuleMappingData(): ByteArray? { return protoMap[JvmClassName.byInternalName(MODULE_MAPPING_FILE_NAME)]?.bytes } @@ -516,6 +557,36 @@ public class IncrementalCacheImpl( override fun dumpValue(value: Boolean) = "" } + private inner class MultifileClassFacadeMap(storageFile: File) : BasicStringMap>(storageFile, StringListExternalizer) { + public fun add(facadeName: JvmClassName, partNames: List) { + storage.put(facadeName.internalName, partNames) + } + + public fun getMultifileClassParts(facadeName: String): List? = storage[facadeName] + + public fun remove(className: JvmClassName) { + storage.remove(className.internalName) + } + + override fun dumpValue(value: List): String = value.toString() + } + + private inner class MultifileClassPartMap(storageFile: File) : BasicStringMap(storageFile, EnumeratorStringDescriptor.INSTANCE) { + public fun add(partName: String, facadeName: String) { + storage.put(partName, facadeName) + } + + public fun getFacadeName(partName: String): String? { + return storage.get(partName) + } + + public fun remove(className: JvmClassName) { + storage.remove(className.internalName) + } + + override fun dumpValue(value: String): String = value + } + private inner class SourceToClassesMap(storageFile: File) : BasicStringMap>(storageFile, PathStringDescriptor.INSTANCE, StringListExternalizer) { public fun clearOutputsForSource(sourceFile: File) { storage.remove(sourceFile.absolutePath) @@ -543,6 +614,8 @@ public class IncrementalCacheImpl( public fun getDirtyOutputClasses(): Collection = storage.keys + public fun isDirty(className: String): Boolean = storage.containsMapping(className) + override fun dumpValue(value: Boolean) = "" } @@ -631,6 +704,21 @@ private fun ByteArray.md5(): Long { ) } +private fun getInternalNameOfTopLevelClassInTheSamePackage(kotlinClass: KotlinJvmBinaryClass, simpleName: String): String { + val classFqName = kotlinClass.classId.packageFqName.child(Name.identifier(simpleName)) + return JvmClassName.byFqNameWithoutInnerClasses(classFqName).internalName +} + +private fun getFullNamesOfMultifileClassParts(kotlinClass: LocalFileKotlinClass): List { + val classHeader = kotlinClass.classHeader + val partClassNames = classHeader.filePartClassNames ?: throw AssertionError("Multifile class has no parts: ${kotlinClass.className}") + val fullNames = arrayListOf() + for (shortName in partClassNames) { + fullNames.add(getInternalNameOfTopLevelClassInTheSamePackage(kotlinClass, shortName)) + } + return fullNames +} + private abstract class StringMapExternalizer : DataExternalizer> { override fun save(out: DataOutput, map: Map?) { out.writeInt(map!!.size()) @@ -698,6 +786,9 @@ private object PathCollectionExternalizer : DataExternalizer> } } +private val File.normalizedPath: String + get() = FileUtil.toSystemIndependentName(canonicalPath) + @TestOnly private fun , V> Map.dumpMap(dumpValue: (V)->String): String = StringBuilder { diff --git a/jps-plugin/test/org/jetbrains/kotlin/jps/build/IncrementalJpsTestGenerated.java b/jps-plugin/test/org/jetbrains/kotlin/jps/build/IncrementalJpsTestGenerated.java index 512804ffb8b..d2f1a958083 100644 --- a/jps-plugin/test/org/jetbrains/kotlin/jps/build/IncrementalJpsTestGenerated.java +++ b/jps-plugin/test/org/jetbrains/kotlin/jps/build/IncrementalJpsTestGenerated.java @@ -347,6 +347,54 @@ public class IncrementalJpsTestGenerated extends AbstractIncrementalJpsTest { doTest(fileName); } + @TestMetadata("multifileClassFileAdded") + public void testMultifileClassFileAdded() throws Exception { + String fileName = JetTestUtils.navigationMetadata("jps-plugin/testData/incremental/pureKotlin/multifileClassFileAdded/"); + doTest(fileName); + } + + @TestMetadata("multifileClassFileChanged") + public void testMultifileClassFileChanged() throws Exception { + String fileName = JetTestUtils.navigationMetadata("jps-plugin/testData/incremental/pureKotlin/multifileClassFileChanged/"); + doTest(fileName); + } + + @TestMetadata("multifileClassFileMovedToAnotherMultifileClass") + public void testMultifileClassFileMovedToAnotherMultifileClass() throws Exception { + String fileName = JetTestUtils.navigationMetadata("jps-plugin/testData/incremental/pureKotlin/multifileClassFileMovedToAnotherMultifileClass/"); + doTest(fileName); + } + + @TestMetadata("multifileClassInlineFunction") + public void testMultifileClassInlineFunction() throws Exception { + String fileName = JetTestUtils.navigationMetadata("jps-plugin/testData/incremental/pureKotlin/multifileClassInlineFunction/"); + doTest(fileName); + } + + @TestMetadata("multifileClassInlineFunctionAccessingField") + public void testMultifileClassInlineFunctionAccessingField() throws Exception { + String fileName = JetTestUtils.navigationMetadata("jps-plugin/testData/incremental/pureKotlin/multifileClassInlineFunctionAccessingField/"); + doTest(fileName); + } + + @TestMetadata("multifileClassRecreated") + public void testMultifileClassRecreated() throws Exception { + String fileName = JetTestUtils.navigationMetadata("jps-plugin/testData/incremental/pureKotlin/multifileClassRecreated/"); + doTest(fileName); + } + + @TestMetadata("multifileClassRecreatedAfterRenaming") + public void testMultifileClassRecreatedAfterRenaming() throws Exception { + String fileName = JetTestUtils.navigationMetadata("jps-plugin/testData/incremental/pureKotlin/multifileClassRecreatedAfterRenaming/"); + doTest(fileName); + } + + @TestMetadata("multifileClassRemoved") + public void testMultifileClassRemoved() throws Exception { + String fileName = JetTestUtils.navigationMetadata("jps-plugin/testData/incremental/pureKotlin/multifileClassRemoved/"); + doTest(fileName); + } + @TestMetadata("multiplePackagesModified") public void testMultiplePackagesModified() throws Exception { String fileName = JetTestUtils.navigationMetadata("jps-plugin/testData/incremental/pureKotlin/multiplePackagesModified/"); diff --git a/jps-plugin/test/org/jetbrains/kotlin/jps/build/classFilesComparison/classFilesComparison.kt b/jps-plugin/test/org/jetbrains/kotlin/jps/build/classFilesComparison/classFilesComparison.kt index 03aacad2200..f62eca04266 100644 --- a/jps-plugin/test/org/jetbrains/kotlin/jps/build/classFilesComparison/classFilesComparison.kt +++ b/jps-plugin/test/org/jetbrains/kotlin/jps/build/classFilesComparison/classFilesComparison.kt @@ -22,9 +22,7 @@ import com.google.common.io.Files import com.google.protobuf.ExtensionRegistry import com.intellij.openapi.util.io.FileUtil import org.jetbrains.kotlin.jps.incremental.LocalFileKotlinClass -import org.jetbrains.kotlin.load.kotlin.header.isCompatibleClassKind -import org.jetbrains.kotlin.load.kotlin.header.isCompatibleFileFacadeKind -import org.jetbrains.kotlin.load.kotlin.header.isCompatiblePackageFacadeKind +import org.jetbrains.kotlin.load.kotlin.header.* import org.jetbrains.kotlin.serialization.DebugProtoBuf import org.jetbrains.kotlin.serialization.jvm.BitEncoding import org.jetbrains.kotlin.serialization.jvm.DebugJvmProtoBuf @@ -148,6 +146,8 @@ fun classFileToString(classFile: File): String { out.write("\n------ file facade proto -----\n${DebugProtoBuf.Package.parseFrom(input, getExtensionRegistry())}") classHeader.isCompatibleClassKind() -> out.write("\n------ class proto -----\n${DebugProtoBuf.Class.parseFrom(input, getExtensionRegistry())}") + classHeader.isCompatibleMultifileClassPartKind() -> + out.write("\n------ multi-file part proto -----\n${DebugProtoBuf.Package.parseFrom(input, getExtensionRegistry())}") else -> throw IllegalStateException() } diff --git a/jps-plugin/testData/incremental/pureKotlin/multifileClassFileAdded/a.kt b/jps-plugin/testData/incremental/pureKotlin/multifileClassFileAdded/a.kt new file mode 100644 index 00000000000..63a63e173a0 --- /dev/null +++ b/jps-plugin/testData/incremental/pureKotlin/multifileClassFileAdded/a.kt @@ -0,0 +1,4 @@ +@file:[JvmName("Test") JvmMultifileClass] +package test + +fun a() = "a" diff --git a/jps-plugin/testData/incremental/pureKotlin/multifileClassFileAdded/b.kt.new b/jps-plugin/testData/incremental/pureKotlin/multifileClassFileAdded/b.kt.new new file mode 100644 index 00000000000..cb1f3f58a0a --- /dev/null +++ b/jps-plugin/testData/incremental/pureKotlin/multifileClassFileAdded/b.kt.new @@ -0,0 +1,4 @@ +@file:[JvmName("Test") JvmMultifileClass] +package test + +fun b() = "b" diff --git a/jps-plugin/testData/incremental/pureKotlin/multifileClassFileAdded/build.log b/jps-plugin/testData/incremental/pureKotlin/multifileClassFileAdded/build.log new file mode 100644 index 00000000000..50ccb081084 --- /dev/null +++ b/jps-plugin/testData/incremental/pureKotlin/multifileClassFileAdded/build.log @@ -0,0 +1,23 @@ +Compiling files: +src/b.kt +End of files +Cleaning output files: +out/production/module/META-INF/module.kotlin_module +out/production/module/test/Test.class +out/production/module/test/TestPackage.class +out/production/module/test/Test__AKt.class +out/production/module/test/Test__BKt.class +End of files +Compiling files: +src/a.kt +src/b.kt +End of files +Cleaning output files: +out/production/module/META-INF/module.kotlin_module +out/production/module/test/Test.class +out/production/module/test/TestPackage.class +out/production/module/test/Test__AKt.class +End of files +Compiling files: +src/a.kt +End of files \ No newline at end of file diff --git a/jps-plugin/testData/incremental/pureKotlin/multifileClassFileChanged/a.kt b/jps-plugin/testData/incremental/pureKotlin/multifileClassFileChanged/a.kt new file mode 100644 index 00000000000..63a63e173a0 --- /dev/null +++ b/jps-plugin/testData/incremental/pureKotlin/multifileClassFileChanged/a.kt @@ -0,0 +1,4 @@ +@file:[JvmName("Test") JvmMultifileClass] +package test + +fun a() = "a" diff --git a/jps-plugin/testData/incremental/pureKotlin/multifileClassFileChanged/b.kt b/jps-plugin/testData/incremental/pureKotlin/multifileClassFileChanged/b.kt new file mode 100644 index 00000000000..cb1f3f58a0a --- /dev/null +++ b/jps-plugin/testData/incremental/pureKotlin/multifileClassFileChanged/b.kt @@ -0,0 +1,4 @@ +@file:[JvmName("Test") JvmMultifileClass] +package test + +fun b() = "b" diff --git a/jps-plugin/testData/incremental/pureKotlin/multifileClassFileChanged/b.kt.new b/jps-plugin/testData/incremental/pureKotlin/multifileClassFileChanged/b.kt.new new file mode 100644 index 00000000000..6ce025497fc --- /dev/null +++ b/jps-plugin/testData/incremental/pureKotlin/multifileClassFileChanged/b.kt.new @@ -0,0 +1,4 @@ +@file:[JvmName("Test") JvmMultifileClass] +package test + +fun b() = "bcd" diff --git a/jps-plugin/testData/incremental/pureKotlin/multifileClassFileChanged/build.log b/jps-plugin/testData/incremental/pureKotlin/multifileClassFileChanged/build.log new file mode 100644 index 00000000000..82b2f80c31e --- /dev/null +++ b/jps-plugin/testData/incremental/pureKotlin/multifileClassFileChanged/build.log @@ -0,0 +1,9 @@ +Cleaning output files: +out/production/module/META-INF/module.kotlin_module +out/production/module/test/Test.class +out/production/module/test/TestPackage.class +out/production/module/test/Test__BKt.class +End of files +Compiling files: +src/b.kt +End of files \ No newline at end of file diff --git a/jps-plugin/testData/incremental/pureKotlin/multifileClassFileMovedToAnotherMultifileClass/a.kt b/jps-plugin/testData/incremental/pureKotlin/multifileClassFileMovedToAnotherMultifileClass/a.kt new file mode 100644 index 00000000000..63a63e173a0 --- /dev/null +++ b/jps-plugin/testData/incremental/pureKotlin/multifileClassFileMovedToAnotherMultifileClass/a.kt @@ -0,0 +1,4 @@ +@file:[JvmName("Test") JvmMultifileClass] +package test + +fun a() = "a" diff --git a/jps-plugin/testData/incremental/pureKotlin/multifileClassFileMovedToAnotherMultifileClass/b.kt b/jps-plugin/testData/incremental/pureKotlin/multifileClassFileMovedToAnotherMultifileClass/b.kt new file mode 100644 index 00000000000..cb1f3f58a0a --- /dev/null +++ b/jps-plugin/testData/incremental/pureKotlin/multifileClassFileMovedToAnotherMultifileClass/b.kt @@ -0,0 +1,4 @@ +@file:[JvmName("Test") JvmMultifileClass] +package test + +fun b() = "b" diff --git a/jps-plugin/testData/incremental/pureKotlin/multifileClassFileMovedToAnotherMultifileClass/b.kt.new b/jps-plugin/testData/incremental/pureKotlin/multifileClassFileMovedToAnotherMultifileClass/b.kt.new new file mode 100644 index 00000000000..5099c5bae8a --- /dev/null +++ b/jps-plugin/testData/incremental/pureKotlin/multifileClassFileMovedToAnotherMultifileClass/b.kt.new @@ -0,0 +1,4 @@ +@file:[JvmName("Test1") JvmMultifileClass] +package test + +fun b() = "b" diff --git a/jps-plugin/testData/incremental/pureKotlin/multifileClassFileMovedToAnotherMultifileClass/build.log b/jps-plugin/testData/incremental/pureKotlin/multifileClassFileMovedToAnotherMultifileClass/build.log new file mode 100644 index 00000000000..8366c68cc13 --- /dev/null +++ b/jps-plugin/testData/incremental/pureKotlin/multifileClassFileMovedToAnotherMultifileClass/build.log @@ -0,0 +1,18 @@ +Cleaning output files: +out/production/module/META-INF/module.kotlin_module +out/production/module/test/Test.class +out/production/module/test/TestPackage.class +out/production/module/test/Test__BKt.class +End of files +Compiling files: +src/b.kt +End of files +Cleaning output files: +out/production/module/META-INF/module.kotlin_module +out/production/module/test/Test.class +out/production/module/test/TestPackage.class +out/production/module/test/Test__AKt.class +End of files +Compiling files: +src/a.kt +End of files \ No newline at end of file diff --git a/jps-plugin/testData/incremental/pureKotlin/multifileClassInlineFunction/build.log b/jps-plugin/testData/incremental/pureKotlin/multifileClassInlineFunction/build.log new file mode 100644 index 00000000000..64f2485efca --- /dev/null +++ b/jps-plugin/testData/incremental/pureKotlin/multifileClassInlineFunction/build.log @@ -0,0 +1,8 @@ +Cleaning output files: +out/production/module/META-INF/module.kotlin_module +out/production/module/test/TestPackage.class +out/production/module/test/UsageKt.class +End of files +Compiling files: +src/usage.kt +End of files \ No newline at end of file diff --git a/jps-plugin/testData/incremental/pureKotlin/multifileClassInlineFunction/inline.kt b/jps-plugin/testData/incremental/pureKotlin/multifileClassInlineFunction/inline.kt new file mode 100644 index 00000000000..f4fa4554f73 --- /dev/null +++ b/jps-plugin/testData/incremental/pureKotlin/multifileClassInlineFunction/inline.kt @@ -0,0 +1,7 @@ +@file:[JvmName("Test") JvmMultifileClass] +package test + +inline fun f(body: () -> Unit) { + println("i'm inline function") + body() +} diff --git a/jps-plugin/testData/incremental/pureKotlin/multifileClassInlineFunction/inlineOther.kt b/jps-plugin/testData/incremental/pureKotlin/multifileClassInlineFunction/inlineOther.kt new file mode 100644 index 00000000000..38501b19b1f --- /dev/null +++ b/jps-plugin/testData/incremental/pureKotlin/multifileClassInlineFunction/inlineOther.kt @@ -0,0 +1,7 @@ +@file:[JvmName("Test") JvmMultifileClass] +package other + +inline fun f(body: () -> Unit) { + println("i'm other inline function") + body() +} diff --git a/jps-plugin/testData/incremental/pureKotlin/multifileClassInlineFunction/usage.kt b/jps-plugin/testData/incremental/pureKotlin/multifileClassInlineFunction/usage.kt new file mode 100644 index 00000000000..e5bb1ff5213 --- /dev/null +++ b/jps-plugin/testData/incremental/pureKotlin/multifileClassInlineFunction/usage.kt @@ -0,0 +1,6 @@ +package test + +fun main(args: Array) { + f { println("to be inlined") } + other.f { println("to be inlined") } +} diff --git a/jps-plugin/testData/incremental/pureKotlin/multifileClassInlineFunction/usage.kt.new b/jps-plugin/testData/incremental/pureKotlin/multifileClassInlineFunction/usage.kt.new new file mode 100644 index 00000000000..e5bb1ff5213 --- /dev/null +++ b/jps-plugin/testData/incremental/pureKotlin/multifileClassInlineFunction/usage.kt.new @@ -0,0 +1,6 @@ +package test + +fun main(args: Array) { + f { println("to be inlined") } + other.f { println("to be inlined") } +} diff --git a/jps-plugin/testData/incremental/pureKotlin/multifileClassInlineFunctionAccessingField/build.log b/jps-plugin/testData/incremental/pureKotlin/multifileClassInlineFunctionAccessingField/build.log new file mode 100644 index 00000000000..64f2485efca --- /dev/null +++ b/jps-plugin/testData/incremental/pureKotlin/multifileClassInlineFunctionAccessingField/build.log @@ -0,0 +1,8 @@ +Cleaning output files: +out/production/module/META-INF/module.kotlin_module +out/production/module/test/TestPackage.class +out/production/module/test/UsageKt.class +End of files +Compiling files: +src/usage.kt +End of files \ No newline at end of file diff --git a/jps-plugin/testData/incremental/pureKotlin/multifileClassInlineFunctionAccessingField/inline.kt b/jps-plugin/testData/incremental/pureKotlin/multifileClassInlineFunctionAccessingField/inline.kt new file mode 100644 index 00000000000..cd2c740e29d --- /dev/null +++ b/jps-plugin/testData/incremental/pureKotlin/multifileClassInlineFunctionAccessingField/inline.kt @@ -0,0 +1,9 @@ +@file:[JvmName("Test") JvmMultifileClass] +package test + +val property = ":)" + +inline fun f(body: () -> Unit) { + println("i'm inline function" + property) + body() +} diff --git a/jps-plugin/testData/incremental/pureKotlin/multifileClassInlineFunctionAccessingField/inlineOther.kt b/jps-plugin/testData/incremental/pureKotlin/multifileClassInlineFunctionAccessingField/inlineOther.kt new file mode 100644 index 00000000000..693cebd353a --- /dev/null +++ b/jps-plugin/testData/incremental/pureKotlin/multifileClassInlineFunctionAccessingField/inlineOther.kt @@ -0,0 +1,9 @@ +@file:[JvmName("Test") JvmMultifileClass] +package other + +val property = ":)" + +inline fun f(body: () -> Unit) { + println("i'm inline function" + property) + body() +} diff --git a/jps-plugin/testData/incremental/pureKotlin/multifileClassInlineFunctionAccessingField/usage.kt b/jps-plugin/testData/incremental/pureKotlin/multifileClassInlineFunctionAccessingField/usage.kt new file mode 100644 index 00000000000..e5bb1ff5213 --- /dev/null +++ b/jps-plugin/testData/incremental/pureKotlin/multifileClassInlineFunctionAccessingField/usage.kt @@ -0,0 +1,6 @@ +package test + +fun main(args: Array) { + f { println("to be inlined") } + other.f { println("to be inlined") } +} diff --git a/jps-plugin/testData/incremental/pureKotlin/multifileClassInlineFunctionAccessingField/usage.kt.new b/jps-plugin/testData/incremental/pureKotlin/multifileClassInlineFunctionAccessingField/usage.kt.new new file mode 100644 index 00000000000..e5bb1ff5213 --- /dev/null +++ b/jps-plugin/testData/incremental/pureKotlin/multifileClassInlineFunctionAccessingField/usage.kt.new @@ -0,0 +1,6 @@ +package test + +fun main(args: Array) { + f { println("to be inlined") } + other.f { println("to be inlined") } +} diff --git a/jps-plugin/testData/incremental/pureKotlin/multifileClassRecreated/a.kt b/jps-plugin/testData/incremental/pureKotlin/multifileClassRecreated/a.kt new file mode 100644 index 00000000000..63a63e173a0 --- /dev/null +++ b/jps-plugin/testData/incremental/pureKotlin/multifileClassRecreated/a.kt @@ -0,0 +1,4 @@ +@file:[JvmName("Test") JvmMultifileClass] +package test + +fun a() = "a" diff --git a/jps-plugin/testData/incremental/pureKotlin/multifileClassRecreated/a.kt.delete.1 b/jps-plugin/testData/incremental/pureKotlin/multifileClassRecreated/a.kt.delete.1 new file mode 100644 index 00000000000..8b137891791 --- /dev/null +++ b/jps-plugin/testData/incremental/pureKotlin/multifileClassRecreated/a.kt.delete.1 @@ -0,0 +1 @@ + diff --git a/jps-plugin/testData/incremental/pureKotlin/multifileClassRecreated/b.kt.new.2 b/jps-plugin/testData/incremental/pureKotlin/multifileClassRecreated/b.kt.new.2 new file mode 100644 index 00000000000..cb1f3f58a0a --- /dev/null +++ b/jps-plugin/testData/incremental/pureKotlin/multifileClassRecreated/b.kt.new.2 @@ -0,0 +1,4 @@ +@file:[JvmName("Test") JvmMultifileClass] +package test + +fun b() = "b" diff --git a/jps-plugin/testData/incremental/pureKotlin/multifileClassRecreated/build.log b/jps-plugin/testData/incremental/pureKotlin/multifileClassRecreated/build.log new file mode 100644 index 00000000000..f920f7c94b5 --- /dev/null +++ b/jps-plugin/testData/incremental/pureKotlin/multifileClassRecreated/build.log @@ -0,0 +1,13 @@ +Cleaning output files: +out/production/module/META-INF/module.kotlin_module +out/production/module/test/Test.class +out/production/module/test/TestPackage.class +out/production/module/test/Test__AKt.class +End of files +Compiling files: +End of files + + +Compiling files: +src/b.kt +End of files \ No newline at end of file diff --git a/jps-plugin/testData/incremental/pureKotlin/multifileClassRecreatedAfterRenaming/a.kt b/jps-plugin/testData/incremental/pureKotlin/multifileClassRecreatedAfterRenaming/a.kt new file mode 100644 index 00000000000..63a63e173a0 --- /dev/null +++ b/jps-plugin/testData/incremental/pureKotlin/multifileClassRecreatedAfterRenaming/a.kt @@ -0,0 +1,4 @@ +@file:[JvmName("Test") JvmMultifileClass] +package test + +fun a() = "a" diff --git a/jps-plugin/testData/incremental/pureKotlin/multifileClassRecreatedAfterRenaming/a.kt.new.1 b/jps-plugin/testData/incremental/pureKotlin/multifileClassRecreatedAfterRenaming/a.kt.new.1 new file mode 100644 index 00000000000..1d3ad0fe2c4 --- /dev/null +++ b/jps-plugin/testData/incremental/pureKotlin/multifileClassRecreatedAfterRenaming/a.kt.new.1 @@ -0,0 +1,4 @@ +@file:[JvmName("Test2") JvmMultifileClass] +package test2 + +fun a() = "a" diff --git a/jps-plugin/testData/incremental/pureKotlin/multifileClassRecreatedAfterRenaming/b.kt.new.2 b/jps-plugin/testData/incremental/pureKotlin/multifileClassRecreatedAfterRenaming/b.kt.new.2 new file mode 100644 index 00000000000..cb1f3f58a0a --- /dev/null +++ b/jps-plugin/testData/incremental/pureKotlin/multifileClassRecreatedAfterRenaming/b.kt.new.2 @@ -0,0 +1,4 @@ +@file:[JvmName("Test") JvmMultifileClass] +package test + +fun b() = "b" diff --git a/jps-plugin/testData/incremental/pureKotlin/multifileClassRecreatedAfterRenaming/build.log b/jps-plugin/testData/incremental/pureKotlin/multifileClassRecreatedAfterRenaming/build.log new file mode 100644 index 00000000000..9e245d73c4a --- /dev/null +++ b/jps-plugin/testData/incremental/pureKotlin/multifileClassRecreatedAfterRenaming/build.log @@ -0,0 +1,23 @@ +Cleaning output files: +out/production/module/META-INF/module.kotlin_module +out/production/module/test/Test.class +out/production/module/test/TestPackage.class +out/production/module/test/Test__AKt.class +End of files +Compiling files: +src/a.kt +End of files + + +Compiling files: +src/b.kt +End of files +Cleaning output files: +out/production/module/META-INF/module.kotlin_module +out/production/module/test2/Test2.class +out/production/module/test2/Test2Package.class +out/production/module/test2/Test2__AKt.class +End of files +Compiling files: +src/a.kt +End of files \ No newline at end of file diff --git a/jps-plugin/testData/incremental/pureKotlin/multifileClassRemoved/a.kt b/jps-plugin/testData/incremental/pureKotlin/multifileClassRemoved/a.kt new file mode 100644 index 00000000000..63a63e173a0 --- /dev/null +++ b/jps-plugin/testData/incremental/pureKotlin/multifileClassRemoved/a.kt @@ -0,0 +1,4 @@ +@file:[JvmName("Test") JvmMultifileClass] +package test + +fun a() = "a" diff --git a/jps-plugin/testData/incremental/pureKotlin/multifileClassRemoved/a.kt.delete b/jps-plugin/testData/incremental/pureKotlin/multifileClassRemoved/a.kt.delete new file mode 100644 index 00000000000..e69de29bb2d diff --git a/jps-plugin/testData/incremental/pureKotlin/multifileClassRemoved/b.kt b/jps-plugin/testData/incremental/pureKotlin/multifileClassRemoved/b.kt new file mode 100644 index 00000000000..cb1f3f58a0a --- /dev/null +++ b/jps-plugin/testData/incremental/pureKotlin/multifileClassRemoved/b.kt @@ -0,0 +1,4 @@ +@file:[JvmName("Test") JvmMultifileClass] +package test + +fun b() = "b" diff --git a/jps-plugin/testData/incremental/pureKotlin/multifileClassRemoved/b.kt.delete b/jps-plugin/testData/incremental/pureKotlin/multifileClassRemoved/b.kt.delete new file mode 100644 index 00000000000..e69de29bb2d diff --git a/jps-plugin/testData/incremental/pureKotlin/multifileClassRemoved/build.log b/jps-plugin/testData/incremental/pureKotlin/multifileClassRemoved/build.log new file mode 100644 index 00000000000..663b207d00c --- /dev/null +++ b/jps-plugin/testData/incremental/pureKotlin/multifileClassRemoved/build.log @@ -0,0 +1,11 @@ +Cleaning output files: +out/production/module/META-INF/module.kotlin_module +out/production/module/test/Test.class +out/production/module/test/TestPackage.class +out/production/module/test/Test__AKt.class +End of files +Cleaning output files: +out/production/module/test/Test__BKt.class +End of files +Compiling files: +End of files \ No newline at end of file