Incremental compilation support for multifile classes.

This commit is contained in:
Dmitry Petrov
2015-09-23 17:10:42 +03:00
parent ea8ada4664
commit 3dfe9951ef
57 changed files with 689 additions and 75 deletions
@@ -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();
}
}
@@ -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,
@@ -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() }
@@ -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?
@@ -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 {
@@ -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()
@@ -0,0 +1,6 @@
@file:[JvmName("Test") JvmMultifileClass]
val property = "K"
inline fun K(body: () -> String): String =
body() + property
@@ -0,0 +1,4 @@
fun main(args: Array<String>) {
val ok = K { "O" }
if (ok != "OK") throw java.lang.AssertionError("Expected: OK, actual: $ok")
}
@@ -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/");
@@ -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"
@@ -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
@@ -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("Test1") JvmMultifileClass]
package test
fun b() = "b"
@@ -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
@@ -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
@@ -0,0 +1,7 @@
@file:[JvmName("Test") JvmMultifileClass]
package test
inline fun f(body: () -> Unit) {
println("i'm inline function")
body()
}
@@ -0,0 +1,7 @@
@file:[JvmName("Test") JvmMultifileClass]
package other
inline fun f(body: () -> Unit) {
println("i'm other inline function")
body()
}
@@ -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,6 @@
package test
fun main(args: Array<String>) {
f { println("to be inlined") }
other.f { println("to be inlined") }
}
@@ -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
@@ -0,0 +1,9 @@
@file:[JvmName("Test") JvmMultifileClass]
package test
val property = ":)"
inline fun f(body: () -> Unit) {
println("i'm inline function" + property)
body()
}
@@ -0,0 +1,9 @@
@file:[JvmName("Test") JvmMultifileClass]
package other
val property = ":)"
inline fun f(body: () -> Unit) {
println("i'm inline function" + property)
body()
}
@@ -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,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"
@@ -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
@@ -0,0 +1,4 @@
@file:[JvmName("Test") JvmMultifileClass]
package test
fun a() = "a"
@@ -0,0 +1,4 @@
@file:[JvmName("Test2") JvmMultifileClass]
package test2
fun a() = "a"
@@ -0,0 +1,4 @@
@file:[JvmName("Test") JvmMultifileClass]
package test
fun b() = "b"
@@ -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