Incremental compilation support for multifile classes.
This commit is contained in:
@@ -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;");
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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<FqName> obsoleteMultifileClasses = new HashSet<FqName>(state.getObsoleteMultifileClasses());
|
||||
for (FqName multifileClassFqName : Sets.union(filesInMultifileClasses.keySet(), obsoleteMultifileClasses)) {
|
||||
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled();
|
||||
generateMultifileClass(state, multifileClassFqName, filesInMultifileClasses.get(multifileClassFqName), errorHandler);
|
||||
}
|
||||
|
||||
Set<FqName> packagesWithObsoleteParts = new HashSet<FqName>(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();
|
||||
}
|
||||
|
||||
@@ -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<DeserializedCallableMemberDescriptor>()
|
||||
else
|
||||
getDeserializedCallables(compiledPackageFragment)
|
||||
|
||||
private fun getDeserializedCallables(compiledPackageFragment: PackageFragmentDescriptor) =
|
||||
compiledPackageFragment.getMemberScope().getDescriptors(DescriptorKindFilter.CALLABLES, JetScope.ALL_NAME_FILTER).filterIsInstance<DeserializedCallableMemberDescriptor>()
|
||||
|
||||
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<CallableMemberDescriptor, () -> Unit>()
|
||||
val partFqNames = arrayListOf<FqName>()
|
||||
|
||||
generateCodeForSourceFiles(errorHandler, generateCallableMemberTasks, partFqNames)
|
||||
|
||||
generateDelegatesToPreviouslyCompiledParts(generateCallableMemberTasks, partFqNames)
|
||||
|
||||
if (!generateCallableMemberTasks.isEmpty()) {
|
||||
generateMultifileFacadeClass(generateCallableMemberTasks, partFqNames)
|
||||
}
|
||||
}
|
||||
|
||||
private fun generateCodeForSourceFiles(
|
||||
errorHandler: CompilationErrorHandler,
|
||||
generateCallableMemberTasks: MutableMap<CallableMemberDescriptor, () -> Unit>,
|
||||
partFqNames: MutableList<FqName>
|
||||
) {
|
||||
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<CallableMemberDescriptor, () -> Unit>,
|
||||
partFqNames: MutableList<FqName>
|
||||
) {
|
||||
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, "<clinit>", "()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)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<JetFile> files;
|
||||
private final Type packageClassType;
|
||||
private final PackageFragmentDescriptor packageFragment;
|
||||
private final PackageFragmentDescriptor compiledPackageFragment;
|
||||
private final IncrementalPackageFragmentProvider.IncrementalPackageFragment compiledPackageFragment;
|
||||
private final List<DeserializedCallableMemberDescriptor> 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<CallableMemberDescriptor, Runnable> 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<JvmSerializationBindings> bindings = new ArrayList<JvmSerializationBindings>(files.size() + 1);
|
||||
|
||||
@@ -302,12 +321,17 @@ public class PackageCodegen {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private ClassBuilder generateFile(@NotNull JetFile file, @NotNull Map<CallableMemberDescriptor, Runnable> generateCallableMemberTasks) {
|
||||
private ClassBuilder generateFile(
|
||||
@NotNull JetFile file,
|
||||
@NotNull Map<CallableMemberDescriptor, Runnable> 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<CallableMemberDescriptor, Runnable> 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()) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -185,8 +185,8 @@ public abstract class CodegenContext<T extends DeclarationDescriptor> {
|
||||
}
|
||||
|
||||
@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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 ?
|
||||
|
||||
@@ -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<FqName> = emptySet(),
|
||||
public val obsoleteMultifileClasses: Collection<FqName> = emptySet(),
|
||||
// for PackageCodegen in incremental compilation mode
|
||||
public val targetId: TargetId? = null,
|
||||
moduleName: String? = null,
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
+11
@@ -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<FqName> packagesWithObsoleteParts;
|
||||
List<FqName> 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<FqName>();
|
||||
for (String internalName : incrementalCache.getObsoletePackageParts()) {
|
||||
packagesWithObsoleteParts.add(JvmClassName.byInternalName(internalName).getPackageFqName());
|
||||
}
|
||||
|
||||
obsoleteMultifileClasses = new ArrayList<FqName>();
|
||||
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,
|
||||
|
||||
+31
@@ -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<String>
|
||||
) : 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<JetScope>())
|
||||
}
|
||||
}
|
||||
|
||||
override fun getMemberScope(): JetScope = memberScope()
|
||||
}
|
||||
|
||||
private inner class IncrementalPackageScope(val packageData: PackageData) : DeserializedPackageMemberScope(
|
||||
this@IncrementalPackageFragment, packageData.packageProto, packageData.nameResolver, deserializationComponents,
|
||||
{ listOf() }
|
||||
|
||||
+6
@@ -23,6 +23,12 @@ data class JvmPackagePartProto(val data: ByteArray, val strings: Array<String>)
|
||||
public interface IncrementalCache {
|
||||
public fun getObsoletePackageParts(): Collection<String>
|
||||
|
||||
public fun getObsoleteMultifileClasses(): Collection<String>
|
||||
|
||||
public fun getStableMultifileFacadeParts(facadeInternalName: String): Collection<String>?
|
||||
|
||||
public fun getMultifileFacade(partInternalName: String): String?
|
||||
|
||||
public fun getPackagePartData(fqName: String): JvmPackagePartProto?
|
||||
|
||||
public fun getModuleMappingData(): ByteArray?
|
||||
|
||||
+6
@@ -31,6 +31,12 @@ public class RemoteIncrementalCacheServer(val cache: IncrementalCache, port: Int
|
||||
|
||||
override fun getObsoletePackageParts(): Collection<String> = cache.getObsoletePackageParts()
|
||||
|
||||
override fun getObsoleteMultifileClassFacades(): Collection<String> = cache.getObsoleteMultifileClasses()
|
||||
|
||||
override fun getMultifileFacadeParts(internalName: String): Collection<String>? = 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()
|
||||
|
||||
@@ -34,6 +34,12 @@ public interface CompileService : Remote {
|
||||
@Throws(RemoteException::class)
|
||||
public fun getObsoletePackageParts(): Collection<String>
|
||||
|
||||
@Throws(RemoteException::class)
|
||||
public fun getObsoleteMultifileClassFacades(): Collection<String>
|
||||
|
||||
@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<String>?
|
||||
}
|
||||
|
||||
public interface RemoteLookupTracker : Remote {
|
||||
|
||||
+6
@@ -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<String> = cache.getObsoleteMultifileClassFacades()
|
||||
|
||||
override fun getStableMultifileFacadeParts(facadeInternalName: String): Collection<String>? = cache.getMultifileFacadeParts(facadeInternalName)
|
||||
|
||||
override fun getObsoletePackageParts(): Collection<String> = 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()
|
||||
|
||||
Vendored
+6
@@ -0,0 +1,6 @@
|
||||
@file:[JvmName("Test") JvmMultifileClass]
|
||||
|
||||
val property = "K"
|
||||
|
||||
inline fun K(body: () -> String): String =
|
||||
body() + property
|
||||
Vendored
+4
@@ -0,0 +1,4 @@
|
||||
fun main(args: Array<String>) {
|
||||
val ok = K { "O" }
|
||||
if (ok != "OK") throw java.lang.AssertionError("Expected: OK, actual: $ok")
|
||||
}
|
||||
+6
@@ -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");
|
||||
|
||||
@@ -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<String> {
|
||||
val obsoleteMultifileClasses = linkedSetOf<String>()
|
||||
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<String>? {
|
||||
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<List<String>>(storageFile, StringListExternalizer) {
|
||||
public fun add(facadeName: JvmClassName, partNames: List<String>) {
|
||||
storage.put(facadeName.internalName, partNames)
|
||||
}
|
||||
|
||||
public fun getMultifileClassParts(facadeName: String): List<String>? = storage[facadeName]
|
||||
|
||||
public fun remove(className: JvmClassName) {
|
||||
storage.remove(className.internalName)
|
||||
}
|
||||
|
||||
override fun dumpValue(value: List<String>): String = value.toString()
|
||||
}
|
||||
|
||||
private inner class MultifileClassPartMap(storageFile: File) : BasicStringMap<String>(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<List<String>>(storageFile, PathStringDescriptor.INSTANCE, StringListExternalizer) {
|
||||
public fun clearOutputsForSource(sourceFile: File) {
|
||||
storage.remove(sourceFile.absolutePath)
|
||||
@@ -543,6 +614,8 @@ public class IncrementalCacheImpl(
|
||||
public fun getDirtyOutputClasses(): Collection<String> =
|
||||
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<String> {
|
||||
val classHeader = kotlinClass.classHeader
|
||||
val partClassNames = classHeader.filePartClassNames ?: throw AssertionError("Multifile class has no parts: ${kotlinClass.className}")
|
||||
val fullNames = arrayListOf<String>()
|
||||
for (shortName in partClassNames) {
|
||||
fullNames.add(getInternalNameOfTopLevelClassInTheSamePackage(kotlinClass, shortName))
|
||||
}
|
||||
return fullNames
|
||||
}
|
||||
|
||||
private abstract class StringMapExternalizer<T> : DataExternalizer<Map<String, T>> {
|
||||
override fun save(out: DataOutput, map: Map<String, T>?) {
|
||||
out.writeInt(map!!.size())
|
||||
@@ -698,6 +786,9 @@ private object PathCollectionExternalizer : DataExternalizer<Collection<String>>
|
||||
}
|
||||
}
|
||||
|
||||
private val File.normalizedPath: String
|
||||
get() = FileUtil.toSystemIndependentName(canonicalPath)
|
||||
|
||||
@TestOnly
|
||||
private fun <K : Comparable<K>, V> Map<K, V>.dumpMap(dumpValue: (V)->String): String =
|
||||
StringBuilder {
|
||||
|
||||
@@ -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/");
|
||||
|
||||
+3
-3
@@ -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()
|
||||
}
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
@file:[JvmName("Test") JvmMultifileClass]
|
||||
package test
|
||||
|
||||
fun a() = "a"
|
||||
@@ -0,0 +1,4 @@
|
||||
@file:[JvmName("Test") JvmMultifileClass]
|
||||
package test
|
||||
|
||||
fun b() = "b"
|
||||
@@ -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
|
||||
@@ -0,0 +1,4 @@
|
||||
@file:[JvmName("Test") JvmMultifileClass]
|
||||
package test
|
||||
|
||||
fun a() = "a"
|
||||
@@ -0,0 +1,4 @@
|
||||
@file:[JvmName("Test") JvmMultifileClass]
|
||||
package test
|
||||
|
||||
fun b() = "b"
|
||||
@@ -0,0 +1,4 @@
|
||||
@file:[JvmName("Test") JvmMultifileClass]
|
||||
package test
|
||||
|
||||
fun b() = "bcd"
|
||||
+9
@@ -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
|
||||
Vendored
+4
@@ -0,0 +1,4 @@
|
||||
@file:[JvmName("Test") JvmMultifileClass]
|
||||
package test
|
||||
|
||||
fun a() = "a"
|
||||
Vendored
+4
@@ -0,0 +1,4 @@
|
||||
@file:[JvmName("Test") JvmMultifileClass]
|
||||
package test
|
||||
|
||||
fun b() = "b"
|
||||
Vendored
+4
@@ -0,0 +1,4 @@
|
||||
@file:[JvmName("Test1") JvmMultifileClass]
|
||||
package test
|
||||
|
||||
fun b() = "b"
|
||||
Vendored
+18
@@ -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
|
||||
+8
@@ -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
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
@file:[JvmName("Test") JvmMultifileClass]
|
||||
package test
|
||||
|
||||
inline fun f(body: () -> Unit) {
|
||||
println("i'm inline function")
|
||||
body()
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
@file:[JvmName("Test") JvmMultifileClass]
|
||||
package other
|
||||
|
||||
inline fun f(body: () -> Unit) {
|
||||
println("i'm other inline function")
|
||||
body()
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
package test
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
f { println("to be inlined") }
|
||||
other.f { println("to be inlined") }
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
package test
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
f { println("to be inlined") }
|
||||
other.f { println("to be inlined") }
|
||||
}
|
||||
Vendored
+8
@@ -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
|
||||
Vendored
+9
@@ -0,0 +1,9 @@
|
||||
@file:[JvmName("Test") JvmMultifileClass]
|
||||
package test
|
||||
|
||||
val property = ":)"
|
||||
|
||||
inline fun f(body: () -> Unit) {
|
||||
println("i'm inline function" + property)
|
||||
body()
|
||||
}
|
||||
jps-plugin/testData/incremental/pureKotlin/multifileClassInlineFunctionAccessingField/inlineOther.kt
Vendored
+9
@@ -0,0 +1,9 @@
|
||||
@file:[JvmName("Test") JvmMultifileClass]
|
||||
package other
|
||||
|
||||
val property = ":)"
|
||||
|
||||
inline fun f(body: () -> Unit) {
|
||||
println("i'm inline function" + property)
|
||||
body()
|
||||
}
|
||||
Vendored
+6
@@ -0,0 +1,6 @@
|
||||
package test
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
f { println("to be inlined") }
|
||||
other.f { println("to be inlined") }
|
||||
}
|
||||
Vendored
+6
@@ -0,0 +1,6 @@
|
||||
package test
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
f { println("to be inlined") }
|
||||
other.f { println("to be inlined") }
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
@file:[JvmName("Test") JvmMultifileClass]
|
||||
package test
|
||||
|
||||
fun a() = "a"
|
||||
+1
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
@file:[JvmName("Test") JvmMultifileClass]
|
||||
package test
|
||||
|
||||
fun b() = "b"
|
||||
@@ -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
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
@file:[JvmName("Test") JvmMultifileClass]
|
||||
package test
|
||||
|
||||
fun a() = "a"
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
@file:[JvmName("Test2") JvmMultifileClass]
|
||||
package test2
|
||||
|
||||
fun a() = "a"
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
@file:[JvmName("Test") JvmMultifileClass]
|
||||
package test
|
||||
|
||||
fun b() = "b"
|
||||
+23
@@ -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
|
||||
@@ -0,0 +1,4 @@
|
||||
@file:[JvmName("Test") JvmMultifileClass]
|
||||
package test
|
||||
|
||||
fun a() = "a"
|
||||
@@ -0,0 +1,4 @@
|
||||
@file:[JvmName("Test") JvmMultifileClass]
|
||||
package test
|
||||
|
||||
fun b() = "b"
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user